View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0006036 | libmicrohttpd | external API | public | 2020-01-07 20:08 | 2021-09-02 17:54 |
Reporter | medoc | Assigned To | Christian Grothoff | ||
Priority | normal | Severity | major | Reproducibility | always |
Status | closed | Resolution | fixed | ||
Product Version | Git master | ||||
Target Version | 0.9.70 | Fixed in Version | 0.9.70 | ||
Summary | 0006036: MHD_USE_NO_LISTEN_SOCKET | MHD_USE_THREAD_PER_CONNECTION always overflows the connection count | ||||
Description | When starting the daemon with the above flags (and MHD_USE_SELECT_INTERNALLY/MHD_USE_INTERNAL_POLLING_THREAD), then using add_connection() to process incoming connections, the connection count always ends up overflowing, and add_connection() fails with "Server reached connection limit (closing inbound connection)", or an out of descriptors error, depending on the configuration and version. As far as I can see, the reason is that nobody in this configuration actually calls MHD_cleanup_connections() (MHD_polling_thread is not running because of NO_LISTEN_SOCKET). With microhttpd 0.9.51, this can be worked around by calling MHD_get_daemon_info(daemon MHD_DAEMON_INFO_CURRENT_CONNECTIONS), which apparently triggers a cleanup. With 0.9.59 and current git code, I found no workaround, it always ends up in overflow. | ||||
Steps To Reproduce | Attaching a sample program, just loop wget on it. | ||||
Tags | No tags attached. | ||||
Attached Files | trmhttp.c (4,403 bytes)
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <errno.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <sys/time.h> #include <microhttpd.h> static char usage [] = " port\n" " \n\n" ; char *thisprog; static void Usage(void) { fprintf(stderr, "%s: usage:\n%s", thisprog, usage); exit(1); } static const int one = 1; int getcon(int port, struct sockaddr *addr, socklen_t *addrlen) { static int listenfd = -1; if (listenfd < 0) { struct sockaddr_in ipaddr; if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); return -1; } (void) setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)); memset(&ipaddr, 0, sizeof(ipaddr)); ipaddr.sin_family = AF_INET; ipaddr.sin_addr.s_addr = htonl(INADDR_ANY); ipaddr.sin_port = htons(port); if (bind(listenfd, (struct sockaddr *)&ipaddr, sizeof(ipaddr)) < 0) { perror("bind"); return -1; } fprintf(stderr, "Listening on port %d\n",(int)port); if (listen(listenfd, 5) < 0) { perror("listen"); return -1; } } int confd = accept(listenfd, addr, addrlen); if (confd < 0) { perror("accept"); return -1; } fprintf(stderr, "Accept returned %d\n", confd); return confd; } static int print_out_key (void *cls, enum MHD_ValueKind kind, const char *key, const char *value) { fprintf(stderr, "kind %d : %s -> %s\n", (int)kind, key, value); return MHD_YES; } static int answer_to_connection( void *cls, struct MHD_Connection *conn, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls) { fprintf(stderr, "answer_to_connection\n"); if (NULL == *con_cls) { // First call, look at headers, method etc. fprintf(stderr, "METHOD: %s\n", method); MHD_get_connection_values(conn,MHD_HEADER_KIND,&print_out_key,0); *con_cls = (void *)1; return MHD_YES; } struct MHD_Response *response = MHD_create_response_from_buffer(0, 0, MHD_RESPMEM_PERSISTENT); if (NULL == response ) { fprintf(stderr, "create_response failed\n"); return MHD_YES; } MHD_add_response_header (response, "Location", "http://go.to.hell/index.html"); MHD_add_response_header (response, "Connection", "close"); int ret = MHD_queue_response(conn, 302, response); MHD_destroy_response(response); return ret; } static void notify_connection_callback( void *cls, struct MHD_Connection *conn, void **socket_context, enum MHD_ConnectionNotificationCode toe) { switch (toe) { case MHD_CONNECTION_NOTIFY_STARTED: fprintf(stderr, "notify_connection_callback: started\n"); break; case MHD_CONNECTION_NOTIFY_CLOSED: fprintf(stderr, "notify_connection_callback: closed\n"); break; } } static void request_completed_callback( void *cls, struct MHD_Connection *conn, void **con_cls, enum MHD_RequestTerminationCode toe) { fprintf(stderr, "Request completed\n"); } static int op_flags; #define OPT_MOINS 0x1 int main(int argc, char **argv) { int fd; int port; struct MHD_Daemon *mhd; thisprog = argv[0]; argc--; argv++; if (argc != 1) Usage(); port = atoi(*argv++);argc --; mhd = MHD_start_daemon( MHD_USE_NO_LISTEN_SOCKET | MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, -1, /* Accept policy callback and arg */ NULL, NULL, /* handler and arg */ &answer_to_connection, NULL, MHD_OPTION_CONNECTION_TIMEOUT, 1, MHD_OPTION_NOTIFY_COMPLETED, request_completed_callback, NULL, MHD_OPTION_NOTIFY_CONNECTION, notify_connection_callback, NULL, MHD_OPTION_END); if (NULL == mhd) { fprintf(stderr, "MHD_start_daemon failed\n"); return 1; } struct sockaddr addr; socklen_t addrlen=sizeof(addr); for (;;) { if ((fd = getcon(port, &addr, &addrlen)) < 0) exit(1); if (MHD_add_connection(mhd, fd, &addr, addrlen) != MHD_YES) { fprintf(stderr, "Add_connection failed\n"); return 0; } #if 0 const union MHD_DaemonInfo *info = MHD_get_daemon_info(mhd, MHD_DAEMON_INFO_CURRENT_CONNECTIONS); if (info) { fprintf(stderr, "Connection count: %d\n", info->num_connections); } else { fprintf(stderr, "MHD_get_daemon_info returned null\n"); } #endif } exit(0); } | ||||
|
Fixed in 94e8d665..6da31a1c by adding a call to MHD_cleanup_connections() inside MHD_add_connection(). Thanks for reporting! |
|
Fix committed to master branch. |
Date Modified | Username | Field | Change |
---|---|---|---|
2020-01-07 20:08 | medoc | New Issue | |
2020-01-07 20:08 | medoc | File Added: trmhttp.c | |
2020-02-07 14:16 | Christian Grothoff | Assigned To | => Christian Grothoff |
2020-02-07 14:16 | Christian Grothoff | Status | new => assigned |
2020-02-07 14:24 | Christian Grothoff | Product Version | => Git master |
2020-02-07 14:24 | Christian Grothoff | Target Version | => 0.9.70 |
2020-02-07 14:28 | Christian Grothoff | Note Added: 0015314 | |
2020-02-07 14:28 | Christian Grothoff | Status | assigned => resolved |
2020-02-07 14:28 | Christian Grothoff | Resolution | open => fixed |
2020-02-07 14:28 | Christian Grothoff | Fixed in Version | => 0.9.70 |
2020-02-08 22:03 | Christian Grothoff | Status | resolved => closed |
2021-09-02 17:54 | Christian Grothoff | Changeset attached | => libmicrohttpd master 6da31a1c |
2021-09-02 17:54 | Christian Grothoff | Note Added: 0018171 | |
2024-01-21 13:24 | Christian Grothoff | Category | libmicrohttpd API => external API |