int kdbus_test_conn_update(struct kdbus_test_env *env) { const struct kdbus_item *item; struct kdbus_conn *conn; struct kdbus_msg *msg; int found = 0; int ret; /* * kdbus_hello() sets all attach flags. Receive a message by this * connection, and make sure a timestamp item (just to pick one) is * present. */ conn = kdbus_hello(env->buspath, 0, NULL, 0); ASSERT_RETURN(conn); ret = kdbus_msg_send(env->conn, NULL, 0x12345678, 0, 0, 0, conn->id); ASSERT_RETURN(ret == 0); ret = kdbus_msg_recv(conn, &msg, NULL); ASSERT_RETURN(ret == 0); KDBUS_ITEM_FOREACH(item, msg, items) if (item->type == KDBUS_ITEM_TIMESTAMP) found = 1; ASSERT_RETURN(found == 1); /* * Now, modify the attach flags and repeat the action. The item must * now be missing. */ found = 0; ret = kdbus_conn_update_attach_flags(conn, _KDBUS_ATTACH_ALL & ~KDBUS_ATTACH_TIMESTAMP); ASSERT_RETURN(ret == 0); ret = kdbus_msg_send(env->conn, NULL, 0x12345678, 0, 0, 0, conn->id); ASSERT_RETURN(ret == 0); ret = kdbus_msg_recv(conn, &msg, NULL); ASSERT_RETURN(ret == 0); KDBUS_ITEM_FOREACH(item, msg, items) if (item->type == KDBUS_ITEM_TIMESTAMP) found = 1; ASSERT_RETURN(found == 0); kdbus_conn_free(conn); return TEST_OK; }
int kdbus_test_monitor(struct kdbus_test_env *env) { struct kdbus_conn *monitor, *conn; unsigned int cookie = 0xdeadbeef; struct kdbus_cmd_name *cmd_name; struct kdbus_msg *msg; size_t size; char *name; int ret; monitor = kdbus_hello(env->buspath, KDBUS_HELLO_MONITOR, NULL, 0); ASSERT_RETURN(monitor); /* taking a name must fail */ name = "foo.bla.blaz"; size = sizeof(*cmd_name) + strlen(name) + 1; cmd_name = alloca(size); memset(cmd_name, 0, size); strcpy(cmd_name->name, name); cmd_name->size = size; cmd_name->flags = 0; /* check that we can acquire a name */ ret = ioctl(monitor->fd, KDBUS_CMD_NAME_ACQUIRE, cmd_name); ASSERT_RETURN(ret == -1 && errno == EOPNOTSUPP); conn = kdbus_hello(env->buspath, 0, NULL, 0); ASSERT_RETURN(conn); ret = kdbus_msg_send(env->conn, NULL, cookie, 0, 0, 0, conn->id); ASSERT_RETURN(ret == 0); /* the recipient should have got the message */ ret = kdbus_msg_recv(conn, &msg); ASSERT_RETURN(ret == 0); ASSERT_RETURN(msg->cookie == cookie); kdbus_msg_free(msg); /* and so should the monitor */ ret = kdbus_msg_recv(monitor, &msg); ASSERT_RETURN(ret == 0); ASSERT_RETURN(msg->cookie == cookie); kdbus_msg_free(msg); kdbus_conn_free(monitor); kdbus_conn_free(conn); return TEST_OK; }
int kdbus_msg_recv_poll(struct kdbus_conn *conn, struct kdbus_msg **msg_out, unsigned int timeout_ms) { int ret; for (; timeout_ms; timeout_ms--) { ret = kdbus_msg_recv(conn, NULL); if (ret == -EAGAIN) { usleep(1000); continue; } if (ret < 0) return ret; if (ret == 0) return 0; } if (timeout_ms == 0) return -ETIMEDOUT; return 0; }
int kdbus_test_fd_passing(struct kdbus_test_env *env) { struct kdbus_conn *conn_src, *conn_dst; const char *str = "stackenblocken"; const struct kdbus_item *item; struct kdbus_msg *msg; unsigned int i; int fds[2]; int ret; /* 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); /* * 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); ASSERT_RETURN(ret == -ELOOP); ret = send_fd(conn_src, conn_dst->id, conn_dst->fd); ASSERT_RETURN(ret == -ELOOP); ret = pipe(fds); ASSERT_RETURN(ret == 0); i = write(fds[1], str, strlen(str)); ASSERT_RETURN(i == strlen(str)); ret = send_fd(conn_src, conn_dst->id, fds[0]); ASSERT_RETURN(ret == 0); ret = kdbus_msg_recv(conn_dst, &msg); ASSERT_RETURN(ret == 0); KDBUS_ITEM_FOREACH(item, msg, items) { if (item->type == KDBUS_ITEM_FDS) { 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)); ASSERT_RETURN(i == sizeof(tmp)); ASSERT_RETURN(memcmp(tmp, str, sizeof(tmp)) == 0); close(item->fds[0]); break; } } return TEST_OK; }
int kdbus_test_message_basic(struct kdbus_test_env *env) { struct kdbus_conn *conn; struct kdbus_conn *sender; struct kdbus_msg *msg; uint64_t cookie = 0x1234abcd5678eeff; uint64_t offset; int ret; sender = kdbus_hello(env->buspath, 0, NULL, 0); ASSERT_RETURN(sender != NULL); /* create a 2nd connection */ conn = kdbus_hello(env->buspath, 0, NULL, 0); ASSERT_RETURN(conn != NULL); ret = kdbus_add_match_empty(conn); ASSERT_RETURN(ret == 0); ret = kdbus_add_match_empty(sender); ASSERT_RETURN(ret == 0); /* send over 1st connection */ ret = kdbus_msg_send(sender, NULL, cookie, 0, 0, 0, KDBUS_DST_ID_BROADCAST); ASSERT_RETURN(ret == 0); /* Make sure that we do not get our own broadcasts */ ret = kdbus_msg_recv(sender, NULL, NULL); ASSERT_RETURN(ret == -EAGAIN); /* ... and receive on the 2nd */ ret = kdbus_msg_recv_poll(conn, 100, &msg, &offset); ASSERT_RETURN(ret == 0); ASSERT_RETURN(msg->cookie == cookie); kdbus_msg_free(msg); ret = kdbus_free(conn, offset); ASSERT_RETURN(ret == 0); kdbus_conn_free(sender); kdbus_conn_free(conn); return TEST_OK; }
int kdbus_test_daemon(struct kdbus_test_env *env) { struct pollfd fds[2]; int count; int ret; /* This test doesn't make any sense in non-interactive mode */ if (!kdbus_util_verbose) return TEST_OK; printf("Created connection %llu on bus '%s'\n", (unsigned long long) env->conn->id, env->buspath); kdbus_name_acquire(env->conn, "com.example.kdbus-test", 0); kdbus_printf(" Aquired name: com.example.kdbus-test\n"); fds[0].fd = env->conn->fd; fds[1].fd = STDIN_FILENO; printf("Monitoring connections:\n"); for (count = 0;; count++) { int i, nfds = sizeof(fds) / sizeof(fds[0]); for (i = 0; i < nfds; i++) { fds[i].events = POLLIN | POLLPRI | POLLHUP; fds[i].revents = 0; } ret = poll(fds, nfds, -1); if (ret <= 0) break; if (fds[0].revents & POLLIN) kdbus_msg_recv(env->conn, NULL); /* stdin */ if (fds[1].revents & POLLIN) break; } printf("Closing bus connection\n"); return TEST_OK; }
int kdbus_msg_recv_poll(struct kdbus_conn *conn, unsigned int timeout_ms, struct kdbus_msg **msg_out, uint64_t *offset) { int ret; for (; timeout_ms; timeout_ms--) { ret = kdbus_msg_recv(conn, msg_out, offset); if (ret == -EAGAIN) { usleep(1000); continue; } if (ret < 0) return ret; if (ret == 0) return 0; } return -ETIMEDOUT; }
static void *run_thread(void *data) { struct pollfd fd; int ret; fd.fd = conn_a->fd; fd.events = POLLIN | POLLPRI | POLLHUP; fd.revents = 0; ret = poll(&fd, 1, 3000); if (ret <= 0) goto thread_exit; if (fd.revents & POLLIN) { kdbus_printf("Thread received message, sending reply ...\n"); kdbus_msg_recv(conn_a, NULL, NULL); kdbus_msg_send(conn_a, NULL, 0, 0, cookie, 0, conn_b->id); } thread_exit: pthread_exit(NULL); return NULL; }
int kdbus_test_activator(struct kdbus_test_env *env) { int ret; struct kdbus_conn *activator; struct pollfd fds[2]; bool activator_done = false; struct kdbus_policy_access access[2]; access[0].type = KDBUS_POLICY_ACCESS_USER; access[0].id = 1001; access[0].access = KDBUS_POLICY_OWN; access[1].type = KDBUS_POLICY_ACCESS_WORLD; access[1].access = KDBUS_POLICY_TALK; activator = kdbus_hello_activator(env->buspath, "foo.test.activator", access, 2); ASSERT_RETURN(activator); ret = kdbus_add_match_empty(env->conn); ASSERT_RETURN(ret == 0); ret = kdbus_name_list(env->conn, KDBUS_NAME_LIST_NAMES | KDBUS_NAME_LIST_UNIQUE | KDBUS_NAME_LIST_ACTIVATORS | KDBUS_NAME_LIST_QUEUED); ASSERT_RETURN(ret == 0); ret = kdbus_msg_send(env->conn, "foo.test.activator", 0xdeafbeef, 0, 0, 0, KDBUS_DST_ID_NAME); ASSERT_RETURN(ret == 0); fds[0].fd = activator->fd; fds[1].fd = env->conn->fd; kdbus_printf("-- entering poll loop ...\n"); for (;;) { int i, nfds = sizeof(fds) / sizeof(fds[0]); for (i = 0; i < nfds; i++) { fds[i].events = POLLIN | POLLPRI; fds[i].revents = 0; } ret = poll(fds, nfds, 3000); ASSERT_RETURN(ret >= 0); ret = kdbus_name_list(env->conn, KDBUS_NAME_LIST_NAMES); ASSERT_RETURN(ret == 0); if ((fds[0].revents & POLLIN) && !activator_done) { kdbus_printf("Starter was called back!\n"); ret = kdbus_name_acquire(env->conn, "foo.test.activator", KDBUS_NAME_REPLACE_EXISTING); ASSERT_RETURN(ret == 0); activator_done = true; } if (fds[1].revents & POLLIN) { kdbus_msg_recv(env->conn, NULL); break; } } kdbus_conn_free(activator); return TEST_OK; }
static void *run_thread_byebye(void *data) { struct kdbus_cmd cmd_byebye = { .size = sizeof(cmd_byebye) }; int ret; ret = kdbus_msg_recv_poll(conn_a, 3000, NULL, NULL); if (ret == 0) { kdbus_printf("Thread received message, invoking BYEBYE ...\n"); kdbus_msg_recv(conn_a, NULL, NULL); if (data == BYEBYE_ME) kdbus_cmd_byebye(conn_b->fd, &cmd_byebye); else if (data == BYEBYE_THEM) kdbus_cmd_byebye(conn_a->fd, &cmd_byebye); } pthread_exit(NULL); return NULL; } int kdbus_test_sync_byebye(struct kdbus_test_env *env) { pthread_t thread; int ret; /* * This sends a synchronous message to a thread, which waits until it * received the message and then invokes BYEBYE on the *ORIGINAL* * connection. That is, on the same connection that synchronously waits * for an reply. * This should properly wake the connection up and cause ECONNRESET as * the connection is disconnected now. * * The second time, we do the same but invoke BYEBYE on the *TARGET* * connection. This should also wake up the synchronous sender as the * reply cannot be sent by a disconnected target. */ conn_a = kdbus_hello(env->buspath, 0, NULL, 0); conn_b = kdbus_hello(env->buspath, 0, NULL, 0); ASSERT_RETURN(conn_a && conn_b); pthread_create(&thread, NULL, run_thread_byebye, BYEBYE_ME); ret = kdbus_msg_send_sync(conn_b, NULL, cookie, KDBUS_MSG_EXPECT_REPLY, 5000000000ULL, 0, conn_a->id, -1); ASSERT_RETURN(ret == -ECONNRESET); pthread_join(thread, NULL); kdbus_conn_free(conn_a); kdbus_conn_free(conn_b); conn_a = kdbus_hello(env->buspath, 0, NULL, 0); conn_b = kdbus_hello(env->buspath, 0, NULL, 0); ASSERT_RETURN(conn_a && conn_b); pthread_create(&thread, NULL, run_thread_byebye, BYEBYE_THEM); ret = kdbus_msg_send_sync(conn_b, NULL, cookie, KDBUS_MSG_EXPECT_REPLY, 5000000000ULL, 0, conn_a->id, -1); ASSERT_RETURN(ret == -EPIPE); pthread_join(thread, NULL); kdbus_conn_free(conn_a); kdbus_conn_free(conn_b); return TEST_OK; }
static int msg_recv_prio(struct kdbus_conn *conn, int64_t requested_prio, int64_t expected_prio) { struct kdbus_cmd_recv recv = { .size = sizeof(recv), .flags = KDBUS_RECV_USE_PRIORITY, .priority = requested_prio, }; struct kdbus_msg *msg; int ret; ret = ioctl(conn->fd, KDBUS_CMD_RECV, &recv); if (ret < 0) { kdbus_printf("error receiving message: %d (%m)\n", -errno); return -errno; } msg = (struct kdbus_msg *)(conn->buf + recv.reply.offset); kdbus_msg_dump(conn, msg); if (msg->priority != expected_prio) { kdbus_printf("expected message prio %lld, got %lld\n", (unsigned long long) expected_prio, (unsigned long long) msg->priority); return -EINVAL; } kdbus_msg_free(msg); ret = kdbus_free(conn, recv.reply.offset); if (ret < 0) return ret; return 0; } int kdbus_test_message_prio(struct kdbus_test_env *env) { struct kdbus_conn *a, *b; uint64_t cookie = 0; a = kdbus_hello(env->buspath, 0, NULL, 0); b = kdbus_hello(env->buspath, 0, NULL, 0); ASSERT_RETURN(a && b); ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, 25, a->id) == 0); ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -600, a->id) == 0); ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, 10, a->id) == 0); ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -35, a->id) == 0); ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -100, a->id) == 0); ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, 20, a->id) == 0); ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -15, a->id) == 0); ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -800, a->id) == 0); ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -150, a->id) == 0); ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, 10, a->id) == 0); ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -800, a->id) == 0); ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -10, a->id) == 0); ASSERT_RETURN(msg_recv_prio(a, -200, -800) == 0); ASSERT_RETURN(msg_recv_prio(a, -100, -800) == 0); ASSERT_RETURN(msg_recv_prio(a, -400, -600) == 0); ASSERT_RETURN(msg_recv_prio(a, -400, -600) == -ENOMSG); ASSERT_RETURN(msg_recv_prio(a, 10, -150) == 0); ASSERT_RETURN(msg_recv_prio(a, 10, -100) == 0); kdbus_printf("--- get priority (all)\n"); ASSERT_RETURN(kdbus_msg_recv(a, NULL, NULL) == 0); kdbus_conn_free(a); kdbus_conn_free(b); return TEST_OK; } static int kdbus_test_notify_kernel_quota(struct kdbus_test_env *env) { int ret; unsigned int i; uint64_t offset; struct kdbus_conn *conn; struct kdbus_conn *reader; struct kdbus_msg *msg = NULL; reader = kdbus_hello(env->buspath, 0, NULL, 0); ASSERT_RETURN(reader); conn = kdbus_hello(env->buspath, 0, NULL, 0); ASSERT_RETURN(conn); /* Register for ID signals */ ret = kdbus_add_match_id(reader, 0x1, KDBUS_ITEM_ID_ADD, KDBUS_MATCH_ID_ANY); ASSERT_RETURN(ret == 0); ret = kdbus_add_match_id(reader, 0x2, KDBUS_ITEM_ID_REMOVE, KDBUS_MATCH_ID_ANY); ASSERT_RETURN(ret == 0); /* Each iteration two notifications: add and remove ID */ for (i = 0; i < KDBUS_CONN_MAX_MSGS / 2; i++) { struct kdbus_conn *notifier; notifier = kdbus_hello(env->buspath, 0, NULL, 0); ASSERT_RETURN(notifier); kdbus_conn_free(notifier); } /* * Now the reader queue is full, message will be lost * but it will not be accounted in dropped msgs */ ret = kdbus_msg_send(conn, NULL, 0xdeadbeef, 0, 0, 0, reader->id); ASSERT_RETURN(ret == -ENOBUFS); /* More ID kernel notifications that will be lost */ kdbus_conn_free(conn); conn = kdbus_hello(env->buspath, 0, NULL, 0); ASSERT_RETURN(conn); kdbus_conn_free(conn); ret = kdbus_msg_recv(reader, &msg, &offset); ASSERT_RETURN(ret == -EOVERFLOW); /* * We lost only 3 packet since only broadcast mesg * are accounted. The connection ID add/remove notification */ ASSERT_RETURN(offset == 3); kdbus_msg_free(msg); /* Read our queue */ for (i = 0; i < KDBUS_CONN_MAX_MSGS; i++) { ret = kdbus_msg_recv_poll(reader, 100, &msg, NULL); ASSERT_RETURN(ret == 0); kdbus_msg_free(msg); } ret = kdbus_msg_recv(reader, NULL, NULL); ASSERT_RETURN(ret == -EAGAIN); kdbus_conn_free(reader); return 0; }
int kdbus_test_chat(struct kdbus_test_env *env) { int ret, cookie; struct kdbus_conn *conn_a, *conn_b; struct pollfd fds[2]; uint64_t flags; int count; conn_a = kdbus_hello(env->buspath, 0, NULL, 0); conn_b = kdbus_hello(env->buspath, 0, NULL, 0); ASSERT_RETURN(conn_a && conn_b); flags = KDBUS_NAME_ALLOW_REPLACEMENT; ret = kdbus_name_acquire(conn_a, "foo.bar.test", &flags); ASSERT_RETURN(ret == 0); ret = kdbus_name_acquire(conn_a, "foo.bar.baz", NULL); ASSERT_RETURN(ret == 0); flags = KDBUS_NAME_QUEUE; ret = kdbus_name_acquire(conn_b, "foo.bar.baz", &flags); ASSERT_RETURN(ret == 0); ret = kdbus_name_acquire(conn_a, "foo.bar.double", NULL); ASSERT_RETURN(ret == 0); ret = kdbus_name_acquire(conn_a, "foo.bar.double", NULL); ASSERT_RETURN(ret == -EALREADY); ret = kdbus_name_release(conn_a, "foo.bar.double"); ASSERT_RETURN(ret == 0); ret = kdbus_name_release(conn_a, "foo.bar.double"); ASSERT_RETURN(ret == -ESRCH); ret = kdbus_list(conn_b, KDBUS_LIST_UNIQUE | KDBUS_LIST_NAMES | KDBUS_LIST_QUEUED | KDBUS_LIST_ACTIVATORS); ASSERT_RETURN(ret == 0); ret = kdbus_add_match_empty(conn_a); ASSERT_RETURN(ret == 0); ret = kdbus_add_match_empty(conn_b); ASSERT_RETURN(ret == 0); cookie = 0; ret = kdbus_msg_send(conn_b, NULL, 0xc0000000 | cookie, 0, 0, 0, KDBUS_DST_ID_BROADCAST); ASSERT_RETURN(ret == 0); fds[0].fd = conn_a->fd; fds[1].fd = conn_b->fd; kdbus_printf("-- entering poll loop ...\n"); for (count = 0;; count++) { int i, nfds = sizeof(fds) / sizeof(fds[0]); for (i = 0; i < nfds; i++) { fds[i].events = POLLIN | POLLPRI | POLLHUP; fds[i].revents = 0; } ret = poll(fds, nfds, 3000); ASSERT_RETURN(ret >= 0); if (fds[0].revents & POLLIN) { if (count > 2) kdbus_name_release(conn_a, "foo.bar.baz"); ret = kdbus_msg_recv(conn_a, NULL, NULL); ASSERT_RETURN(ret == 0); ret = kdbus_msg_send(conn_a, NULL, 0xc0000000 | cookie++, 0, 0, 0, conn_b->id); ASSERT_RETURN(ret == 0); } if (fds[1].revents & POLLIN) { ret = kdbus_msg_recv(conn_b, NULL, NULL); ASSERT_RETURN(ret == 0); ret = kdbus_msg_send(conn_b, NULL, 0xc0000000 | cookie++, 0, 0, 0, conn_a->id); ASSERT_RETURN(ret == 0); } ret = kdbus_list(conn_b, KDBUS_LIST_UNIQUE | KDBUS_LIST_NAMES | KDBUS_LIST_QUEUED | KDBUS_LIST_ACTIVATORS); ASSERT_RETURN(ret == 0); if (count > 10) break; } kdbus_printf("-- closing bus connections\n"); kdbus_conn_free(conn_a); kdbus_conn_free(conn_b); return TEST_OK; }