259931d0be8e38a7811841e41218b7bb7cf9fa22
[ust.git] / libustcomm / ustcomm.c
1 /* Copyright (C) 2009 Pierre-Marc Fournier
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17
18 #define _GNU_SOURCE
19 #include <sys/types.h>
20 #include <signal.h>
21 #include <errno.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 #include <unistd.h>
25 #include <poll.h>
26 #include <sys/stat.h>
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <execinfo.h>
32
33 #include "ustcomm.h"
34 #include "usterr.h"
35 #include "share.h"
36
37 #define UNIX_PATH_MAX 108
38
39 #define MSG_MAX 10000
40
41 /* FIXME: ustcomm blocks on message sending, which might be problematic in
42 * some cases. Fix the poll() usage so sends are buffered until they don't
43 * block.
44 */
45
46 //static void bt(void)
47 //{
48 // void *buffer[100];
49 // int result;
50 //
51 // result = backtrace(&buffer, 100);
52 // backtrace_symbols_fd(buffer, result, STDERR_FILENO);
53 //}
54
55 static int mkdir_p(const char *path, mode_t mode)
56 {
57 const char *path_p;
58 char *tmp;
59
60 int retval = 0;
61 int result;
62
63 tmp = malloc(strlen(path) + 1);
64 if (tmp == NULL)
65 return -1;
66
67 /* skip first / */
68 path_p = path+1;
69
70 for(;;) {
71 while (*path_p != '/') {
72 if(*path_p == 0)
73 break;
74 ++path_p;
75 }
76 if (*path_p == '/') {
77 strncpy(tmp, path, path_p - path);
78 tmp[path_p-path] = '\0';
79 if (tmp[path_p - path - 1] != '/') {
80 result = mkdir(tmp, mode);
81 if(result == -1) {
82 if (!(errno == EEXIST || errno == EACCES || errno == EROFS)) {
83 /* Then this is a real error */
84 retval = -1;
85 break;
86 }
87 }
88 }
89 /* pass / */
90 path_p++;
91 } else {
92 /* last component */
93 result = mkdir(path, mode);
94 if (result == -1)
95 retval = -1;
96 break;
97 }
98 }
99
100 free(tmp);
101 return retval;
102 }
103
104 char *strdup_malloc(const char *s)
105 {
106 char *retval;
107
108 if(s == NULL)
109 return NULL;
110
111 retval = (char *) malloc(strlen(s)+1);
112
113 strcpy(retval, s);
114
115 return retval;
116 }
117
118 static int signal_process(pid_t pid)
119 {
120 return 0;
121 }
122
123 void ustcomm_init_connection(struct ustcomm_connection *conn)
124 {
125 conn->recv_buf = NULL;
126 conn->recv_buf_size = 0;
127 conn->recv_buf_alloc = 0;
128 }
129
130 int pid_is_online(pid_t pid) {
131 return 1;
132 }
133
134 /* Send a message
135 *
136 * @fd: file descriptor to send to
137 * @msg: a null-terminated string containing the message to send
138 *
139 * Return value:
140 * -1: error
141 * 0: connection closed
142 * 1: success
143 */
144
145 static int send_message_fd(int fd, const char *msg)
146 {
147 int result;
148
149 /* Send including the final \0 */
150 result = patient_send(fd, msg, strlen(msg)+1, MSG_NOSIGNAL);
151 if(result == -1) {
152 if(errno != EPIPE)
153 PERROR("send");
154 return -1;
155 }
156 else if(result == 0) {
157 return 0;
158 }
159
160 DBG("sent message \"%s\"", msg);
161 return 1;
162 }
163
164 /* Called by an app to ask the consumer daemon to connect to it. */
165
166 int ustcomm_request_consumer(pid_t pid, const char *channel)
167 {
168 char path[UNIX_PATH_MAX];
169 int result;
170 char *msg=NULL;
171 int retval = 0;
172 struct ustcomm_connection conn;
173 char *explicit_daemon_socket_path;
174
175 explicit_daemon_socket_path = getenv("UST_DAEMON_SOCKET");
176 if(explicit_daemon_socket_path) {
177 /* user specified explicitly a socket path */
178 result = snprintf(path, UNIX_PATH_MAX, "%s", explicit_daemon_socket_path);
179 }
180 else {
181 /* just use the default path */
182 result = snprintf(path, UNIX_PATH_MAX, "%s/ustd", SOCK_DIR);
183 }
184
185 if(result >= UNIX_PATH_MAX) {
186 ERR("string overflow allocating socket name");
187 return -1;
188 }
189
190 asprintf(&msg, "collect %d %s", pid, channel);
191
192 /* don't signal it because it's the daemon */
193 result = ustcomm_connect_path(path, &conn, -1);
194 if(result == -1) {
195 WARN("ustcomm_connect_path failed");
196 retval = -1;
197 goto del_string;
198 }
199
200 result = ustcomm_send_request(&conn, msg, NULL);
201 if(result == -1) {
202 WARN("ustcomm_send_request failed");
203 retval = -1;
204 goto disconnect;
205 }
206
207 disconnect:
208 ustcomm_disconnect(&conn);
209 del_string:
210 free(msg);
211
212 return retval;
213 }
214
215 /* returns 1 to indicate a message was received
216 * returns 0 to indicate no message was received (end of stream)
217 * returns -1 to indicate an error
218 */
219
220 #define RECV_INCREMENT 1000
221 #define RECV_INITIAL_BUF_SIZE 10
222
223 static int recv_message_fd(int fd, char **recv_buf, int *recv_buf_size, int *recv_buf_alloc, char **msg)
224 {
225 int result;
226
227 /* 1. Check if there is a message in the buf */
228 /* 2. If not, do:
229 2.1 receive chunk and put it in buffer
230 2.2 process full message if there is one
231 -- while no message arrived
232 */
233
234 for(;;) {
235 int i;
236 int nulfound = 0;
237
238 /* Search for full message in buffer */
239 for(i=0; i<*recv_buf_size; i++) {
240 if((*recv_buf)[i] == '\0') {
241 nulfound = 1;
242 break;
243 }
244 }
245
246 /* Process found message */
247 if(nulfound == 1) {
248 char *newbuf;
249
250 if(i == 0) {
251 /* problem */
252 WARN("received empty message");
253 }
254 *msg = strndup(*recv_buf, i);
255
256 /* Remove processed message from buffer */
257 newbuf = (char *) malloc(*recv_buf_size - (i+1));
258 memcpy(newbuf, *recv_buf + (i+1), *recv_buf_size - (i+1));
259 free(*recv_buf);
260 *recv_buf = newbuf;
261 *recv_buf_size -= (i+1);
262 *recv_buf_alloc -= (i+1);
263
264 return 1;
265 }
266
267 /* Receive a chunk from the fd */
268 if(*recv_buf_alloc - *recv_buf_size < RECV_INCREMENT) {
269 *recv_buf_alloc += RECV_INCREMENT - (*recv_buf_alloc - *recv_buf_size);
270 *recv_buf = (char *) realloc(*recv_buf, *recv_buf_alloc);
271 }
272
273 result = recv(fd, *recv_buf+*recv_buf_size, RECV_INCREMENT, 0);
274 if(result == -1) {
275 if(errno == ECONNRESET) {
276 *recv_buf_size = 0;
277 return 0;
278 }
279 /* real error */
280 PERROR("recv");
281 return -1;
282 }
283 if(result == 0) {
284 return 0;
285 }
286 *recv_buf_size += result;
287
288 /* Go back to the beginning to check if there is a full message in the buffer */
289 }
290
291 DBG("received message \"%s\"", *recv_buf);
292
293 return 1;
294
295 }
296
297 static int recv_message_conn(struct ustcomm_connection *conn, char **msg)
298 {
299 return recv_message_fd(conn->fd, &conn->recv_buf, &conn->recv_buf_size, &conn->recv_buf_alloc, msg);
300 }
301
302 int ustcomm_send_reply(struct ustcomm_server *server, char *msg, struct ustcomm_source *src)
303 {
304 int result;
305
306 result = send_message_fd(src->fd, msg);
307 if(result < 0) {
308 ERR("error in send_message_fd");
309 return -1;
310 }
311
312 return 0;
313 }
314
315 /* Called after a fork. */
316
317 int ustcomm_close_all_connections(struct ustcomm_server *server)
318 {
319 struct ustcomm_connection *conn;
320 struct ustcomm_connection *deletable_conn = NULL;
321
322 list_for_each_entry(conn, &server->connections, list) {
323 free(deletable_conn);
324 deletable_conn = conn;
325 ustcomm_close_app(conn);
326 list_del(&conn->list);
327 }
328
329 return 0;
330 }
331
332 /* @timeout: max blocking time in milliseconds, -1 means infinity
333 *
334 * returns 1 to indicate a message was received
335 * returns 0 to indicate no message was received
336 * returns -1 to indicate an error
337 */
338
339 int ustcomm_recv_message(struct ustcomm_server *server, char **msg, struct ustcomm_source *src, int timeout)
340 {
341 struct pollfd *fds;
342 struct ustcomm_connection **conn_table;
343 struct ustcomm_connection *conn;
344 int result;
345 int retval;
346
347 for(;;) {
348 int idx = 0;
349 int n_fds = 1;
350
351 list_for_each_entry(conn, &server->connections, list) {
352 n_fds++;
353 }
354
355 fds = (struct pollfd *) malloc(n_fds * sizeof(struct pollfd));
356 if(fds == NULL) {
357 ERR("malloc returned NULL");
358 return -1;
359 }
360
361 conn_table = (struct ustcomm_connection **) malloc(n_fds * sizeof(struct ustcomm_connection *));
362 if(conn_table == NULL) {
363 ERR("malloc returned NULL");
364 retval = -1;
365 goto free_fds_return;
366 }
367
368 /* special idx 0 is for listening socket */
369 fds[idx].fd = server->listen_fd;
370 fds[idx].events = POLLIN;
371 idx++;
372
373 list_for_each_entry(conn, &server->connections, list) {
374 fds[idx].fd = conn->fd;
375 fds[idx].events = POLLIN;
376 conn_table[idx] = conn;
377 idx++;
378 }
379
380 while((result = poll(fds, n_fds, timeout)) == -1 && errno == EINTR)
381 /* nothing */;
382 if(result == -1) {
383 PERROR("poll");
384 retval = -1;
385 goto free_conn_table_return;
386 }
387
388 if(result == 0) {
389 retval = 0;
390 goto free_conn_table_return;
391 }
392
393 if(fds[0].revents) {
394 struct ustcomm_connection *newconn;
395 int newfd;
396
397 result = newfd = accept(server->listen_fd, NULL, NULL);
398 if(result == -1) {
399 PERROR("accept");
400 retval = -1;
401 goto free_conn_table_return;
402 }
403
404 newconn = (struct ustcomm_connection *) malloc(sizeof(struct ustcomm_connection));
405 if(newconn == NULL) {
406 ERR("malloc returned NULL");
407 return -1;
408 }
409
410 ustcomm_init_connection(newconn);
411 newconn->fd = newfd;
412
413 list_add(&newconn->list, &server->connections);
414 }
415
416 for(idx=1; idx<n_fds; idx++) {
417 if(fds[idx].revents) {
418 retval = recv_message_conn(conn_table[idx], msg);
419 if(src)
420 src->fd = fds[idx].fd;
421
422 if(retval == 0) {
423 /* connection finished */
424 close(fds[idx].fd);
425
426 list_for_each_entry(conn, &server->connections, list) {
427 if(conn->fd == fds[idx].fd) {
428 ustcomm_close_app(conn);
429 list_del(&conn->list);
430 free(conn);
431 break;
432 }
433 }
434 }
435 else {
436 goto free_conn_table_return;
437 }
438 }
439 }
440
441 free(fds);
442 free(conn_table);
443 }
444
445 free_conn_table_return:
446 free(conn_table);
447 free_fds_return:
448 free(fds);
449 return retval;
450 }
451
452 int ustcomm_ustd_recv_message(struct ustcomm_ustd *ustd, char **msg, struct ustcomm_source *src, int timeout)
453 {
454 return ustcomm_recv_message(&ustd->server, msg, src, timeout);
455 }
456
457 int ustcomm_app_recv_message(struct ustcomm_app *app, char **msg, struct ustcomm_source *src, int timeout)
458 {
459 return ustcomm_recv_message(&app->server, msg, src, timeout);
460 }
461
462 /* This removes src from the list of active connections of app.
463 */
464
465 int ustcomm_app_detach_client(struct ustcomm_app *app, struct ustcomm_source *src)
466 {
467 struct ustcomm_server *server = (struct ustcomm_server *)app;
468 struct ustcomm_connection *conn;
469
470 list_for_each_entry(conn, &server->connections, list) {
471 if(conn->fd == src->fd) {
472 list_del(&conn->list);
473 goto found;
474 }
475 }
476
477 return -1;
478 found:
479 return src->fd;
480 }
481
482 static int init_named_socket(const char *name, char **path_out)
483 {
484 int result;
485 int fd;
486
487 struct sockaddr_un addr;
488
489 result = fd = socket(PF_UNIX, SOCK_STREAM, 0);
490 if(result == -1) {
491 PERROR("socket");
492 return -1;
493 }
494
495 addr.sun_family = AF_UNIX;
496
497 strncpy(addr.sun_path, name, UNIX_PATH_MAX);
498 addr.sun_path[UNIX_PATH_MAX-1] = '\0';
499
500 result = access(name, F_OK);
501 if(result == 0) {
502 /* file exists */
503 result = unlink(name);
504 if(result == -1) {
505 PERROR("unlink of socket file");
506 goto close_sock;
507 }
508 WARN("socket already exists; overwriting");
509 }
510
511 result = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
512 if(result == -1) {
513 PERROR("bind");
514 goto close_sock;
515 }
516
517 result = listen(fd, 1);
518 if(result == -1) {
519 PERROR("listen");
520 goto close_sock;
521 }
522
523 if(path_out) {
524 *path_out = strdup(addr.sun_path);
525 }
526
527 return fd;
528
529 close_sock:
530 close(fd);
531
532 return -1;
533 }
534
535 /*
536 * Return value:
537 * 0: Success, but no reply because recv() returned 0
538 * 1: Success
539 * -1: Error
540 *
541 * On error, the error message is printed, except on
542 * ECONNRESET, which is normal when the application dies.
543 */
544
545 int ustcomm_send_request(struct ustcomm_connection *conn, const char *req, char **reply)
546 {
547 int result;
548
549 /* Send including the final \0 */
550 result = send_message_fd(conn->fd, req);
551 if(result != 1)
552 return result;
553
554 if(!reply)
555 return 1;
556
557 result = recv_message_conn(conn, reply);
558 if(result == -1) {
559 return -1;
560 }
561 else if(result == 0) {
562 return 0;
563 }
564
565 return 1;
566 }
567
568 /* Return value:
569 * 0: success
570 * -1: error
571 */
572
573 int ustcomm_connect_path(const char *path, struct ustcomm_connection *conn, pid_t signalpid)
574 {
575 int fd;
576 int result;
577 struct sockaddr_un addr;
578
579 ustcomm_init_connection(conn);
580
581 result = fd = socket(PF_UNIX, SOCK_STREAM, 0);
582 if(result == -1) {
583 PERROR("socket");
584 return -1;
585 }
586
587 addr.sun_family = AF_UNIX;
588
589 result = snprintf(addr.sun_path, UNIX_PATH_MAX, "%s", path);
590 if(result >= UNIX_PATH_MAX) {
591 ERR("string overflow allocating socket name");
592 return -1;
593 }
594
595 if(signalpid >= 0) {
596 result = signal_process(signalpid);
597 if(result == -1) {
598 ERR("could not signal process");
599 return -1;
600 }
601 }
602
603 result = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
604 if(result == -1) {
605 PERROR("connect (path=%s)", path);
606 return -1;
607 }
608
609 conn->fd = fd;
610
611 return 0;
612 }
613
614 int ustcomm_disconnect(struct ustcomm_connection *conn)
615 {
616 return close(conn->fd);
617 }
618
619 /* Open a connection to a traceable app.
620 *
621 * Return value:
622 * 0: success
623 * -1: error
624 */
625
626 int ustcomm_connect_app(pid_t pid, struct ustcomm_connection *conn)
627 {
628 int result;
629 char path[UNIX_PATH_MAX];
630
631
632 result = snprintf(path, UNIX_PATH_MAX, "%s/%d", SOCK_DIR, pid);
633 if(result >= UNIX_PATH_MAX) {
634 ERR("string overflow allocating socket name");
635 return -1;
636 }
637
638 return ustcomm_connect_path(path, conn, pid);
639 }
640
641 /* Close a connection to a traceable app. It frees the
642 * resources. It however does not free the
643 * ustcomm_connection itself.
644 */
645
646 int ustcomm_close_app(struct ustcomm_connection *conn)
647 {
648 close(conn->fd);
649 free(conn->recv_buf);
650
651 return 0;
652 }
653
654 static int ensure_dir_exists(const char *dir)
655 {
656 struct stat st;
657 int result;
658
659 if(!strcmp(dir, ""))
660 return -1;
661
662 result = stat(dir, &st);
663 if(result == -1 && errno != ENOENT) {
664 return -1;
665 }
666 else if(result == -1) {
667 /* ENOENT */
668 int result;
669
670 result = mkdir_p(dir, 0777);
671 if(result != 0) {
672 ERR("executing in recursive creation of directory %s", dir);
673 return -1;
674 }
675 }
676
677 return 0;
678 }
679
680 /* Called by an application to initialize its server so daemons can
681 * connect to it.
682 */
683
684 int ustcomm_init_app(pid_t pid, struct ustcomm_app *handle)
685 {
686 int result;
687 char *name;
688
689 result = asprintf(&name, "%s/%d", SOCK_DIR, (int)pid);
690 if(result >= UNIX_PATH_MAX) {
691 ERR("string overflow allocating socket name");
692 return -1;
693 }
694
695 result = ensure_dir_exists(SOCK_DIR);
696 if(result == -1) {
697 ERR("Unable to create socket directory %s", SOCK_DIR);
698 return -1;
699 }
700
701 handle->server.listen_fd = init_named_socket(name, &(handle->server.socketpath));
702 if(handle->server.listen_fd < 0) {
703 ERR("Error initializing named socket (%s). Check that directory exists and that it is writable.", name);
704 goto free_name;
705 }
706 free(name);
707
708 INIT_LIST_HEAD(&handle->server.connections);
709
710 return 0;
711
712 free_name:
713 free(name);
714 return -1;
715 }
716
717 /* Used by the daemon to initialize its server so applications
718 * can connect to it.
719 */
720
721 int ustcomm_init_ustd(struct ustcomm_ustd *handle, const char *sock_path)
722 {
723 char *name;
724 int retval = 0;
725
726 if(sock_path) {
727 asprintf(&name, "%s", sock_path);
728 }
729 else {
730 int result;
731
732 /* Only check if socket dir exists if we are using the default directory */
733 result = ensure_dir_exists(SOCK_DIR);
734 if(result == -1) {
735 ERR("Unable to create socket directory %s", SOCK_DIR);
736 return -1;
737 }
738
739 asprintf(&name, "%s/%s", SOCK_DIR, "ustd");
740 }
741
742 handle->server.listen_fd = init_named_socket(name, &handle->server.socketpath);
743 if(handle->server.listen_fd < 0) {
744 ERR("error initializing named socket at %s", name);
745 retval = -1;
746 goto free_name;
747 }
748
749 INIT_LIST_HEAD(&handle->server.connections);
750
751 free_name:
752 free(name);
753
754 return retval;
755 }
756
757 static void ustcomm_fini_server(struct ustcomm_server *server, int keep_socket_file)
758 {
759 int result;
760 struct stat st;
761
762 if(!keep_socket_file) {
763 /* Destroy socket */
764 result = stat(server->socketpath, &st);
765 if(result == -1) {
766 PERROR("stat (%s)", server->socketpath);
767 return;
768 }
769
770 /* Paranoid check before deleting. */
771 result = S_ISSOCK(st.st_mode);
772 if(!result) {
773 ERR("The socket we are about to delete is not a socket.");
774 return;
775 }
776
777 result = unlink(server->socketpath);
778 if(result == -1) {
779 PERROR("unlink");
780 }
781 }
782
783 free(server->socketpath);
784
785 result = close(server->listen_fd);
786 if(result == -1) {
787 PERROR("close");
788 return;
789 }
790 }
791
792 /* Free a traceable application server */
793
794 void ustcomm_fini_app(struct ustcomm_app *handle, int keep_socket_file)
795 {
796 ustcomm_fini_server(&handle->server, keep_socket_file);
797 }
798
799 /* Free a ustd server */
800
801 void ustcomm_fini_ustd(struct ustcomm_ustd *handle)
802 {
803 ustcomm_fini_server(&handle->server, 0);
804 }
805
806 static const char *find_tok(const char *str)
807 {
808 while(*str == ' ') {
809 str++;
810
811 if(*str == 0)
812 return NULL;
813 }
814
815 return str;
816 }
817
818 static const char *find_sep(const char *str)
819 {
820 while(*str != ' ') {
821 str++;
822
823 if(*str == 0)
824 break;
825 }
826
827 return str;
828 }
829
830 int nth_token_is(const char *str, const char *token, int tok_no)
831 {
832 int i;
833 const char *start;
834 const char *end;
835
836 for(i=0; i<=tok_no; i++) {
837 str = find_tok(str);
838 if(str == NULL)
839 return -1;
840
841 start = str;
842
843 str = find_sep(str);
844 if(str == NULL)
845 return -1;
846
847 end = str;
848 }
849
850 if(end-start != strlen(token))
851 return 0;
852
853 if(strncmp(start, token, end-start))
854 return 0;
855
856 return 1;
857 }
858
859 char *nth_token(const char *str, int tok_no)
860 {
861 static char *retval = NULL;
862 int i;
863 const char *start;
864 const char *end;
865
866 for(i=0; i<=tok_no; i++) {
867 str = find_tok(str);
868 if(str == NULL)
869 return NULL;
870
871 start = str;
872
873 str = find_sep(str);
874 if(str == NULL)
875 return NULL;
876
877 end = str;
878 }
879
880 if(retval) {
881 free(retval);
882 retval = NULL;
883 }
884
885 asprintf(&retval, "%.*s", (int)(end-start), start);
886
887 return retval;
888 }
889
This page took 0.045268 seconds and 3 git commands to generate.