@cryptotaxi247 / netdata-1 / commits / d052989fb

netdata can now bind to multiple ip:port combinations; hostnames and ips but also numeric ports and service names are also supported; fixes #458; contributes to #314

Costa Tsaousis committed Jul 23, 2016 at 21:47 UTC d052989fb0a1a117dfc01e0d860753350e33afe4
5 files changed +311 -184
src/appconfig.c
+46
@@ -194,6 +194,52 @@ static inline struct config_value *config_value_create(struct config *co, const
194 return cv;
195 }
196
197 +int config_exists(const char *section, const char *name) {
198 + struct config_value *cv;
199 +
200 + debug(D_CONFIG, "request to get config in section '%s', name '%s'", section, name);
201 +
202 + struct config *co = config_section_find(section);
203 + if(!co) return 0;
204 +
205 + cv = config_value_index_find(co, name, 0);
206 + if(!cv) return 0;
207 +
208 + return 1;
209 +}
210 +
211 +int config_rename(const char *section, const char *old, const char *new) {
212 + struct config_value *cv, *cv2;
213 +
214 + debug(D_CONFIG, "request to rename config in section '%s', old name '%s', new name '%s'", section, old, new);
215 +
216 + struct config *co = config_section_find(section);
217 + if(!co) return -1;
218 +
219 + config_section_write_lock(co);
220 +
221 + cv = config_value_index_find(co, old, 0);
222 + if(!cv) goto cleanup;
223 +
224 + cv2 = config_value_index_find(co, new, 0);
225 + if(cv2) goto cleanup;
226 +
227 + config_value_index_del(co, cv);
228 +
229 + free(cv->name);
230 + cv->name = strdup(new);
231 + if(!cv->name) fatal("Cannot allocate memory for config_rename()");
232 +
233 + config_value_index_add(co, cv);
234 + config_section_unlock(co);
235 +
236 + return 0;
237 +
238 +cleanup:
239 + config_section_unlock(co);
240 + return -1;
241 +}
242 +
243 char *config_get(const char *section, const char *name, const char *default_value)
244 {
245 struct config_value *cv;
src/appconfig.h
+3
@@ -26,6 +26,9 @@ extern const char *config_set_default(const char *section, const char *name, con
26 extern long long config_set_number(const char *section, const char *name, long long value);
27 extern int config_set_boolean(const char *section, const char *name, int value);
28
29 +extern int config_exists(const char *section, const char *name);
30 +extern int config_rename(const char *section, const char *old, const char *new);
31 +
32 extern void generate_config(BUFFER *wb, int only_changed);
33
34 #endif /* NETDATA_CONFIG_H */
src/main.c
+1 -3
@@ -652,9 +652,7 @@ int main(int argc, char **argv)
652
653 // --------------------------------------------------------------------
654
655 - listen_fd = create_listen_socket();
656 - if(listen_fd == -1)
657 - fatal("Cannot listen socket.");
655 + create_listen_sockets();
656 }
657
658 // never become a problem
src/web_server.c
+256 -175
@@ -14,6 +14,7 @@
14 #include <netinet/tcp.h>
15 #include <malloc.h>
16 #include <poll.h>
17 +#include <ctype.h>
18
19 #include "common.h"
20 #include "log.h"
@@ -28,7 +29,8 @@
29 #include "../config.h"
30
31 int listen_backlog = LISTEN_BACKLOG;
31 -int listen_fd = -1;
32 +int listen_fds_count = 0;
33 +int listen_fds[MAX_LISTEN_FDS] = { [0 ... 99] = -1 };
34 int listen_port = LISTEN_PORT;
35 int web_server_mode = WEB_SERVER_MODE_MULTI_THREADED;
36
@@ -84,158 +86,269 @@ int accept4(int sock, struct sockaddr *addr, socklen_t *addrlen, int flags) {
86 }
87 #endif
88
87 -static int is_ip_anything(const char *ip)
88 -{
89 - if(!ip || !*ip
90 - || !strcmp(ip, "any")
91 - || !strcmp(ip, "all")
92 - || !strcmp(ip, "*")
93 - || !strcmp(ip, "::")
94 - || !strcmp(ip, "0.0.0.0")
95 - ) return 1;
96 -
97 - return 0;
98 -}
99 -
100 -int create_listen_socket4(const char *ip, int port, int listen_backlog)
101 -{
89 +int create_listen_socket4(const char *ip, int port, int listen_backlog) {
90 int sock;
91 int sockopt = 1;
92
105 - debug(D_LISTENER, "IPv4 creating new listening socket on port %d", port);
93 + debug(D_LISTENER, "IPv4 creating new listening socket on ip '%s' port %d", ip, port);
94
95 sock = socket(AF_INET, SOCK_STREAM, 0);
96 if(sock < 0) {
109 - error("IPv4 socket() failed.");
97 + error("IPv4 socket() on ip '%s' port %d failed.", ip, port);
98 return -1;
99 }
100
101 /* avoid "address already in use" */
102 if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&sockopt, sizeof(sockopt)) != 0)
115 - error("Cannot set SO_REUSEADDR on port's %d socket.", port);
103 + error("Cannot set SO_REUSEADDR on ip '%s' port's %d.", ip, port);
104
105 struct sockaddr_in name;
106 memset(&name, 0, sizeof(struct sockaddr_in));
107 name.sin_family = AF_INET;
108 name.sin_port = htons (port);
109
122 - if(is_ip_anything(ip)) {
123 - name.sin_addr.s_addr = htonl(INADDR_ANY);
124 - // info("Listening on any IPs (IPv4).");
125 - }
126 - else {
127 - int ret = inet_pton(AF_INET, ip, (void *)&name.sin_addr.s_addr);
128 - if(ret != 1) {
129 - error("Failed to convert IP '%s' to a valid IPv4 address.", ip);
130 - close(sock);
131 - return -1;
132 - }
133 - // info("Listening on IP '%s' (IPv4).", ip);
134 - }
110 + int ret = inet_pton(AF_INET, ip, (void *)&name.sin_addr.s_addr);
111 + if(ret != 1) {
112 + error("Failed to convert IP '%s' to a valid IPv4 address.", ip);
113 + close(sock);
114 + return -1;
115 + }
116
117 if(bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
118 close(sock);
138 - error("IPv4 bind() failed.");
119 + error("IPv4 bind() on ip '%s' port %d failed.", ip, port);
120 return -1;
121 }
122
123 if(listen(sock, listen_backlog) < 0) {
124 close(sock);
144 - fatal("IPv4 listen() failed.");
125 + fatal("IPv4 listen() on ip '%s' port %d failed.", ip, port);
126 return -1;
127 }
128
148 - debug(D_LISTENER, "IPv4 listening port %d created", port);
129 + debug(D_LISTENER, "Listening on IPv4 ip '%s' port %d", ip, port);
130 return sock;
131 }
132
152 -int create_listen_socket6(const char *ip, int port, int listen_backlog)
153 -{
133 +int create_listen_socket6(const char *ip, int port, int listen_backlog) {
134 int sock = -1;
135 int sockopt = 1;
136 + int ipv6only = 1;
137
157 - debug(D_LISTENER, "IPv6 creating new listening socket on port %d", port);
138 + debug(D_LISTENER, "IPv6 creating new listening socket on ip '%s' port %d", ip, port);
139
140 sock = socket(AF_INET6, SOCK_STREAM, 0);
141 if (sock < 0) {
161 - error("IPv6 socket() failed. Disabling IPv6.");
142 + error("IPv6 socket() on ip '%s' port %d failed.", ip, port);
143 return -1;
144 }
145
165 - /* avoid "address already in use" */
166 - if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&sockopt, sizeof(sockopt)) != 0)
167 - error("Cannot set SO_REUSEADDR on port's %d socket.", port);
146 + /* avoid "address already in use" */
147 + if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&sockopt, sizeof(sockopt)) != 0)
148 + error("Cannot set SO_REUSEADDR on ip '%s' port's %d.", ip, port);
149 +
150 + /* IPv6 only */
151 + if(setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&ipv6only, sizeof(ipv6only)) != 0)
152 + error("Cannot set IPV6_V6ONLY on ip '%s' port's %d.", ip, port);
153
169 - struct sockaddr_in6 name;
154 + struct sockaddr_in6 name;
155 memset(&name, 0, sizeof(struct sockaddr_in6));
156 name.sin6_family = AF_INET6;
157 name.sin6_port = htons ((uint16_t) port);
158
174 - if(is_ip_anything(ip)) {
175 - name.sin6_addr = in6addr_any;
176 - // info("Listening on all IPs (IPv6 and IPv4)");
177 - }
178 - else {
179 - int ret = inet_pton(AF_INET6, ip, (void *)&name.sin6_addr.s6_addr);
180 - if(ret != 1) {
181 - error("Failed to convert IP '%s' to a valid IPv6 address. Disabling IPv6.", ip);
182 - close(sock);
183 - return -1;
184 - }
185 - // info("Listening on IP '%s' (IPv6)", ip);
186 - }
159 + int ret = inet_pton(AF_INET6, ip, (void *)&name.sin6_addr.s6_addr);
160 + if(ret != 1) {
161 + error("Failed to convert IP '%s' to a valid IPv6 address.", ip);
162 + close(sock);
163 + return -1;
164 + }
165
166 name.sin6_scope_id = 0;
167
168 if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
169 close(sock);
192 - error("IPv6 bind() failed. Disabling IPv6.");
170 + error("IPv6 bind() on ip '%s' port %d failed.", ip, port);
171 return -1;
172 }
173
174 if (listen(sock, listen_backlog) < 0) {
175 close(sock);
198 - error("IPv6 listen() failed. Disabling IPv6.");
176 + error("IPv6 listen() on ip '%s' port %d failed.", ip, port);
177 return -1;
178 }
179
202 - debug(D_LISTENER, "IPv6 listening port %d created", port);
180 + debug(D_LISTENER, "Listening on IPv6 ip '%s' port %d", ip, port);
181 return sock;
182 }
183
184 +static inline int add_listen_socket(int fd) {
185 + if(listen_fds_count >= MAX_LISTEN_FDS)
186 + return -1;
187 +
188 + listen_fds[listen_fds_count++] = fd;
189 +
190 + return 0;
191 +}
192 +
193 +int is_listen_socket(int fd) {
194 + int i;
195 + for(i = 0; i < listen_fds_count ;i++)
196 + if(listen_fds[i] == fd) return 1;
197 +
198 + return 0;
199 +}
200 +
201 +static inline void close_listen_sockets(void) {
202 + int i;
203 + for(i = 0; i < listen_fds_count ;i++)
204 + close(listen_fds[i]);
205 + listen_fds_count = 0;
206 +}
207 +
208 +static inline int bind_to_one(const char *definition, int default_port, int listen_backlog) {
209 + int added = 0;
210 + struct addrinfo hints;
211 + struct addrinfo *result, *rp;
212 +
213 + char buffer[strlen(definition) + 1];
214 + strcpy(buffer, definition);
215 +
216 + char buffer2[10 + 1];
217 + snprintfz(buffer2, 10, "%d", default_port);
218 +
219 + char *ip = buffer, *port = buffer2;
220 +
221 + char *e = ip;
222 + if(*e == '[') {
223 + e = ++ip;
224 + while(*e && *e != ']') e++;
225 + if(*e == ']') {
226 + *e = '\0';
227 + e++;
228 + }
229 + }
230 + else {
231 + while(*e && *e != ':') e++;
232 + }
233 +
234 + if(*e == ':') {
235 + port = e + 1;
236 + *e = '\0';
237 + }
238 +
239 + if(!*ip || *ip == '*' || !strcmp(ip, "any") || !strcmp(ip, "all"))
240 + ip = NULL;
241 + if(!*port)
242 + port = buffer2;
243 +
244 + memset(&hints, 0, sizeof(struct addrinfo));
245 + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
246 + hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
247 + hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
248 + hints.ai_protocol = 0; /* Any protocol */
249 + hints.ai_canonname = NULL;
250 + hints.ai_addr = NULL;
251 + hints.ai_next = NULL;
252 +
253 + int r = getaddrinfo(ip, port, &hints, &result);
254 + if (r != 0) {
255 + error("getaddrinfo('%s', '%s'): %s\n", ip, port, gai_strerror(r));
256 + return -1;
257 + }
258 +
259 + for (rp = result; rp != NULL; rp = rp->ai_next) {
260 + int fd = -1;
261 +
262 + char rip[INET_ADDRSTRLEN + INET6_ADDRSTRLEN] = "INVALID";
263 + switch (rp->ai_addr->sa_family) {
264 + case AF_INET: {
265 + struct sockaddr_in *sin = (struct sockaddr_in *) rp->ai_addr;
266 + inet_ntop(AF_INET, &sin->sin_addr, rip, INET_ADDRSTRLEN);
267 + fd = create_listen_socket4(rip, ntohs(sin->sin_port), listen_backlog);
268 + break;
269 + }
270 +
271 + case AF_INET6: {
272 + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) rp->ai_addr;
273 + inet_ntop(AF_INET6, &sin6->sin6_addr, rip, INET6_ADDRSTRLEN);
274 + fd = create_listen_socket6(rip, ntohs(sin6->sin6_port), listen_backlog);
275 + break;
276 + }
277 + }
278 +
279 + if (fd == -1)
280 + error("Cannot bind to ip '%s', port %d", rip, default_port);
281 + else {
282 + add_listen_socket(fd);
283 + added++;
284 + }
285 + }
286 +
287 + return added;
288 +}
289
207 -int create_listen_socket(void) {
290 +int create_listen_sockets(void) {
291 listen_backlog = (int) config_get_number("global", "http port listen backlog", LISTEN_BACKLOG);
292
210 - listen_port = (int) config_get_number("global", "port", LISTEN_PORT);
293 + if(config_exists("global", "bind socket to IP") && !config_exists("global", "bind to"))
294 + config_rename("global", "bind socket to IP", "bind to");
295 +
296 + if(config_exists("global", "port") && !config_exists("global", "default port"))
297 + config_rename("global", "port", "default port");
298 +
299 + listen_port = (int) config_get_number("global", "default port", LISTEN_PORT);
300 if(listen_port < 1 || listen_port > 65535) {
301 error("Invalid listen port %d given. Defaulting to %d.", listen_port, LISTEN_PORT);
213 - listen_port = LISTEN_PORT;
214 - }
215 - else debug(D_OPTIONS, "Listen port set to %d.", listen_port);
216 -
217 - int ip = 0;
218 - char *ipv = config_get("global", "ip version", "any");
219 - if(!strcmp(ipv, "any") || !strcmp(ipv, "both") || !strcmp(ipv, "all")) ip = 0;
220 - else if(!strcmp(ipv, "ipv4") || !strcmp(ipv, "IPV4") || !strcmp(ipv, "IPv4") || !strcmp(ipv, "4")) ip = 4;
221 - else if(!strcmp(ipv, "ipv6") || !strcmp(ipv, "IPV6") || !strcmp(ipv, "IPv6") || !strcmp(ipv, "6")) ip = 6;
222 - else error("Cannot understand ip version '%s'. Assuming 'any'.", ipv);
223 -
224 - if(ip == 0 || ip == 6)
225 - listen_fd = create_listen_socket6(config_get("global", "bind socket to IP", "*"), listen_port, listen_backlog);
226 -
227 - if(listen_fd == -1) {
228 - listen_fd = create_listen_socket4(config_get("global", "bind socket to IP", "*"), listen_port, listen_backlog);
229 - //if(listen_fd != -1 && ip != 4)
230 - // info("Managed to open an IPv4 socket on port %d.", listen_port);
302 + listen_port = (int) config_set_number("global", "default port", LISTEN_PORT);
303 }
304 + debug(D_OPTIONS, "Default listen port set to %d.", listen_port);
305 +
306 + char *s = config_get("global", "bind to", "*");
307 + while(*s) {
308 + char *e = s;
309 +
310 + // skip separators, moving both s(tart) and e(nd)
311 + while(isspace(*e) || *e == ',') s = ++e;
312 +
313 + // move e(nd) to the first separator
314 + while(*e && !isspace(*e) && *e != ',') e++;
315 +
316 + // is there anything?
317 + if(!*s || s == e) break;
318
233 - return listen_fd;
319 + char buf[e - s + 1];
320 + strncpyz(buf, s, e - s);
321 + bind_to_one(buf, listen_port, listen_backlog);
322 +
323 + s = e;
324 + }
325 +
326 + if(!listen_fds_count)
327 + fatal("Cannot listen on any socket. Exiting...");
328 +
329 + return listen_fds_count;
330 }
331
332 // --------------------------------------------------------------------------------------
333 // the main socket listener
334
335 +static inline void cleanup_web_clients(void) {
336 + struct web_client *w;
337 +
338 + for (w = web_clients; w;) {
339 + if (w->obsolete) {
340 + debug(D_WEB_CLIENT, "%llu: Removing client.", w->id);
341 + // pthread_cancel(w->thread);
342 + // pthread_join(w->thread, NULL);
343 + w = web_client_free(w);
344 +#ifdef NETDATA_INTERNAL_CHECKS
345 + log_allocations();
346 +#endif
347 + }
348 + else w = w->next;
349 + }
350 +}
351 +
352 // 1. it accepts new incoming requests on our port
353 // 2. creates a new web_client for each connection received
354 // 3. spawns a new pthread to serve the client (this is optimal for keep-alive clients)
@@ -250,7 +363,7 @@ void *socket_listen_main_multi_threaded(void *ptr) {
363 info("Multi-threaded WEB SERVER thread created with task id %d", gettid());
364
365 struct web_client *w;
253 - int retval, failures = 0, counter = 0;
366 + int retval, counter = 0;
367
368 if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
369 error("Cannot set pthread cancel type to DEFERRED.");
@@ -258,38 +371,45 @@ void *socket_listen_main_multi_threaded(void *ptr) {
371 if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
372 error("Cannot set pthread cancel state to ENABLE.");
373
261 - if(listen_fd < 0)
262 - fatal("LISTENER: Listen socket %d is not ready, or invalid.", listen_fd);
374 + if(!listen_fds_count)
375 + fatal("LISTENER: No sockets to listen to.");
376
264 - for(;;) {
265 - struct pollfd fd = { .fd = listen_fd, .events = POLLIN, .revents = 0 };
266 - int timeout = 10 * 1000;
377 + struct pollfd *fds = calloc(sizeof(struct pollfd), listen_fds_count);
378 + if(!fds)
379 + fatal("LISTENER: Cannot allocate memory for poll fds.");
380 +
381 + int i;
382 + for(i = 0; i < listen_fds_count ;i++) {
383 + fds[i].fd = listen_fds[i];
384 + fds[i].events = POLLIN;
385 + fds[i].revents = 0;
386 + }
387 +
388 + int timeout = 10 * 1000;
389
390 + for(;;) {
391 // debug(D_WEB_CLIENT, "LISTENER: Waiting...");
269 - retval = poll(&fd, 1, timeout);
392 + retval = poll(fds, listen_fds_count, timeout);
393
394 if(unlikely(retval == -1)) {
272 - debug(D_WEB_CLIENT, "LISTENER: poll() failed.");
273 - failures++;
274 -
275 - if(failures > 10) {
276 - error("LISTENER: our listen port %d seems dead. Re-opening it.", listen_fd);
277 - close(listen_fd);
278 - listen_fd = -1;
279 - sleep(5);
280 - create_listen_socket();
281 - if(listen_fd < 0)
282 - fatal("Cannot listen for web clients (connected clients %lu).", global_statistics.connected_clients);
283 -
284 - failures = 0;
285 - }
286 -
395 + error("LISTENER: poll() failed.");
396 continue;
397 }
289 - else if(likely(retval)) {
398 + else if(unlikely(!retval)) {
399 + debug(D_WEB_CLIENT, "LISTENER: select() timeout.");
400 + counter = 0;
401 + cleanup_web_clients();
402 + continue;
403 + }
404 +
405 + for(i = 0 ; i < listen_fds_count ; i++) {
406 + short int revents = fds[i].revents;
407 +
408 // check for new incoming connections
291 - if(fd.revents & POLLIN || fd.revents & POLLPRI) {
292 - w = web_client_create(listen_fd);
409 + if(revents & POLLIN || revents & POLLPRI) {
410 + fds[i].revents = 0;
411 +
412 + w = web_client_create(fds[i].fd);
413 if(unlikely(!w)) {
414 // no need for error log - web_client_create already logged the error
415 continue;
@@ -304,41 +424,19 @@ void *socket_listen_main_multi_threaded(void *ptr) {
424 w->obsolete = 1;
425 }
426 }
307 - else {
308 - failures++;
309 - debug(D_WEB_CLIENT, "LISTENER: select() didn't do anything.");
310 - continue;
311 - }
312 - }
313 - else {
314 - debug(D_WEB_CLIENT, "LISTENER: select() timeout.");
315 - counter = CLEANUP_EVERY_EVENTS;
427 }
428
429 // cleanup unused clients
430 counter++;
320 - if(counter > CLEANUP_EVERY_EVENTS) {
431 + if(counter >= CLEANUP_EVERY_EVENTS) {
432 counter = 0;
322 - for (w = web_clients; w;) {
323 - if (w->obsolete) {
324 - debug(D_WEB_CLIENT, "%llu: Removing client.", w->id);
325 - // pthread_cancel(w->thread);
326 - // pthread_join(w->thread, NULL);
327 - w = web_client_free(w);
328 -#ifdef NETDATA_INTERNAL_CHECKS
329 - log_allocations();
330 -#endif
331 - }
332 - else w = w->next;
333 - }
433 + cleanup_web_clients();
434 }
335 -
336 - failures = 0;
435 }
436
437 debug(D_WEB_CLIENT, "LISTENER: exit!");
340 - close(listen_fd);
341 - listen_fd = -1;
438 + close_listen_sockets();
439 +
440 return NULL;
441 }
442
@@ -394,7 +492,7 @@ void *socket_listen_main_single_threaded(void *ptr) {
492 info("Single threaded WEB SERVER thread created with task id %d", gettid());
493
494 struct web_client *w;
397 - int retval, failures = 0;
495 + int retval;
496
497 if(ptr) { ; }
498
@@ -404,10 +502,11 @@ void *socket_listen_main_single_threaded(void *ptr) {
502 if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
503 error("Cannot set pthread cancel state to ENABLE.");
504
407 - if(listen_fd < 0 || listen_fd >= FD_SETSIZE)
408 - fatal("LISTENER: Listen socket %d is not ready, or invalid.", listen_fd);
409 -
505 int i;
506 +
507 + if(!listen_fds_count)
508 + fatal("LISTENER: no listen sockets available.");
509 +
510 for(i = 0; i < FD_SETSIZE ; i++)
511 single_threaded_clients[i] = NULL;
512
@@ -415,12 +514,20 @@ void *socket_listen_main_single_threaded(void *ptr) {
514 FD_ZERO (&ifds);
515 FD_ZERO (&ofds);
516 FD_ZERO (&efds);
418 - FD_SET(listen_fd, &ifds);
419 - FD_SET(listen_fd, &efds);
420 - int fdmax = listen_fd;
517 + int fdmax = 0;
518 +
519 + for(i = 0; i < listen_fds_count ; i++) {
520 + if (listen_fds[i] < 0 || listen_fds[i] >= FD_SETSIZE)
521 + fatal("LISTENER: Listen socket %d is not ready, or invalid.", listen_fds[i]);
522 +
523 + FD_SET(listen_fds[i], &ifds);
524 + FD_SET(listen_fds[i], &efds);
525 + if(fdmax < listen_fds[i])
526 + fdmax = listen_fds[i];
527 + }
528
529 for(;;) {
423 - debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server waiting (listen fd = %d, fdmax = %d)...", listen_fd, fdmax);
530 + debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server waiting (fdmax = %d)...", fdmax);
531
532 struct timeval tv = { .tv_sec = 1, .tv_usec = 0 };
533 rifds = ifds;
@@ -429,44 +536,19 @@ void *socket_listen_main_single_threaded(void *ptr) {
536 retval = select(fdmax+1, &rifds, &rofds, &refds, &tv);
537
538 if(unlikely(retval == -1)) {
432 - debug(D_WEB_CLIENT, "LISTENER: select() failed.");
433 - failures++;
434 - if(failures > 10) {
435 - if(global_statistics.connected_clients) {
436 - error("REMOVING ALL %lu WEB CLIENTS !", global_statistics.connected_clients);
437 - while (web_clients) {
438 - single_threaded_unlink_client(web_clients, &ifds, &ofds, &efds);
439 - web_client_free(web_clients);
440 - }
441 - }
442 -
443 - error("LISTENER: our listen port %d seems dead. Re-opening it.", listen_fd);
444 -
445 - close(listen_fd);
446 - listen_fd = -1;
447 - sleep(5);
448 -
449 - create_listen_socket();
450 - if(listen_fd < 0 || listen_fd >= FD_SETSIZE)
451 - fatal("Cannot listen for web clients (connected clients %lu).", global_statistics.connected_clients);
452 -
453 - FD_ZERO (&ifds);
454 - FD_ZERO (&ofds);
455 - FD_ZERO (&efds);
456 - FD_SET(listen_fd, &ifds);
457 - FD_SET(listen_fd, &efds);
458 - failures = 0;
459 - }
539 + error("LISTENER: select() failed.");
540 + continue;
541 }
542 else if(likely(retval)) {
462 - failures = 0;
543 debug(D_WEB_CLIENT_ACCESS, "LISTENER: got something.");
544
465 - if(FD_ISSET(listen_fd, &rifds)) {
466 - debug(D_WEB_CLIENT_ACCESS, "LISTENER: new connection.");
467 - w = web_client_create(listen_fd);
468 - if(single_threaded_link_client(w, &ifds, &ofds, &ifds, &fdmax) != 0) {
469 - web_client_free(w);
545 + for(i = 0; i < listen_fds_count ; i++) {
546 + if (FD_ISSET(listen_fds[i], &rifds)) {
547 + debug(D_WEB_CLIENT_ACCESS, "LISTENER: new connection.");
548 + w = web_client_create(listen_fds[i]);
549 + if (single_threaded_link_client(w, &ifds, &ofds, &ifds, &fdmax) != 0) {
550 + web_client_free(w);
551 + }
552 }
553 }
554
@@ -522,7 +604,6 @@ void *socket_listen_main_single_threaded(void *ptr) {
604 }
605
606 debug(D_WEB_CLIENT, "LISTENER: exit!");
525 - close(listen_fd);
526 - listen_fd = -1;
607 + close_listen_sockets();
608 return NULL;
609 }
src/web_server.h
+5 -6
@@ -9,19 +9,18 @@
9 #define LISTEN_PORT 19999
10 #define LISTEN_BACKLOG 100
11
12 -extern int listen_backlog;
13 -extern int listen_fd;
14 -extern int listen_port;
12 +#ifndef MAX_LISTEN_FDS
13 +#define MAX_LISTEN_FDS 100
14 +#endif
15
16 #define WEB_SERVER_MODE_MULTI_THREADED 0
17 #define WEB_SERVER_MODE_SINGLE_THREADED 1
18 extern int web_server_mode;
19
20 -extern int create_listen_socket4(const char *ip, int port, int listen_backlog);
21 -extern int create_listen_socket6(const char *ip, int port, int listen_backlog);
20 extern void *socket_listen_main_multi_threaded(void *ptr);
21 extern void *socket_listen_main_single_threaded(void *ptr);
24 -extern int create_listen_socket(void);
22 +extern int create_listen_sockets(void);
23 +extern int is_listen_socket(int fd);
24
25 #ifndef HAVE_ACCEPT4
26 extern int accept4(int sock, struct sockaddr *addr, socklen_t *addrlen, int flags);