/* sock I/O tests Copyright (C) Amitay Isaacs 2017 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include "replace.h" #include "system/filesys.h" #include "system/network.h" #include "system/wait.h" #include #include "common/sock_io.c" static int socket_init(const char *sockpath) { struct sockaddr_un addr; int fd, ret; size_t len; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; len = strlcpy(addr.sun_path, sockpath, sizeof(addr.sun_path)); assert(len < sizeof(addr.sun_path)); fd = socket(AF_UNIX, SOCK_STREAM, 0); assert(fd != -1); ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); assert(ret != -1); ret = listen(fd, 10); assert(ret != -1); return fd; } static void test1_writer(int fd) { uint8_t buf[1024]; ssize_t nwritten; uint32_t len; for (len = 10; len < 1000; len += 10) { int value = len / 10; uint32_t buflen = len + sizeof(uint32_t); memset(buf, value, buflen); memcpy(buf, &buflen, sizeof(uint32_t)); nwritten = sys_write(fd, buf, buflen); assert(nwritten == buflen); } } struct test1_reader_state { size_t pkt_len; bool done; }; static void test1_reader(uint8_t *buf, size_t buflen, void *private_data) { struct test1_reader_state *state = (struct test1_reader_state *)private_data; if (buflen == 0) { state->done = true; return; } assert(buflen == state->pkt_len); state->pkt_len += 10; } static void test1(TALLOC_CTX *mem_ctx, const char *sockpath) { struct test1_reader_state state; struct tevent_context *ev; struct sock_queue *queue; pid_t pid; int pfd[2], fd, ret; ssize_t n; ret = pipe(pfd); assert(ret == 0); pid = fork(); assert(pid != -1); if (pid == 0) { int newfd; close(pfd[0]); fd = socket_init(sockpath); assert(fd != -1); ret = 1; n = sys_write(pfd[1], &ret, sizeof(int)); assert(n == sizeof(int)); newfd = accept(fd, NULL, NULL); assert(newfd != -1); test1_writer(newfd); close(newfd); unlink(sockpath); exit(0); } close(pfd[1]); n = sys_read(pfd[0], &ret, sizeof(int)); assert(n == sizeof(int)); assert(ret == 1); close(pfd[0]); fd = sock_connect(sockpath); assert(fd != -1); ev = tevent_context_init(mem_ctx); assert(ev != NULL); state.pkt_len = 10 + sizeof(uint32_t); state.done = false; queue = sock_queue_setup(mem_ctx, ev, fd, test1_reader, &state); assert(queue != NULL); while (! state.done) { tevent_loop_once(ev); } talloc_free(queue); talloc_free(ev); pid = wait(&ret); assert(pid != -1); } static void test2_reader(int fd) { uint8_t buf[1024]; size_t pkt_len = 10 + sizeof(uint32_t); ssize_t n; while (1) { n = sys_read(fd, buf, 1024); assert(n != -1); if (n == 0) { return; } assert((size_t)n == pkt_len); pkt_len += 10; } } static void test2_dummy_reader(uint8_t *buf, size_t buflen, void *private_data) { abort(); } static void test2_writer(struct sock_queue *queue) { uint8_t buf[1024]; uint32_t len; int ret; for (len = 10; len < 1000; len += 10) { int value = len / 10; uint32_t buflen = len + sizeof(uint32_t); memset(buf, value, buflen); memcpy(buf, &buflen, sizeof(uint32_t)); ret = sock_queue_write(queue, buf, buflen); assert(ret == 0); } } static void test2(TALLOC_CTX *mem_ctx, const char *sockpath) { struct tevent_context *ev; struct sock_queue *queue; pid_t pid; int pfd[2], fd, ret; ssize_t n; ret = pipe(pfd); assert(ret == 0); pid = fork(); assert(pid != -1); if (pid == 0) { int newfd; close(pfd[0]); fd = socket_init(sockpath); assert(fd != -1); ret = 1; n = sys_write(pfd[1], &ret, sizeof(int)); assert(n == sizeof(int)); newfd = accept(fd, NULL, NULL); assert(newfd != -1); test2_reader(newfd); close(newfd); unlink(sockpath); exit(0); } close(pfd[1]); n = sys_read(pfd[0], &ret, sizeof(int)); assert(n == sizeof(int)); assert(ret == 1); close(pfd[0]); fd = sock_connect(sockpath); assert(fd != -1); ev = tevent_context_init(mem_ctx); assert(ev != NULL); queue = sock_queue_setup(mem_ctx, ev, fd, test2_dummy_reader, NULL); assert(queue != NULL); test2_writer(queue); talloc_free(queue); talloc_free(ev); pid = wait(&ret); assert(pid != -1); } int main(int argc, const char **argv) { TALLOC_CTX *mem_ctx; const char *sockpath; if (argc != 2) { fprintf(stderr, "%s \n", argv[0]); exit(1); } sockpath = argv[1]; mem_ctx = talloc_new(NULL); assert(mem_ctx != NULL); test1(mem_ctx, sockpath); test2(mem_ctx, sockpath); return 0; }