Allow listening on multiple interfaces

This commit is contained in:
2025-09-03 16:09:16 -04:00
parent b8eb00e313
commit 46edb7cd26
6 changed files with 172 additions and 106 deletions

View File

@@ -29,48 +29,41 @@ void signal_handler(int sig) {
}
}
std::vector<int> create_listen_sockets(const weaseldb::Config &config) {
std::vector<int> listen_fds;
// Check if unix socket path is specified
if (!config.server.unix_socket_path.empty()) {
// Create unix socket
int sfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sfd == -1) {
perror("socket");
std::abort();
}
// Remove existing socket file if it exists
unlink(config.server.unix_socket_path.c_str());
struct sockaddr_un addr;
std::memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
if (config.server.unix_socket_path.length() >= sizeof(addr.sun_path)) {
std::fprintf(stderr, "Unix socket path too long\n");
std::abort();
}
std::strncpy(addr.sun_path, config.server.unix_socket_path.c_str(),
sizeof(addr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
perror("bind");
std::abort();
}
if (listen(sfd, SOMAXCONN) == -1) {
perror("listen");
std::abort();
}
listen_fds.push_back(sfd);
return listen_fds;
int create_unix_socket(const std::string &path) {
int sfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sfd == -1) {
perror("socket");
std::abort();
}
// TCP socket creation
// Remove existing socket file if it exists
unlink(path.c_str());
struct sockaddr_un addr;
std::memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
if (path.length() >= sizeof(addr.sun_path)) {
std::fprintf(stderr, "Unix socket path too long: %s\n", path.c_str());
std::abort();
}
std::strncpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
perror("bind");
std::abort();
}
if (listen(sfd, SOMAXCONN) == -1) {
perror("listen");
std::abort();
}
return sfd;
}
int create_tcp_socket(const std::string &address, int port) {
struct addrinfo hints;
struct addrinfo *result, *rp;
int s;
@@ -84,8 +77,8 @@ std::vector<int> create_listen_sockets(const weaseldb::Config &config) {
hints.ai_addr = nullptr;
hints.ai_next = nullptr;
s = getaddrinfo(config.server.bind_address.c_str(),
std::to_string(config.server.port).c_str(), &hints, &result);
s = getaddrinfo(address.c_str(), std::to_string(port).c_str(), &hints,
&result);
if (s != 0) {
std::fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
std::abort();
@@ -94,18 +87,13 @@ std::vector<int> create_listen_sockets(const weaseldb::Config &config) {
int sfd = -1;
for (rp = result; rp != nullptr; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sfd == -1) {
if (sfd == -1)
continue;
}
int val = 1;
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) == -1) {
perror("setsockopt SO_REUSEADDR");
int e = close(sfd);
if (e == -1 && errno != EINTR) {
perror("close sfd (SO_REUSEADDR failed)");
std::abort();
}
close(sfd);
continue;
}
@@ -113,40 +101,56 @@ std::vector<int> create_listen_sockets(const weaseldb::Config &config) {
if (rp->ai_family == AF_INET || rp->ai_family == AF_INET6) {
if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) == -1) {
perror("setsockopt TCP_NODELAY");
int e = close(sfd);
if (e == -1 && errno != EINTR) {
perror("close sfd (TCP_NODELAY failed)");
std::abort();
}
close(sfd);
continue;
}
}
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) {
if (listen(sfd, SOMAXCONN) == -1) {
perror("listen");
close(sfd);
freeaddrinfo(result);
std::abort();
}
break; /* Success */
}
int e = close(sfd);
if (e == -1 && errno != EINTR) {
perror("close sfd (bind failed)");
std::abort();
}
close(sfd);
sfd = -1;
}
freeaddrinfo(result);
if (rp == nullptr || sfd == -1) {
std::fprintf(stderr, "Could not bind to any address\n");
if (sfd == -1) {
std::fprintf(stderr, "Could not bind to %s:%d\n", address.c_str(), port);
std::abort();
}
if (listen(sfd, SOMAXCONN) == -1) {
perror("listen");
return sfd;
}
std::vector<int> create_listen_sockets(const weaseldb::Config &config) {
std::vector<int> listen_fds;
for (const auto &iface : config.server.interfaces) {
int fd;
if (iface.type == weaseldb::ListenInterface::Type::TCP) {
fd = create_tcp_socket(iface.address, iface.port);
std::cout << "Listening on TCP " << iface.address << ":" << iface.port
<< std::endl;
} else {
fd = create_unix_socket(iface.path);
std::cout << "Listening on Unix socket " << iface.path << std::endl;
}
listen_fds.push_back(fd);
}
if (listen_fds.empty()) {
std::fprintf(stderr, "No interfaces configured\n");
std::abort();
}
listen_fds.push_back(sfd);
return listen_fds;
}
@@ -218,13 +222,13 @@ int main(int argc, char *argv[]) {
}
std::cout << "Configuration loaded successfully:" << std::endl;
if (!config->server.unix_socket_path.empty()) {
std::cout << "Unix socket path: " << config->server.unix_socket_path
<< std::endl;
} else {
std::cout << "Server bind address: " << config->server.bind_address
<< std::endl;
std::cout << "Server port: " << config->server.port << std::endl;
std::cout << "Interfaces: " << config->server.interfaces.size() << std::endl;
for (const auto &iface : config->server.interfaces) {
if (iface.type == weaseldb::ListenInterface::Type::TCP) {
std::cout << " TCP: " << iface.address << ":" << iface.port << std::endl;
} else {
std::cout << " Unix socket: " << iface.path << std::endl;
}
}
std::cout << "Max request size: " << config->server.max_request_size_bytes
<< " bytes" << std::endl;