From 6dcf2c7eab0f39a17f22b09df94e5fcdac8726d1 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 24 Feb 2014 11:48:16 +0000 Subject: lib: Add unix_msg This is a messaging layer based on unix domain datagram sockets. Sending to an idle socket is just one single nonblocking sendmsg call. If the recv queue is full, we start a background thread to do a blocking call. The source4 based imessaging uses a polling fallback. In a situation where thousands of senders beat one single blocked socket, this will generate load on the system due to the constant polling. This does not happen with a threaded blocking send call. The threaded approach has another advantage: We save become_root() calls on the retries. The access checks are done when the blocking socket is connected, the threaded blocking send call does not check permissions anymore. Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/lib/unix_msg/tests.c | 225 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 source3/lib/unix_msg/tests.c (limited to 'source3/lib/unix_msg/tests.c') diff --git a/source3/lib/unix_msg/tests.c b/source3/lib/unix_msg/tests.c new file mode 100644 index 0000000000..2a4cf86234 --- /dev/null +++ b/source3/lib/unix_msg/tests.c @@ -0,0 +1,225 @@ +#include "replace.h" +#include "unix_msg.h" +#include "poll_funcs/poll_funcs_tevent.h" +#include "tevent.h" + +struct cb_state { + unsigned num_received; + uint8_t *buf; + size_t buflen; +}; + +static void recv_cb(struct unix_msg_ctx *ctx, + uint8_t *msg, size_t msg_len, + void *private_data); + +static void expect_messages(struct tevent_context *ev, struct cb_state *state, + unsigned num_msgs) +{ + state->num_received = 0; + + while (state->num_received < num_msgs) { + int ret; + + ret = tevent_loop_once(ev); + if (ret == -1) { + fprintf(stderr, "tevent_loop_once failed: %s\n", + strerror(errno)); + exit(1); + } + } +} + +int main(void) +{ + struct poll_funcs funcs; + const char *sock1 = "sock1"; + const char *sock2 = "sock2"; + struct unix_msg_ctx *ctx1, *ctx2; + struct tevent_context *ev; + struct iovec iov; + uint8_t msg; + int i, ret; + static uint8_t buf[1755]; + + struct cb_state state; + + unlink(sock1); + unlink(sock2); + + ev = tevent_context_init(NULL); + if (ev == NULL) { + perror("tevent_context_init failed"); + return 1; + } + poll_funcs_init_tevent(&funcs, ev); + + ret = unix_msg_init(sock1, &funcs, 256, 1, + recv_cb, &state, &ctx1); + if (ret != 0) { + fprintf(stderr, "unix_msg_init failed: %s\n", + strerror(ret)); + return 1; + } + + ret = unix_msg_init(sock1, &funcs, 256, 1, + recv_cb, &state, &ctx1); + if (ret == 0) { + fprintf(stderr, "unix_msg_init succeeded unexpectedly\n"); + return 1; + } + if (ret != EADDRINUSE) { + fprintf(stderr, "unix_msg_init returned %s, expected " + "EADDRINUSE\n", strerror(ret)); + return 1; + } + + ret = unix_msg_init(sock2, &funcs, 256, 1, + recv_cb, &state, &ctx2); + if (ret != 0) { + fprintf(stderr, "unix_msg_init failed: %s\n", + strerror(ret)); + return 1; + } + + printf("sending a 0-length message\n"); + + state.buf = NULL; + state.buflen = 0; + + ret = unix_msg_send(ctx1, sock2, NULL, 0); + if (ret != 0) { + fprintf(stderr, "unix_msg_send failed: %s\n", + strerror(ret)); + return 1; + } + + expect_messages(ev, &state, 1); + + printf("sending a small message\n"); + + msg = random(); + iov.iov_base = &msg; + iov.iov_len = sizeof(msg); + state.buf = &msg; + state.buflen = sizeof(msg); + + ret = unix_msg_send(ctx1, sock2, &iov, 1); + if (ret != 0) { + fprintf(stderr, "unix_msg_send failed: %s\n", + strerror(ret)); + return 1; + } + + expect_messages(ev, &state, 1); + + printf("sending six large, interleaved messages\n"); + + for (i=0; ibuflen) { + fprintf(stderr, "expected %u bytes, got %u\n", + (unsigned)state->buflen, (unsigned)msg_len); + exit(1); + } + if ((msg_len != 0) && (memcmp(msg, state->buf, msg_len) != 0)) { + fprintf(stderr, "message content differs\n"); + exit(1); + } + state->num_received += 1; +} -- cgit