Cygwin doesn't support file descriptors passing over UNIX sockets [1].
LTTng-ust and LTTng-tools make extensive use of this feature to pass
the shm and the wakeup pipe file descriptor from the userspace tracer
to the session daemon. The sessiond then pass those file descriptors
to the consumer.
To workaround this limitation, we pass the file paths of the shm and the
named wakeup pipe. These paths are relayed by the sessiond to the
consumer. The consumer then needs to open these paths.
The files are created in /tmp/lttng-fds and have the following format:
SHM : ust-shm-<pid>-<uuid>
Wakeup pipe : ust-wait-<pid>-<uuid>
[1] - http://cygwin.com/ml/cygwin/2009-10/msg00403.html
Signed-off-by: Christian Babeux <christian.babeux@efficios.com>
struct lttng_ust_object_data {
int handle;
int shm_fd;
+ char *shm_path;
int wait_fd;
+ char *wait_pipe_path;
uint64_t memory_map_size;
char padding[LTTNG_UST_OBJECT_DATA_PADDING];
};
union ust_args {
struct {
int *shm_fd;
+ char *shm_path;
int *wait_fd;
+ char *wait_pipe_path;
uint64_t *memory_map_size;
} channel;
struct {
int *shm_fd;
+ char *shm_path;
int *wait_fd;
+ char *wait_pipe_path;
uint64_t *memory_map_size;
} stream;
};
struct ust_app_channel *uchan,
uid_t uid, gid_t gid)
{
- int ret, fd;
+ int ret;
struct lttcomm_consumer_msg lum;
struct ltt_ust_stream *stream, *tmp;
PERROR("send consumer channel");
goto error;
}
- fd = uchan->obj->shm_fd;
- ret = lttcomm_send_fds_unix_sock(sock, &fd, 1);
+
+ DBG("Sending channel shm path: %s\n", uchan->obj->shm_path);
+ ret = lttcomm_send_string(sock,
+ uchan->obj->shm_path,
+ strlen(uchan->obj->shm_path));
if (ret < 0) {
- PERROR("send consumer channel ancillary data");
+ PERROR("send consumer channel shm path");
goto error;
}
cds_list_for_each_entry_safe(stream, tmp, &uchan->streams.head, list) {
- int fds[2];
if (!stream->obj->shm_fd) {
continue;
goto error;
}
- fds[0] = stream->obj->shm_fd;
- fds[1] = stream->obj->wait_fd;
- ret = lttcomm_send_fds_unix_sock(sock, fds, 2);
+ DBG("Sending stream shm path: %s\n", stream->obj->shm_path);
+ ret = lttcomm_send_string(sock,
+ stream->obj->shm_path,
+ strlen(stream->obj->shm_path));
if (ret < 0) {
- PERROR("send consumer stream ancillary data");
+ PERROR("send consumer stream shm path");
+ goto error;
+ }
+
+ DBG("Sending stream wait pipe path: %s\n", stream->obj->wait_pipe_path);
+ ret = lttcomm_send_string(sock,
+ stream->obj->wait_pipe_path,
+ strlen(stream->obj->wait_pipe_path));
+
+ if (ret < 0) {
+ PERROR("send consumer stream wait pipe path");
goto error;
}
}
}
if (usess->metadata->obj->shm_fd != 0) {
- int fd;
- int fds[2];
-
/* Send metadata channel fd */
lum.cmd_type = LTTNG_CONSUMER_ADD_CHANNEL;
lum.u.channel.channel_key = usess->metadata->obj->shm_fd;
PERROR("send consumer channel");
goto error;
}
- fd = usess->metadata->obj->shm_fd;
- ret = lttcomm_send_fds_unix_sock(sock, &fd, 1);
+
+ DBG("Sending metadata channel shm path: %s\n", usess->metadata->obj->shm_path);
+ ret = lttcomm_send_string(sock,
+ usess->metadata->obj->shm_path,
+ strlen(usess->metadata->obj->shm_path));
if (ret < 0) {
PERROR("send consumer metadata channel");
goto error;
PERROR("send consumer metadata stream");
goto error;
}
- fds[0] = usess->metadata->stream_obj->shm_fd;
- fds[1] = usess->metadata->stream_obj->wait_fd;
- ret = lttcomm_send_fds_unix_sock(sock, fds, 2);
+
+ DBG("Sending metadata stream shm path: %s\n",
+ usess->metadata->stream_obj->shm_path);
+ ret = lttcomm_send_string(sock,
+ usess->metadata->stream_obj->shm_path,
+ strlen(usess->metadata->stream_obj->shm_path));
+
if (ret < 0) {
- PERROR("send consumer stream");
+ PERROR("send consumer shm stream");
+ goto error;
+ }
+
+ DBG("Sending metadata stream wait pipe path: %s\n",
+ usess->metadata->stream_obj->wait_pipe_path);
+ ret = lttcomm_send_string(sock,
+ usess->metadata->stream_obj->wait_pipe_path,
+ strlen(usess->metadata->stream_obj->wait_pipe_path));
+
+ if (ret < 0) {
+ PERROR("send consumer shm stream");
goto error;
}
+
}
/* Send each channel fd streams of session */
return ret;
}
+ssize_t lttcomm_send_string(int sock, char *str, size_t len)
+{
+ ssize_t slen, ret = -1;
+
+ if (!str) {
+ goto end;
+ }
+
+ /* Send string len first */
+ slen = lttcomm_send_unix_sock(sock, &len, sizeof(len));
+
+ if (slen != sizeof(len)) {
+ fprintf(stderr,
+ "Unexpected sent size. Expected %zu got %zu\n",
+ sizeof(len), slen);
+ ret = -1;
+ goto end;
+ }
+
+ /* Send the actual string */
+ slen = lttcomm_send_unix_sock(sock, str, len);
+ if (slen != len) {
+ fprintf(stderr,
+ "Unexpected sent size. Expected %zu got %zu\n",
+ len, slen);
+ ret = -1;
+ goto end;
+ }
+
+ ret = slen;
+
+end:
+ return ret;
+}
+
+/*
+ * Allocate and return the received string.
+ * Return NULL on error.
+ * Caller is responsible of freeing the allocated string.
+ */
+char *lttcomm_recv_string(int sock)
+{
+ ssize_t rlen;
+ size_t len;
+ char *ret;
+
+ /* Get the string len first */
+ rlen = lttcomm_recv_unix_sock(sock, &len, sizeof(len));
+
+ if (rlen != sizeof(len)) {
+ fprintf(stderr,
+ "Unexpected received size. Expected %zu got %zu\n",
+ sizeof(len), rlen);
+ ret = NULL;
+ goto end;
+ }
+
+ /* Account for the NULL byte */
+ ret = malloc(len + 1);
+ if (!ret) {
+ ret = NULL;
+ goto end;
+ }
+
+ /* Get the actual string */
+ rlen = lttcomm_recv_unix_sock(sock, ret, len);
+ if (rlen != len) {
+ fprintf(stderr,
+ "Unexpected received size. Expected %zu got %zu\n",
+ len, rlen);
+ free(ret);
+ ret = NULL;
+ goto end;
+ }
+
+ /* Set terminating NULL byte */
+ ret[len] = '\0';
+
+end:
+ return ret;
+}
+
+
/*
* Send a message with credentials over a unix socket.
*
extern ssize_t lttcomm_recv_unix_sock(int sock, void *buf, size_t len);
extern ssize_t lttcomm_send_unix_sock(int sock, void *buf, size_t len);
+/* Send/recv string over unix socket */
+extern ssize_t lttcomm_send_string(int sock, char *str, size_t len);
+extern char *lttcomm_recv_string(int sock);
+
extern ssize_t lttcomm_send_creds_unix_sock(int sock, void *buf, size_t len);
extern ssize_t lttcomm_recv_creds_unix_sock(int sock, void *buf, size_t len,
lttng_sock_cred *creds);
{
struct lttng_consumer_channel *new_channel;
int fds[1];
- size_t nb_fd = 1;
+ char *path;
/* block */
if (lttng_consumer_poll_socket(consumer_sockpoll) < 0) {
return -EINTR;
}
- ret = lttcomm_recv_fds_unix_sock(sock, fds, nb_fd);
- if (ret != sizeof(fds)) {
+
+ path = lttcomm_recv_string(sock);
+
+ if (!path) {
lttng_consumer_send_error(ctx, CONSUMERD_ERROR_RECV_FD);
- return ret;
+ return -1;
+ }
+
+ DBG("consumer_add_channel received path %s", path);
+
+ fds[0] = open(path, O_RDWR);
+
+ if (fds[0] < 0) {
+ DBG("consumer_add_channel open error on path %s", path);
+ free(path);
+ return -1;
+ }
+
+ if (fcntl(fds[0], F_SETFD, FD_CLOEXEC) < 0) {
+ DBG("consumer_add_channel fcntl error");
+ free(path);
+ return -1;
}
+ free(path);
+
DBG("consumer_add_channel %d", msg.u.channel.channel_key);
new_channel = consumer_allocate_channel(msg.u.channel.channel_key,
case LTTNG_CONSUMER_ADD_STREAM:
{
struct lttng_consumer_stream *new_stream;
- int fds[2];
- size_t nb_fd = 2;
+ int fds[2], i;
+ char *shm_path, *wait_pipe_path;
/* block */
if (lttng_consumer_poll_socket(consumer_sockpoll) < 0) {
return -EINTR;
}
- ret = lttcomm_recv_fds_unix_sock(sock, fds, nb_fd);
- if (ret != sizeof(fds)) {
+
+ shm_path = lttcomm_recv_string(sock);
+
+ if (!shm_path) {
lttng_consumer_send_error(ctx, CONSUMERD_ERROR_RECV_FD);
- return ret;
+ return -1;
+ }
+
+ wait_pipe_path = lttcomm_recv_string(sock);
+
+ if (!wait_pipe_path) {
+ lttng_consumer_send_error(ctx, CONSUMERD_ERROR_RECV_FD);
+ free(shm_path);
+ return -1;
+ }
+
+ DBG("consumer_add_stream received path %s", shm_path);
+ DBG("consumer_add_stream received path %s", wait_pipe_path);
+
+ fds[0] = open(shm_path, O_RDWR);
+
+ if (fds[0] < 0) {
+ DBG("consumer_add_stream open error on path %s", shm_path);
+ free(shm_path);
+ free(wait_pipe_path);
+ return -1;
+ }
+
+ fds[1] = open(wait_pipe_path, O_RDONLY);
+
+ if (fds[1] < 0) {
+ DBG("consumer_add_stream open error on path %s", wait_pipe_path);
+ PERROR("open");
+ free(shm_path);
+ free(wait_pipe_path);
+ return -1;
+ }
+
+ free(shm_path);
+ free(wait_pipe_path);
+
+ for (i = 0; i < 2; ++i) {
+ if (fcntl(fds[i], F_SETFD, FD_CLOEXEC) < 0) {
+ DBG("consumer_add_stream fcntl error");
+ return -1;
+ }
}
DBG("consumer_add_stream %s (%d,%d)", msg.u.stream.path_name,