test-fd: add tests for fd and memfd accounting
authorDjalal Harouni <tixxdz@opendz.org>
Mon, 20 Oct 2014 16:12:12 +0000 (17:12 +0100)
committerDjalal Harouni <tixxdz@opendz.org>
Mon, 20 Oct 2014 16:12:12 +0000 (17:12 +0100)
Signed-off-by: Djalal Harouni <tixxdz@opendz.org>
test/test-fd.c

index 031c6ad7cdb3a8c1e611bb9ce172a85df8b5c3eb..89117db69a5f4ad01654d5ab9124c9d7880dad9a 100644 (file)
 #include "kdbus-util.h"
 #include "kdbus-enum.h"
 
+#define KDBUS_MSG_MAX_ITEMS     128
+#define KDBUS_MSG_MAX_FDS       253
 #define KDBUS_USER_MAX_CONN    256
 
-static int send_memfd(struct kdbus_conn *conn, uint64_t dst_id)
+static int make_msg_payload_dbus(uint64_t src_id, uint64_t dst_id,
+                                uint64_t msg_size,
+                                struct kdbus_msg **msg_dbus)
 {
-       struct kdbus_item *item;
        struct kdbus_msg *msg;
-       uint64_t size;
-       time_t now;
-       int ret, memfd;
 
-       now = time(NULL);
+       msg = malloc(msg_size);
+       ASSERT_RETURN_VAL(msg, -ENOMEM);
 
-       size = sizeof(struct kdbus_msg);
-       size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd));
+       memset(msg, 0, msg_size);
+       msg->size = msg_size;
+       msg->src_id = src_id;
+       msg->dst_id = dst_id;
+       msg->payload_type = KDBUS_PAYLOAD_DBUS;
+
+       *msg_dbus = msg;
+
+       return 0;
+}
+
+static void make_item_memfds(struct kdbus_item *item,
+                            int *memfds, size_t memfd_size)
+{
+       size_t i;
+
+       for (i = 0; i < memfd_size; i++) {
+               item->type = KDBUS_ITEM_PAYLOAD_MEMFD;
+               item->size = KDBUS_ITEM_HEADER_SIZE +
+                            sizeof(struct kdbus_memfd);
+               item->memfd.fd = memfds[i];
+               item->memfd.size = sizeof(uint64_t); /* const size */
+               item = KDBUS_ITEM_NEXT(item);
+       }
+}
 
-       memfd = sys_memfd_create("memfd-name", 0);
+static void make_item_fds(struct kdbus_item *item,
+                         int *fd_array, size_t fd_size)
+{
+       size_t i;
+       item->type = KDBUS_ITEM_FDS;
+       item->size = KDBUS_ITEM_HEADER_SIZE + (sizeof(int) * fd_size);
+
+       for (i = 0; i < fd_size; i++)
+               item->fds[i] = fd_array[i];
+}
+
+static int memfd_write(const char *name, void *buf, size_t bufsize)
+{
+       ssize_t ret;
+       int memfd;
+
+       memfd = sys_memfd_create(name, 0);
        ASSERT_RETURN_VAL(memfd >= 0, memfd);
 
-       ret = write(memfd, &now, sizeof(now));
-       ASSERT_RETURN_VAL(ret == sizeof(now), -EAGAIN);
+       ret = write(memfd, buf, bufsize);
+       ASSERT_RETURN_VAL(ret == (ssize_t)bufsize, -EAGAIN);
 
        ret = sys_memfd_seal_set(memfd);
        ASSERT_RETURN_VAL(ret == 0, -errno);
 
-       msg = malloc(size);
-       ASSERT_RETURN_VAL(msg, -ENOMEM);
+       return memfd;
+}
 
-       memset(msg, 0, size);
-       msg->size = size;
-       msg->src_id = conn->id;
-       msg->dst_id = dst_id;
-       msg->payload_type = KDBUS_PAYLOAD_DBUS;
+static int send_memfds(struct kdbus_conn *conn, uint64_t dst_id,
+                      int *memfds_array, size_t memfd_count)
+{
+       struct kdbus_item *item;
+       struct kdbus_msg *msg;
+       uint64_t size;
+       int ret;
+
+       size = sizeof(struct kdbus_msg);
+       size += memfd_count * KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd));
+
+       ret = make_msg_payload_dbus(conn->id, dst_id, size, &msg);
+       ASSERT_RETURN_VAL(ret == 0, ret);
 
        item = msg->items;
 
-       item->type = KDBUS_ITEM_PAYLOAD_MEMFD;
-       item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_memfd);
-       item->memfd.size = sizeof(now);
-       item->memfd.fd = memfd;
+       make_item_memfds(item, memfds_array, memfd_count);
 
        ret = ioctl(conn->fd, KDBUS_CMD_MSG_SEND, msg);
-       if (ret) {
-               kdbus_printf("error sending message: %d err %d (%m)\n",
-                            ret, errno);
-               return -errno;
+       if (ret < 0) {
+               ret = -errno;
+               kdbus_printf("error sending message: %d (%m)\n", ret);
+               return ret;
        }
 
-       close(memfd);
        free(msg);
-
        return 0;
 }
 
-static int send_fd(struct kdbus_conn *conn, uint64_t dst_id, int fd)
+static int send_fds(struct kdbus_conn *conn, uint64_t dst_id,
+                   int *fd_array, size_t fd_count)
 {
        struct kdbus_item *item;
        struct kdbus_msg *msg;
@@ -76,29 +120,132 @@ static int send_fd(struct kdbus_conn *conn, uint64_t dst_id, int fd)
        int ret;
 
        size = sizeof(struct kdbus_msg);
-       size += KDBUS_ITEM_SIZE(sizeof(int[2]));
+       size += KDBUS_ITEM_SIZE(sizeof(int) * fd_count);
 
-       msg = alloca(size);
+       ret = make_msg_payload_dbus(conn->id, dst_id, size, &msg);
+       ASSERT_RETURN_VAL(ret == 0, ret);
 
-       memset(msg, 0, size);
-       msg->size = size;
-       msg->src_id = conn->id;
-       msg->dst_id = dst_id;
-       msg->payload_type = KDBUS_PAYLOAD_DBUS;
+       item = msg->items;
+
+       make_item_fds(item, fd_array, fd_count);
+
+       ret = ioctl(conn->fd, KDBUS_CMD_MSG_SEND, msg);
+       if (ret < 0) {
+               ret = -errno;
+               kdbus_printf("error sending message: %d (%m)\n", ret);
+               return ret;
+       }
+
+       free(msg);
+       return ret;
+}
+
+static int send_fds_memfds(struct kdbus_conn *conn, uint64_t dst_id,
+                          int *fds_array, size_t fd_count,
+                          int *memfds_array, size_t memfd_count)
+{
+       struct kdbus_item *item;
+       struct kdbus_msg *msg;
+       uint64_t size;
+       int ret;
+
+       size = sizeof(struct kdbus_msg);
+       size += memfd_count * KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd));
+       size += KDBUS_ITEM_SIZE(sizeof(int) * fd_count);
+
+       ret = make_msg_payload_dbus(conn->id, dst_id, size, &msg);
+       ASSERT_RETURN_VAL(ret == 0, ret);
 
        item = msg->items;
 
-       item->type = KDBUS_ITEM_FDS;
-       item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(int);
-       item->fds[0] = fd;
+       make_item_fds(item, fds_array, fd_count);
+       item = KDBUS_ITEM_NEXT(item);
+       make_item_memfds(item, memfds_array, memfd_count);
 
        ret = ioctl(conn->fd, KDBUS_CMD_MSG_SEND, msg);
-       if (ret) {
-               kdbus_printf("error sending message: %d err %d (%m)\n",
-                            ret, errno);
-               return -errno;
+       if (ret < 0) {
+               ret = -errno;
+               kdbus_printf("error sending message: %d (%m)\n", ret);
+               return ret;
+       }
+
+       free(msg);
+       return ret;
+}
+
+static int kdbus_send_multiple_fds(struct kdbus_conn *conn_src,
+                                  struct kdbus_conn *conn_dst)
+{
+       int ret, i;
+       int fds[KDBUS_MSG_MAX_FDS + 1];
+       int memfds[KDBUS_MSG_MAX_ITEMS + 1];
+       struct kdbus_msg *msg;
+       uint64_t dummy_value;
+
+       dummy_value = time(NULL);
+
+       for (i = 0; i < KDBUS_MSG_MAX_FDS + 1; i++) {
+               fds[i] = open("/dev/null", O_RDWR|O_CLOEXEC);
+               ASSERT_RETURN_VAL(fds[i] >= 0, -errno);
        }
 
+       /* Send KDBUS_MSG_MAX_FDS with one more fd */
+       ret = send_fds(conn_src, conn_dst->id, fds, KDBUS_MSG_MAX_FDS + 1);
+       ASSERT_RETURN(ret == -EMFILE);
+
+       /* Retry with the correct KDBUS_MSG_MAX_FDS */
+       ret = send_fds(conn_src, conn_dst->id, fds, KDBUS_MSG_MAX_FDS);
+       ASSERT_RETURN(ret == 0);
+
+       ret = kdbus_msg_recv(conn_dst, &msg, NULL);
+       ASSERT_RETURN(ret == 0);
+
+       kdbus_msg_free(msg);
+
+       for (i = 0; i < KDBUS_MSG_MAX_ITEMS + 1; i++, dummy_value++) {
+               memfds[i] = memfd_write("memfd-name",
+                                       &dummy_value,
+                                       sizeof(dummy_value));
+               ASSERT_RETURN_VAL(memfds[i] >= 0, memfds[i]);
+       }
+
+       /* Send KDBUS_MSG_MAX_FDS with one more memfd */
+       ret = send_memfds(conn_src, conn_dst->id,
+                         memfds, KDBUS_MSG_MAX_ITEMS + 1);
+       ASSERT_RETURN(ret == -E2BIG);
+
+       /* Retry with the correct KDBUS_MSG_MAX_ITEMS */
+       ret = send_memfds(conn_src, conn_dst->id,
+                         memfds, KDBUS_MSG_MAX_ITEMS);
+       ASSERT_RETURN(ret == 0);
+
+       ret = kdbus_msg_recv(conn_dst, &msg, NULL);
+       ASSERT_RETURN(ret == 0);
+
+       kdbus_msg_free(msg);
+
+
+       /* Combine multiple 154 fds and 100 memfds */
+       ret = send_fds_memfds(conn_src, conn_dst->id,
+                             fds, 154, memfds, 100);
+       ASSERT_RETURN(ret == -EMFILE);
+
+       ret = send_fds_memfds(conn_src, conn_dst->id,
+                             fds, 153, memfds, 100);
+       ASSERT_RETURN(ret == 0);
+
+       ret = kdbus_msg_recv(conn_dst, &msg, NULL);
+       ASSERT_RETURN(ret == 0);
+
+       kdbus_msg_free(msg);
+
+
+       for (i = 0; i < KDBUS_MSG_MAX_FDS + 1; i++)
+               close(fds[i]);
+
+       for (i = 0; i < KDBUS_MSG_MAX_ITEMS + 1; i++)
+               close(memfds[i]);
+
        return 0;
 }
 
@@ -109,22 +256,30 @@ int kdbus_test_fd_passing(struct kdbus_test_env *env)
        const struct kdbus_item *item;
        struct kdbus_msg *msg;
        unsigned int i;
+       time_t now;
+       int fds_conn[2];
        int fds[2];
+       int memfd;
        int ret;
 
+       now = time(NULL);
+
        /* create two connections */
        conn_src = kdbus_hello(env->buspath, 0, NULL, 0);
        conn_dst = kdbus_hello(env->buspath, 0, NULL, 0);
        ASSERT_RETURN(conn_src && conn_dst);
 
+       fds_conn[0] = conn_src->fd;
+       fds_conn[1] = conn_dst->fd;
+
        /*
         * Try to ass the handle of a connection as message payload.
         * This must fail.
         */
-       ret = send_fd(conn_src, conn_dst->id, conn_src->fd);
+       ret = send_fds(conn_src, conn_dst->id, fds_conn, 2);
        ASSERT_RETURN(ret == -ENOTSUP);
 
-       ret = send_fd(conn_src, conn_dst->id, conn_dst->fd);
+       ret = send_fds(conn_src, conn_dst->id, fds_conn, 2);
        ASSERT_RETURN(ret == -ENOTSUP);
 
        ret = pipe(fds);
@@ -134,10 +289,10 @@ int kdbus_test_fd_passing(struct kdbus_test_env *env)
        ASSERT_RETURN(i == strlen(str));
 
        /* Try to broadcast file descriptors. This must fail. */
-       ret = send_fd(conn_src, KDBUS_DST_ID_BROADCAST, fds[0]);
+       ret = send_fds(conn_src, KDBUS_DST_ID_BROADCAST, fds, 1);
        ASSERT_RETURN(ret == -ENOTUNIQ);
 
-       ret = send_fd(conn_src, conn_dst->id, fds[0]);
+       ret = send_fds(conn_src, conn_dst->id, fds, 1);
        ASSERT_RETURN(ret == 0);
 
        ret = kdbus_msg_recv(conn_dst, &msg, NULL);
@@ -148,7 +303,6 @@ int kdbus_test_fd_passing(struct kdbus_test_env *env)
                        char tmp[14];
                        int nfds = (item->size - KDBUS_ITEM_HEADER_SIZE) /
                                        sizeof(int);
-
                        ASSERT_RETURN(nfds == 1);
 
                        i = read(item->fds[0], tmp, sizeof(tmp));
@@ -159,12 +313,22 @@ int kdbus_test_fd_passing(struct kdbus_test_env *env)
                }
        }
 
+       kdbus_msg_free(msg);
+
+       memfd = memfd_write("memfd-name", &now, sizeof(now));
+       ASSERT_RETURN(memfd >= 0);
+
        /* Try to broadcast memfd. This must fail. */
-       ret = send_memfd(conn_src, KDBUS_DST_ID_BROADCAST);
+       ret = send_memfds(conn_src, KDBUS_DST_ID_BROADCAST,
+                         (int *)&memfd, 1);
        ASSERT_RETURN(ret == -ENOTUNIQ);
 
+       ret = kdbus_send_multiple_fds(conn_src, conn_dst);
+       ASSERT_RETURN(ret == 0);
+
        close(fds[0]);
        close(fds[1]);
+       close(memfd);
 
        kdbus_conn_free(conn_src);
        kdbus_conn_free(conn_dst);