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