ust: add info exchange between app and ustd
[ust.git] / libustcomm / ustcomm.c
CommitLineData
d0b5f2b9 1#define _GNU_SOURCE
f9e5ce61
PMF
2#include <sys/types.h>
3#include <signal.h>
4#include <errno.h>
5#include <sys/socket.h>
6#include <sys/un.h>
d0b5f2b9 7#include <unistd.h>
aca1ad90 8#include <poll.h>
f9e5ce61
PMF
9
10#include <stdio.h>
11#include <stdlib.h>
d0b5f2b9 12#include <string.h>
b0540e11 13#include <execinfo.h>
d0b5f2b9
PMF
14
15#include "ustcomm.h"
16#include "localerr.h"
f9e5ce61
PMF
17
18#define UNIX_PATH_MAX 108
19#define SOCK_DIR "/tmp/socks"
20#define UST_SIGNAL SIGIO
21
d0b5f2b9
PMF
22#define MSG_MAX 1000
23
aca1ad90
PMF
24/* FIXME: ustcomm blocks on message sending, which might be problematic in
25 * some cases. Fix the poll() usage so sends are buffered until they don't
26 * block.
27 */
28
3847c3ba
PMF
29//static void bt(void)
30//{
31// void *buffer[100];
32// int result;
33//
34// result = backtrace(&buffer, 100);
35// backtrace_symbols_fd(buffer, result, STDERR_FILENO);
36//}
b0540e11 37
f9e5ce61
PMF
38static void signal_process(pid_t pid)
39{
40 int result;
41
42 result = kill(pid, UST_SIGNAL);
43 if(result == -1) {
b0540e11 44 PERROR("kill");
f9e5ce61
PMF
45 return;
46 }
47
48 sleep(1);
49}
50
811e4b93
PMF
51int send_message_fd(int fd, const char *msg, char **reply)
52{
53 int result;
54
55 result = send(fd, msg, strlen(msg), 0);
56 if(result == -1) {
57 PERROR("send");
58 return -1;
59 }
60
61 if(!reply)
62 return 0;
63
64 *reply = (char *) malloc(MSG_MAX+1);
65 result = recv(fd, *reply, MSG_MAX, 0);
66 if(result == -1) {
67 PERROR("recv");
68 return -1;
69 }
70
71 (*reply)[result] = '\0';
72
73 return 0;
74}
75
b0540e11 76int send_message_path(const char *path, const char *msg, char **reply, int signalpid)
f9e5ce61
PMF
77{
78 int fd;
79 int result;
80 struct sockaddr_un addr;
f9e5ce61 81
aca1ad90 82 result = fd = socket(PF_UNIX, SOCK_STREAM, 0);
f9e5ce61 83 if(result == -1) {
b0540e11 84 PERROR("socket");
d0b5f2b9 85 return -1;
f9e5ce61
PMF
86 }
87
88 addr.sun_family = AF_UNIX;
89
b0540e11 90 result = snprintf(addr.sun_path, UNIX_PATH_MAX, "%s", path);
f9e5ce61 91 if(result >= UNIX_PATH_MAX) {
b0540e11 92 ERR("string overflow allocating socket name");
d0b5f2b9 93 return -1;
f9e5ce61
PMF
94 }
95
b0540e11
PMF
96 if(signalpid >= 0)
97 signal_process(signalpid);
f9e5ce61 98
aca1ad90 99 result = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
f9e5ce61 100 if(result == -1) {
aca1ad90
PMF
101 PERROR("connect");
102 return -1;
103 }
104
811e4b93 105 return send_message_fd(fd, msg, reply);
f9e5ce61
PMF
106}
107
b0540e11
PMF
108/* pid: the pid of the trace process that must receive the msg
109 msg: pointer to a null-terminated message to send
110 reply: location where to put the null-terminated string of the reply;
111 it must be free'd after usage
112 */
113
114int send_message(pid_t pid, const char *msg, char **reply)
115{
116 int result;
117 char path[UNIX_PATH_MAX];
118
119 result = snprintf(path, UNIX_PATH_MAX, "%s/%d", SOCK_DIR, pid);
120 if(result >= UNIX_PATH_MAX) {
121 fprintf(stderr, "string overflow allocating socket name");
122 return -1;
123 }
124
125 send_message_path(path, msg, reply, pid);
126
127 return 0;
128}
129
130/* Called by an app to ask the consumer daemon to connect to it. */
131
132int ustcomm_request_consumer(pid_t pid, const char *channel)
133{
134 char path[UNIX_PATH_MAX];
135 int result;
136 char *msg;
137
138 result = snprintf(path, UNIX_PATH_MAX, "%s/ustd", SOCK_DIR);
139 if(result >= UNIX_PATH_MAX) {
140 fprintf(stderr, "string overflow allocating socket name");
141 return -1;
142 }
143
144 asprintf(&msg, "collect %d %s", pid, channel);
145
3847c3ba 146 send_message_path(path, msg, NULL, -1);
b0540e11
PMF
147 free(msg);
148
149 return 0;
150}
151
811e4b93
PMF
152
153
b02e31e5 154static int recv_message_fd(int fd, char **msg, struct ustcomm_source *src)
d0b5f2b9 155{
d0b5f2b9 156 int result;
d0b5f2b9
PMF
157
158 *msg = (char *) malloc(MSG_MAX+1);
b02e31e5 159
aca1ad90 160 result = recv(fd, *msg, MSG_MAX, 0);
d0b5f2b9
PMF
161 if(result == -1) {
162 PERROR("recvfrom");
163 return -1;
164 }
b0540e11 165
d0b5f2b9 166 (*msg)[result] = '\0';
b0540e11
PMF
167
168 DBG("ustcomm_app_recv_message: result is %d, message is %s", result, (*msg));
169
811e4b93
PMF
170 if(src)
171 src->fd = fd;
172
d0b5f2b9
PMF
173 return 0;
174}
175
811e4b93
PMF
176int ustcomm_send_reply(struct ustcomm_server *server, char *msg, struct ustcomm_source *src)
177{
178 int result;
179
180 result = send_message_fd(src->fd, msg, NULL);
181 if(result) {
182 ERR("error in send_message_fd");
183 return -1;
184 }
185
186 return 0;
187}
188
189int ustcomm_recv_message(struct ustcomm_server *server, char **msg, struct ustcomm_source *src)
b0540e11 190{
aca1ad90
PMF
191 struct pollfd *fds;
192 struct ustcomm_connection *conn;
193 int result;
194 int retval;
195
196 for(;;) {
197 int idx = 0;
198 int n_fds = 1;
199
811e4b93 200 list_for_each_entry(conn, &server->connections, list) {
aca1ad90
PMF
201 n_fds++;
202 }
203
204 fds = (struct pollfd *) malloc(n_fds * sizeof(struct pollfd));
205 if(fds == NULL) {
206 ERR("malloc returned NULL");
207 return -1;
208 }
209
210 /* special idx 0 is for listening socket */
811e4b93 211 fds[idx].fd = server->listen_fd;
aca1ad90
PMF
212 fds[idx].events = POLLIN;
213 idx++;
214
811e4b93 215 list_for_each_entry(conn, &server->connections, list) {
aca1ad90
PMF
216 fds[idx].fd = conn->fd;
217 fds[idx].events = POLLIN;
218 idx++;
219 }
220
221 result = poll(fds, n_fds, -1);
222 if(result == -1) {
223 PERROR("poll");
224 return -1;
225 }
226
227 if(fds[0].revents) {
228 struct ustcomm_connection *newconn;
229 int newfd;
230
811e4b93 231 result = newfd = accept(server->listen_fd, NULL, NULL);
aca1ad90
PMF
232 if(result == -1) {
233 PERROR("accept");
234 return -1;
235 }
236
237 newconn = (struct ustcomm_connection *) malloc(sizeof(struct ustcomm_connection));
238 if(newconn == NULL) {
239 ERR("malloc returned NULL");
240 return -1;
241 }
242
243 newconn->fd = newfd;
244
811e4b93 245 list_add(&newconn->list, &server->connections);
aca1ad90
PMF
246 }
247
248 for(idx=1; idx<n_fds; idx++) {
249 if(fds[idx].revents) {
250 retval = recv_message_fd(fds[idx].fd, msg, src);
251 if(**msg == 0) {
252 /* connection finished */
253 close(fds[idx].fd);
254
811e4b93 255 list_for_each_entry(conn, &server->connections, list) {
aca1ad90
PMF
256 if(conn->fd == fds[idx].fd) {
257 list_del(&conn->list);
258 break;
259 }
260 }
261 }
262 else {
263 goto free_fds_return;
264 }
265 }
266 }
267
268 free(fds);
269 }
270
271free_fds_return:
272 free(fds);
273 return retval;
b0540e11
PMF
274}
275
811e4b93
PMF
276int ustcomm_ustd_recv_message(struct ustcomm_ustd *ustd, char **msg, struct ustcomm_source *src)
277{
278 return ustcomm_recv_message(&ustd->server, msg, src);
279}
280
b02e31e5 281int ustcomm_app_recv_message(struct ustcomm_app *app, char **msg, struct ustcomm_source *src)
b0540e11 282{
811e4b93 283 return ustcomm_recv_message(&app->server, msg, src);
b0540e11
PMF
284}
285
d0b5f2b9
PMF
286static int init_named_socket(char *name, char **path_out)
287{
288 int result;
289 int fd;
290
291 struct sockaddr_un addr;
292
aca1ad90 293 result = fd = socket(PF_UNIX, SOCK_STREAM, 0);
d0b5f2b9
PMF
294 if(result == -1) {
295 PERROR("socket");
296 return -1;
297 }
298
299 addr.sun_family = AF_UNIX;
300
301 strncpy(addr.sun_path, name, UNIX_PATH_MAX);
302 addr.sun_path[UNIX_PATH_MAX-1] = '\0';
303
aca1ad90
PMF
304 result = access(name, F_OK);
305 if(result == 0) {
306 /* file exists */
307 result = unlink(name);
308 if(result == -1) {
309 PERROR("unlink of socket file");
310 goto close_sock;
311 }
312 WARN("socket already exists; overwriting");
313 }
314
d0b5f2b9
PMF
315 result = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
316 if(result == -1) {
317 PERROR("bind");
318 goto close_sock;
319 }
320
aca1ad90
PMF
321 result = listen(fd, 1);
322 if(result == -1) {
323 PERROR("listen");
324 goto close_sock;
325 }
326
b0540e11
PMF
327 if(path_out) {
328 *path_out = "";
d0b5f2b9 329 *path_out = strdupa(addr.sun_path);
b0540e11 330 }
d0b5f2b9
PMF
331
332 return fd;
333
334 close_sock:
335 close(fd);
336
337 return -1;
338}
339
340int ustcomm_init_app(pid_t pid, struct ustcomm_app *handle)
341{
342 int result;
343 char *name;
344
345 result = asprintf(&name, "%s/%d", SOCK_DIR, (int)pid);
346 if(result >= UNIX_PATH_MAX) {
347 ERR("string overflow allocating socket name");
348 return -1;
349 }
350
811e4b93
PMF
351 handle->server.listen_fd = init_named_socket(name, &(handle->server.socketpath));
352 if(handle->server.listen_fd < 0) {
aca1ad90 353 ERR("error initializing named socket");
d0b5f2b9
PMF
354 goto free_name;
355 }
356 free(name);
357
811e4b93 358 INIT_LIST_HEAD(&handle->server.connections);
aca1ad90 359
d0b5f2b9
PMF
360 return 0;
361
362free_name:
363 free(name);
364 return -1;
365}
366
367int ustcomm_init_ustd(struct ustcomm_ustd *handle)
368{
3847c3ba
PMF
369 int result;
370 char *name;
371
372 result = asprintf(&name, "%s/%s", SOCK_DIR, "ustd");
373 if(result >= UNIX_PATH_MAX) {
374 ERR("string overflow allocating socket name");
375 return -1;
376 }
377
811e4b93
PMF
378 handle->server.listen_fd = init_named_socket(name, &handle->server.socketpath);
379 if(handle->server.listen_fd < 0) {
aca1ad90
PMF
380 ERR("error initializing named socket");
381 goto free_name;
382 }
3847c3ba 383 free(name);
d0b5f2b9 384
811e4b93 385 INIT_LIST_HEAD(&handle->server.connections);
aca1ad90 386
d0b5f2b9 387 return 0;
aca1ad90
PMF
388
389free_name:
390 free(name);
391 return -1;
d0b5f2b9 392}
b02e31e5 393
aca1ad90 394static char *find_tok(char *str)
b02e31e5
PMF
395{
396 while(*str == ' ') {
397 str++;
398
399 if(*str == 0)
400 return NULL;
401 }
402
403 return str;
404}
405
406static char *find_sep(char *str)
407{
408 while(*str != ' ') {
409 str++;
410
411 if(*str == 0)
412 break;
413 }
414
415 return str;
416}
417
418int nth_token_is(char *str, char *token, int tok_no)
419{
420 int i;
421 char *start;
422 char *end;
423
424 for(i=0; i<=tok_no; i++) {
425 str = find_tok(str);
426 if(str == NULL)
427 return -1;
428
429 start = str;
430
431 str = find_sep(str);
432 if(str == NULL)
433 return -1;
434
435 end = str;
436 }
437
438 if(end-start != strlen(token))
439 return 0;
440
441 if(strncmp(start, token, end-start))
442 return 0;
443
444 return 1;
445}
446
447char *nth_token(char *str, int tok_no)
448{
449 static char *retval = NULL;
450 int i;
451 char *start;
452 char *end;
453
454 for(i=0; i<=tok_no; i++) {
455 str = find_tok(str);
456 if(str == NULL)
457 return NULL;
458
459 start = str;
460
461 str = find_sep(str);
462 if(str == NULL)
463 return NULL;
464
465 end = str;
466 }
467
468 if(retval) {
469 free(retval);
470 retval = NULL;
471 }
472
aca1ad90 473 asprintf(&retval, "%.*s", (int)(end-start), start);
b02e31e5
PMF
474
475 return retval;
476}
477
This page took 0.040562 seconds and 4 git commands to generate.