Improve some error handling
Handle EINTR in signal handler Handle getListenFd errors by trying the next address
This commit is contained in:
33
src/main.cpp
33
src/main.cpp
@@ -30,10 +30,13 @@ int shutdown_eventfd = -1;
|
|||||||
void signal_handler(int sig) {
|
void signal_handler(int sig) {
|
||||||
if (sig == SIGTERM || sig == SIGINT) {
|
if (sig == SIGTERM || sig == SIGINT) {
|
||||||
if (shutdown_eventfd != -1) {
|
if (shutdown_eventfd != -1) {
|
||||||
uint64_t val = 1;
|
char val = 1;
|
||||||
// write() is async-signal-safe per POSIX - safe to use in signal handler
|
// write() is async-signal-safe per POSIX - safe to use in signal handler
|
||||||
if (write(shutdown_eventfd, &val, sizeof(val)) == -1) {
|
// Write single byte to avoid partial write complexity
|
||||||
abort(); // Critical failure - can't signal shutdown
|
while (write(shutdown_eventfd, &val, 1) == -1) {
|
||||||
|
if (errno != EINTR) {
|
||||||
|
abort(); // graceful shutdown didn't work. Let's go ungraceful.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,12 +76,23 @@ int getListenFd(const char *node, const char *service) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int val = 1;
|
int val = 1;
|
||||||
setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
|
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) == -1) {
|
||||||
|
perror("setsockopt SO_REUSEADDR");
|
||||||
|
close(sfd);
|
||||||
|
continue; // Try next address
|
||||||
|
}
|
||||||
|
|
||||||
// Set socket to non-blocking for graceful shutdown
|
// Set socket to non-blocking for graceful shutdown
|
||||||
int flags = fcntl(sfd, F_GETFL, 0);
|
int flags = fcntl(sfd, F_GETFL, 0);
|
||||||
if (flags != -1) {
|
if (flags == -1) {
|
||||||
fcntl(sfd, F_SETFL, flags | O_NONBLOCK);
|
perror("fcntl F_GETFL");
|
||||||
|
close(sfd);
|
||||||
|
continue; // Try next address
|
||||||
|
}
|
||||||
|
if (fcntl(sfd, F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||||
|
perror("fcntl F_SETFL");
|
||||||
|
close(sfd);
|
||||||
|
continue; // Try next address
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) {
|
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) {
|
||||||
@@ -104,13 +118,6 @@ int getListenFd(const char *node, const char *service) {
|
|||||||
return sfd;
|
return sfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getAcceptFd(int listenFd, struct sockaddr_storage *addr) {
|
|
||||||
// Use sockaddr_storage (not sockaddr) to handle both IPv4 and IPv6
|
|
||||||
socklen_t addrlen = sizeof(sockaddr_storage);
|
|
||||||
int fd = accept4(listenFd, (struct sockaddr *)addr, &addrlen, SOCK_NONBLOCK);
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since only one thread owns a connection at a time, no synchronization is
|
// Since only one thread owns a connection at a time, no synchronization is
|
||||||
// necessary
|
// necessary
|
||||||
// Connection ownership model:
|
// Connection ownership model:
|
||||||
|
|||||||
Reference in New Issue
Block a user