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>
37 #define UNIX_PATH_MAX 108
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
46 //static void bt(void)
51 // result = backtrace(&buffer, 100);
52 // backtrace_symbols_fd(buffer, result, STDERR_FILENO);
55 char *strdup_malloc(const char *s
)
62 retval
= (char *) malloc(strlen(s
)+1);
69 static int signal_process(pid_t pid
)
74 int pid_is_online(pid_t pid
) {
80 * @fd: file descriptor to send to
81 * @msg: a null-terminated string containing the message to send
85 * 0: connection closed
89 static int send_message_fd(int fd
, const char *msg
)
93 /* Send including the final \0 */
94 result
= patient_send(fd
, msg
, strlen(msg
)+1, MSG_NOSIGNAL
);
100 else if(result
== 0) {
104 DBG("sent message \"%s\"", msg
);
108 /* Called by an app to ask the consumer daemon to connect to it. */
110 int ustcomm_request_consumer(pid_t pid
, const char *channel
)
112 char path
[UNIX_PATH_MAX
];
116 struct ustcomm_connection conn
;
117 char *explicit_daemon_socket_path
;
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
);
125 /* just use the default path */
126 result
= snprintf(path
, UNIX_PATH_MAX
, "%s/ustd", SOCK_DIR
);
129 if(result
>= UNIX_PATH_MAX
) {
130 ERR("string overflow allocating socket name");
134 asprintf(&msg
, "collect %d %s", pid
, channel
);
136 /* don't signal it because it's the daemon */
137 result
= ustcomm_connect_path(path
, &conn
, -1);
139 WARN("ustcomm_connect_path failed");
144 result
= ustcomm_send_request(&conn
, msg
, NULL
);
146 WARN("ustcomm_send_request failed");
152 ustcomm_disconnect(&conn
);
159 /* returns 1 to indicate a message was received
160 * returns 0 to indicate no message was received (end of stream)
161 * returns -1 to indicate an error
164 #define RECV_INCREMENT 1
165 #define RECV_INITIAL_BUF_SIZE 10
167 static int recv_message_fd(int fd
, char **msg
)
170 int buf_alloc_size
= 0;
172 int buf_used_size
= 0;
174 buf
= malloc(RECV_INITIAL_BUF_SIZE
);
175 buf_alloc_size
= RECV_INITIAL_BUF_SIZE
;
178 if(buf_used_size
+ RECV_INCREMENT
> buf_alloc_size
) {
181 new_buf
= (char *) realloc(buf
, buf_alloc_size
);
182 if(new_buf
== NULL
) {
183 ERR("realloc returned NULL");
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);
195 if(errno
!= ECONNRESET
)
208 buf_used_size
+= result
;
210 if(buf
[buf_used_size
-1] == 0) {
217 DBG("received message \"%s\"", buf
);
223 int ustcomm_send_reply(struct ustcomm_server
*server
, char *msg
, struct ustcomm_source
*src
)
227 result
= send_message_fd(src
->fd
, msg
);
229 ERR("error in send_message_fd");
236 /* Called after a fork. */
238 int ustcomm_close_all_connections(struct ustcomm_server
*server
)
240 struct ustcomm_connection
*conn
;
241 struct ustcomm_connection
*deletable_conn
= NULL
;
243 list_for_each_entry(conn
, &server
->connections
, list
) {
244 free(deletable_conn
);
245 deletable_conn
= conn
;
247 list_del(&conn
->list
);
253 /* @timeout: max blocking time in milliseconds, -1 means infinity
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
260 int ustcomm_recv_message(struct ustcomm_server
*server
, char **msg
, struct ustcomm_source
*src
, int timeout
)
263 struct ustcomm_connection
*conn
;
271 list_for_each_entry(conn
, &server
->connections
, list
) {
275 fds
= (struct pollfd
*) malloc(n_fds
* sizeof(struct pollfd
));
277 ERR("malloc returned NULL");
281 /* special idx 0 is for listening socket */
282 fds
[idx
].fd
= server
->listen_fd
;
283 fds
[idx
].events
= POLLIN
;
286 list_for_each_entry(conn
, &server
->connections
, list
) {
287 fds
[idx
].fd
= conn
->fd
;
288 fds
[idx
].events
= POLLIN
;
292 while((result
= poll(fds
, n_fds
, timeout
)) == -1 && errno
== EINTR
)
303 struct ustcomm_connection
*newconn
;
306 result
= newfd
= accept(server
->listen_fd
, NULL
, NULL
);
312 newconn
= (struct ustcomm_connection
*) malloc(sizeof(struct ustcomm_connection
));
313 if(newconn
== NULL
) {
314 ERR("malloc returned NULL");
320 list_add(&newconn
->list
, &server
->connections
);
323 for(idx
=1; idx
<n_fds
; idx
++) {
324 if(fds
[idx
].revents
) {
325 retval
= recv_message_fd(fds
[idx
].fd
, msg
);
327 src
->fd
= fds
[idx
].fd
;
330 /* connection finished */
333 list_for_each_entry(conn
, &server
->connections
, list
) {
334 if(conn
->fd
== fds
[idx
].fd
) {
335 list_del(&conn
->list
);
341 goto free_fds_return
;
354 int ustcomm_ustd_recv_message(struct ustcomm_ustd
*ustd
, char **msg
, struct ustcomm_source
*src
, int timeout
)
356 return ustcomm_recv_message(&ustd
->server
, msg
, src
, timeout
);
359 int ustcomm_app_recv_message(struct ustcomm_app
*app
, char **msg
, struct ustcomm_source
*src
, int timeout
)
361 return ustcomm_recv_message(&app
->server
, msg
, src
, timeout
);
364 /* This removes src from the list of active connections of app.
367 int ustcomm_app_detach_client(struct ustcomm_app
*app
, struct ustcomm_source
*src
)
369 struct ustcomm_server
*server
= (struct ustcomm_server
*)app
;
370 struct ustcomm_connection
*conn
;
372 list_for_each_entry(conn
, &server
->connections
, list
) {
373 if(conn
->fd
== src
->fd
) {
374 list_del(&conn
->list
);
384 static int init_named_socket(const char *name
, char **path_out
)
389 struct sockaddr_un addr
;
391 result
= fd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
397 addr
.sun_family
= AF_UNIX
;
399 strncpy(addr
.sun_path
, name
, UNIX_PATH_MAX
);
400 addr
.sun_path
[UNIX_PATH_MAX
-1] = '\0';
402 result
= access(name
, F_OK
);
405 result
= unlink(name
);
407 PERROR("unlink of socket file");
410 WARN("socket already exists; overwriting");
413 result
= bind(fd
, (struct sockaddr
*)&addr
, sizeof(addr
));
419 result
= listen(fd
, 1);
426 *path_out
= strdup(addr
.sun_path
);
439 * 0: Success, but no reply because recv() returned 0
443 * On error, the error message is printed, except on
444 * ECONNRESET, which is normal when the application dies.
447 int ustcomm_send_request(struct ustcomm_connection
*conn
, const char *req
, char **reply
)
451 /* Send including the final \0 */
452 result
= send_message_fd(conn
->fd
, req
);
459 result
= recv_message_fd(conn
->fd
, reply
);
463 else if(result
== 0) {
470 int ustcomm_connect_path(const char *path
, struct ustcomm_connection
*conn
, pid_t signalpid
)
474 struct sockaddr_un addr
;
476 result
= fd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
482 addr
.sun_family
= AF_UNIX
;
484 result
= snprintf(addr
.sun_path
, UNIX_PATH_MAX
, "%s", path
);
485 if(result
>= UNIX_PATH_MAX
) {
486 ERR("string overflow allocating socket name");
491 result
= signal_process(signalpid
);
493 ERR("could not signal process");
498 result
= connect(fd
, (struct sockaddr
*)&addr
, sizeof(addr
));
500 PERROR("connect (path=%s)", path
);
509 int ustcomm_disconnect(struct ustcomm_connection
*conn
)
511 return close(conn
->fd
);
514 int ustcomm_connect_app(pid_t pid
, struct ustcomm_connection
*conn
)
517 char path
[UNIX_PATH_MAX
];
520 result
= snprintf(path
, UNIX_PATH_MAX
, "%s/%d", SOCK_DIR
, pid
);
521 if(result
>= UNIX_PATH_MAX
) {
522 ERR("string overflow allocating socket name");
526 return ustcomm_connect_path(path
, conn
, pid
);
529 static int ensure_dir_exists(const char *dir
)
537 result
= stat(dir
, &st
);
538 if(result
== -1 && errno
!= ENOENT
) {
541 else if(result
== -1) {
546 result
= snprintf(buf
, sizeof(buf
), "mkdir -p \"%s\"", dir
);
547 if(result
>= sizeof(buf
)) {
548 ERR("snprintf buffer overflow");
551 result
= system(buf
);
553 ERR("executing command %s", buf
);
561 /* Called by an application to initialize its server so daemons can
565 int ustcomm_init_app(pid_t pid
, struct ustcomm_app
*handle
)
570 result
= asprintf(&name
, "%s/%d", SOCK_DIR
, (int)pid
);
571 if(result
>= UNIX_PATH_MAX
) {
572 ERR("string overflow allocating socket name");
576 result
= ensure_dir_exists(SOCK_DIR
);
578 ERR("Unable to create socket directory %s", SOCK_DIR
);
582 handle
->server
.listen_fd
= init_named_socket(name
, &(handle
->server
.socketpath
));
583 if(handle
->server
.listen_fd
< 0) {
584 ERR("Error initializing named socket (%s). Check that directory exists and that it is writable.", name
);
589 INIT_LIST_HEAD(&handle
->server
.connections
);
598 /* Used by the daemon to initialize its server so applications
602 int ustcomm_init_ustd(struct ustcomm_ustd
*handle
, const char *sock_path
)
608 asprintf(&name
, "%s", sock_path
);
613 /* Only check if socket dir exists if we are using the default directory */
614 result
= ensure_dir_exists(SOCK_DIR
);
616 ERR("Unable to create socket directory %s", SOCK_DIR
);
620 asprintf(&name
, "%s/%s", SOCK_DIR
, "ustd");
623 handle
->server
.listen_fd
= init_named_socket(name
, &handle
->server
.socketpath
);
624 if(handle
->server
.listen_fd
< 0) {
625 ERR("error initializing named socket at %s", name
);
630 INIT_LIST_HEAD(&handle
->server
.connections
);
638 void ustcomm_fini_app(struct ustcomm_app
*handle
)
644 result
= stat(handle
->server
.socketpath
, &st
);
646 PERROR("stat (%s)", handle
->server
.socketpath
);
650 /* Paranoid check before deleting. */
651 result
= S_ISSOCK(st
.st_mode
);
653 ERR("The socket we are about to delete is not a socket.");
657 result
= unlink(handle
->server
.socketpath
);
663 static const char *find_tok(const char *str
)
675 static const char *find_sep(const char *str
)
687 int nth_token_is(const char *str
, const char *token
, int tok_no
)
693 for(i
=0; i
<=tok_no
; i
++) {
707 if(end
-start
!= strlen(token
))
710 if(strncmp(start
, token
, end
-start
))
716 char *nth_token(const char *str
, int tok_no
)
718 static char *retval
= NULL
;
723 for(i
=0; i
<=tok_no
; i
++) {
742 asprintf(&retval
, "%.*s", (int)(end
-start
), start
);