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