1 /* Copyright (C) 2009 Pierre-Marc Fournier
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.
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.
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
19 #include <sys/types.h>
22 #include <sys/socket.h>
35 #define UNIX_PATH_MAX 108
39 /* FIXME: ustcomm blocks on message sending, which might be problematic in
40 * some cases. Fix the poll() usage so sends are buffered until they don't
44 //static void bt(void)
49 // result = backtrace(&buffer, 100);
50 // backtrace_symbols_fd(buffer, result, STDERR_FILENO);
53 char *strdup_malloc(const char *s
)
60 retval
= (char *) malloc(strlen(s
)+1);
67 static int signal_process(pid_t pid
)
71 result
= kill(pid
, UST_SIGNAL
);
77 /* FIXME: should wait in a better way */
83 int pid_is_online(pid_t pid
) {
84 return kill(pid
, UST_SIGNAL
) != -1;
87 static int send_message_fd(int fd
, const char *msg
)
91 result
= send(fd
, msg
, strlen(msg
), 0);
96 else if(result
== 0) {
103 /* Called by an app to ask the consumer daemon to connect to it. */
105 int ustcomm_request_consumer(pid_t pid
, const char *channel
)
107 char path
[UNIX_PATH_MAX
];
111 struct ustcomm_connection conn
;
112 char *explicit_daemon_socket_path
;
114 explicit_daemon_socket_path
= getenv("UST_DAEMON_SOCKET");
115 if(explicit_daemon_socket_path
) {
116 /* user specified explicitly a socket path */
117 result
= snprintf(path
, UNIX_PATH_MAX
, "%s", explicit_daemon_socket_path
);
120 /* just use the default path */
121 result
= snprintf(path
, UNIX_PATH_MAX
, "%s/ustd", SOCK_DIR
);
124 if(result
>= UNIX_PATH_MAX
) {
125 ERR("string overflow allocating socket name");
129 asprintf(&msg
, "collect %d %s", pid
, channel
);
131 /* don't signal it because it's the daemon */
132 result
= ustcomm_connect_path(path
, &conn
, -1);
134 WARN("ustcomm_connect_path failed");
139 result
= ustcomm_send_request(&conn
, msg
, NULL
);
141 WARN("ustcomm_send_request failed");
147 ustcomm_disconnect(&conn
);
154 /* returns 1 to indicate a message was received
155 * returns 0 to indicate no message was received (cannot happen)
156 * returns -1 to indicate an error
159 static int recv_message_fd(int fd
, char **msg
, struct ustcomm_source
*src
)
163 *msg
= (char *) malloc(MSG_MAX
+1);
165 result
= recv(fd
, *msg
, MSG_MAX
, 0);
171 (*msg
)[result
] = '\0';
173 DBG("ustcomm_app_recv_message: result is %d, message is %s", result
, (*msg
));
181 int ustcomm_send_reply(struct ustcomm_server
*server
, char *msg
, struct ustcomm_source
*src
)
185 result
= send_message_fd(src
->fd
, msg
);
187 ERR("error in send_message_fd");
194 /* @timeout: max blocking time in milliseconds, -1 means infinity
196 * returns 1 to indicate a message was received
197 * returns 0 to indicate no message was received
198 * returns -1 to indicate an error
201 int ustcomm_recv_message(struct ustcomm_server
*server
, char **msg
, struct ustcomm_source
*src
, int timeout
)
204 struct ustcomm_connection
*conn
;
212 list_for_each_entry(conn
, &server
->connections
, list
) {
216 fds
= (struct pollfd
*) malloc(n_fds
* sizeof(struct pollfd
));
218 ERR("malloc returned NULL");
222 /* special idx 0 is for listening socket */
223 fds
[idx
].fd
= server
->listen_fd
;
224 fds
[idx
].events
= POLLIN
;
227 list_for_each_entry(conn
, &server
->connections
, list
) {
228 fds
[idx
].fd
= conn
->fd
;
229 fds
[idx
].events
= POLLIN
;
233 while((result
= poll(fds
, n_fds
, timeout
)) == -1 && errno
== EINTR
)
244 struct ustcomm_connection
*newconn
;
247 result
= newfd
= accept(server
->listen_fd
, NULL
, NULL
);
253 newconn
= (struct ustcomm_connection
*) malloc(sizeof(struct ustcomm_connection
));
254 if(newconn
== NULL
) {
255 ERR("malloc returned NULL");
261 list_add(&newconn
->list
, &server
->connections
);
264 for(idx
=1; idx
<n_fds
; idx
++) {
265 if(fds
[idx
].revents
) {
266 retval
= recv_message_fd(fds
[idx
].fd
, msg
, src
);
268 /* connection finished */
271 list_for_each_entry(conn
, &server
->connections
, list
) {
272 if(conn
->fd
== fds
[idx
].fd
) {
273 list_del(&conn
->list
);
279 goto free_fds_return
;
292 int ustcomm_ustd_recv_message(struct ustcomm_ustd
*ustd
, char **msg
, struct ustcomm_source
*src
, int timeout
)
294 return ustcomm_recv_message(&ustd
->server
, msg
, src
, timeout
);
297 int ustcomm_app_recv_message(struct ustcomm_app
*app
, char **msg
, struct ustcomm_source
*src
, int timeout
)
299 return ustcomm_recv_message(&app
->server
, msg
, src
, timeout
);
302 /* This removes src from the list of active connections of app.
305 int ustcomm_app_detach_client(struct ustcomm_app
*app
, struct ustcomm_source
*src
)
307 struct ustcomm_server
*server
= (struct ustcomm_server
*)app
;
308 struct ustcomm_connection
*conn
;
310 list_for_each_entry(conn
, &server
->connections
, list
) {
311 if(conn
->fd
== src
->fd
) {
312 list_del(&conn
->list
);
322 static int init_named_socket(const char *name
, char **path_out
)
327 struct sockaddr_un addr
;
329 result
= fd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
335 addr
.sun_family
= AF_UNIX
;
337 strncpy(addr
.sun_path
, name
, UNIX_PATH_MAX
);
338 addr
.sun_path
[UNIX_PATH_MAX
-1] = '\0';
340 result
= access(name
, F_OK
);
343 result
= unlink(name
);
345 PERROR("unlink of socket file");
348 WARN("socket already exists; overwriting");
351 result
= bind(fd
, (struct sockaddr
*)&addr
, sizeof(addr
));
357 result
= listen(fd
, 1);
365 *path_out
= strdupa(addr
.sun_path
);
376 int ustcomm_send_request(struct ustcomm_connection
*conn
, const char *req
, char **reply
)
380 result
= send(conn
->fd
, req
, strlen(req
), 0);
389 *reply
= (char *) malloc(MSG_MAX
+1);
390 result
= recv(conn
->fd
, *reply
, MSG_MAX
, 0);
395 else if(result
== 0) {
399 (*reply
)[result
] = '\0';
404 int ustcomm_connect_path(const char *path
, struct ustcomm_connection
*conn
, pid_t signalpid
)
408 struct sockaddr_un addr
;
410 result
= fd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
416 addr
.sun_family
= AF_UNIX
;
418 result
= snprintf(addr
.sun_path
, UNIX_PATH_MAX
, "%s", path
);
419 if(result
>= UNIX_PATH_MAX
) {
420 ERR("string overflow allocating socket name");
425 result
= signal_process(signalpid
);
427 ERR("could not signal process");
432 result
= connect(fd
, (struct sockaddr
*)&addr
, sizeof(addr
));
443 int ustcomm_disconnect(struct ustcomm_connection
*conn
)
445 return close(conn
->fd
);
448 int ustcomm_connect_app(pid_t pid
, struct ustcomm_connection
*conn
)
451 char path
[UNIX_PATH_MAX
];
454 result
= snprintf(path
, UNIX_PATH_MAX
, "%s/%d", SOCK_DIR
, pid
);
455 if(result
>= UNIX_PATH_MAX
) {
456 ERR("string overflow allocating socket name");
460 return ustcomm_connect_path(path
, conn
, pid
);
463 /* Called by an application to initialize its server so daemons can
467 int ustcomm_init_app(pid_t pid
, struct ustcomm_app
*handle
)
472 result
= asprintf(&name
, "%s/%d", SOCK_DIR
, (int)pid
);
473 if(result
>= UNIX_PATH_MAX
) {
474 ERR("string overflow allocating socket name");
478 handle
->server
.listen_fd
= init_named_socket(name
, &(handle
->server
.socketpath
));
479 if(handle
->server
.listen_fd
< 0) {
480 ERR("error initializing named socket");
485 INIT_LIST_HEAD(&handle
->server
.connections
);
494 /* Used by the daemon to initialize its server so applications
498 int ustcomm_init_ustd(struct ustcomm_ustd
*handle
, const char *sock_path
)
504 asprintf(&name
, "%s", sock_path
);
507 asprintf(&name
, "%s/%s", SOCK_DIR
, "ustd");
510 handle
->server
.listen_fd
= init_named_socket(name
, &handle
->server
.socketpath
);
511 if(handle
->server
.listen_fd
< 0) {
512 ERR("error initializing named socket at %s", name
);
517 INIT_LIST_HEAD(&handle
->server
.connections
);
525 static char *find_tok(char *str
)
537 static char *find_sep(char *str
)
549 int nth_token_is(char *str
, char *token
, int tok_no
)
555 for(i
=0; i
<=tok_no
; i
++) {
569 if(end
-start
!= strlen(token
))
572 if(strncmp(start
, token
, end
-start
))
578 char *nth_token(char *str
, int tok_no
)
580 static char *retval
= NULL
;
585 for(i
=0; i
<=tok_no
; i
++) {
604 asprintf(&retval
, "%.*s", (int)(end
-start
), start
);