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