Fix asprintf and scanf ignoring return value
[ust.git] / libustcomm / ustcomm.c
... / ...
CommitLineData
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/* API used by UST components to communicate with each other via sockets. */
19
20#define _GNU_SOURCE
21#include <sys/types.h>
22#include <signal.h>
23#include <errno.h>
24#include <sys/socket.h>
25#include <sys/un.h>
26#include <unistd.h>
27#include <poll.h>
28#include <sys/stat.h>
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <execinfo.h>
34
35#include "ustcomm.h"
36#include "usterr.h"
37#include "share.h"
38#include "multipoll.h"
39
40#define UNIX_PATH_MAX 108
41
42static int mkdir_p(const char *path, mode_t mode)
43{
44 const char *path_p;
45 char *tmp;
46
47 int retval = 0;
48 int result;
49 mode_t old_umask;
50
51 tmp = zmalloc(strlen(path) + 1);
52 if (tmp == NULL)
53 return -1;
54
55 /* skip first / */
56 path_p = path+1;
57
58 old_umask = umask(0);
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);
90 umask(old_umask);
91 return retval;
92}
93
94static int signal_process(pid_t pid)
95{
96 return 0;
97}
98
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
106int pid_is_online(pid_t pid) {
107 return 1;
108}
109
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
121static int send_message_fd(int fd, const char *msg)
122{
123 int result;
124
125 /* Send including the final \0 */
126 result = patient_send(fd, msg, strlen(msg)+1, MSG_NOSIGNAL);
127 if(result == -1) {
128 if(errno != EPIPE)
129 PERROR("send");
130 return -1;
131 }
132 else if(result == 0) {
133 return 0;
134 }
135
136 DBG("sent message \"%s\"", msg);
137 return 1;
138}
139
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;
146 char *msg=NULL;
147 int retval = 0;
148 struct ustcomm_connection conn;
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 }
160
161 if(result >= UNIX_PATH_MAX) {
162 ERR("string overflow allocating socket name");
163 return -1;
164 }
165
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 }
171
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:
190 free(msg);
191
192 return retval;
193}
194
195/* returns 1 to indicate a message was received
196 * returns 0 to indicate no message was received (end of stream)
197 * returns -1 to indicate an error
198 */
199
200#define RECV_INCREMENT 1000
201#define RECV_INITIAL_BUF_SIZE 10
202
203static int recv_message_fd(int fd, char **recv_buf, int *recv_buf_size, int *recv_buf_alloc, char **msg)
204{
205 int result;
206
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 */
213
214 for(;;) {
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;
223 }
224 }
225
226 /* Process found message */
227 if(nulfound == 1) {
228 char *newbuf;
229
230 if(i == 0) {
231 /* problem */
232 WARN("received empty message");
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);
254 if(result == -1) {
255 if(errno == ECONNRESET) {
256 *recv_buf_size = 0;
257 return 0;
258 }
259 else if(errno == EINTR) {
260 return -1;
261 }
262 else {
263 PERROR("recv");
264 return -1;
265 }
266 }
267 if(result == 0) {
268 return 0;
269 }
270 *recv_buf_size += result;
271
272 /* Go back to the beginning to check if there is a full message in the buffer */
273 }
274
275 DBG("received message \"%s\"", *recv_buf);
276
277 return 1;
278
279}
280
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
286int ustcomm_send_reply(struct ustcomm_server *server, char *msg, struct ustcomm_source *src)
287{
288 int result;
289
290 result = send_message_fd(src->fd, msg);
291 if(result < 0) {
292 ERR("error in send_message_fd");
293 return -1;
294 }
295
296 return 0;
297}
298
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;
309 ustcomm_close_app(conn);
310 list_del(&conn->list);
311 }
312
313 return 0;
314}
315
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)
324{
325 struct pollfd *fds;
326 struct ustcomm_connection **conn_table;
327 struct ustcomm_connection *conn;
328 int result;
329 int retval;
330
331 for(;;) {
332 int idx = 0;
333 int n_fds = 1;
334
335 list_for_each_entry(conn, &server->connections, list) {
336 n_fds++;
337 }
338
339 fds = (struct pollfd *) zmalloc(n_fds * sizeof(struct pollfd));
340 if(fds == NULL) {
341 ERR("zmalloc returned NULL");
342 return -1;
343 }
344
345 conn_table = (struct ustcomm_connection **) zmalloc(n_fds * sizeof(struct ustcomm_connection *));
346 if(conn_table == NULL) {
347 ERR("zmalloc returned NULL");
348 retval = -1;
349 goto free_fds_return;
350 }
351
352 /* special idx 0 is for listening socket */
353 fds[idx].fd = server->listen_fd;
354 fds[idx].events = POLLIN;
355 idx++;
356
357 list_for_each_entry(conn, &server->connections, list) {
358 fds[idx].fd = conn->fd;
359 fds[idx].events = POLLIN;
360 conn_table[idx] = conn;
361 idx++;
362 }
363
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) {
371 PERROR("poll");
372 retval = -1;
373 goto free_conn_table_return;
374 }
375 else if(result == 0) {
376 retval = 0;
377 goto free_conn_table_return;
378 }
379
380 if(fds[0].revents) {
381 struct ustcomm_connection *newconn;
382 int newfd;
383
384 result = newfd = accept(server->listen_fd, NULL, NULL);
385 if(result == -1) {
386 PERROR("accept");
387 retval = -1;
388 goto free_conn_table_return;
389 }
390
391 newconn = (struct ustcomm_connection *) zmalloc(sizeof(struct ustcomm_connection));
392 if(newconn == NULL) {
393 ERR("zmalloc returned NULL");
394 return -1;
395 }
396
397 ustcomm_init_connection(newconn);
398 newconn->fd = newfd;
399
400 list_add(&newconn->list, &server->connections);
401 }
402
403 for(idx=1; idx<n_fds; idx++) {
404 if(fds[idx].revents) {
405 retval = recv_message_conn(conn_table[idx], msg);
406 if(src)
407 src->fd = fds[idx].fd;
408
409 if(retval == 0) {
410 /* connection finished */
411 list_for_each_entry(conn, &server->connections, list) {
412 if(conn->fd == fds[idx].fd) {
413 ustcomm_close_app(conn);
414 list_del(&conn->list);
415 free(conn);
416 break;
417 }
418 }
419 }
420 else {
421 goto free_conn_table_return;
422 }
423 }
424 }
425
426 free(fds);
427 free(conn_table);
428 }
429
430free_conn_table_return:
431 free(conn_table);
432free_fds_return:
433 free(fds);
434 return retval;
435}
436
437int ustcomm_ustd_recv_message(struct ustcomm_ustd *ustd, char **msg, struct ustcomm_source *src, int timeout)
438{
439 return ustcomm_recv_message(&ustd->server, msg, src, timeout);
440}
441
442int ustcomm_app_recv_message(struct ustcomm_app *app, char **msg, struct ustcomm_source *src, int timeout)
443{
444 return ustcomm_recv_message(&app->server, msg, src, timeout);
445}
446
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
467static int init_named_socket(const char *name, char **path_out)
468{
469 int result;
470 int fd;
471
472 struct sockaddr_un addr;
473
474 result = fd = socket(PF_UNIX, SOCK_STREAM, 0);
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
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 }
493 DBG("socket already exists; overwriting");
494 }
495
496 result = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
497 if(result == -1) {
498 PERROR("bind");
499 goto close_sock;
500 }
501
502 result = listen(fd, 1);
503 if(result == -1) {
504 PERROR("listen");
505 goto close_sock;
506 }
507
508 if(path_out) {
509 *path_out = strdup(addr.sun_path);
510 }
511
512 return fd;
513
514 close_sock:
515 close(fd);
516
517 return -1;
518}
519
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
530int ustcomm_send_request(struct ustcomm_connection *conn, const char *req, char **reply)
531{
532 int result;
533
534 /* Send including the final \0 */
535 result = send_message_fd(conn->fd, req);
536 if(result != 1)
537 return result;
538
539 if(!reply)
540 return 1;
541
542 result = recv_message_conn(conn, reply);
543 if(result == -1) {
544 return -1;
545 }
546 else if(result == 0) {
547 return 0;
548 }
549
550 return 1;
551}
552
553/* Return value:
554 * 0: success
555 * -1: error
556 */
557
558int ustcomm_connect_path(const char *path, struct ustcomm_connection *conn, pid_t signalpid)
559{
560 int fd;
561 int result;
562 struct sockaddr_un addr;
563
564 ustcomm_init_connection(conn);
565
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
580 if(signalpid >= 0) {
581 result = signal_process(signalpid);
582 if(result == -1) {
583 ERR("could not signal process");
584 return -1;
585 }
586 }
587
588 result = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
589 if(result == -1) {
590 PERROR("connect (path=%s)", path);
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
604/* Open a connection to a traceable app.
605 *
606 * Return value:
607 * 0: success
608 * -1: error
609 */
610
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) {
619 ERR("string overflow allocating socket name");
620 return -1;
621 }
622
623 return ustcomm_connect_path(path, conn, pid);
624}
625
626/* Close a connection to a traceable app. It frees the
627 * resources. It however does not free the
628 * ustcomm_connection itself.
629 */
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
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 */
653 int result;
654
655 /* mkdir mode to 0777 */
656 result = mkdir_p(dir, S_IRWXU | S_IRWXG | S_IRWXO);
657 if(result != 0) {
658 ERR("executing in recursive creation of directory %s", dir);
659 return -1;
660 }
661 }
662
663 return 0;
664}
665
666/* Called by an application to initialize its server so daemons can
667 * connect to it.
668 */
669
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
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
687 handle->server.listen_fd = init_named_socket(name, &(handle->server.socketpath));
688 if(handle->server.listen_fd < 0) {
689 ERR("Error initializing named socket (%s). Check that directory exists and that it is writable.", name);
690 goto free_name;
691 }
692 free(name);
693
694 INIT_LIST_HEAD(&handle->server.connections);
695
696 return 0;
697
698free_name:
699 free(name);
700 return -1;
701}
702
703/* Used by the daemon to initialize its server so applications
704 * can connect to it.
705 */
706
707int ustcomm_init_ustd(struct ustcomm_ustd *handle, const char *sock_path)
708{
709 char *name;
710 int retval = 0;
711
712 if(sock_path) {
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 }
718 }
719 else {
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
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 }
734 }
735
736 handle->server.listen_fd = init_named_socket(name, &handle->server.socketpath);
737 if(handle->server.listen_fd < 0) {
738 ERR("error initializing named socket at %s", name);
739 retval = -1;
740 goto free_name;
741 }
742
743 INIT_LIST_HEAD(&handle->server.connections);
744
745free_name:
746 free(name);
747
748 return retval;
749}
750
751static void ustcomm_fini_server(struct ustcomm_server *server, int keep_socket_file)
752{
753 int result;
754 struct stat st;
755
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 }
763
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 }
775 }
776
777 free(server->socketpath);
778
779 result = close(server->listen_fd);
780 if(result == -1) {
781 PERROR("close");
782 return;
783 }
784}
785
786/* Free a traceable application server */
787
788void ustcomm_fini_app(struct ustcomm_app *handle, int keep_socket_file)
789{
790 ustcomm_fini_server(&handle->server, keep_socket_file);
791}
792
793/* Free a ustd server */
794
795void ustcomm_fini_ustd(struct ustcomm_ustd *handle)
796{
797 ustcomm_fini_server(&handle->server, 0);
798}
799
800static const char *find_tok(const char *str)
801{
802 while(*str == ' ') {
803 str++;
804
805 if(*str == 0)
806 return NULL;
807 }
808
809 return str;
810}
811
812static const char *find_sep(const char *str)
813{
814 while(*str != ' ') {
815 str++;
816
817 if(*str == 0)
818 break;
819 }
820
821 return str;
822}
823
824int nth_token_is(const char *str, const char *token, int tok_no)
825{
826 int i;
827 const char *start;
828 const char *end;
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
853char *nth_token(const char *str, int tok_no)
854{
855 static char *retval = NULL;
856 int i;
857 const char *start;
858 const char *end;
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
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 }
884
885 return retval;
886}
887
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
905 newconn = (struct ustcomm_connection *) zmalloc(sizeof(struct ustcomm_connection));
906 if(newconn == NULL) {
907 ERR("zmalloc returned NULL");
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
959void ustcomm_mp_add_app_clients(struct mpentries *ent, struct ustcomm_app *app, int (*cb)(char *recvbuf, struct ustcomm_source *src))
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) {
967 struct ustcomm_multipoll_conn_info *mpinfo = (struct ustcomm_multipoll_conn_info *) zmalloc(sizeof(struct ustcomm_multipoll_conn_info));
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.02574 seconds and 4 git commands to generate.