Newer
Older
// 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 <cassert> // for assert
#include <cstdlib> // for mkstemp, exit, EXIT_SUCCESS
#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 "emper.hpp" // for spawn
#include "fixtures/network.hpp" // for echo_client
#include "io.hpp" // for readFile, accept, recv, send
#include "io/Future.hpp" // for Future
#define PORT 4243
#define MAX 1024
static void server_func(int sockfd) {
struct sockaddr_in clientaddr;
socklen_t clientaddr_len = sizeof(clientaddr);

Florian Fischer
committed
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];
for (;;) {

Florian Fischer
committed
ssize_t received = emper::io::recvAndWait(client_fd, recv_buf, sizeof(recv_buf), 0);
if (received == 0) {
exit(EXIT_SUCCESS);
}
if (received == -1) {
DIE_MSG_ERRNO("recv failed");
break;
}
// 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");
}

Florian Fischer
committed
ssize_t written = emper::io::writeFileAndWait(file_fd, recv_buf, received);
if (written < 0) {
DIE_MSG_ERRNO("write failed");
}
close(file_fd);
file_fd = emper::io::openAndWait(file_name, O_RDONLY);
if (file_fd == -1) {
DIE_MSG_ERRNO("open failed");
}

Florian Fischer
committed
ssize_t bytes_read = emper::io::readFileAndWait(file_fd, read_buf, written);
if (bytes_read == 0) {
DIE_MSG("nothing to read");
}
if (bytes_read < 0) {
DIE_MSG_ERRNO("read failed");
}
close(file_fd);

Florian Fischer
committed
ssize_t sent = emper::io::sendAndWait(client_fd, read_buf, bytes_read, 0);
if (sent == 0) {
DIE_MSG("client socket unexpected shutdown");
}
if (sent == -1) {
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");
}
const int iovcnt = 2;
// NOLINTNEXTLINE(modernize-avoid-c-arrays)
struct iovec iov[iovcnt];
std::string s1 = "foo";
std::string s2 = "bar";
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();
auto writevFuture = emper::io::writev(file_fd, &iov[0], iovcnt);

Florian Fischer
committed
written = writevFuture->waitAndSetErrno();
if (written < 0) {
DIE_MSG_ERRNO("wrtev failed");
}
close(file_fd);
file_fd = emper::io::openAndWait(file2_name, O_RDONLY);
if (file_fd == -1) {
DIE_MSG_ERRNO("open failed");
}
auto readFuture = emper::io::readFile(file_fd, read_buf, written, 0, true);

Florian Fischer
committed
bytes_read = readFuture->waitAndSetErrno();
if (bytes_read == 0) {
DIE_MSG("nothing to read");
}
if (bytes_read < 0) {
DIE_MSG_ERRNO("read failed");
}
assert(written == bytes_read);
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);
close(file_fd);
}
}
void emperTest() {
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
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");
}
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);
int reuseaddr = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)) == -1) {
DIE_MSG_ERRNO("setsockopt failed");
}
if (bind(sockfd, (sockaddr*)&servaddr, sizeof(servaddr)) == -1) {
DIE_MSG_ERRNO("bind failed");
}
if (listen(sockfd, 1) != 0) {
DIE_MSG_ERRNO("listen failed");
}
spawn([=] { server_func(sockfd); }, cps);
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);
cps.wait();
}