libustcomm: fix warning
[ust.git] / libustcomm / ustcomm.c
CommitLineData
c39c72ee
PMF
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
d0b5f2b9 18#define _GNU_SOURCE
f9e5ce61
PMF
19#include <sys/types.h>
20#include <signal.h>
21#include <errno.h>
22#include <sys/socket.h>
23#include <sys/un.h>
d0b5f2b9 24#include <unistd.h>
aca1ad90 25#include <poll.h>
803a4f58 26#include <sys/stat.h>
f9e5ce61
PMF
27
28#include <stdio.h>
29#include <stdlib.h>
d0b5f2b9 30#include <string.h>
b0540e11 31#include <execinfo.h>
d0b5f2b9
PMF
32
33#include "ustcomm.h"
6af64c43 34#include "usterr.h"
2dae156b 35#include "share.h"
f9e5ce61
PMF
36
37#define UNIX_PATH_MAX 108
f9e5ce61 38
058a68cb 39#define MSG_MAX 10000
d0b5f2b9 40
aca1ad90
PMF
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
3847c3ba
PMF
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//}
b0540e11 54
d6d27063
PMF
55static int mkdir_p(const char *path, mode_t mode)
56{
c555b133 57 const char *path_p;
d6d27063
PMF
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
688760ef
PMF
104char *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
52c51a47 118static int signal_process(pid_t pid)
f9e5ce61 119{
52c51a47 120 return 0;
f9e5ce61
PMF
121}
122
ab33e65c 123int pid_is_online(pid_t pid) {
2944a629 124 return 1;
ab33e65c
PP
125}
126
2dae156b
PMF
127/* Send a message
128 *
129 * @fd: file descriptor to send to
130 * @msg: a null-terminated string containing the message to send
131 *
132 * Return value:
133 * -1: error
134 * 0: connection closed
135 * 1: success
136 */
137
4e2a8808 138static int send_message_fd(int fd, const char *msg)
811e4b93
PMF
139{
140 int result;
141
2dae156b
PMF
142 /* Send including the final \0 */
143 result = patient_send(fd, msg, strlen(msg)+1, MSG_NOSIGNAL);
811e4b93 144 if(result == -1) {
2dae156b
PMF
145 if(errno != EPIPE)
146 PERROR("send");
811e4b93
PMF
147 return -1;
148 }
688760ef
PMF
149 else if(result == 0) {
150 return 0;
151 }
811e4b93 152
2dae156b 153 DBG("sent message \"%s\"", msg);
688760ef 154 return 1;
811e4b93
PMF
155}
156
b0540e11
PMF
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;
08230db7
PMF
163 char *msg=NULL;
164 int retval = 0;
165 struct ustcomm_connection conn;
c97d4437
PMF
166 char *explicit_daemon_socket_path;
167
168 explicit_daemon_socket_path = getenv("UST_DAEMON_SOCKET");
169 if(explicit_daemon_socket_path) {
170 /* user specified explicitly a socket path */
171 result = snprintf(path, UNIX_PATH_MAX, "%s", explicit_daemon_socket_path);
172 }
173 else {
174 /* just use the default path */
175 result = snprintf(path, UNIX_PATH_MAX, "%s/ustd", SOCK_DIR);
176 }
b0540e11 177
b0540e11 178 if(result >= UNIX_PATH_MAX) {
08230db7 179 ERR("string overflow allocating socket name");
b0540e11
PMF
180 return -1;
181 }
182
183 asprintf(&msg, "collect %d %s", pid, channel);
184
08230db7
PMF
185 /* don't signal it because it's the daemon */
186 result = ustcomm_connect_path(path, &conn, -1);
187 if(result == -1) {
188 WARN("ustcomm_connect_path failed");
189 retval = -1;
190 goto del_string;
191 }
192
193 result = ustcomm_send_request(&conn, msg, NULL);
194 if(result == -1) {
195 WARN("ustcomm_send_request failed");
196 retval = -1;
197 goto disconnect;
198 }
199
200 disconnect:
201 ustcomm_disconnect(&conn);
202 del_string:
b0540e11
PMF
203 free(msg);
204
08230db7 205 return retval;
b0540e11
PMF
206}
207
688760ef 208/* returns 1 to indicate a message was received
da000ba4 209 * returns 0 to indicate no message was received (end of stream)
688760ef
PMF
210 * returns -1 to indicate an error
211 */
811e4b93 212
2dae156b 213#define RECV_INCREMENT 1
da000ba4 214#define RECV_INITIAL_BUF_SIZE 10
2dae156b
PMF
215
216static int recv_message_fd(int fd, char **msg)
d0b5f2b9 217{
d0b5f2b9 218 int result;
2dae156b
PMF
219 int buf_alloc_size = 0;
220 char *buf = NULL;
221 int buf_used_size = 0;
d0b5f2b9 222
da000ba4
PMF
223 buf = malloc(RECV_INITIAL_BUF_SIZE);
224 buf_alloc_size = RECV_INITIAL_BUF_SIZE;
b02e31e5 225
2dae156b
PMF
226 for(;;) {
227 if(buf_used_size + RECV_INCREMENT > buf_alloc_size) {
da000ba4 228 char *new_buf;
2dae156b 229 buf_alloc_size *= 2;
da000ba4
PMF
230 new_buf = (char *) realloc(buf, buf_alloc_size);
231 if(new_buf == NULL) {
232 ERR("realloc returned NULL");
233 free(buf);
234 return -1;
235 }
236 buf = new_buf;
2dae156b 237 }
b0540e11 238
2dae156b
PMF
239 /* FIXME: this is really inefficient; but with count>1 we would
240 * need a buffering mechanism */
241 result = recv(fd, buf+buf_used_size, RECV_INCREMENT, 0);
242 if(result == -1) {
243 free(buf);
244 if(errno != ECONNRESET)
245 PERROR("recv");
246 return -1;
247 }
248 if(result == 0) {
249 if(buf_used_size)
250 goto ret;
251 else {
252 free(buf);
253 return 0;
254 }
255 }
256
2dae156b
PMF
257 buf_used_size += result;
258
259 if(buf[buf_used_size-1] == 0) {
260 goto ret;
261 }
262 }
b0540e11 263
2dae156b
PMF
264ret:
265 *msg = buf;
266 DBG("received message \"%s\"", buf);
811e4b93 267
688760ef 268 return 1;
2dae156b 269
d0b5f2b9
PMF
270}
271
811e4b93
PMF
272int ustcomm_send_reply(struct ustcomm_server *server, char *msg, struct ustcomm_source *src)
273{
274 int result;
275
4e2a8808 276 result = send_message_fd(src->fd, msg);
3a7b90de 277 if(result < 0) {
811e4b93
PMF
278 ERR("error in send_message_fd");
279 return -1;
280 }
281
282 return 0;
283}
284
99b72dc0
PMF
285/* Called after a fork. */
286
287int ustcomm_close_all_connections(struct ustcomm_server *server)
288{
289 struct ustcomm_connection *conn;
290 struct ustcomm_connection *deletable_conn = NULL;
291
292 list_for_each_entry(conn, &server->connections, list) {
293 free(deletable_conn);
294 deletable_conn = conn;
295 close(conn->fd);
296 list_del(&conn->list);
297 }
298
299 return 0;
300}
301
688760ef
PMF
302/* @timeout: max blocking time in milliseconds, -1 means infinity
303 *
304 * returns 1 to indicate a message was received
305 * returns 0 to indicate no message was received
306 * returns -1 to indicate an error
307 */
308
309int ustcomm_recv_message(struct ustcomm_server *server, char **msg, struct ustcomm_source *src, int timeout)
b0540e11 310{
aca1ad90
PMF
311 struct pollfd *fds;
312 struct ustcomm_connection *conn;
313 int result;
314 int retval;
315
316 for(;;) {
317 int idx = 0;
318 int n_fds = 1;
319
811e4b93 320 list_for_each_entry(conn, &server->connections, list) {
aca1ad90
PMF
321 n_fds++;
322 }
323
324 fds = (struct pollfd *) malloc(n_fds * sizeof(struct pollfd));
325 if(fds == NULL) {
326 ERR("malloc returned NULL");
327 return -1;
328 }
329
330 /* special idx 0 is for listening socket */
811e4b93 331 fds[idx].fd = server->listen_fd;
aca1ad90
PMF
332 fds[idx].events = POLLIN;
333 idx++;
334
811e4b93 335 list_for_each_entry(conn, &server->connections, list) {
aca1ad90
PMF
336 fds[idx].fd = conn->fd;
337 fds[idx].events = POLLIN;
338 idx++;
339 }
340
69ba0156
PMF
341 while((result = poll(fds, n_fds, timeout)) == -1 && errno == EINTR)
342 /* nothing */;
aca1ad90
PMF
343 if(result == -1) {
344 PERROR("poll");
345 return -1;
346 }
347
688760ef
PMF
348 if(result == 0)
349 return 0;
350
aca1ad90
PMF
351 if(fds[0].revents) {
352 struct ustcomm_connection *newconn;
353 int newfd;
354
811e4b93 355 result = newfd = accept(server->listen_fd, NULL, NULL);
aca1ad90
PMF
356 if(result == -1) {
357 PERROR("accept");
358 return -1;
359 }
360
361 newconn = (struct ustcomm_connection *) malloc(sizeof(struct ustcomm_connection));
362 if(newconn == NULL) {
363 ERR("malloc returned NULL");
364 return -1;
365 }
366
367 newconn->fd = newfd;
368
811e4b93 369 list_add(&newconn->list, &server->connections);
aca1ad90
PMF
370 }
371
372 for(idx=1; idx<n_fds; idx++) {
373 if(fds[idx].revents) {
2dae156b
PMF
374 retval = recv_message_fd(fds[idx].fd, msg);
375 if(src)
376 src->fd = fds[idx].fd;
377
e2b815a9 378 if(retval == 0) {
aca1ad90
PMF
379 /* connection finished */
380 close(fds[idx].fd);
381
811e4b93 382 list_for_each_entry(conn, &server->connections, list) {
aca1ad90
PMF
383 if(conn->fd == fds[idx].fd) {
384 list_del(&conn->list);
385 break;
386 }
387 }
388 }
389 else {
390 goto free_fds_return;
391 }
392 }
393 }
394
395 free(fds);
396 }
397
398free_fds_return:
399 free(fds);
400 return retval;
b0540e11
PMF
401}
402
688760ef 403int ustcomm_ustd_recv_message(struct ustcomm_ustd *ustd, char **msg, struct ustcomm_source *src, int timeout)
811e4b93 404{
688760ef 405 return ustcomm_recv_message(&ustd->server, msg, src, timeout);
811e4b93
PMF
406}
407
688760ef 408int ustcomm_app_recv_message(struct ustcomm_app *app, char **msg, struct ustcomm_source *src, int timeout)
b0540e11 409{
688760ef 410 return ustcomm_recv_message(&app->server, msg, src, timeout);
b0540e11
PMF
411}
412
46ef48cd
PMF
413/* This removes src from the list of active connections of app.
414 */
415
416int ustcomm_app_detach_client(struct ustcomm_app *app, struct ustcomm_source *src)
417{
418 struct ustcomm_server *server = (struct ustcomm_server *)app;
419 struct ustcomm_connection *conn;
420
421 list_for_each_entry(conn, &server->connections, list) {
422 if(conn->fd == src->fd) {
423 list_del(&conn->list);
424 goto found;
425 }
426 }
427
428 return -1;
429found:
430 return src->fd;
431}
432
08230db7 433static int init_named_socket(const char *name, char **path_out)
d0b5f2b9
PMF
434{
435 int result;
436 int fd;
437
438 struct sockaddr_un addr;
439
aca1ad90 440 result = fd = socket(PF_UNIX, SOCK_STREAM, 0);
d0b5f2b9
PMF
441 if(result == -1) {
442 PERROR("socket");
443 return -1;
444 }
445
446 addr.sun_family = AF_UNIX;
447
448 strncpy(addr.sun_path, name, UNIX_PATH_MAX);
449 addr.sun_path[UNIX_PATH_MAX-1] = '\0';
450
aca1ad90
PMF
451 result = access(name, F_OK);
452 if(result == 0) {
453 /* file exists */
454 result = unlink(name);
455 if(result == -1) {
456 PERROR("unlink of socket file");
457 goto close_sock;
458 }
459 WARN("socket already exists; overwriting");
460 }
461
d0b5f2b9
PMF
462 result = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
463 if(result == -1) {
464 PERROR("bind");
465 goto close_sock;
466 }
467
aca1ad90
PMF
468 result = listen(fd, 1);
469 if(result == -1) {
470 PERROR("listen");
471 goto close_sock;
472 }
473
b0540e11 474 if(path_out) {
803a4f58 475 *path_out = strdup(addr.sun_path);
b0540e11 476 }
d0b5f2b9
PMF
477
478 return fd;
479
480 close_sock:
481 close(fd);
482
483 return -1;
484}
485
34b460e6
PMF
486/*
487 * Return value:
488 * 0: Success, but no reply because recv() returned 0
489 * 1: Success
490 * -1: Error
491 *
492 * On error, the error message is printed, except on
493 * ECONNRESET, which is normal when the application dies.
494 */
495
772030fe 496int ustcomm_send_request(struct ustcomm_connection *conn, const char *req, char **reply)
4e2a8808
PMF
497{
498 int result;
499
2dae156b
PMF
500 /* Send including the final \0 */
501 result = send_message_fd(conn->fd, req);
502 if(result != 1)
503 return result;
4e2a8808
PMF
504
505 if(!reply)
506 return 1;
507
2dae156b 508 result = recv_message_fd(conn->fd, reply);
4e2a8808 509 if(result == -1) {
4e2a8808
PMF
510 return -1;
511 }
512 else if(result == 0) {
513 return 0;
514 }
515
4e2a8808
PMF
516 return 1;
517}
518
08230db7 519int ustcomm_connect_path(const char *path, struct ustcomm_connection *conn, pid_t signalpid)
4e2a8808
PMF
520{
521 int fd;
522 int result;
523 struct sockaddr_un addr;
524
525 result = fd = socket(PF_UNIX, SOCK_STREAM, 0);
526 if(result == -1) {
527 PERROR("socket");
528 return -1;
529 }
530
531 addr.sun_family = AF_UNIX;
532
533 result = snprintf(addr.sun_path, UNIX_PATH_MAX, "%s", path);
534 if(result >= UNIX_PATH_MAX) {
535 ERR("string overflow allocating socket name");
536 return -1;
537 }
538
52c51a47
PMF
539 if(signalpid >= 0) {
540 result = signal_process(signalpid);
541 if(result == -1) {
542 ERR("could not signal process");
543 return -1;
544 }
545 }
4e2a8808
PMF
546
547 result = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
548 if(result == -1) {
2dae156b 549 PERROR("connect (path=%s)", path);
4e2a8808
PMF
550 return -1;
551 }
552
553 conn->fd = fd;
554
555 return 0;
556}
557
558int ustcomm_disconnect(struct ustcomm_connection *conn)
559{
560 return close(conn->fd);
561}
562
563int ustcomm_connect_app(pid_t pid, struct ustcomm_connection *conn)
564{
565 int result;
566 char path[UNIX_PATH_MAX];
567
568
569 result = snprintf(path, UNIX_PATH_MAX, "%s/%d", SOCK_DIR, pid);
570 if(result >= UNIX_PATH_MAX) {
08230db7 571 ERR("string overflow allocating socket name");
4e2a8808
PMF
572 return -1;
573 }
574
575 return ustcomm_connect_path(path, conn, pid);
576}
577
dce0b474
PMF
578static int ensure_dir_exists(const char *dir)
579{
580 struct stat st;
581 int result;
582
583 if(!strcmp(dir, ""))
584 return -1;
585
586 result = stat(dir, &st);
587 if(result == -1 && errno != ENOENT) {
588 return -1;
589 }
590 else if(result == -1) {
591 /* ENOENT */
dce0b474
PMF
592 int result;
593
d6d27063 594 result = mkdir_p(dir, 0777);
dce0b474 595 if(result != 0) {
d6d27063 596 ERR("executing in recursive creation of directory %s", dir);
dce0b474
PMF
597 return -1;
598 }
599 }
600
601 return 0;
602}
603
08230db7
PMF
604/* Called by an application to initialize its server so daemons can
605 * connect to it.
606 */
4e2a8808 607
d0b5f2b9
PMF
608int ustcomm_init_app(pid_t pid, struct ustcomm_app *handle)
609{
610 int result;
611 char *name;
612
613 result = asprintf(&name, "%s/%d", SOCK_DIR, (int)pid);
614 if(result >= UNIX_PATH_MAX) {
615 ERR("string overflow allocating socket name");
616 return -1;
617 }
618
dce0b474
PMF
619 result = ensure_dir_exists(SOCK_DIR);
620 if(result == -1) {
621 ERR("Unable to create socket directory %s", SOCK_DIR);
622 return -1;
623 }
624
811e4b93
PMF
625 handle->server.listen_fd = init_named_socket(name, &(handle->server.socketpath));
626 if(handle->server.listen_fd < 0) {
68ab7a5d 627 ERR("Error initializing named socket (%s). Check that directory exists and that it is writable.", name);
d0b5f2b9
PMF
628 goto free_name;
629 }
630 free(name);
631
811e4b93 632 INIT_LIST_HEAD(&handle->server.connections);
aca1ad90 633
d0b5f2b9
PMF
634 return 0;
635
636free_name:
637 free(name);
638 return -1;
639}
640
08230db7
PMF
641/* Used by the daemon to initialize its server so applications
642 * can connect to it.
643 */
644
c97d4437 645int ustcomm_init_ustd(struct ustcomm_ustd *handle, const char *sock_path)
d0b5f2b9 646{
3847c3ba 647 char *name;
c97d4437 648 int retval = 0;
3847c3ba 649
c97d4437
PMF
650 if(sock_path) {
651 asprintf(&name, "%s", sock_path);
652 }
653 else {
dce0b474
PMF
654 int result;
655
656 /* Only check if socket dir exists if we are using the default directory */
657 result = ensure_dir_exists(SOCK_DIR);
658 if(result == -1) {
659 ERR("Unable to create socket directory %s", SOCK_DIR);
660 return -1;
661 }
662
c97d4437 663 asprintf(&name, "%s/%s", SOCK_DIR, "ustd");
3847c3ba
PMF
664 }
665
811e4b93
PMF
666 handle->server.listen_fd = init_named_socket(name, &handle->server.socketpath);
667 if(handle->server.listen_fd < 0) {
6cb88bc0 668 ERR("error initializing named socket at %s", name);
c97d4437 669 retval = -1;
aca1ad90
PMF
670 goto free_name;
671 }
d0b5f2b9 672
811e4b93 673 INIT_LIST_HEAD(&handle->server.connections);
aca1ad90 674
aca1ad90
PMF
675free_name:
676 free(name);
c97d4437
PMF
677
678 return retval;
d0b5f2b9 679}
b02e31e5 680
803a4f58
PMF
681void ustcomm_fini_app(struct ustcomm_app *handle)
682{
683 int result;
684 struct stat st;
685
686 /* Destroy socket */
803a4f58
PMF
687 result = stat(handle->server.socketpath, &st);
688 if(result == -1) {
689 PERROR("stat (%s)", handle->server.socketpath);
690 return;
691 }
692
693 /* Paranoid check before deleting. */
694 result = S_ISSOCK(st.st_mode);
695 if(!result) {
696 ERR("The socket we are about to delete is not a socket.");
697 return;
698 }
699
700 result = unlink(handle->server.socketpath);
701 if(result == -1) {
702 PERROR("unlink");
703 }
704}
705
7e92827d 706static const char *find_tok(const char *str)
b02e31e5
PMF
707{
708 while(*str == ' ') {
709 str++;
710
711 if(*str == 0)
712 return NULL;
713 }
714
715 return str;
716}
717
7e92827d 718static const char *find_sep(const char *str)
b02e31e5
PMF
719{
720 while(*str != ' ') {
721 str++;
722
723 if(*str == 0)
724 break;
725 }
726
727 return str;
728}
729
7e92827d 730int nth_token_is(const char *str, const char *token, int tok_no)
b02e31e5
PMF
731{
732 int i;
7e92827d
PMF
733 const char *start;
734 const char *end;
b02e31e5
PMF
735
736 for(i=0; i<=tok_no; i++) {
737 str = find_tok(str);
738 if(str == NULL)
739 return -1;
740
741 start = str;
742
743 str = find_sep(str);
744 if(str == NULL)
745 return -1;
746
747 end = str;
748 }
749
750 if(end-start != strlen(token))
751 return 0;
752
753 if(strncmp(start, token, end-start))
754 return 0;
755
756 return 1;
757}
758
7e92827d 759char *nth_token(const char *str, int tok_no)
b02e31e5
PMF
760{
761 static char *retval = NULL;
762 int i;
7e92827d
PMF
763 const char *start;
764 const char *end;
b02e31e5
PMF
765
766 for(i=0; i<=tok_no; i++) {
767 str = find_tok(str);
768 if(str == NULL)
769 return NULL;
770
771 start = str;
772
773 str = find_sep(str);
774 if(str == NULL)
775 return NULL;
776
777 end = str;
778 }
779
780 if(retval) {
781 free(retval);
782 retval = NULL;
783 }
784
aca1ad90 785 asprintf(&retval, "%.*s", (int)(end-start), start);
b02e31e5
PMF
786
787 return retval;
788}
789
This page took 0.060175 seconds and 4 git commands to generate.