-
Florian Fischer authored
I could not identify the commit that changes this behavior but it is reproducible on our bigboxes and my arch system.
Florian Fischer authoredI could not identify the commit that changes this behavior but it is reproducible on our bigboxes and my arch system.
TimeoutTest.cpp 3.68 KiB
// SPDX-License-Identifier: LGPL-3.0-or-later
// Copyright © 2021 Florian Fischer
#include <netinet/in.h>
#include <sys/eventfd.h>
#include <sys/socket.h>
#include <cerrno>
#include <cstdint>
#include <cstring>
#include <memory>
#include "Common.hpp"
#include "CountingPrivateSemaphore.hpp"
#include "Debug.hpp"
#include "Future.hpp"
#include "emper.hpp"
#include "fixtures/assert.hpp"
#include "io.hpp"
#include "lib/LinuxVersion.hpp"
using emper::io::ReadFuture;
using emper::io::TimeoutWrapper;
static void setupSockPair(int& sock1, int& sock2) {
const int PORT = 4242;
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(PORT);
int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
if (listen_sock == -1) DIE_MSG_ERRNO("creating listen socket failed");
int enable = 1;
if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) == -1)
DIE_MSG_ERRNO("setsockopt SO_REUSEADDR failed");
if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(enable)) == -1)
DIE_MSG_ERRNO("setsockopt SO_REUSEPORT failed");
if (bind(listen_sock, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) == -1)
DIE_MSG_ERRNO("bind failed");
if (listen(listen_sock, 1) != 0) DIE_MSG_ERRNO("listen failed");
sock2 = socket(AF_INET, SOCK_STREAM, 0);
if (sock2 == -1) DIE_MSG_ERRNO("creating client socket failed");
CPS cps;
spawn(
[&]() {
if ((sock1 = emper::io::acceptAndWait(listen_sock, nullptr, nullptr)) == -1)
DIE_MSG_ERRNO("accept failed");
},
cps);
if (emper::io::connectAndWait(sock2, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) ==
-1)
DIE_MSG_ERRNO("connect failed");
cps.wait();
emper::io::closeAndForget(listen_sock);
}
void sockTest() {
int sock1, sock2;
DBG("setup sockets");
setupSockPair(sock1, sock2);
uint64_t recvBuf;
DBG("submit recv");
TimeoutWrapper::Timespec ts = {.tv_sec = 1, .tv_nsec = 0};
ssize_t res = emper::io::recvAndTryWait(sock1, &recvBuf, sizeof(recvBuf), 0, ts);
ASSERT(res == -1);
ASSERT(errno == ECANCELED);
// TODO: find a way to test sendAndTryWait
// // allocate a huge buffer which is surely bigger then the sockets buffer and
// // thus causing the send to block triggering the timeout
// const ssize_t MEMB = 1 << 20;
// auto* sendBuf = new char[MEMB];
// DBG("submit send");
// res = emper::io::sendAndTryWait(sock1, &sendBuf, MEMB, 0, ts, true);
// ASSERT(res == -1);
// ASSERT(errno == ECANCELED);
// delete[] sendBuf;
emper::io::closeAndForget(sock1);
emper::io::closeAndForget(sock2);
}
void readTest() {
int efd = eventfd(0, EFD_SEMAPHORE);
if (efd == -1) {
DIE_MSG_ERRNO("eventfd failed");
}
uint64_t readBuf;
TimeoutWrapper::Timespec ts = {.tv_sec = 1, .tv_nsec = 0};
ssize_t res = emper::io::readFileAndTryWait(efd, &readBuf, sizeof(readBuf), ts);
ASSERT(res == -1);
ASSERT(errno == ECANCELED);
emper::io::closeAndForget(efd);
}
void writeTest() {
int efd = eventfd(0, EFD_SEMAPHORE);
if (efd == -1) {
DIE_MSG_ERRNO("eventfd failed");
}
// fill up the eventfd
uint64_t writeBuf = 0xfffffffffffffffe;
if (emper::io::writeFileAndWait(efd, &writeBuf, sizeof(writeBuf)) == -1) {
DIE_MSG("eventfd prep write failed");
}
writeBuf = 1;
TimeoutWrapper::Timespec ts = {.tv_sec = 1, .tv_nsec = 0};
ssize_t res = emper::io::writeFileAndTryWait(efd, &writeBuf, sizeof(writeBuf), ts);
ASSERT(res == -1);
// write requests can't be canceled when in execution so this
// will return as interupted
const int err = errno;
ASSERT(err == EINTR || (EMPER_LINUX_GE("5.16.0") && err == ECANCELED));
emper::io::closeAndForget(efd);
}
void emperTest() {
sockTest();
readTest();
writeTest();
}