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);