X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=libustcomm%2Fustcomm.c;h=e401c4256e6666292a3ea6b9f5dddd948d811b64;hb=304f67a5f2d2eaaa7407c09b2ac7d6e049bccf1f;hp=d537eebf8a7164b0acf02c415889e6fb632e62fb;hpb=93e5ce29599beb7b32858b3074b8433dfffdab34;p=ust.git diff --git a/libustcomm/ustcomm.c b/libustcomm/ustcomm.c index d537eeb..e401c42 100644 --- a/libustcomm/ustcomm.c +++ b/libustcomm/ustcomm.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -35,9 +36,6 @@ #include "ustcomm.h" #include "usterr.h" #include "share.h" -#include "multipoll.h" - -#define UNIX_PATH_MAX 108 static int mkdir_p(const char *path, mode_t mode) { @@ -46,14 +44,16 @@ static int mkdir_p(const char *path, mode_t mode) int retval = 0; int result; + mode_t old_umask; - tmp = malloc(strlen(path) + 1); + tmp = zmalloc(strlen(path) + 1); if (tmp == NULL) return -1; /* skip first / */ path_p = path+1; + old_umask = umask(0); for(;;) { while (*path_p != '/') { if(*path_p == 0) @@ -85,462 +85,409 @@ static int mkdir_p(const char *path, mode_t mode) } free(tmp); + umask(old_umask); return retval; } -static int signal_process(pid_t pid) +static struct sockaddr_un * create_sock_addr(const char *name, + size_t *sock_addr_size) { - return 0; -} + struct sockaddr_un * addr; + size_t alloc_size; -void ustcomm_init_connection(struct ustcomm_connection *conn) -{ - conn->recv_buf = NULL; - conn->recv_buf_size = 0; - conn->recv_buf_alloc = 0; -} + alloc_size = (size_t) (((struct sockaddr_un *) 0)->sun_path) + + strlen(name) + 1; -int pid_is_online(pid_t pid) { - return 1; -} + addr = malloc(alloc_size); + if (addr < 0) { + ERR("allocating addr failed"); + return NULL; + } -/* Send a message - * - * @fd: file descriptor to send to - * @msg: a null-terminated string containing the message to send - * - * Return value: - * -1: error - * 0: connection closed - * 1: success - */ + addr->sun_family = AF_UNIX; + strcpy(addr->sun_path, name); + + *sock_addr_size = alloc_size; + + return addr; +} -static int send_message_fd(int fd, const char *msg) +struct ustcomm_sock * ustcomm_init_sock(int fd, int epoll_fd, + struct cds_list_head *list) { - int result; + struct epoll_event ev; + struct ustcomm_sock *sock; - /* Send including the final \0 */ - result = patient_send(fd, msg, strlen(msg)+1, MSG_NOSIGNAL); - if(result == -1) { - if(errno != EPIPE) - PERROR("send"); - return -1; + sock = malloc(sizeof(struct ustcomm_sock)); + if (!sock) { + perror("malloc: couldn't allocate ustcomm_sock"); + return NULL; } - else if(result == 0) { - return 0; + + ev.events = EPOLLIN; + ev.data.ptr = sock; + sock->fd = fd; + + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock->fd, &ev) == -1) { + perror("epoll_ctl: failed to add socket\n"); + free(sock); + return NULL; } - DBG("sent message \"%s\"", msg); - return 1; + sock->epoll_fd = epoll_fd; + if (list) { + cds_list_add(&sock->list, list); + } else { + CDS_INIT_LIST_HEAD(&sock->list); + } + + return sock; } -/* Called by an app to ask the consumer daemon to connect to it. */ +void ustcomm_del_sock(struct ustcomm_sock *sock, int keep_in_epoll) +{ + cds_list_del(&sock->list); + if (!keep_in_epoll) { + if (epoll_ctl(sock->epoll_fd, EPOLL_CTL_DEL, sock->fd, NULL) == -1) { + PERROR("epoll_ctl: failed to delete socket"); + } + } + close(sock->fd); + free(sock); +} -int ustcomm_request_consumer(pid_t pid, const char *channel) +struct ustcomm_sock * ustcomm_init_named_socket(const char *name, + int epoll_fd) { - char path[UNIX_PATH_MAX]; int result; - char *msg=NULL; - int retval = 0; - struct ustcomm_connection conn; - char *explicit_daemon_socket_path; + int fd; + size_t sock_addr_size; + struct sockaddr_un * addr; + struct ustcomm_sock *sock; - explicit_daemon_socket_path = getenv("UST_DAEMON_SOCKET"); - if(explicit_daemon_socket_path) { - /* user specified explicitly a socket path */ - result = snprintf(path, UNIX_PATH_MAX, "%s", explicit_daemon_socket_path); - } - else { - /* just use the default path */ - result = snprintf(path, UNIX_PATH_MAX, "%s/ustd", SOCK_DIR); + fd = socket(PF_UNIX, SOCK_STREAM, 0); + if(fd == -1) { + PERROR("socket"); + return NULL; } - if(result >= UNIX_PATH_MAX) { - ERR("string overflow allocating socket name"); - return -1; + addr = create_sock_addr(name, &sock_addr_size); + if (addr == NULL) { + ERR("allocating addr, UST thread bailing"); + goto close_sock; } - asprintf(&msg, "collect %d %s", pid, channel); + result = access(name, F_OK); + if(result == 0) { + /* file exists */ + result = unlink(name); + if(result == -1) { + PERROR("unlink of socket file"); + goto free_addr; + } + DBG("socket already exists; overwriting"); + } - /* don't signal it because it's the daemon */ - result = ustcomm_connect_path(path, &conn, -1); + result = bind(fd, (struct sockaddr *)addr, sock_addr_size); if(result == -1) { - WARN("ustcomm_connect_path failed"); - retval = -1; - goto del_string; + PERROR("bind"); + goto free_addr; } - result = ustcomm_send_request(&conn, msg, NULL); + result = listen(fd, 1); if(result == -1) { - WARN("ustcomm_send_request failed"); - retval = -1; - goto disconnect; + PERROR("listen"); + goto free_addr; } - disconnect: - ustcomm_disconnect(&conn); - del_string: - free(msg); + sock = ustcomm_init_sock(fd, epoll_fd, + NULL); + if (!sock) { + ERR("failed to create ustcomm_sock"); + goto free_addr; + } - return retval; -} + free(addr); -/* returns 1 to indicate a message was received - * returns 0 to indicate no message was received (end of stream) - * returns -1 to indicate an error - */ + return sock; + +free_addr: + free(addr); +close_sock: + close(fd); -#define RECV_INCREMENT 1000 -#define RECV_INITIAL_BUF_SIZE 10 + return NULL; +} -static int recv_message_fd(int fd, char **recv_buf, int *recv_buf_size, int *recv_buf_alloc, char **msg) +void ustcomm_del_named_sock(struct ustcomm_sock *sock, + int keep_socket_file) { - int result; + int result, fd; + struct stat st; + struct sockaddr dummy; + struct sockaddr_un *sockaddr = NULL; + int alloc_size; - /* 1. Check if there is a message in the buf */ - /* 2. If not, do: - 2.1 receive chunk and put it in buffer - 2.2 process full message if there is one - -- while no message arrived - */ + fd = sock->fd; - for(;;) { - int i; - int nulfound = 0; + if(!keep_socket_file) { - /* Search for full message in buffer */ - for(i=0; i<*recv_buf_size; i++) { - if((*recv_buf)[i] == '\0') { - nulfound = 1; - break; - } + /* Get the socket name */ + alloc_size = sizeof(dummy); + if (getsockname(fd, &dummy, (socklen_t *)&alloc_size) < 0) { + PERROR("getsockname failed"); + goto del_sock; } - /* Process found message */ - if(nulfound == 1) { - char *newbuf; - - if(i == 0) { - /* problem */ - WARN("received empty message"); - } - *msg = strndup(*recv_buf, i); - - /* Remove processed message from buffer */ - newbuf = (char *) malloc(*recv_buf_size - (i+1)); - memcpy(newbuf, *recv_buf + (i+1), *recv_buf_size - (i+1)); - free(*recv_buf); - *recv_buf = newbuf; - *recv_buf_size -= (i+1); - *recv_buf_alloc -= (i+1); - - return 1; + sockaddr = zmalloc(alloc_size); + if (!sockaddr) { + ERR("failed to allocate sockaddr"); + goto del_sock; } - /* Receive a chunk from the fd */ - if(*recv_buf_alloc - *recv_buf_size < RECV_INCREMENT) { - *recv_buf_alloc += RECV_INCREMENT - (*recv_buf_alloc - *recv_buf_size); - *recv_buf = (char *) realloc(*recv_buf, *recv_buf_alloc); + if (getsockname(fd, sockaddr, (socklen_t *)&alloc_size) < 0) { + PERROR("getsockname failed"); + goto free_sockaddr; } - result = recv(fd, *recv_buf+*recv_buf_size, RECV_INCREMENT, 0); - if(result == -1) { - if(errno == ECONNRESET) { - *recv_buf_size = 0; - return 0; - } - else if(errno == EINTR) { - return -1; - } - else { - PERROR("recv"); - return -1; - } + /* Destroy socket */ + result = stat(sockaddr->sun_path, &st); + if(result < 0) { + PERROR("stat (%s)", sockaddr->sun_path); + goto free_sockaddr; } - if(result == 0) { - return 0; + + /* Paranoid check before deleting. */ + result = S_ISSOCK(st.st_mode); + if(!result) { + ERR("The socket we are about to delete is not a socket."); + goto free_sockaddr; } - *recv_buf_size += result; - /* Go back to the beginning to check if there is a full message in the buffer */ + result = unlink(sockaddr->sun_path); + if(result < 0) { + PERROR("unlink"); + } } - DBG("received message \"%s\"", *recv_buf); - - return 1; - -} +free_sockaddr: + free(sockaddr); -static int recv_message_conn(struct ustcomm_connection *conn, char **msg) -{ - return recv_message_fd(conn->fd, &conn->recv_buf, &conn->recv_buf_size, &conn->recv_buf_alloc, msg); +del_sock: + ustcomm_del_sock(sock, keep_socket_file); } -int ustcomm_send_reply(struct ustcomm_server *server, char *msg, struct ustcomm_source *src) -{ +int ustcomm_recv_alloc(int sock, + struct ustcomm_header *header, + char **data) { int result; + struct ustcomm_header peek_header; + struct iovec iov[2]; + struct msghdr msg; - result = send_message_fd(src->fd, msg); - if(result < 0) { - ERR("error in send_message_fd"); - return -1; + /* Just to make the caller fail hard */ + *data = NULL; + + result = recv(sock, &peek_header, sizeof(peek_header), + MSG_PEEK | MSG_WAITALL); + if (result <= 0) { + if(errno == ECONNRESET) { + return 0; + } else if (errno == EINTR) { + return -1; + } else if (result < 0) { + PERROR("recv"); + return -1; + } + return 0; } - return 0; -} + memset(&msg, 0, sizeof(msg)); -/* Called after a fork. */ + iov[0].iov_base = (char *)header; + iov[0].iov_len = sizeof(struct ustcomm_header); -int ustcomm_close_all_connections(struct ustcomm_server *server) -{ - struct ustcomm_connection *conn; - struct ustcomm_connection *deletable_conn = NULL; + msg.msg_iov = iov; + msg.msg_iovlen = 1; - list_for_each_entry(conn, &server->connections, list) { - free(deletable_conn); - deletable_conn = conn; - ustcomm_close_app(conn); - list_del(&conn->list); + if (peek_header.size) { + *data = zmalloc(peek_header.size); + if (!*data) { + return -ENOMEM; + } + + iov[1].iov_base = *data; + iov[1].iov_len = peek_header.size; + + msg.msg_iovlen++; } - return 0; + result = recvmsg(sock, &msg, MSG_WAITALL); + if (result < 0) { + free(*data); + PERROR("recvmsg failed"); + } + + return result; } -/* @timeout: max blocking time in milliseconds, -1 means infinity - * - * returns 1 to indicate a message was received - * returns 0 to indicate no message was received +/* returns 1 to indicate a message was received + * returns 0 to indicate no message was received (end of stream) * returns -1 to indicate an error */ - -int ustcomm_recv_message(struct ustcomm_server *server, char **msg, struct ustcomm_source *src, int timeout) +int ustcomm_recv_fd(int sock, + struct ustcomm_header *header, + char *data, int *fd) { - struct pollfd *fds; - struct ustcomm_connection **conn_table; - struct ustcomm_connection *conn; int result; - int retval; - - for(;;) { - int idx = 0; - int n_fds = 1; - - list_for_each_entry(conn, &server->connections, list) { - n_fds++; - } - - fds = (struct pollfd *) malloc(n_fds * sizeof(struct pollfd)); - if(fds == NULL) { - ERR("malloc returned NULL"); + struct ustcomm_header peek_header; + struct iovec iov[2]; + struct msghdr msg; + struct cmsghdr *cmsg; + char buf[CMSG_SPACE(sizeof(int))]; + + result = recv(sock, &peek_header, sizeof(peek_header), + MSG_PEEK | MSG_WAITALL); + if (result <= 0) { + if(errno == ECONNRESET) { + return 0; + } else if (errno == EINTR) { + return -1; + } else if (result < 0) { + PERROR("recv"); return -1; } + return 0; + } - conn_table = (struct ustcomm_connection **) malloc(n_fds * sizeof(struct ustcomm_connection *)); - if(conn_table == NULL) { - ERR("malloc returned NULL"); - retval = -1; - goto free_fds_return; - } + memset(&msg, 0, sizeof(msg)); - /* special idx 0 is for listening socket */ - fds[idx].fd = server->listen_fd; - fds[idx].events = POLLIN; - idx++; + iov[0].iov_base = (char *)header; + iov[0].iov_len = sizeof(struct ustcomm_header); - list_for_each_entry(conn, &server->connections, list) { - fds[idx].fd = conn->fd; - fds[idx].events = POLLIN; - conn_table[idx] = conn; - idx++; - } + msg.msg_iov = iov; + msg.msg_iovlen = 1; - result = poll(fds, n_fds, timeout); - if(result == -1 && errno == EINTR) { - /* That's ok. ustd receives signals to notify it must shutdown. */ - retval = -1; - goto free_conn_table_return; - } - else if(result == -1) { - PERROR("poll"); - retval = -1; - goto free_conn_table_return; - } - else if(result == 0) { - retval = 0; - goto free_conn_table_return; + if (peek_header.size && data) { + if (peek_header.size < 0 || + peek_header.size > USTCOMM_DATA_SIZE) { + ERR("big peek header! %ld", peek_header.size); + return 0; } - if(fds[0].revents) { - struct ustcomm_connection *newconn; - int newfd; + iov[1].iov_base = data; + iov[1].iov_len = peek_header.size; - result = newfd = accept(server->listen_fd, NULL, NULL); - if(result == -1) { - PERROR("accept"); - retval = -1; - goto free_conn_table_return; - } - - newconn = (struct ustcomm_connection *) malloc(sizeof(struct ustcomm_connection)); - if(newconn == NULL) { - ERR("malloc returned NULL"); - return -1; - } + msg.msg_iovlen++; + } - ustcomm_init_connection(newconn); - newconn->fd = newfd; + if (fd && peek_header.fd_included) { + msg.msg_control = buf; + msg.msg_controllen = sizeof(buf); + } - list_add(&newconn->list, &server->connections); + result = recvmsg(sock, &msg, MSG_WAITALL); + if (result <= 0) { + if (result < 0) { + PERROR("recvmsg failed"); } + return result; + } - for(idx=1; idxfd = fds[idx].fd; - - if(retval == 0) { - /* connection finished */ - list_for_each_entry(conn, &server->connections, list) { - if(conn->fd == fds[idx].fd) { - ustcomm_close_app(conn); - list_del(&conn->list); - free(conn); - break; - } - } - } - else { - goto free_conn_table_return; - } + if (fd && peek_header.fd_included) { + cmsg = CMSG_FIRSTHDR(&msg); + result = 0; + while (cmsg != NULL) { + if (cmsg->cmsg_level == SOL_SOCKET + && cmsg->cmsg_type == SCM_RIGHTS) { + *fd = *(int *) CMSG_DATA(cmsg); + result = 1; + break; } + cmsg = CMSG_NXTHDR(&msg, cmsg); + } + if (!result) { + ERR("Failed to receive file descriptor\n"); } - - free(fds); - free(conn_table); } -free_conn_table_return: - free(conn_table); -free_fds_return: - free(fds); - return retval; -} - -int ustcomm_ustd_recv_message(struct ustcomm_ustd *ustd, char **msg, struct ustcomm_source *src, int timeout) -{ - return ustcomm_recv_message(&ustd->server, msg, src, timeout); + return 1; } -int ustcomm_app_recv_message(struct ustcomm_app *app, char **msg, struct ustcomm_source *src, int timeout) +int ustcomm_recv(int sock, + struct ustcomm_header *header, + char *data) { - return ustcomm_recv_message(&app->server, msg, src, timeout); + return ustcomm_recv_fd(sock, header, data, NULL); } -/* This removes src from the list of active connections of app. - */ -int ustcomm_app_detach_client(struct ustcomm_app *app, struct ustcomm_source *src) -{ - struct ustcomm_server *server = (struct ustcomm_server *)app; - struct ustcomm_connection *conn; - - list_for_each_entry(conn, &server->connections, list) { - if(conn->fd == src->fd) { - list_del(&conn->list); - goto found; - } - } - - return -1; -found: - return src->fd; -} - -static int init_named_socket(const char *name, char **path_out) +int ustcomm_send_fd(int sock, + const struct ustcomm_header *header, + const char *data, + int *fd) { + struct iovec iov[2]; + struct msghdr msg; int result; - int fd; + struct cmsghdr *cmsg; + char buf[CMSG_SPACE(sizeof(int))]; - struct sockaddr_un addr; - - result = fd = socket(PF_UNIX, SOCK_STREAM, 0); - if(result == -1) { - PERROR("socket"); - return -1; - } + memset(&msg, 0, sizeof(msg)); - addr.sun_family = AF_UNIX; + iov[0].iov_base = (char *)header; + iov[0].iov_len = sizeof(struct ustcomm_header); - strncpy(addr.sun_path, name, UNIX_PATH_MAX); - addr.sun_path[UNIX_PATH_MAX-1] = '\0'; + msg.msg_iov = iov; + msg.msg_iovlen = 1; - result = access(name, F_OK); - if(result == 0) { - /* file exists */ - result = unlink(name); - if(result == -1) { - PERROR("unlink of socket file"); - goto close_sock; - } - DBG("socket already exists; overwriting"); - } + if (header->size && data) { + iov[1].iov_base = (char *)data; + iov[1].iov_len = header->size; - result = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); - if(result == -1) { - PERROR("bind"); - goto close_sock; - } + msg.msg_iovlen++; - result = listen(fd, 1); - if(result == -1) { - PERROR("listen"); - goto close_sock; } - if(path_out) { - *path_out = strdup(addr.sun_path); + if (fd && header->fd_included) { + msg.msg_control = buf; + msg.msg_controllen = sizeof(buf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + *(int *) CMSG_DATA(cmsg) = *fd; + msg.msg_controllen = cmsg->cmsg_len; } - return fd; - - close_sock: - close(fd); - - return -1; + result = sendmsg(sock, &msg, MSG_NOSIGNAL); + if (result < 0 && errno != EPIPE) { + PERROR("sendmsg failed"); + } + return result; } -/* - * Return value: - * 0: Success, but no reply because recv() returned 0 - * 1: Success - * -1: Error - * - * On error, the error message is printed, except on - * ECONNRESET, which is normal when the application dies. - */ +int ustcomm_send(int sock, + const struct ustcomm_header *header, + const char *data) +{ + return ustcomm_send_fd(sock, header, data, NULL); +} -int ustcomm_send_request(struct ustcomm_connection *conn, const char *req, char **reply) +int ustcomm_req(int sock, + const struct ustcomm_header *req_header, + const char *req_data, + struct ustcomm_header *res_header, + char *res_data) { int result; - /* Send including the final \0 */ - result = send_message_fd(conn->fd, req); - if(result != 1) + result = ustcomm_send(sock, req_header, req_data); + if ( result <= 0) { return result; - - if(!reply) - return 1; - - result = recv_message_conn(conn, reply); - if(result == -1) { - return -1; - } - else if(result == 0) { - return 0; } - - return 1; + + return ustcomm_recv(sock, res_header, res_data); } /* Return value: @@ -548,50 +495,58 @@ int ustcomm_send_request(struct ustcomm_connection *conn, const char *req, char * -1: error */ -int ustcomm_connect_path(const char *path, struct ustcomm_connection *conn, pid_t signalpid) +int ustcomm_connect_path(const char *name, int *connection_fd) { - int fd; - int result; - struct sockaddr_un addr; - - ustcomm_init_connection(conn); + int result, fd; + size_t sock_addr_size; + struct sockaddr_un *addr; - result = fd = socket(PF_UNIX, SOCK_STREAM, 0); - if(result == -1) { + fd = socket(PF_UNIX, SOCK_STREAM, 0); + if(fd == -1) { PERROR("socket"); return -1; } - addr.sun_family = AF_UNIX; - - result = snprintf(addr.sun_path, UNIX_PATH_MAX, "%s", path); - if(result >= UNIX_PATH_MAX) { - ERR("string overflow allocating socket name"); - return -1; - } - - if(signalpid >= 0) { - result = signal_process(signalpid); - if(result == -1) { - ERR("could not signal process"); - return -1; - } + addr = create_sock_addr(name, &sock_addr_size); + if (addr == NULL) { + ERR("allocating addr failed"); + goto close_sock; } - result = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); + result = connect(fd, (struct sockaddr *)addr, sock_addr_size); if(result == -1) { - PERROR("connect (path=%s)", path); - return -1; + PERROR("connect (path=%s)", name); + goto free_sock_addr; } - conn->fd = fd; + *connection_fd = fd; + + free(addr); return 0; + +free_sock_addr: + free(addr); +close_sock: + close(fd); + + return -1; } -int ustcomm_disconnect(struct ustcomm_connection *conn) +/* Returns the current users socket directory, must be freed */ +char *ustcomm_user_sock_dir(void) { - return close(conn->fd); + int result; + char *sock_dir = NULL; + + result = asprintf(&sock_dir, "%s%s", USER_SOCK_DIR, + cuserid(NULL)); + if (result < 0) { + ERR("string overflow allocating directory name"); + return NULL; + } + + return sock_dir; } /* Open a connection to a traceable app. @@ -601,352 +556,301 @@ int ustcomm_disconnect(struct ustcomm_connection *conn) * -1: error */ -int ustcomm_connect_app(pid_t pid, struct ustcomm_connection *conn) +int ustcomm_connect_app(pid_t pid, int *app_fd) { int result; - char path[UNIX_PATH_MAX]; + int retval = 0; + char *dir_name, *sock_name; + dir_name = ustcomm_user_sock_dir(); + if (!dir_name) + return -ENOMEM; - result = snprintf(path, UNIX_PATH_MAX, "%s/%d", SOCK_DIR, pid); - if(result >= UNIX_PATH_MAX) { - ERR("string overflow allocating socket name"); - return -1; + result = asprintf(&sock_name, "%s/%d", dir_name, pid); + if (result < 0) { + ERR("failed to allocate socket name"); + retval = -1; + goto free_dir_name; } - return ustcomm_connect_path(path, conn, pid); -} - -/* Close a connection to a traceable app. It frees the - * resources. It however does not free the - * ustcomm_connection itself. - */ + result = ustcomm_connect_path(sock_name, app_fd); + if (result < 0) { + ERR("failed to connect to app"); + retval = -1; + goto free_sock_name; + } -int ustcomm_close_app(struct ustcomm_connection *conn) -{ - close(conn->fd); - free(conn->recv_buf); +free_sock_name: + free(sock_name); +free_dir_name: + free(dir_name); - return 0; + return retval; } -static int ensure_dir_exists(const char *dir) +int ensure_dir_exists(const char *dir, mode_t mode) { struct stat st; int result; - if(!strcmp(dir, "")) + if (!strcmp(dir, "")) return -1; result = stat(dir, &st); - if(result == -1 && errno != ENOENT) { + if (result < 0 && errno != ENOENT) { return -1; - } - else if(result == -1) { + } else if (result < 0) { /* ENOENT */ int result; - result = mkdir_p(dir, 0777); + result = mkdir_p(dir, mode); if(result != 0) { ERR("executing in recursive creation of directory %s", dir); return -1; } + } else { + if (st.st_mode != mode) { + result = chmod(dir, mode); + if (result < 0) { + ERR("couldn't set directory mode on %s", dir); + return -1; + } + } } return 0; } -/* Called by an application to initialize its server so daemons can - * connect to it. - */ - -int ustcomm_init_app(pid_t pid, struct ustcomm_app *handle) +char * ustcomm_print_data(char *data_field, int field_size, + int *offset, const char *format, ...) { - int result; - char *name; - - result = asprintf(&name, "%s/%d", SOCK_DIR, (int)pid); - if(result >= UNIX_PATH_MAX) { - ERR("string overflow allocating socket name"); - return -1; - } + va_list args; + int count, limit; + char *ptr = USTCOMM_POISON_PTR; - result = ensure_dir_exists(SOCK_DIR); - if(result == -1) { - ERR("Unable to create socket directory %s", SOCK_DIR); - return -1; - } + limit = field_size - *offset; + va_start(args, format); + count = vsnprintf(&data_field[*offset], limit, format, args); + va_end(args); - handle->server.listen_fd = init_named_socket(name, &(handle->server.socketpath)); - if(handle->server.listen_fd < 0) { - ERR("Error initializing named socket (%s). Check that directory exists and that it is writable.", name); - goto free_name; + if (count < limit && count > -1) { + ptr = NULL + *offset; + *offset = *offset + count + 1; } - free(name); - INIT_LIST_HEAD(&handle->server.connections); + return ptr; +} - return 0; +char * ustcomm_restore_ptr(char *ptr, char *data_field, int data_field_size) +{ + if ((unsigned long)ptr > data_field_size || + ptr == USTCOMM_POISON_PTR) { + return NULL; + } -free_name: - free(name); - return -1; + return data_field + (long)ptr; } -/* Used by the daemon to initialize its server so applications - * can connect to it. - */ - -int ustcomm_init_ustd(struct ustcomm_ustd *handle, const char *sock_path) +int ustcomm_pack_single_field(struct ustcomm_header *header, + struct ustcomm_single_field *single_field, + const char *string) { - char *name; - int retval = 0; + int offset = 0; - if(sock_path) { - asprintf(&name, "%s", sock_path); - } - else { - int result; + single_field->field = ustcomm_print_data(single_field->data, + sizeof(single_field->data), + &offset, + string); - /* Only check if socket dir exists if we are using the default directory */ - result = ensure_dir_exists(SOCK_DIR); - if(result == -1) { - ERR("Unable to create socket directory %s", SOCK_DIR); - return -1; - } - - asprintf(&name, "%s/%s", SOCK_DIR, "ustd"); + if (single_field->field == USTCOMM_POISON_PTR) { + return -ENOMEM; } - handle->server.listen_fd = init_named_socket(name, &handle->server.socketpath); - if(handle->server.listen_fd < 0) { - ERR("error initializing named socket at %s", name); - retval = -1; - goto free_name; - } + header->size = COMPUTE_MSG_SIZE(single_field, offset); - INIT_LIST_HEAD(&handle->server.connections); + return 0; +} -free_name: - free(name); +int ustcomm_unpack_single_field(struct ustcomm_single_field *single_field) +{ + single_field->field = ustcomm_restore_ptr(single_field->field, + single_field->data, + sizeof(single_field->data)); + if (!single_field->field) { + return -EINVAL; + } - return retval; + return 0; } -static void ustcomm_fini_server(struct ustcomm_server *server, int keep_socket_file) +int ustcomm_pack_channel_info(struct ustcomm_header *header, + struct ustcomm_channel_info *ch_inf, + const char *trace, + const char *channel) { - int result; - struct stat st; + int offset = 0; - if(!keep_socket_file) { - /* Destroy socket */ - result = stat(server->socketpath, &st); - if(result == -1) { - PERROR("stat (%s)", server->socketpath); - return; - } + ch_inf->trace = ustcomm_print_data(ch_inf->data, + sizeof(ch_inf->data), + &offset, + trace); - /* Paranoid check before deleting. */ - result = S_ISSOCK(st.st_mode); - if(!result) { - ERR("The socket we are about to delete is not a socket."); - return; - } - - result = unlink(server->socketpath); - if(result == -1) { - PERROR("unlink"); - } + if (ch_inf->trace == USTCOMM_POISON_PTR) { + return -ENOMEM; } - free(server->socketpath); + ch_inf->channel = ustcomm_print_data(ch_inf->data, + sizeof(ch_inf->data), + &offset, + channel); - result = close(server->listen_fd); - if(result == -1) { - PERROR("close"); - return; + if (ch_inf->channel == USTCOMM_POISON_PTR) { + return -ENOMEM; } -} -/* Free a traceable application server */ + header->size = COMPUTE_MSG_SIZE(ch_inf, offset); -void ustcomm_fini_app(struct ustcomm_app *handle, int keep_socket_file) -{ - ustcomm_fini_server(&handle->server, keep_socket_file); + return 0; } -/* Free a ustd server */ - -void ustcomm_fini_ustd(struct ustcomm_ustd *handle) -{ - ustcomm_fini_server(&handle->server, 0); -} -static const char *find_tok(const char *str) +int ustcomm_unpack_channel_info(struct ustcomm_channel_info *ch_inf) { - while(*str == ' ') { - str++; - - if(*str == 0) - return NULL; + ch_inf->trace = ustcomm_restore_ptr(ch_inf->trace, + ch_inf->data, + sizeof(ch_inf->data)); + if (!ch_inf->trace) { + return -EINVAL; } - return str; -} - -static const char *find_sep(const char *str) -{ - while(*str != ' ') { - str++; - - if(*str == 0) - break; + ch_inf->channel = ustcomm_restore_ptr(ch_inf->channel, + ch_inf->data, + sizeof(ch_inf->data)); + if (!ch_inf->channel) { + return -EINVAL; } - return str; + return 0; } -int nth_token_is(const char *str, const char *token, int tok_no) +int ustcomm_pack_buffer_info(struct ustcomm_header *header, + struct ustcomm_buffer_info *buf_inf, + const char *trace, + const char *channel, + int channel_cpu) { - int i; - const char *start; - const char *end; + int offset = 0; - for(i=0; i<=tok_no; i++) { - str = find_tok(str); - if(str == NULL) - return -1; + buf_inf->trace = ustcomm_print_data(buf_inf->data, + sizeof(buf_inf->data), + &offset, + trace); - start = str; + if (buf_inf->trace == USTCOMM_POISON_PTR) { + return -ENOMEM; + } - str = find_sep(str); - if(str == NULL) - return -1; + buf_inf->channel = ustcomm_print_data(buf_inf->data, + sizeof(buf_inf->data), + &offset, + channel); - end = str; + if (buf_inf->channel == USTCOMM_POISON_PTR) { + return -ENOMEM; } - if(end-start != strlen(token)) - return 0; + buf_inf->ch_cpu = channel_cpu; - if(strncmp(start, token, end-start)) - return 0; + header->size = COMPUTE_MSG_SIZE(buf_inf, offset); - return 1; + return 0; } -char *nth_token(const char *str, int tok_no) -{ - static char *retval = NULL; - int i; - const char *start; - const char *end; - - for(i=0; i<=tok_no; i++) { - str = find_tok(str); - if(str == NULL) - return NULL; - - start = str; - str = find_sep(str); - if(str == NULL) - return NULL; - - end = str; +int ustcomm_unpack_buffer_info(struct ustcomm_buffer_info *buf_inf) +{ + buf_inf->trace = ustcomm_restore_ptr(buf_inf->trace, + buf_inf->data, + sizeof(buf_inf->data)); + if (!buf_inf->trace) { + return -EINVAL; } - if(retval) { - free(retval); - retval = NULL; + buf_inf->channel = ustcomm_restore_ptr(buf_inf->channel, + buf_inf->data, + sizeof(buf_inf->data)); + if (!buf_inf->channel) { + return -EINVAL; } - asprintf(&retval, "%.*s", (int)(end-start), start); - - return retval; + return 0; } -/* Callback from multipoll. - * Receive a new connection on the listening socket. - */ - -static int process_mp_incoming_conn(void *priv, int fd, short events) +int ustcomm_pack_marker_info(struct ustcomm_header *header, + struct ustcomm_marker_info *marker_inf, + const char *trace, + const char *channel, + const char *marker) { - struct ustcomm_connection *newconn; - struct ustcomm_server *server = (struct ustcomm_server *) priv; - int newfd; - int result; + int offset = 0; - result = newfd = accept(server->listen_fd, NULL, NULL); - if(result == -1) { - PERROR("accept"); - return -1; - } + marker_inf->trace = ustcomm_print_data(marker_inf->data, + sizeof(marker_inf->data), + &offset, + trace); - newconn = (struct ustcomm_connection *) malloc(sizeof(struct ustcomm_connection)); - if(newconn == NULL) { - ERR("malloc returned NULL"); - return -1; + if (marker_inf->trace == USTCOMM_POISON_PTR) { + return -ENOMEM; } - ustcomm_init_connection(newconn); - newconn->fd = newfd; - list_add(&newconn->list, &server->connections); + marker_inf->channel = ustcomm_print_data(marker_inf->data, + sizeof(marker_inf->data), + &offset, + channel); - return 0; -} - -/* Callback from multipoll. - * Receive a message on an existing connection. - */ - -static int process_mp_conn_msg(void *priv, int fd, short revents) -{ - struct ustcomm_multipoll_conn_info *mpinfo = (struct ustcomm_multipoll_conn_info *) priv; - int result; - char *msg; - struct ustcomm_source src; + if (marker_inf->channel == USTCOMM_POISON_PTR) { + return -ENOMEM; + } - if(revents) { - src.fd = fd; - result = recv_message_conn(mpinfo->conn, &msg); - if(result == -1) { - ERR("error in recv_message_conn"); - } + marker_inf->marker = ustcomm_print_data(marker_inf->data, + sizeof(marker_inf->data), + &offset, + marker); - else if(result == 0) { - /* connection finished */ - ustcomm_close_app(mpinfo->conn); - list_del(&mpinfo->conn->list); - free(mpinfo->conn); - } - else { - mpinfo->cb(msg, &src); - free(msg); - } + if (marker_inf->marker == USTCOMM_POISON_PTR) { + return -ENOMEM; } - return 0; -} + header->size = COMPUTE_MSG_SIZE(marker_inf, offset); -int free_ustcomm_client_poll(void *data) -{ - free(data); return 0; } -void ustcomm_mp_add_app_clients(struct mpentries *ent, struct ustcomm_app *app, int (*cb)(char *recvbuf, struct ustcomm_source *src)) +int ustcomm_unpack_marker_info(struct ustcomm_marker_info *marker_inf) { - struct ustcomm_connection *conn; + marker_inf->trace = ustcomm_restore_ptr(marker_inf->trace, + marker_inf->data, + sizeof(marker_inf->data)); + if (!marker_inf->trace) { + return -EINVAL; + } - /* add listener socket */ - multipoll_add(ent, app->server.listen_fd, POLLIN, process_mp_incoming_conn, &app->server, NULL); + marker_inf->channel = ustcomm_restore_ptr(marker_inf->channel, + marker_inf->data, + sizeof(marker_inf->data)); + if (!marker_inf->channel) { + return -EINVAL; + } - list_for_each_entry(conn, &app->server.connections, list) { - struct ustcomm_multipoll_conn_info *mpinfo = (struct ustcomm_multipoll_conn_info *) malloc(sizeof(struct ustcomm_multipoll_conn_info)); - mpinfo->conn = conn; - mpinfo->cb = cb; - multipoll_add(ent, conn->fd, POLLIN, process_mp_conn_msg, mpinfo, free_ustcomm_client_poll); + marker_inf->marker = ustcomm_restore_ptr(marker_inf->marker, + marker_inf->data, + sizeof(marker_inf->data)); + if (!marker_inf->marker) { + return -EINVAL; } + + return 0; } +