From 24bd31f2a083a72af02ac4e8db3f093343e95ce7 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 18 Sep 2018 11:54:58 +0100 Subject: [PATCH] Fix excessive CPU usage when the number of sockets exceeds the system limit. Closes #948. Thanks to wiebeytec. --- ChangeLog.txt | 4 +++- src/mosquitto.c | 1 + src/mosquitto_broker_internal.h | 1 + src/net.c | 26 +++++++++++++++++++++++++- 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 15ea64bc..69c26cd4 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -4,9 +4,11 @@ Broker: - Fix build when using WITH_ADNS=yes. - Fix incorrect call to setsockopt() for TCP_NODELAY. Closes #941. +- Fix excessive CPU usage when the number of sockets exceeds the system limit. + Closes #948. Build: -- Make it easier to build with bundled uthash.h using "WITH_BUNDLED_DEPS=no". +- Make it easier to build without bundled uthash.h using "WITH_BUNDLED_DEPS=no". 1.5.1 - 20180816 diff --git a/src/mosquitto.c b/src/mosquitto.c index 77c5f60a..4f2f32e0 100644 --- a/src/mosquitto.c +++ b/src/mosquitto.c @@ -239,6 +239,7 @@ int main(int argc, char *argv[]) memset(&int_db, 0, sizeof(struct mosquitto_db)); net__init(); + int_db.spare_sock = socket(AF_INET, SOCK_STREAM, 0); config__init(&int_db, &config); rc = config__parse_args(&int_db, &config, argc, argv); diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index c6bc4bed..e41a80dd 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -392,6 +392,7 @@ struct mosquitto_db{ #ifdef WITH_EPOLL int epollfd; #endif + mosq_sock_t spare_sock; }; enum mosquitto__bridge_direction{ diff --git a/src/net.c b/src/net.c index a4acd695..60f9ecc8 100644 --- a/src/net.c +++ b/src/net.c @@ -97,7 +97,31 @@ int net__socket_accept(struct mosquitto_db *db, mosq_sock_t listensock) #endif new_sock = accept(listensock, NULL, 0); - if(new_sock == INVALID_SOCKET) return -1; + if(new_sock == INVALID_SOCKET){ +#ifdef WIN32 + errno = WSAGetLastError(); + if(errno == WSAEMFILE){ +#else + if(errno == EMFILE || errno == ENFILE){ +#endif + /* Close the spare socket, which means we should be able to accept + * this connection. Accept it, then close it immediately and create + * a new spare_sock. This prevents the situation of ever properly + * running out of sockets. + * It would be nice to send a "server not available" connack here, + * but there are lots of reasons why this would be tricky (TLS + * being the big one). */ + COMPAT_CLOSE(db->spare_sock); + new_sock = accept(listensock, NULL, 0); + if(new_sock != INVALID_SOCKET){ + COMPAT_CLOSE(new_sock); + } + db->spare_sock = socket(AF_INET, SOCK_STREAM, 0); + log__printf(NULL, MOSQ_LOG_NOTICE, + "Unable to accept new connection, system socket count has been exceeded. Try increasing \"ulimit -n\" or equivalent."); + } + return -1; + } G_SOCKET_CONNECTIONS_INC();