forstio/driver/io-unix.h

443 lines
9.9 KiB
C
Raw Normal View History

2020-08-23 15:47:14 +02:00
#pragma once
2020-08-25 19:51:45 +02:00
#ifndef GIN_UNIX
2020-09-23 21:25:59 +02:00
#error "Don't include this"
2020-08-23 15:47:14 +02:00
#endif
2020-08-25 19:51:45 +02:00
#include <csignal>
#include <sys/signalfd.h>
2021-02-18 19:05:52 +01:00
#include <fcntl.h>
2020-08-28 16:59:25 +02:00
#include <netdb.h>
#include <netinet/in.h>
#include <sys/epoll.h>
2020-08-25 19:51:45 +02:00
#include <sys/socket.h>
2020-08-28 16:59:25 +02:00
#include <sys/stat.h>
2020-08-25 19:51:45 +02:00
#include <sys/types.h>
#include <sys/un.h>
#include <cassert>
#include <cstring>
#include <errno.h>
2020-08-28 16:59:25 +02:00
#include <unistd.h>
2020-08-25 19:51:45 +02:00
2020-09-28 19:36:35 +02:00
#include <queue>
2020-08-28 21:08:04 +02:00
#include <unordered_map>
#include <vector>
2020-08-28 21:08:04 +02:00
#include "./io.h"
2021-05-30 00:46:45 +02:00
#include "kelgin/io.h"
2020-08-25 19:51:45 +02:00
2020-08-23 15:47:14 +02:00
namespace gin {
namespace unix {
2020-08-25 19:51:45 +02:00
constexpr int MAX_EPOLL_EVENTS = 256;
2020-09-28 19:36:35 +02:00
class UnixEventPort;
class IFdOwner {
protected:
UnixEventPort &event_port;
2020-09-28 19:36:35 +02:00
private:
int file_descriptor;
int fd_flags;
uint32_t event_mask;
2020-08-25 19:51:45 +02:00
public:
2020-09-28 19:36:35 +02:00
IFdOwner(UnixEventPort &event_port, int file_descriptor, int fd_flags,
uint32_t event_mask);
2020-08-25 19:51:45 +02:00
2020-09-28 19:36:35 +02:00
virtual ~IFdOwner();
2020-08-25 19:51:45 +02:00
2020-09-28 19:36:35 +02:00
virtual void notify(uint32_t mask) = 0;
2020-08-25 19:51:45 +02:00
2020-09-28 19:36:35 +02:00
int fd() const { return file_descriptor; }
};
2020-08-28 16:59:25 +02:00
2020-11-12 00:51:35 +01:00
class UnixEventPort final : public EventPort {
2020-08-25 19:51:45 +02:00
private:
int epoll_fd;
int signal_fd;
sigset_t signal_fd_set;
2020-08-28 21:08:04 +02:00
std::unordered_multimap<Signal, Own<ConveyorFeeder<void>>> signal_conveyors;
2020-11-17 20:21:59 +01:00
int pipefds[2];
std::vector<int> toUnixSignal(Signal signal) const {
switch (signal) {
2020-09-23 21:25:59 +02:00
case Signal::User1:
return {SIGUSR1};
case Signal::Terminate:
default:
return {SIGTERM, SIGQUIT, SIGINT};
}
}
Signal fromUnixSignal(int signal) const {
switch (signal) {
2020-09-23 21:25:59 +02:00
case SIGUSR1:
return Signal::User1;
2020-08-28 21:44:26 +02:00
case SIGTERM:
case SIGINT:
case SIGQUIT:
2020-08-28 21:44:26 +02:00
default:
return Signal::Terminate;
2020-08-28 21:44:26 +02:00
}
}
void notifySignalListener(int sig) {
Signal signal = fromUnixSignal(sig);
2020-08-28 21:44:26 +02:00
auto equal_range = signal_conveyors.equal_range(signal);
for (auto iter = equal_range.first; iter != equal_range.second;
++iter) {
2020-10-11 22:21:06 +02:00
2020-08-28 21:44:26 +02:00
if (iter->second) {
if (iter->second->space() > 0) {
iter->second->feed();
}
}
2020-08-25 19:51:45 +02:00
}
}
bool pollImpl(int time) {
2020-08-28 16:59:25 +02:00
epoll_event events[MAX_EPOLL_EVENTS];
2020-08-25 19:51:45 +02:00
int nfds = 0;
2020-08-28 16:59:25 +02:00
do {
2020-08-25 19:51:45 +02:00
nfds = epoll_wait(epoll_fd, events, MAX_EPOLL_EVENTS, time);
2020-08-28 16:59:25 +02:00
if (nfds < 0) {
2020-08-25 19:51:45 +02:00
/// @todo error_handling
return false;
}
2020-08-28 16:59:25 +02:00
for (int i = 0; i < nfds; ++i) {
if (events[i].data.u64 == 0) {
while (1) {
2020-08-25 19:51:45 +02:00
struct ::signalfd_siginfo siginfo;
2020-08-28 16:59:25 +02:00
ssize_t n =
::read(signal_fd, &siginfo, sizeof(siginfo));
if (n < 0) {
2020-08-25 19:51:45 +02:00
break;
}
2020-08-28 16:59:25 +02:00
assert(n == sizeof(siginfo));
2020-08-25 19:51:45 +02:00
notifySignalListener(siginfo.ssi_signo);
}
} else if (events[i].data.u64 == 1) {
2020-11-17 20:21:59 +01:00
uint8_t i;
if (pipefds[0] < 0) {
2020-11-17 20:21:59 +01:00
continue;
}
while (1) {
2021-02-18 19:05:52 +01:00
ssize_t n = ::recv(pipefds[0], &i, sizeof(i), 0);
if (n < 0) {
2020-11-17 20:21:59 +01:00
break;
}
}
2020-08-28 16:59:25 +02:00
} else {
IFdOwner *owner =
reinterpret_cast<IFdOwner *>(events[i].data.ptr);
if (owner) {
2020-08-25 19:51:45 +02:00
owner->notify(events[i].events);
}
}
}
2020-08-28 16:59:25 +02:00
} while (nfds == MAX_EPOLL_EVENTS);
2020-08-25 19:51:45 +02:00
return true;
}
2020-08-28 16:59:25 +02:00
2020-08-25 19:51:45 +02:00
public:
2020-08-28 16:59:25 +02:00
UnixEventPort() : epoll_fd{-1}, signal_fd{-1} {
2020-08-25 19:51:45 +02:00
::signal(SIGPIPE, SIG_IGN);
epoll_fd = ::epoll_create1(EPOLL_CLOEXEC);
2020-08-28 16:59:25 +02:00
if (epoll_fd < 0) {
2020-08-25 19:51:45 +02:00
return;
}
::sigemptyset(&signal_fd_set);
signal_fd = ::signalfd(-1, &signal_fd_set, SFD_NONBLOCK | SFD_CLOEXEC);
2020-08-28 16:59:25 +02:00
if (signal_fd < 0) {
2020-08-25 19:51:45 +02:00
return;
}
struct epoll_event event;
memset(&event, 0, sizeof(event));
event.events = EPOLLIN;
event.data.u64 = 0;
::epoll_ctl(epoll_fd, EPOLL_CTL_ADD, signal_fd, &event);
2020-11-17 20:21:59 +01:00
2021-02-18 19:05:52 +01:00
int rc = ::pipe2(pipefds, O_NONBLOCK | O_CLOEXEC);
if (rc < 0) {
2020-11-17 20:21:59 +01:00
return;
}
memset(&event, 0, sizeof(event));
event.events = EPOLLIN;
event.data.u64 = 1;
::epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pipefds[0], &event);
2020-08-25 19:51:45 +02:00
}
2020-08-28 16:59:25 +02:00
~UnixEventPort() {
2020-08-25 19:51:45 +02:00
::close(epoll_fd);
::close(signal_fd);
2020-11-17 20:21:59 +01:00
::close(pipefds[0]);
::close(pipefds[1]);
2020-08-25 19:51:45 +02:00
}
Conveyor<void> onSignal(Signal signal) override {
auto caf = newConveyorAndFeeder<void>();
2020-08-28 21:08:04 +02:00
signal_conveyors.insert(std::make_pair(signal, std::move(caf.feeder)));
std::vector<int> sig = toUnixSignal(signal);
for (auto iter = sig.begin(); iter != sig.end(); ++iter) {
::sigaddset(&signal_fd_set, *iter);
}
::sigprocmask(SIG_BLOCK, &signal_fd_set, nullptr);
::signalfd(signal_fd, &signal_fd_set, SFD_NONBLOCK | SFD_CLOEXEC);
2020-08-28 21:08:04 +02:00
auto node_and_storage =
Conveyor<void>::fromConveyor(std::move(caf.conveyor));
return Conveyor<void>::toConveyor(std::move(node_and_storage.first),
node_and_storage.second);
2020-08-25 19:51:45 +02:00
}
void poll() override { pollImpl(0); }
2020-09-02 16:50:42 +02:00
void wait() override { pollImpl(-1); }
2020-10-11 22:21:06 +02:00
void wait(const std::chrono::steady_clock::duration &duration) override {
2020-10-22 18:38:56 +02:00
pollImpl(std::chrono::duration_cast<std::chrono::milliseconds>(duration)
.count());
2020-10-11 22:21:06 +02:00
}
2020-10-22 18:38:56 +02:00
void
wait(const std::chrono::steady_clock::time_point &time_point) override {
2020-10-11 22:21:06 +02:00
auto now = std::chrono::steady_clock::now();
2020-10-22 18:38:56 +02:00
if (time_point <= now) {
2020-10-11 22:21:06 +02:00
poll();
2020-10-22 18:38:56 +02:00
} else {
pollImpl(std::chrono::duration_cast<std::chrono::milliseconds>(
time_point - now)
.count());
2020-10-11 22:21:06 +02:00
}
}
void wake() override {
/// @todo pipe() in the beginning and write something minor into it like
/// uint8_t or sth the value itself doesn't matter
if (pipefds[1] < 0) {
2020-11-17 20:21:59 +01:00
return;
}
uint8_t i = 0;
2021-02-18 19:05:52 +01:00
::send(pipefds[1], &i, sizeof(i), MSG_DONTWAIT);
2020-11-17 20:21:59 +01:00
}
2020-08-28 16:59:25 +02:00
void subscribe(IFdOwner &owner, int fd, uint32_t event_mask) {
if (epoll_fd < 0 || fd < 0) {
2020-08-25 19:51:45 +02:00
return;
}
::epoll_event event;
memset(&event, 0, sizeof(event));
event.events = event_mask | EPOLLET;
event.data.ptr = &owner;
2020-08-28 16:59:25 +02:00
if (::epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &event) < 0) {
2020-08-25 19:51:45 +02:00
/// @todo error_handling
return;
}
}
2020-08-28 16:59:25 +02:00
void unsubscribe(int fd) {
if (epoll_fd < 0 || fd < 0) {
2020-08-25 19:51:45 +02:00
return;
}
2020-08-28 16:59:25 +02:00
if (::epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, nullptr) < 0) {
2020-08-25 19:51:45 +02:00
/// @todo error_handling
return;
}
}
};
2021-05-30 00:46:45 +02:00
ssize_t unixRead(int fd, void *buffer, size_t length);
ssize_t unixWrite(int fd, const void *buffer, size_t length);
2021-06-04 14:43:40 +02:00
class UnixIoStream final : public IoStream, public IFdOwner {
2020-09-28 19:36:35 +02:00
private:
2021-06-04 14:43:40 +02:00
Own<ConveyorFeeder<void>> read_ready = nullptr;
Own<ConveyorFeeder<void>> on_read_disconnect = nullptr;
Own<ConveyorFeeder<void>> write_ready = nullptr;
2020-09-28 19:36:35 +02:00
public:
UnixIoStream(UnixEventPort &event_port, int file_descriptor, int fd_flags,
uint32_t event_mask);
2020-09-28 19:36:35 +02:00
2021-06-04 23:21:25 +02:00
ErrorOr<size_t> read(void *buffer, size_t length) override;
2021-06-04 14:43:40 +02:00
2020-09-28 19:36:35 +02:00
Conveyor<void> readReady() override;
Conveyor<void> onReadDisconnected() override;
2021-06-04 23:21:25 +02:00
ErrorOr<size_t> write(const void *buffer, size_t length) override;
2021-06-04 14:43:40 +02:00
2020-09-28 19:36:35 +02:00
Conveyor<void> writeReady() override;
2021-06-04 14:43:40 +02:00
/*
void read(void *buffer, size_t min_length, size_t max_length) override;
Conveyor<size_t> readDone() override;
Conveyor<void> readReady() override;
Conveyor<void> onReadDisconnected() override;
void write(const void *buffer, size_t length) override;
Conveyor<size_t> writeDone() override;
Conveyor<void> writeReady() override;
*/
2020-09-28 19:36:35 +02:00
void notify(uint32_t mask) override;
};
2020-11-12 00:51:35 +01:00
class UnixServer final : public Server, public IFdOwner {
2020-09-28 19:36:35 +02:00
private:
Own<ConveyorFeeder<Own<IoStream>>> accept_feeder = nullptr;
2020-09-28 19:36:35 +02:00
public:
UnixServer(UnixEventPort &event_port, int file_descriptor, int fd_flags);
Conveyor<Own<IoStream>> accept() override;
void notify(uint32_t mask) override;
};
2020-09-23 21:25:59 +02:00
class SocketAddress {
private:
union {
struct sockaddr generic;
struct sockaddr_un unix;
struct sockaddr_in inet;
struct sockaddr_in6 inet6;
struct sockaddr_storage storage;
} address;
socklen_t address_length;
bool wildcard;
SocketAddress() : wildcard{false} {}
2020-09-23 21:25:59 +02:00
public:
SocketAddress(const void *sockaddr, socklen_t len, bool wildcard)
: address_length{len}, wildcard{wildcard} {
2020-09-23 21:25:59 +02:00
assert(len <= sizeof(address));
memcpy(&address.generic, sockaddr, len);
}
int socket(int type) const {
bool is_stream = type & SOCK_STREAM;
type |= SOCK_NONBLOCK | SOCK_CLOEXEC;
int result = ::socket(address.generic.sa_family, type, 0);
return result;
}
bool bind(int fd) const {
if (wildcard) {
2020-09-23 21:25:59 +02:00
int value = 0;
::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &value, sizeof(value));
}
int error = ::bind(fd, &address.generic, address_length);
2021-06-30 15:41:56 +02:00
return error < 0;
2020-09-23 21:25:59 +02:00
}
const struct ::sockaddr *getRaw() const { return &address.generic; }
2020-09-23 21:25:59 +02:00
socklen_t getRawLength() const { return address_length; }
2020-09-23 21:25:59 +02:00
static std::list<SocketAddress> parse(std::string_view str,
uint16_t port_hint) {
2020-09-23 21:25:59 +02:00
std::list<SocketAddress> results;
struct ::addrinfo *head;
2020-09-23 21:25:59 +02:00
struct ::addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
std::string port_string = std::to_string(port_hint);
bool wildcard = str == "*" || str == "::";
std::string address_string{str};
int error = ::getaddrinfo(address_string.c_str(), port_string.c_str(),
&hints, &head);
if (error) {
2020-09-23 21:25:59 +02:00
return {};
}
for (struct ::addrinfo *it = head; it != nullptr; it = it->ai_next) {
if (it->ai_addrlen > sizeof(SocketAddress::address)) {
2020-09-23 21:25:59 +02:00
continue;
}
results.push_back({it->ai_addr, it->ai_addrlen, wildcard});
}
::freeaddrinfo(head);
return results;
}
};
2020-11-12 00:51:35 +01:00
class UnixNetworkAddress final : public NetworkAddress {
2020-09-19 21:12:16 +02:00
private:
UnixEventPort &event_port;
2020-09-23 21:25:59 +02:00
const std::string path;
uint16_t port_hint;
std::list<SocketAddress> addresses;
2020-09-23 21:25:59 +02:00
public:
2020-11-11 23:08:37 +01:00
UnixNetworkAddress(UnixEventPort &event_port, const std::string &path,
uint16_t port_hint, std::list<SocketAddress> &&addr)
: event_port{event_port}, path{path}, port_hint{port_hint},
addresses{std::move(addr)} {}
2020-09-23 21:25:59 +02:00
2020-09-19 21:12:16 +02:00
Own<Server> listen() override;
Conveyor<Own<IoStream>> connect() override;
2020-09-19 21:12:16 +02:00
2020-09-28 19:36:35 +02:00
std::string toString() const override;
2021-06-18 00:17:18 +02:00
const std::string &address() const override;
uint16_t port() const override;
2020-09-19 21:12:16 +02:00
};
2020-11-11 23:08:37 +01:00
class UnixNetwork final : public Network {
private:
UnixEventPort &event_port;
public:
UnixNetwork(UnixEventPort &event_port);
2021-06-04 14:43:40 +02:00
Conveyor<Own<NetworkAddress>> parseAddress(const std::string &address,
uint16_t port_hint = 0) override;
2020-11-11 23:08:37 +01:00
};
2021-06-04 14:43:40 +02:00
class UnixIoProvider final : public IoProvider {
2020-08-25 19:51:45 +02:00
private:
2020-10-26 16:03:09 +01:00
UnixEventPort &event_port;
2020-08-25 19:51:45 +02:00
EventLoop event_loop;
2020-08-28 16:59:25 +02:00
2020-11-11 23:08:37 +01:00
UnixNetwork unix_network;
2020-08-25 19:51:45 +02:00
public:
2021-06-04 14:43:40 +02:00
UnixIoProvider(UnixEventPort &port_ref, Own<EventPort> port);
2021-05-09 15:19:09 +02:00
Network &network() override;
2020-08-25 19:51:45 +02:00
2020-09-23 21:25:59 +02:00
Own<InputStream> wrapInputFd(int fd) override;
2020-08-28 16:59:25 +02:00
EventLoop &eventLoop();
2020-08-25 19:51:45 +02:00
};
2021-05-30 00:46:45 +02:00
} // namespace unix
2020-11-11 23:08:37 +01:00
} // namespace gin