add feature to enable/disable markers
[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
688760ef
PMF
38char *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
52c51a47 52static int signal_process(pid_t pid)
f9e5ce61
PMF
53{
54 int result;
55
56 result = kill(pid, UST_SIGNAL);
57 if(result == -1) {
b0540e11 58 PERROR("kill");
52c51a47 59 return -1;
f9e5ce61
PMF
60 }
61
3bb56863 62 /* FIXME: should wait in a better way */
52c51a47
PMF
63 //sleep(1);
64
65 return 0;
f9e5ce61
PMF
66}
67
4e2a8808 68static int send_message_fd(int fd, const char *msg)
811e4b93
PMF
69{
70 int result;
71
72 result = send(fd, msg, strlen(msg), 0);
73 if(result == -1) {
74 PERROR("send");
75 return -1;
76 }
688760ef
PMF
77 else if(result == 0) {
78 return 0;
79 }
811e4b93 80
688760ef 81 return 1;
4e2a8808
PMF
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;
811e4b93
PMF
96}
97
4e2a8808 98static int send_message_path(const char *path, const char *msg, int signalpid)
f9e5ce61
PMF
99{
100 int fd;
101 int result;
102 struct sockaddr_un addr;
f9e5ce61 103
aca1ad90 104 result = fd = socket(PF_UNIX, SOCK_STREAM, 0);
f9e5ce61 105 if(result == -1) {
b0540e11 106 PERROR("socket");
d0b5f2b9 107 return -1;
f9e5ce61
PMF
108 }
109
110 addr.sun_family = AF_UNIX;
111
b0540e11 112 result = snprintf(addr.sun_path, UNIX_PATH_MAX, "%s", path);
f9e5ce61 113 if(result >= UNIX_PATH_MAX) {
b0540e11 114 ERR("string overflow allocating socket name");
d0b5f2b9 115 return -1;
f9e5ce61
PMF
116 }
117
52c51a47
PMF
118 if(signalpid >= 0) {
119 result = signal_process(signalpid);
120 if(result == -1) {
121 ERR("could not signal process");
122 return -1;
123 }
124 }
f9e5ce61 125
aca1ad90 126 result = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
f9e5ce61 127 if(result == -1) {
aca1ad90
PMF
128 PERROR("connect");
129 return -1;
130 }
131
4e2a8808 132 return send_message_fd(fd, msg);
f9e5ce61
PMF
133}
134
4e2a8808
PMF
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//}
b0540e11
PMF
156
157/* Called by an app to ask the consumer daemon to connect to it. */
158
159int 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
4e2a8808 173 send_message_path(path, msg, -1);
b0540e11
PMF
174 free(msg);
175
176 return 0;
177}
178
688760ef
PMF
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 */
811e4b93 183
b02e31e5 184static int recv_message_fd(int fd, char **msg, struct ustcomm_source *src)
d0b5f2b9 185{
d0b5f2b9 186 int result;
d0b5f2b9
PMF
187
188 *msg = (char *) malloc(MSG_MAX+1);
b02e31e5 189
aca1ad90 190 result = recv(fd, *msg, MSG_MAX, 0);
d0b5f2b9 191 if(result == -1) {
688760ef 192 PERROR("recv");
d0b5f2b9
PMF
193 return -1;
194 }
b0540e11 195
d0b5f2b9 196 (*msg)[result] = '\0';
b0540e11
PMF
197
198 DBG("ustcomm_app_recv_message: result is %d, message is %s", result, (*msg));
199
811e4b93
PMF
200 if(src)
201 src->fd = fd;
202
688760ef 203 return 1;
d0b5f2b9
PMF
204}
205
811e4b93
PMF
206int ustcomm_send_reply(struct ustcomm_server *server, char *msg, struct ustcomm_source *src)
207{
208 int result;
209
4e2a8808 210 result = send_message_fd(src->fd, msg);
3a7b90de 211 if(result < 0) {
811e4b93
PMF
212 ERR("error in send_message_fd");
213 return -1;
214 }
215
216 return 0;
217}
218
688760ef
PMF
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
226int ustcomm_recv_message(struct ustcomm_server *server, char **msg, struct ustcomm_source *src, int timeout)
b0540e11 227{
aca1ad90
PMF
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
811e4b93 237 list_for_each_entry(conn, &server->connections, list) {
aca1ad90
PMF
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 */
811e4b93 248 fds[idx].fd = server->listen_fd;
aca1ad90
PMF
249 fds[idx].events = POLLIN;
250 idx++;
251
811e4b93 252 list_for_each_entry(conn, &server->connections, list) {
aca1ad90
PMF
253 fds[idx].fd = conn->fd;
254 fds[idx].events = POLLIN;
255 idx++;
256 }
257
688760ef 258 result = poll(fds, n_fds, timeout);
aca1ad90
PMF
259 if(result == -1) {
260 PERROR("poll");
261 return -1;
262 }
263
688760ef
PMF
264 if(result == 0)
265 return 0;
266
aca1ad90
PMF
267 if(fds[0].revents) {
268 struct ustcomm_connection *newconn;
269 int newfd;
270
811e4b93 271 result = newfd = accept(server->listen_fd, NULL, NULL);
aca1ad90
PMF
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
811e4b93 285 list_add(&newconn->list, &server->connections);
aca1ad90
PMF
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
811e4b93 295 list_for_each_entry(conn, &server->connections, list) {
aca1ad90
PMF
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
311free_fds_return:
312 free(fds);
313 return retval;
b0540e11
PMF
314}
315
688760ef 316int ustcomm_ustd_recv_message(struct ustcomm_ustd *ustd, char **msg, struct ustcomm_source *src, int timeout)
811e4b93 317{
688760ef 318 return ustcomm_recv_message(&ustd->server, msg, src, timeout);
811e4b93
PMF
319}
320
688760ef 321int ustcomm_app_recv_message(struct ustcomm_app *app, char **msg, struct ustcomm_source *src, int timeout)
b0540e11 322{
688760ef 323 return ustcomm_recv_message(&app->server, msg, src, timeout);
b0540e11
PMF
324}
325
46ef48cd
PMF
326/* This removes src from the list of active connections of app.
327 */
328
329int 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;
342found:
343 return src->fd;
344}
345
d0b5f2b9
PMF
346static int init_named_socket(char *name, char **path_out)
347{
348 int result;
349 int fd;
350
351 struct sockaddr_un addr;
352
aca1ad90 353 result = fd = socket(PF_UNIX, SOCK_STREAM, 0);
d0b5f2b9
PMF
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
aca1ad90
PMF
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
d0b5f2b9
PMF
375 result = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
376 if(result == -1) {
377 PERROR("bind");
378 goto close_sock;
379 }
380
aca1ad90
PMF
381 result = listen(fd, 1);
382 if(result == -1) {
383 PERROR("listen");
384 goto close_sock;
385 }
386
b0540e11
PMF
387 if(path_out) {
388 *path_out = "";
d0b5f2b9 389 *path_out = strdupa(addr.sun_path);
b0540e11 390 }
d0b5f2b9
PMF
391
392 return fd;
393
394 close_sock:
395 close(fd);
396
397 return -1;
398}
399
4e2a8808
PMF
400int 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 }
4e2a8808
PMF
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
428int 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
52c51a47
PMF
448 if(signalpid >= 0) {
449 result = signal_process(signalpid);
450 if(result == -1) {
451 ERR("could not signal process");
452 return -1;
453 }
454 }
4e2a8808
PMF
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
467int ustcomm_disconnect(struct ustcomm_connection *conn)
468{
469 return close(conn->fd);
470}
471
472int 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
487int ustcomm_disconnect_app(struct ustcomm_connection *conn)
488{
489 close(conn->fd);
490 return 0;
491}
492
d0b5f2b9
PMF
493int 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
811e4b93
PMF
504 handle->server.listen_fd = init_named_socket(name, &(handle->server.socketpath));
505 if(handle->server.listen_fd < 0) {
aca1ad90 506 ERR("error initializing named socket");
d0b5f2b9
PMF
507 goto free_name;
508 }
509 free(name);
510
811e4b93 511 INIT_LIST_HEAD(&handle->server.connections);
aca1ad90 512
d0b5f2b9
PMF
513 return 0;
514
515free_name:
516 free(name);
517 return -1;
518}
519
520int ustcomm_init_ustd(struct ustcomm_ustd *handle)
521{
3847c3ba
PMF
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
811e4b93
PMF
531 handle->server.listen_fd = init_named_socket(name, &handle->server.socketpath);
532 if(handle->server.listen_fd < 0) {
6cb88bc0 533 ERR("error initializing named socket at %s", name);
aca1ad90
PMF
534 goto free_name;
535 }
3847c3ba 536 free(name);
d0b5f2b9 537
811e4b93 538 INIT_LIST_HEAD(&handle->server.connections);
aca1ad90 539
d0b5f2b9 540 return 0;
aca1ad90
PMF
541
542free_name:
543 free(name);
544 return -1;
d0b5f2b9 545}
b02e31e5 546
aca1ad90 547static char *find_tok(char *str)
b02e31e5
PMF
548{
549 while(*str == ' ') {
550 str++;
551
552 if(*str == 0)
553 return NULL;
554 }
555
556 return str;
557}
558
559static 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
571int 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
600char *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
aca1ad90 626 asprintf(&retval, "%.*s", (int)(end-start), start);
b02e31e5
PMF
627
628 return retval;
629}
630
This page took 0.047915 seconds and 4 git commands to generate.