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
18 /* API used by UST components to communicate with each other via sockets. */
22 #include <sys/types.h>
25 #include <sys/socket.h>
29 #include <sys/epoll.h>
41 static int mkdir_p(const char *path
, mode_t mode
)
50 tmp
= zmalloc(strlen(path
) + 1);
59 while (*path_p
!= '/') {
65 strncpy(tmp
, path
, path_p
- path
);
66 tmp
[path_p
-path
] = '\0';
67 if (tmp
[path_p
- path
- 1] != '/') {
68 result
= mkdir(tmp
, mode
);
70 if (!(errno
== EEXIST
|| errno
== EACCES
|| errno
== EROFS
)) {
71 /* Then this is a real error */
81 result
= mkdir(path
, mode
);
93 static struct sockaddr_un
* create_sock_addr(const char *name
,
94 size_t *sock_addr_size
)
96 struct sockaddr_un
* addr
;
99 alloc_size
= (size_t) (((struct sockaddr_un
*) 0)->sun_path
) +
102 addr
= malloc(alloc_size
);
104 ERR("allocating addr failed");
108 addr
->sun_family
= AF_UNIX
;
109 strcpy(addr
->sun_path
, name
);
111 *sock_addr_size
= alloc_size
;
116 struct ustcomm_sock
* ustcomm_init_sock(int fd
, int epoll_fd
,
117 struct cds_list_head
*list
)
119 struct epoll_event ev
;
120 struct ustcomm_sock
*sock
;
122 sock
= malloc(sizeof(struct ustcomm_sock
));
124 perror("malloc: couldn't allocate ustcomm_sock");
132 if (epoll_ctl(epoll_fd
, EPOLL_CTL_ADD
, sock
->fd
, &ev
) == -1) {
133 perror("epoll_ctl: failed to add socket\n");
138 sock
->epoll_fd
= epoll_fd
;
140 cds_list_add(&sock
->list
, list
);
142 CDS_INIT_LIST_HEAD(&sock
->list
);
148 void ustcomm_del_sock(struct ustcomm_sock
*sock
, int keep_in_epoll
)
150 cds_list_del(&sock
->list
);
151 if (!keep_in_epoll
) {
152 if (epoll_ctl(sock
->epoll_fd
, EPOLL_CTL_DEL
, sock
->fd
, NULL
) == -1) {
153 PERROR("epoll_ctl: failed to delete socket");
160 struct ustcomm_sock
* ustcomm_init_named_socket(const char *name
,
165 size_t sock_addr_size
;
166 struct sockaddr_un
* addr
;
167 struct ustcomm_sock
*sock
;
169 fd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
175 addr
= create_sock_addr(name
, &sock_addr_size
);
177 ERR("allocating addr, UST thread bailing");
181 result
= access(name
, F_OK
);
184 result
= unlink(name
);
186 PERROR("unlink of socket file");
189 DBG("socket already exists; overwriting");
192 result
= bind(fd
, (struct sockaddr
*)addr
, sock_addr_size
);
198 result
= listen(fd
, 1);
204 sock
= ustcomm_init_sock(fd
, epoll_fd
,
207 ERR("failed to create ustcomm_sock");
223 void ustcomm_del_named_sock(struct ustcomm_sock
*sock
,
224 int keep_socket_file
)
228 struct sockaddr dummy
;
229 struct sockaddr_un
*sockaddr
= NULL
;
234 if(!keep_socket_file
) {
236 /* Get the socket name */
237 alloc_size
= sizeof(dummy
);
238 if (getsockname(fd
, &dummy
, (socklen_t
*)&alloc_size
) < 0) {
239 PERROR("getsockname failed");
243 sockaddr
= zmalloc(alloc_size
);
245 ERR("failed to allocate sockaddr");
249 if (getsockname(fd
, sockaddr
, (socklen_t
*)&alloc_size
) < 0) {
250 PERROR("getsockname failed");
255 result
= stat(sockaddr
->sun_path
, &st
);
257 PERROR("stat (%s)", sockaddr
->sun_path
);
261 /* Paranoid check before deleting. */
262 result
= S_ISSOCK(st
.st_mode
);
264 ERR("The socket we are about to delete is not a socket.");
268 result
= unlink(sockaddr
->sun_path
);
278 ustcomm_del_sock(sock
, keep_socket_file
);
281 int ustcomm_recv_alloc(int sock
,
282 struct ustcomm_header
*header
,
285 struct ustcomm_header peek_header
;
289 /* Just to make the caller fail hard */
292 result
= recv(sock
, &peek_header
, sizeof(peek_header
),
293 MSG_PEEK
| MSG_WAITALL
);
295 if(errno
== ECONNRESET
) {
297 } else if (errno
== EINTR
) {
299 } else if (result
< 0) {
306 memset(&msg
, 0, sizeof(msg
));
308 iov
[0].iov_base
= (char *)header
;
309 iov
[0].iov_len
= sizeof(struct ustcomm_header
);
314 if (peek_header
.size
) {
315 *data
= zmalloc(peek_header
.size
);
320 iov
[1].iov_base
= *data
;
321 iov
[1].iov_len
= peek_header
.size
;
326 result
= recvmsg(sock
, &msg
, MSG_WAITALL
);
329 PERROR("recvmsg failed");
335 /* returns 1 to indicate a message was received
336 * returns 0 to indicate no message was received (end of stream)
337 * returns -1 to indicate an error
339 int ustcomm_recv_fd(int sock
,
340 struct ustcomm_header
*header
,
344 struct ustcomm_header peek_header
;
347 struct cmsghdr
*cmsg
;
348 char buf
[CMSG_SPACE(sizeof(int))];
350 result
= recv(sock
, &peek_header
, sizeof(peek_header
),
351 MSG_PEEK
| MSG_WAITALL
);
353 if(errno
== ECONNRESET
) {
355 } else if (errno
== EINTR
) {
357 } else if (result
< 0) {
364 memset(&msg
, 0, sizeof(msg
));
366 iov
[0].iov_base
= (char *)header
;
367 iov
[0].iov_len
= sizeof(struct ustcomm_header
);
372 if (peek_header
.size
&& data
) {
373 if (peek_header
.size
< 0 ||
374 peek_header
.size
> USTCOMM_DATA_SIZE
) {
375 ERR("big peek header! %ld", peek_header
.size
);
379 iov
[1].iov_base
= data
;
380 iov
[1].iov_len
= peek_header
.size
;
385 if (fd
&& peek_header
.fd_included
) {
386 msg
.msg_control
= buf
;
387 msg
.msg_controllen
= sizeof(buf
);
390 result
= recvmsg(sock
, &msg
, MSG_WAITALL
);
393 PERROR("recvmsg failed");
398 if (fd
&& peek_header
.fd_included
) {
399 cmsg
= CMSG_FIRSTHDR(&msg
);
401 while (cmsg
!= NULL
) {
402 if (cmsg
->cmsg_level
== SOL_SOCKET
403 && cmsg
->cmsg_type
== SCM_RIGHTS
) {
404 *fd
= *(int *) CMSG_DATA(cmsg
);
408 cmsg
= CMSG_NXTHDR(&msg
, cmsg
);
411 ERR("Failed to receive file descriptor\n");
418 int ustcomm_recv(int sock
,
419 struct ustcomm_header
*header
,
422 return ustcomm_recv_fd(sock
, header
, data
, NULL
);
426 int ustcomm_send_fd(int sock
,
427 const struct ustcomm_header
*header
,
434 struct cmsghdr
*cmsg
;
435 char buf
[CMSG_SPACE(sizeof(int))];
437 memset(&msg
, 0, sizeof(msg
));
439 iov
[0].iov_base
= (char *)header
;
440 iov
[0].iov_len
= sizeof(struct ustcomm_header
);
445 if (header
->size
&& data
) {
446 iov
[1].iov_base
= (char *)data
;
447 iov
[1].iov_len
= header
->size
;
453 if (fd
&& header
->fd_included
) {
454 msg
.msg_control
= buf
;
455 msg
.msg_controllen
= sizeof(buf
);
456 cmsg
= CMSG_FIRSTHDR(&msg
);
457 cmsg
->cmsg_level
= SOL_SOCKET
;
458 cmsg
->cmsg_type
= SCM_RIGHTS
;
459 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int));
460 *(int *) CMSG_DATA(cmsg
) = *fd
;
461 msg
.msg_controllen
= cmsg
->cmsg_len
;
464 result
= sendmsg(sock
, &msg
, MSG_NOSIGNAL
);
465 if (result
< 0 && errno
!= EPIPE
) {
466 PERROR("sendmsg failed");
471 int ustcomm_send(int sock
,
472 const struct ustcomm_header
*header
,
475 return ustcomm_send_fd(sock
, header
, data
, NULL
);
478 int ustcomm_req(int sock
,
479 const struct ustcomm_header
*req_header
,
480 const char *req_data
,
481 struct ustcomm_header
*res_header
,
486 result
= ustcomm_send(sock
, req_header
, req_data
);
491 return ustcomm_recv(sock
, res_header
, res_data
);
499 int ustcomm_connect_path(const char *name
, int *connection_fd
)
502 size_t sock_addr_size
;
503 struct sockaddr_un
*addr
;
505 fd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
511 addr
= create_sock_addr(name
, &sock_addr_size
);
513 ERR("allocating addr failed");
517 result
= connect(fd
, (struct sockaddr
*)addr
, sock_addr_size
);
519 PERROR("connect (path=%s)", name
);
537 /* Returns the current users socket directory, must be freed */
538 char *ustcomm_user_sock_dir(void)
541 char *sock_dir
= NULL
;
543 result
= asprintf(&sock_dir
, "%s%s", USER_SOCK_DIR
,
546 ERR("string overflow allocating directory name");
553 /* Open a connection to a traceable app.
560 static int connect_app_non_root(pid_t pid
, int *app_fd
)
564 char *dir_name
, *sock_name
;
566 dir_name
= ustcomm_user_sock_dir();
570 result
= asprintf(&sock_name
, "%s/%d", dir_name
, pid
);
572 ERR("failed to allocate socket name");
577 result
= ustcomm_connect_path(sock_name
, app_fd
);
579 ERR("failed to connect to app");
594 static int connect_app_root(pid_t pid
, int *app_fd
)
597 struct dirent
*dirent
;
601 tmp_dir
= opendir(USER_TMP_DIR
);
606 while ((dirent
= readdir(tmp_dir
))) {
607 if (!strncmp(dirent
->d_name
, USER_SOCK_DIR_BASE
,
608 strlen(USER_SOCK_DIR_BASE
))) {
610 if (asprintf(&sock_name
, USER_TMP_DIR
"/%s/%u",
611 dirent
->d_name
, pid
) < 0) {
615 result
= ustcomm_connect_path(sock_name
, app_fd
);
631 int ustcomm_connect_app(pid_t pid
, int *app_fd
)
636 return connect_app_non_root(pid
, app_fd
);
638 return connect_app_root(pid
, app_fd
);
643 int ensure_dir_exists(const char *dir
, mode_t mode
)
648 if (!strcmp(dir
, ""))
651 result
= stat(dir
, &st
);
652 if (result
< 0 && errno
!= ENOENT
) {
654 } else if (result
< 0) {
658 result
= mkdir_p(dir
, mode
);
660 ERR("executing in recursive creation of directory %s", dir
);
664 if (st
.st_mode
!= mode
) {
665 result
= chmod(dir
, mode
);
667 ERR("couldn't set directory mode on %s", dir
);
676 char * ustcomm_print_data(char *data_field
, int field_size
,
677 int *offset
, const char *format
, ...)
681 char *ptr
= USTCOMM_POISON_PTR
;
683 limit
= field_size
- *offset
;
684 va_start(args
, format
);
685 count
= vsnprintf(&data_field
[*offset
], limit
, format
, args
);
688 if (count
< limit
&& count
> -1) {
689 ptr
= NULL
+ *offset
;
690 *offset
= *offset
+ count
+ 1;
696 char * ustcomm_restore_ptr(char *ptr
, char *data_field
, int data_field_size
)
698 if ((unsigned long)ptr
> data_field_size
||
699 ptr
== USTCOMM_POISON_PTR
) {
703 return data_field
+ (long)ptr
;
706 int ustcomm_pack_single_field(struct ustcomm_header
*header
,
707 struct ustcomm_single_field
*single_field
,
712 single_field
->field
= ustcomm_print_data(single_field
->data
,
713 sizeof(single_field
->data
),
717 if (single_field
->field
== USTCOMM_POISON_PTR
) {
721 header
->size
= COMPUTE_MSG_SIZE(single_field
, offset
);
726 int ustcomm_unpack_single_field(struct ustcomm_single_field
*single_field
)
728 single_field
->field
= ustcomm_restore_ptr(single_field
->field
,
730 sizeof(single_field
->data
));
731 if (!single_field
->field
) {
738 int ustcomm_pack_channel_info(struct ustcomm_header
*header
,
739 struct ustcomm_channel_info
*ch_inf
,
745 ch_inf
->trace
= ustcomm_print_data(ch_inf
->data
,
746 sizeof(ch_inf
->data
),
750 if (ch_inf
->trace
== USTCOMM_POISON_PTR
) {
754 ch_inf
->channel
= ustcomm_print_data(ch_inf
->data
,
755 sizeof(ch_inf
->data
),
759 if (ch_inf
->channel
== USTCOMM_POISON_PTR
) {
763 header
->size
= COMPUTE_MSG_SIZE(ch_inf
, offset
);
769 int ustcomm_unpack_channel_info(struct ustcomm_channel_info
*ch_inf
)
771 ch_inf
->trace
= ustcomm_restore_ptr(ch_inf
->trace
,
773 sizeof(ch_inf
->data
));
774 if (!ch_inf
->trace
) {
778 ch_inf
->channel
= ustcomm_restore_ptr(ch_inf
->channel
,
780 sizeof(ch_inf
->data
));
781 if (!ch_inf
->channel
) {
788 int ustcomm_pack_buffer_info(struct ustcomm_header
*header
,
789 struct ustcomm_buffer_info
*buf_inf
,
796 buf_inf
->trace
= ustcomm_print_data(buf_inf
->data
,
797 sizeof(buf_inf
->data
),
801 if (buf_inf
->trace
== USTCOMM_POISON_PTR
) {
805 buf_inf
->channel
= ustcomm_print_data(buf_inf
->data
,
806 sizeof(buf_inf
->data
),
810 if (buf_inf
->channel
== USTCOMM_POISON_PTR
) {
814 buf_inf
->ch_cpu
= channel_cpu
;
816 header
->size
= COMPUTE_MSG_SIZE(buf_inf
, offset
);
822 int ustcomm_unpack_buffer_info(struct ustcomm_buffer_info
*buf_inf
)
824 buf_inf
->trace
= ustcomm_restore_ptr(buf_inf
->trace
,
826 sizeof(buf_inf
->data
));
827 if (!buf_inf
->trace
) {
831 buf_inf
->channel
= ustcomm_restore_ptr(buf_inf
->channel
,
833 sizeof(buf_inf
->data
));
834 if (!buf_inf
->channel
) {
841 int ustcomm_pack_ust_marker_info(struct ustcomm_header
*header
,
842 struct ustcomm_ust_marker_info
*ust_marker_inf
,
845 const char *ust_marker
)
849 ust_marker_inf
->trace
= ustcomm_print_data(ust_marker_inf
->data
,
850 sizeof(ust_marker_inf
->data
),
854 if (ust_marker_inf
->trace
== USTCOMM_POISON_PTR
) {
859 ust_marker_inf
->channel
= ustcomm_print_data(ust_marker_inf
->data
,
860 sizeof(ust_marker_inf
->data
),
864 if (ust_marker_inf
->channel
== USTCOMM_POISON_PTR
) {
869 ust_marker_inf
->ust_marker
= ustcomm_print_data(ust_marker_inf
->data
,
870 sizeof(ust_marker_inf
->data
),
874 if (ust_marker_inf
->ust_marker
== USTCOMM_POISON_PTR
) {
878 header
->size
= COMPUTE_MSG_SIZE(ust_marker_inf
, offset
);
883 int ustcomm_unpack_ust_marker_info(struct ustcomm_ust_marker_info
*ust_marker_inf
)
885 ust_marker_inf
->trace
= ustcomm_restore_ptr(ust_marker_inf
->trace
,
886 ust_marker_inf
->data
,
887 sizeof(ust_marker_inf
->data
));
888 if (!ust_marker_inf
->trace
) {
892 ust_marker_inf
->channel
= ustcomm_restore_ptr(ust_marker_inf
->channel
,
893 ust_marker_inf
->data
,
894 sizeof(ust_marker_inf
->data
));
895 if (!ust_marker_inf
->channel
) {
899 ust_marker_inf
->ust_marker
= ustcomm_restore_ptr(ust_marker_inf
->ust_marker
,
900 ust_marker_inf
->data
,
901 sizeof(ust_marker_inf
->data
));
902 if (!ust_marker_inf
->ust_marker
) {