diff --git a/tests/io/SimpleDiskAndNetworkTest.cpp b/tests/io/SimpleDiskAndNetworkTest.cpp index 99bf37e22293c8c2ed6f7078b1dace3bca325d24..89e0db0c1562f2c28f9b82d41035e36615ba3be2 100644 --- a/tests/io/SimpleDiskAndNetworkTest.cpp +++ b/tests/io/SimpleDiskAndNetworkTest.cpp @@ -1,46 +1,37 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // Copyright © 2020-2021 Florian Fischer -#include <arpa/inet.h> // for inet_addr #include <bits/types/struct_iovec.h> // for iovec #include <fcntl.h> // for open, O_RDONLY -#include <netinet/in.h> // for sockaddr_in, htons, in_addr -#include <sys/socket.h> // for bind, listen, setsockopt -#include <unistd.h> // for close +#include <sys/types.h> +#include <array> #include <cstdlib> // for mkstemp #include <cstring> // for memcmp, memset #include <memory> // for allocator, unique_ptr #include <string> // for string #include <vector> // for vector -#include "Common.hpp" // for DIE_MSG_ERRNO, DIE_MSG -#include "CountingPrivateSemaphore.hpp" // for CPS +#include "Common.hpp" +#include "Debug.hpp" #include "Runtime.hpp" -#include "emper.hpp" #include "fixtures/assert.hpp" #include "fixtures/network.hpp" #include "io.hpp" #include "io/Future.hpp" +class Fiber; -#define PORT 4243 +using namespace emper::io; + +static const std::string HOST = "127.0.0.1"; +static const std::string PORT = "4243"; #define MAX 1024 -static void server_func(int sockfd) { - struct sockaddr_in clientaddr; - socklen_t clientaddr_len = sizeof(clientaddr); - auto client_fd = emper::io::acceptAndWait(sockfd, reinterpret_cast<struct sockaddr*>(&clientaddr), - &clientaddr_len); - - if (client_fd < 0) { - DIE_MSG_ERRNO("accept failed"); - } - // NOLINTNEXTLINE(modernize-avoid-c-arrays) - char recv_buf[MAX]; - // NOLINTNEXTLINE(modernize-avoid-c-arrays) - char read_buf[MAX]; +static void server_func(int client_fd) { + std::array<char, MAX> recv_buf; + std::array<char, MAX> read_buf; for (;;) { - ssize_t received = emper::io::recvAndWait(client_fd, recv_buf, sizeof(recv_buf), 0); + ssize_t received = recvAndWait(client_fd, recv_buf.data(), recv_buf.size(), 0); if (received == 0) { Runtime::getRuntime()->initiateTermination(); return; @@ -51,6 +42,8 @@ static void server_func(int sockfd) { break; } + DBG("Server got msg from client -> writing to file"); + // NOLINTNEXTLINE(modernize-avoid-c-arrays) char file_name[] = "/tmp/emper-SimpleDiskAndNetworkTestFile-XXXXXX"; int file_fd = mkstemp(file_name); @@ -58,18 +51,20 @@ static void server_func(int sockfd) { DIE_MSG_ERRNO("mkstemp failed"); } - ssize_t written = emper::io::writeFileAndWait(file_fd, recv_buf, received); + ssize_t written = writeFileAndWait(file_fd, recv_buf.data(), received); if (written < 0) { DIE_MSG_ERRNO("write failed"); } - close(file_fd); + closeAndWait(file_fd); - file_fd = emper::io::openAndWait(file_name, O_RDONLY); + DBG("Msg written to file"); + + file_fd = openAndWait(file_name, O_RDONLY); if (file_fd == -1) { DIE_MSG_ERRNO("open failed"); } - ssize_t bytes_read = emper::io::readFileAndWait(file_fd, read_buf, written); + ssize_t bytes_read = readFileAndWait(file_fd, read_buf.data(), written); if (bytes_read == 0) { DIE_MSG("nothing to read"); } @@ -77,9 +72,11 @@ static void server_func(int sockfd) { if (bytes_read < 0) { DIE_MSG_ERRNO("read failed"); } - close(file_fd); + closeAndWait(file_fd); + + DBG("Msg read from file"); - ssize_t sent = emper::io::sendAndWait(client_fd, read_buf, bytes_read, 0); + ssize_t sent = sendAndWait(client_fd, read_buf.data(), bytes_read, 0); if (sent == 0) { DIE_MSG("client socket unexpected shutdown"); } @@ -88,94 +85,79 @@ static void server_func(int sockfd) { DIE_MSG_ERRNO("send failed"); } - // NOLINTNEXTLINE(modernize-avoid-c-arrays) - char file2_name[] = "/tmp/emper-SimpleDiskAndNetworkTestFile-XXXXXX"; - file_fd = mkstemp(file2_name); - if (file_fd == -1) { - DIE_MSG_ERRNO("mkstemp failed"); - } + DBG("Msg sent back to client"); + } +} - const int iovcnt = 2; - // NOLINTNEXTLINE(modernize-avoid-c-arrays) - struct iovec iov[iovcnt]; +static void testDiskAndNetwork() { + Fiber* listener = tcp_listener(HOST, PORT, server_func, 1024, {SockOpt::ReusePort}); + if (!listener) { + DIE_MSG("creating listener failed"); + } + Runtime::getRuntime()->schedule(*listener); - std::string s1 = "foo"; - std::string s2 = "bar"; + const std::vector<std::string> msgs{"foo", "bar"}; + echo_client(HOST, PORT, msgs); +} - iov[0].iov_base = (void*)s1.c_str(); - iov[0].iov_len = s1.length(); - iov[1].iov_base = (void*)s2.c_str(); - iov[1].iov_len = s2.length(); +static void testIov() { + // NOLINTNEXTLINE(modernize-avoid-c-arrays) + char file_name[] = "/tmp/emper-SimpleDiskAndNetworkTestFile-XXXXXX"; + int file_fd = mkstemp(file_name); + if (file_fd == -1) { + DIE_MSG_ERRNO("mkstemp failed"); + } - auto writevFuture = emper::io::writev(file_fd, &iov[0], iovcnt); - written = writevFuture->waitAndSetErrno(); - if (written < 0) { - DIE_MSG_ERRNO("wrtev failed"); - } - close(file_fd); + DBG("Opened temp file to test writev"); - file_fd = emper::io::openAndWait(file2_name, O_RDONLY); - if (file_fd == -1) { - DIE_MSG_ERRNO("open failed"); - } + std::array<char, MAX> read_buf; - auto readFuture = emper::io::readFile(file_fd, read_buf, written, 0, true); - bytes_read = readFuture->waitAndSetErrno(); - if (bytes_read == 0) { - DIE_MSG("nothing to read"); - } + const int iovcnt = 2; + std::array<struct iovec, iovcnt> iov; - if (bytes_read < 0) { - DIE_MSG_ERRNO("read failed"); - } + std::string s1 = "foo"; + std::string s2 = "bar"; - ASSERT(written == bytes_read); + iov[0].iov_base = (void*)s1.c_str(); + iov[0].iov_len = s1.length(); + iov[1].iov_base = (void*)s2.c_str(); + iov[1].iov_len = s2.length(); - ASSERT(memcmp(read_buf, iov[0].iov_base, iov[0].iov_len) == 0); - ASSERT(memcmp((char*)read_buf + iov[0].iov_len, iov[1].iov_base, iov[1].iov_len) == 0); + DBG("Prepared iov"); - close(file_fd); + auto writevFuture = emper::io::writev(file_fd, &iov[0], iovcnt); + ssize_t written = writevFuture->waitAndSetErrno(); + if (written < 0) { + DIE_MSG_ERRNO("writev failed"); } -} + closeAndWait(file_fd); -void emperTest() { - int sockfd; - struct sockaddr_in servaddr; - - // socket creation and verification - sockfd = socket(AF_INET, SOCK_STREAM, 0); - if (sockfd == -1) { - DIE_MSG_ERRNO("socket creation failed"); + file_fd = openAndWait(file_name, O_RDONLY); + if (file_fd == -1) { + DIE_MSG_ERRNO("open failed"); } - memset(&servaddr, 0, sizeof(servaddr)); - // assign IP, PORT - servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); - servaddr.sin_port = htons(PORT); + DBG("Reread written data"); - int enable = 1; - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(enable)) == -1) { - DIE_MSG_ERRNO("setsockopt SO_REUSEPORT failed"); - } - if (bind(sockfd, (sockaddr*)&servaddr, sizeof(servaddr)) == -1) { - DIE_MSG_ERRNO("bind failed"); + auto readFuture = readFile(file_fd, read_buf.data(), written, 0, true); + ssize_t bytes_read = readFuture->waitAndSetErrno(); + if (bytes_read == 0) { + DIE_MSG("nothing to read"); } - if (listen(sockfd, 1) != 0) { - DIE_MSG_ERRNO("listen failed"); + + if (bytes_read < 0) { + DIE_MSG_ERRNO("read failed"); } - CPS cps; - spawn([=] { server_func(sockfd); }, cps); + ASSERT(written == bytes_read); + + ASSERT(memcmp(read_buf.data(), iov[0].iov_base, iov[0].iov_len) == 0); + ASSERT(memcmp(read_buf.data() + iov[0].iov_len, iov[1].iov_base, iov[1].iov_len) == 0); - spawn( - [] { - const std::vector<std::string> msgs{"foo", "bar"}; - std::string port = std::to_string(PORT); - std::string host("127.0.0.1"); - echo_client(host, port, msgs); - }, - cps); + closeAndWait(file_fd); +} - cps.wait(); +void emperTest() { + testDiskAndNetwork(); + testIov(); }