From 3c84f22524decbb7a8b0d7fa805686e95f23e98d Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Thu, 28 Jan 2021 14:46:01 +0000 Subject: [PATCH] server: Gracefully close connections when the client went away Signed-off-by: Michael Tremer --- src/server.c | 50 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/src/server.c b/src/server.c index 07a8a3f..67eeb27 100644 --- a/src/server.c +++ b/src/server.c @@ -29,6 +29,12 @@ #define SOCKET_BACKLOG 1024 +// Struct to collect server statistics +struct fireperf_server_stats { + // Total number of open connections + unsigned int connections; +}; + static int create_socket(struct fireperf_config* conf) { // Open a new socket int fd = socket(AF_INET6, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0); @@ -100,11 +106,6 @@ static int handle_io_on_connection(struct fireperf_config* conf, int fd) { if (bytes_read < 0) { ERROR(conf, "Could not read from socket %d: %s\n", fd, strerror(errno)); return -1; - - // Connection closed - } else if (bytes_read == 0) { - DEBUG(conf, "Connection %d has closed\n", fd); - return 1; } DEBUG(conf, "Read %zu bytes from socket %d\n", bytes_read, fd); @@ -113,6 +114,8 @@ static int handle_io_on_connection(struct fireperf_config* conf, int fd) { } int fireperf_server(struct fireperf_config* conf) { + struct fireperf_server_stats stats; + DEBUG(conf, "Launching " PACKAGE_NAME " in server mode\n"); int sockfd = -1; @@ -169,7 +172,7 @@ int fireperf_server(struct fireperf_config* conf) { goto ERROR; // Add the new socket to epoll() - ev.events = EPOLLIN; + ev.events = EPOLLIN|EPOLLHUP; ev.data.fd = connfd; if (epoll_ctl(epollfd, EPOLL_CTL_ADD, connfd, &ev)) { @@ -178,19 +181,36 @@ int fireperf_server(struct fireperf_config* conf) { goto ERROR; } + // A connection has been opened + stats.connections++; + continue; + } + + // Handle any connection events (like disconnects) + if (ev.events & EPOLLHUP) { + DEBUG(conf, "Connection %d has closed\n", fd); + + // Remove the file descriptor from epoll() + if (epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, NULL)) { + ERROR(conf, "Could not remove socket file descriptfor from epoll(): %s\n", + strerror(errno)); + } + + // Free up any resources + close(fd); + + // This connection is now closed + stats.connections--; + + // Skip processing anything else, because it would be pointless + continue; + } + // One of the connections had IO - } else { + if (ev.events & EPOLLIN) { r = handle_io_on_connection(conf, fd); if (r < 0) goto ERROR; - - // Connection closed? - else if (r == 1) { - if (epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, NULL)) { - ERROR(conf, "Could not remove socket file descriptfor from epoll(): %s\n", - strerror(errno)); - } - } } } } -- 2.47.2