add feature to enable/disable markers
[ust.git] / libustcomm / ustcomm.c
1 #define _GNU_SOURCE
2 #include <sys/types.h>
3 #include <signal.h>
4 #include <errno.h>
5 #include <sys/socket.h>
6 #include <sys/un.h>
7 #include <unistd.h>
8 #include <poll.h>
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <execinfo.h>
14
15 #include "ustcomm.h"
16 #include "localerr.h"
17
18 #define UNIX_PATH_MAX 108
19 #define SOCK_DIR "/tmp/socks"
20 #define UST_SIGNAL SIGIO
21
22 #define MSG_MAX 1000
23
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
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 //}
37
38 char *strdup_malloc(const char *s)
39 {
40 char *retval;
41
42 if(s == NULL)
43 return NULL;
44
45 retval = (char *) malloc(strlen(s)+1);
46
47 strcpy(retval, s);
48
49 return retval;
50 }
51
52 static int signal_process(pid_t pid)
53 {
54 int result;
55
56 result = kill(pid, UST_SIGNAL);
57 if(result == -1) {
58 PERROR("kill");
59 return -1;
60 }
61
62 /* FIXME: should wait in a better way */
63 //sleep(1);
64
65 return 0;
66 }
67
68 static int send_message_fd(int fd, const char *msg)
69 {
70 int result;
71
72 result = send(fd, msg, strlen(msg), 0);
73 if(result == -1) {
74 PERROR("send");
75 return -1;
76 }
77 else if(result == 0) {
78 return 0;
79 }
80
81 return 1;
82
83 // *reply = (char *) malloc(MSG_MAX+1);
84 // result = recv(fd, *reply, MSG_MAX, 0);
85 // if(result == -1) {
86 // PERROR("recv");
87 // return -1;
88 // }
89 // else if(result == 0) {
90 // return 0;
91 // }
92 //
93 // (*reply)[result] = '\0';
94 //
95 // return 1;
96 }
97
98 static int send_message_path(const char *path, const char *msg, int signalpid)
99 {
100 int fd;
101 int result;
102 struct sockaddr_un addr;
103
104 result = fd = socket(PF_UNIX, SOCK_STREAM, 0);
105 if(result == -1) {
106 PERROR("socket");
107 return -1;
108 }
109
110 addr.sun_family = AF_UNIX;
111
112 result = snprintf(addr.sun_path, UNIX_PATH_MAX, "%s", path);
113 if(result >= UNIX_PATH_MAX) {
114 ERR("string overflow allocating socket name");
115 return -1;
116 }
117
118 if(signalpid >= 0) {
119 result = signal_process(signalpid);
120 if(result == -1) {
121 ERR("could not signal process");
122 return -1;
123 }
124 }
125
126 result = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
127 if(result == -1) {
128 PERROR("connect");
129 return -1;
130 }
131
132 return send_message_fd(fd, msg);
133 }
134
135 ///* pid: the pid of the trace process that must receive the msg
136 // msg: pointer to a null-terminated message to send
137 // reply: location where to put the null-terminated string of the reply;
138 // it must be free'd after usage
139 // */
140 //
141 //int send_message_pid(pid_t pid, const char *msg, char **reply)
142 //{
143 // int result;
144 // char path[UNIX_PATH_MAX];
145 //
146 // result = snprintf(path, UNIX_PATH_MAX, "%s/%d", SOCK_DIR, pid);
147 // if(result >= UNIX_PATH_MAX) {
148 // fprintf(stderr, "string overflow allocating socket name");
149 // return -1;
150 // }
151 //
152 // send_message_path(path, msg, reply, pid);
153 //
154 // return 0;
155 //}
156
157 /* Called by an app to ask the consumer daemon to connect to it. */
158
159 int ustcomm_request_consumer(pid_t pid, const char *channel)
160 {
161 char path[UNIX_PATH_MAX];
162 int result;
163 char *msg;
164
165 result = snprintf(path, UNIX_PATH_MAX, "%s/ustd", SOCK_DIR);
166 if(result >= UNIX_PATH_MAX) {
167 fprintf(stderr, "string overflow allocating socket name");
168 return -1;
169 }
170
171 asprintf(&msg, "collect %d %s", pid, channel);
172
173 send_message_path(path, msg, -1);
174 free(msg);
175
176 return 0;
177 }
178
179 /* returns 1 to indicate a message was received
180 * returns 0 to indicate no message was received (cannot happen)
181 * returns -1 to indicate an error
182 */
183
184 static int recv_message_fd(int fd, char **msg, struct ustcomm_source *src)
185 {
186 int result;
187
188 *msg = (char *) malloc(MSG_MAX+1);
189
190 result = recv(fd, *msg, MSG_MAX, 0);
191 if(result == -1) {
192 PERROR("recv");
193 return -1;
194 }
195
196 (*msg)[result] = '\0';
197
198 DBG("ustcomm_app_recv_message: result is %d, message is %s", result, (*msg));
199
200 if(src)
201 src->fd = fd;
202
203 return 1;
204 }
205
206 int ustcomm_send_reply(struct ustcomm_server *server, char *msg, struct ustcomm_source *src)
207 {
208 int result;
209
210 result = send_message_fd(src->fd, msg);
211 if(result < 0) {
212 ERR("error in send_message_fd");
213 return -1;
214 }
215
216 return 0;
217 }
218
219 /* @timeout: max blocking time in milliseconds, -1 means infinity
220 *
221 * returns 1 to indicate a message was received
222 * returns 0 to indicate no message was received
223 * returns -1 to indicate an error
224 */
225
226 int ustcomm_recv_message(struct ustcomm_server *server, char **msg, struct ustcomm_source *src, int timeout)
227 {
228 struct pollfd *fds;
229 struct ustcomm_connection *conn;
230 int result;
231 int retval;
232
233 for(;;) {
234 int idx = 0;
235 int n_fds = 1;
236
237 list_for_each_entry(conn, &server->connections, list) {
238 n_fds++;
239 }
240
241 fds = (struct pollfd *) malloc(n_fds * sizeof(struct pollfd));
242 if(fds == NULL) {
243 ERR("malloc returned NULL");
244 return -1;
245 }
246
247 /* special idx 0 is for listening socket */
248 fds[idx].fd = server->listen_fd;
249 fds[idx].events = POLLIN;
250 idx++;
251
252 list_for_each_entry(conn, &server->connections, list) {
253 fds[idx].fd = conn->fd;
254 fds[idx].events = POLLIN;
255 idx++;
256 }
257
258 result = poll(fds, n_fds, timeout);
259 if(result == -1) {
260 PERROR("poll");
261 return -1;
262 }
263
264 if(result == 0)
265 return 0;
266
267 if(fds[0].revents) {
268 struct ustcomm_connection *newconn;
269 int newfd;
270
271 result = newfd = accept(server->listen_fd, NULL, NULL);
272 if(result == -1) {
273 PERROR("accept");
274 return -1;
275 }
276
277 newconn = (struct ustcomm_connection *) malloc(sizeof(struct ustcomm_connection));
278 if(newconn == NULL) {
279 ERR("malloc returned NULL");
280 return -1;
281 }
282
283 newconn->fd = newfd;
284
285 list_add(&newconn->list, &server->connections);
286 }
287
288 for(idx=1; idx<n_fds; idx++) {
289 if(fds[idx].revents) {
290 retval = recv_message_fd(fds[idx].fd, msg, src);
291 if(**msg == 0) {
292 /* connection finished */
293 close(fds[idx].fd);
294
295 list_for_each_entry(conn, &server->connections, list) {
296 if(conn->fd == fds[idx].fd) {
297 list_del(&conn->list);
298 break;
299 }
300 }
301 }
302 else {
303 goto free_fds_return;
304 }
305 }
306 }
307
308 free(fds);
309 }
310
311 free_fds_return:
312 free(fds);
313 return retval;
314 }
315
316 int ustcomm_ustd_recv_message(struct ustcomm_ustd *ustd, char **msg, struct ustcomm_source *src, int timeout)
317 {
318 return ustcomm_recv_message(&ustd->server, msg, src, timeout);
319 }
320
321 int ustcomm_app_recv_message(struct ustcomm_app *app, char **msg, struct ustcomm_source *src, int timeout)
322 {
323 return ustcomm_recv_message(&app->server, msg, src, timeout);
324 }
325
326 /* This removes src from the list of active connections of app.
327 */
328
329 int ustcomm_app_detach_client(struct ustcomm_app *app, struct ustcomm_source *src)
330 {
331 struct ustcomm_server *server = (struct ustcomm_server *)app;
332 struct ustcomm_connection *conn;
333
334 list_for_each_entry(conn, &server->connections, list) {
335 if(conn->fd == src->fd) {
336 list_del(&conn->list);
337 goto found;
338 }
339 }
340
341 return -1;
342 found:
343 return src->fd;
344 }
345
346 static int init_named_socket(char *name, char **path_out)
347 {
348 int result;
349 int fd;
350
351 struct sockaddr_un addr;
352
353 result = fd = socket(PF_UNIX, SOCK_STREAM, 0);
354 if(result == -1) {
355 PERROR("socket");
356 return -1;
357 }
358
359 addr.sun_family = AF_UNIX;
360
361 strncpy(addr.sun_path, name, UNIX_PATH_MAX);
362 addr.sun_path[UNIX_PATH_MAX-1] = '\0';
363
364 result = access(name, F_OK);
365 if(result == 0) {
366 /* file exists */
367 result = unlink(name);
368 if(result == -1) {
369 PERROR("unlink of socket file");
370 goto close_sock;
371 }
372 WARN("socket already exists; overwriting");
373 }
374
375 result = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
376 if(result == -1) {
377 PERROR("bind");
378 goto close_sock;
379 }
380
381 result = listen(fd, 1);
382 if(result == -1) {
383 PERROR("listen");
384 goto close_sock;
385 }
386
387 if(path_out) {
388 *path_out = "";
389 *path_out = strdupa(addr.sun_path);
390 }
391
392 return fd;
393
394 close_sock:
395 close(fd);
396
397 return -1;
398 }
399
400 int ustcomm_send_request(struct ustcomm_connection *conn, char *req, char **reply)
401 {
402 int result;
403
404 result = send(conn->fd, req, strlen(req), 0);
405 if(result == -1) {
406 PERROR("send");
407 return -1;
408 }
409
410 if(!reply)
411 return 1;
412
413 *reply = (char *) malloc(MSG_MAX+1);
414 result = recv(conn->fd, *reply, MSG_MAX, 0);
415 if(result == -1) {
416 PERROR("recv");
417 return -1;
418 }
419 else if(result == 0) {
420 return 0;
421 }
422
423 (*reply)[result] = '\0';
424
425 return 1;
426 }
427
428 int ustcomm_connect_path(char *path, struct ustcomm_connection *conn, pid_t signalpid)
429 {
430 int fd;
431 int result;
432 struct sockaddr_un addr;
433
434 result = fd = socket(PF_UNIX, SOCK_STREAM, 0);
435 if(result == -1) {
436 PERROR("socket");
437 return -1;
438 }
439
440 addr.sun_family = AF_UNIX;
441
442 result = snprintf(addr.sun_path, UNIX_PATH_MAX, "%s", path);
443 if(result >= UNIX_PATH_MAX) {
444 ERR("string overflow allocating socket name");
445 return -1;
446 }
447
448 if(signalpid >= 0) {
449 result = signal_process(signalpid);
450 if(result == -1) {
451 ERR("could not signal process");
452 return -1;
453 }
454 }
455
456 result = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
457 if(result == -1) {
458 PERROR("connect");
459 return -1;
460 }
461
462 conn->fd = fd;
463
464 return 0;
465 }
466
467 int ustcomm_disconnect(struct ustcomm_connection *conn)
468 {
469 return close(conn->fd);
470 }
471
472 int ustcomm_connect_app(pid_t pid, struct ustcomm_connection *conn)
473 {
474 int result;
475 char path[UNIX_PATH_MAX];
476
477
478 result = snprintf(path, UNIX_PATH_MAX, "%s/%d", SOCK_DIR, pid);
479 if(result >= UNIX_PATH_MAX) {
480 fprintf(stderr, "string overflow allocating socket name");
481 return -1;
482 }
483
484 return ustcomm_connect_path(path, conn, pid);
485 }
486
487 int ustcomm_disconnect_app(struct ustcomm_connection *conn)
488 {
489 close(conn->fd);
490 return 0;
491 }
492
493 int ustcomm_init_app(pid_t pid, struct ustcomm_app *handle)
494 {
495 int result;
496 char *name;
497
498 result = asprintf(&name, "%s/%d", SOCK_DIR, (int)pid);
499 if(result >= UNIX_PATH_MAX) {
500 ERR("string overflow allocating socket name");
501 return -1;
502 }
503
504 handle->server.listen_fd = init_named_socket(name, &(handle->server.socketpath));
505 if(handle->server.listen_fd < 0) {
506 ERR("error initializing named socket");
507 goto free_name;
508 }
509 free(name);
510
511 INIT_LIST_HEAD(&handle->server.connections);
512
513 return 0;
514
515 free_name:
516 free(name);
517 return -1;
518 }
519
520 int ustcomm_init_ustd(struct ustcomm_ustd *handle)
521 {
522 int result;
523 char *name;
524
525 result = asprintf(&name, "%s/%s", SOCK_DIR, "ustd");
526 if(result >= UNIX_PATH_MAX) {
527 ERR("string overflow allocating socket name");
528 return -1;
529 }
530
531 handle->server.listen_fd = init_named_socket(name, &handle->server.socketpath);
532 if(handle->server.listen_fd < 0) {
533 ERR("error initializing named socket at %s", name);
534 goto free_name;
535 }
536 free(name);
537
538 INIT_LIST_HEAD(&handle->server.connections);
539
540 return 0;
541
542 free_name:
543 free(name);
544 return -1;
545 }
546
547 static char *find_tok(char *str)
548 {
549 while(*str == ' ') {
550 str++;
551
552 if(*str == 0)
553 return NULL;
554 }
555
556 return str;
557 }
558
559 static char *find_sep(char *str)
560 {
561 while(*str != ' ') {
562 str++;
563
564 if(*str == 0)
565 break;
566 }
567
568 return str;
569 }
570
571 int nth_token_is(char *str, char *token, int tok_no)
572 {
573 int i;
574 char *start;
575 char *end;
576
577 for(i=0; i<=tok_no; i++) {
578 str = find_tok(str);
579 if(str == NULL)
580 return -1;
581
582 start = str;
583
584 str = find_sep(str);
585 if(str == NULL)
586 return -1;
587
588 end = str;
589 }
590
591 if(end-start != strlen(token))
592 return 0;
593
594 if(strncmp(start, token, end-start))
595 return 0;
596
597 return 1;
598 }
599
600 char *nth_token(char *str, int tok_no)
601 {
602 static char *retval = NULL;
603 int i;
604 char *start;
605 char *end;
606
607 for(i=0; i<=tok_no; i++) {
608 str = find_tok(str);
609 if(str == NULL)
610 return NULL;
611
612 start = str;
613
614 str = find_sep(str);
615 if(str == NULL)
616 return NULL;
617
618 end = str;
619 }
620
621 if(retval) {
622 free(retval);
623 retval = NULL;
624 }
625
626 asprintf(&retval, "%.*s", (int)(end-start), start);
627
628 return retval;
629 }
630
This page took 0.042737 seconds and 4 git commands to generate.