moved all socket related code to socket.c/h
Costa Tsaousis (ktsaou) committed
Apr 23, 2017 at 04:18 UTC
4add904179400312845a6d15186fb00e951a0fcc
5 files changed
+415
-382
src/main.c
+1
-1
@@ -920,7 +920,7 @@ int main(int argc, char **argv) {
920
web_server_threading_selection();
921
922
if(web_server_mode != WEB_SERVER_MODE_NONE)
923
- create_api_listen_sockets();
923
+ api_listen_sockets_setup();
924
}
925
926
// initialize the log files
src/socket.c
+369
@@ -1,5 +1,328 @@
1
#include "common.h"
2
3
+// --------------------------------------------------------------------------------------------------------------------
4
+// listening sockets
5
+
6
+int create_listen_socket4(int socktype, const char *ip, int port, int listen_backlog) {
7
+ int sock;
8
+ int sockopt = 1;
9
+
10
+ debug(D_LISTENER, "IPv4 creating new listening socket on ip '%s' port %d", ip, port);
11
+
12
+ sock = socket(AF_INET, socktype, 0);
13
+ if(sock < 0) {
14
+ error("IPv4 socket() on ip '%s' port %d failed.", ip, port);
15
+ return -1;
16
+ }
17
+
18
+ /* avoid "address already in use" */
19
+ if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&sockopt, sizeof(sockopt)) != 0)
20
+ error("Cannot set SO_REUSEADDR on ip '%s' port's %d.", ip, port);
21
+
22
+ struct sockaddr_in name;
23
+ memset(&name, 0, sizeof(struct sockaddr_in));
24
+ name.sin_family = AF_INET;
25
+ name.sin_port = htons (port);
26
+
27
+ int ret = inet_pton(AF_INET, ip, (void *)&name.sin_addr.s_addr);
28
+ if(ret != 1) {
29
+ error("Failed to convert IP '%s' to a valid IPv4 address.", ip);
30
+ close(sock);
31
+ return -1;
32
+ }
33
+
34
+ if(bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
35
+ close(sock);
36
+ error("IPv4 bind() on ip '%s' port %d failed.", ip, port);
37
+ return -1;
38
+ }
39
+
40
+ if(listen(sock, listen_backlog) < 0) {
41
+ close(sock);
42
+ error("IPv4 listen() on ip '%s' port %d failed.", ip, port);
43
+ return -1;
44
+ }
45
+
46
+ debug(D_LISTENER, "Listening on IPv4 ip '%s' port %d", ip, port);
47
+ return sock;
48
+}
49
+
50
+int create_listen_socket6(int socktype, uint32_t scope_id, const char *ip, int port, int listen_backlog) {
51
+ int sock = -1;
52
+ int sockopt = 1;
53
+ int ipv6only = 1;
54
+
55
+ debug(D_LISTENER, "IPv6 creating new listening socket on ip '%s' port %d", ip, port);
56
+
57
+ sock = socket(AF_INET6, socktype, 0);
58
+ if (sock < 0) {
59
+ error("IPv6 socket() on ip '%s' port %d failed.", ip, port);
60
+ return -1;
61
+ }
62
+
63
+ /* avoid "address already in use" */
64
+ if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&sockopt, sizeof(sockopt)) != 0)
65
+ error("Cannot set SO_REUSEADDR on ip '%s' port's %d.", ip, port);
66
+
67
+ /* IPv6 only */
68
+ if(setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&ipv6only, sizeof(ipv6only)) != 0)
69
+ error("Cannot set IPV6_V6ONLY on ip '%s' port's %d.", ip, port);
70
+
71
+ struct sockaddr_in6 name;
72
+ memset(&name, 0, sizeof(struct sockaddr_in6));
73
+ name.sin6_family = AF_INET6;
74
+ name.sin6_port = htons ((uint16_t) port);
75
+ name.sin6_scope_id = scope_id;
76
+
77
+ int ret = inet_pton(AF_INET6, ip, (void *)&name.sin6_addr.s6_addr);
78
+ if(ret != 1) {
79
+ error("Failed to convert IP '%s' to a valid IPv6 address.", ip);
80
+ close(sock);
81
+ return -1;
82
+ }
83
+
84
+ name.sin6_scope_id = scope_id;
85
+
86
+ if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
87
+ close(sock);
88
+ error("IPv6 bind() on ip '%s' port %d failed.", ip, port);
89
+ return -1;
90
+ }
91
+
92
+ if (listen(sock, listen_backlog) < 0) {
93
+ close(sock);
94
+ error("IPv6 listen() on ip '%s' port %d failed.", ip, port);
95
+ return -1;
96
+ }
97
+
98
+ debug(D_LISTENER, "Listening on IPv6 ip '%s' port %d", ip, port);
99
+ return sock;
100
+}
101
+
102
+static inline int listen_sockets_add(LISTEN_SOCKETS *sockets, int fd, const char *protocol, const char *ip, int port) {
103
+ if(sockets->opened >= MAX_LISTEN_FDS) {
104
+ error("Too many listening sockets. Failed to add listening %s socket at ip '%s' port %d", protocol, ip, port);
105
+ close(fd);
106
+ return -1;
107
+ }
108
+
109
+ sockets->fds[sockets->opened] = fd;
110
+
111
+ char buffer[100 + 1];
112
+ snprintfz(buffer, 100, "%s:[%s]:%d", protocol, ip, port);
113
+ sockets->fds_names[sockets->opened] = strdupz(buffer);
114
+
115
+ sockets->opened++;
116
+ return 0;
117
+}
118
+
119
+int listen_sockets_check_is_member(LISTEN_SOCKETS *sockets, int fd) {
120
+ size_t i;
121
+ for(i = 0; i < sockets->opened ;i++)
122
+ if(sockets->fds[i] == fd) return 1;
123
+
124
+ return 0;
125
+}
126
+
127
+static inline void listen_sockets_init(LISTEN_SOCKETS *sockets) {
128
+ size_t i;
129
+ for(i = 0; i < MAX_LISTEN_FDS ;i++) {
130
+ sockets->fds[i] = -1;
131
+ sockets->fds_names[i] = NULL;
132
+ }
133
+
134
+ sockets->opened = 0;
135
+ sockets->failed = 0;
136
+}
137
+
138
+void listen_sockets_close(LISTEN_SOCKETS *sockets) {
139
+ size_t i;
140
+ for(i = 0; i < sockets->opened ;i++) {
141
+ close(sockets->fds[i]);
142
+ sockets->fds[i] = -1;
143
+
144
+ freez(sockets->fds_names[i]);
145
+ sockets->fds_names[i] = NULL;
146
+ }
147
+
148
+ sockets->opened = 0;
149
+ sockets->failed = 0;
150
+}
151
+
152
+static inline int bind_to_one(LISTEN_SOCKETS *sockets, const char *definition, int default_port, int listen_backlog) {
153
+ int added = 0;
154
+ struct addrinfo hints;
155
+ struct addrinfo *result = NULL, *rp = NULL;
156
+
157
+ char buffer[strlen(definition) + 1];
158
+ strcpy(buffer, definition);
159
+
160
+ char buffer2[10 + 1];
161
+ snprintfz(buffer2, 10, "%d", default_port);
162
+
163
+ char *ip = buffer, *port = buffer2, *interface = "";;
164
+
165
+ int protocol = IPPROTO_TCP, socktype = SOCK_STREAM;
166
+ const char *protocol_str = "tcp";
167
+
168
+ if(strncmp(ip, "tcp:", 4) == 0) {
169
+ ip += 4;
170
+ protocol = IPPROTO_TCP;
171
+ socktype = SOCK_STREAM;
172
+ protocol_str = "tcp";
173
+ }
174
+ else if(strncmp(ip, "udp:", 4) == 0) {
175
+ ip += 4;
176
+ protocol = IPPROTO_UDP;
177
+ socktype = SOCK_DGRAM;
178
+ protocol_str = "udp";
179
+ }
180
+
181
+ char *e = ip;
182
+ if(*e == '[') {
183
+ e = ++ip;
184
+ while(*e && *e != ']') e++;
185
+ if(*e == ']') {
186
+ *e = '\0';
187
+ e++;
188
+ }
189
+ }
190
+ else {
191
+ while(*e && *e != ':' && *e != '%') e++;
192
+ }
193
+
194
+ if(*e == '%') {
195
+ *e = '\0';
196
+ e++;
197
+ interface = e;
198
+ while(*e && *e != ':') e++;
199
+ }
200
+
201
+ if(*e == ':') {
202
+ port = e + 1;
203
+ *e = '\0';
204
+ }
205
+
206
+ uint32_t scope_id = 0;
207
+ if(*interface) {
208
+ scope_id = if_nametoindex(interface);
209
+ if(!scope_id)
210
+ error("Cannot find a network interface named '%s'. Continuing with limiting the network interface", interface);
211
+ }
212
+
213
+ if(!*ip || *ip == '*' || !strcmp(ip, "any") || !strcmp(ip, "all"))
214
+ ip = NULL;
215
+
216
+ if(!*port)
217
+ port = buffer2;
218
+
219
+ memset(&hints, 0, sizeof(hints));
220
+ hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
221
+ hints.ai_socktype = socktype;
222
+ hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
223
+ hints.ai_protocol = protocol;
224
+ hints.ai_canonname = NULL;
225
+ hints.ai_addr = NULL;
226
+ hints.ai_next = NULL;
227
+
228
+ int r = getaddrinfo(ip, port, &hints, &result);
229
+ if (r != 0) {
230
+ error("getaddrinfo('%s', '%s'): %s\n", ip, port, gai_strerror(r));
231
+ return -1;
232
+ }
233
+
234
+ for (rp = result; rp != NULL; rp = rp->ai_next) {
235
+ int fd = -1;
236
+
237
+ char rip[INET_ADDRSTRLEN + INET6_ADDRSTRLEN] = "INVALID";
238
+ int rport = default_port;
239
+
240
+ switch (rp->ai_addr->sa_family) {
241
+ case AF_INET: {
242
+ struct sockaddr_in *sin = (struct sockaddr_in *) rp->ai_addr;
243
+ inet_ntop(AF_INET, &sin->sin_addr, rip, INET_ADDRSTRLEN);
244
+ rport = ntohs(sin->sin_port);
245
+ fd = create_listen_socket4(socktype, rip, rport, listen_backlog);
246
+ break;
247
+ }
248
+
249
+ case AF_INET6: {
250
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) rp->ai_addr;
251
+ inet_ntop(AF_INET6, &sin6->sin6_addr, rip, INET6_ADDRSTRLEN);
252
+ rport = ntohs(sin6->sin6_port);
253
+ fd = create_listen_socket6(socktype, scope_id, rip, rport, listen_backlog);
254
+ break;
255
+ }
256
+
257
+ default:
258
+ debug(D_LISTENER, "Unknown socket family %d", rp->ai_addr->sa_family);
259
+ break;
260
+ }
261
+
262
+ if (fd == -1) {
263
+ error("Cannot bind to ip '%s', port %d", rip, rport);
264
+ sockets->failed++;
265
+ }
266
+ else {
267
+ listen_sockets_add(sockets, fd, protocol_str, rip, rport);
268
+ added++;
269
+ }
270
+ }
271
+
272
+ freeaddrinfo(result);
273
+
274
+ return added;
275
+}
276
+
277
+int listen_sockets_setup(LISTEN_SOCKETS *sockets) {
278
+ listen_sockets_init(sockets);
279
+
280
+ sockets->backlog = (int) config_get_number(sockets->config_section, "listen backlog", sockets->backlog);
281
+
282
+ int old_port = sockets->default_port;
283
+ sockets->default_port = (int) config_get_number(sockets->config_section, "default port", sockets->default_port);
284
+ if(sockets->default_port < 1 || sockets->default_port > 65535) {
285
+ error("Invalid listen port %d given. Defaulting to %d.", sockets->default_port, old_port);
286
+ sockets->default_port = (int) config_set_number(sockets->config_section, "default port", old_port);
287
+ }
288
+ debug(D_OPTIONS, "Default listen port set to %d.", sockets->default_port);
289
+
290
+ char *s = config_get(sockets->config_section, "bind to", "*");
291
+ while(*s) {
292
+ char *e = s;
293
+
294
+ // skip separators, moving both s(tart) and e(nd)
295
+ while(isspace(*e) || *e == ',') s = ++e;
296
+
297
+ // move e(nd) to the first separator
298
+ while(*e && !isspace(*e) && *e != ',') e++;
299
+
300
+ // is there anything?
301
+ if(!*s || s == e) break;
302
+
303
+ char buf[e - s + 1];
304
+ strncpyz(buf, s, e - s);
305
+ bind_to_one(sockets, buf, sockets->default_port, sockets->backlog);
306
+
307
+ s = e;
308
+ }
309
+
310
+ if(!sockets->opened)
311
+ fatal("Cannot listen on any socket. Exiting...");
312
+
313
+ else if(sockets->failed) {
314
+ size_t i;
315
+ for(i = 0; i < sockets->opened ;i++)
316
+ info("Listen socket %s opened successfully.", sockets->fds_names[i]);
317
+ }
318
+
319
+ return (int)sockets->opened;
320
+}
321
+
322
+
323
+// --------------------------------------------------------------------------------------------------------------------
324
+// connect to another host/port
325
+
326
// _connect_to()
327
// protocol IPPROTO_TCP, IPPROTO_UDP
328
// socktype SOCK_STREAM, SOCK_DGRAM
@@ -228,6 +551,10 @@ int connect_to_one_of(const char *destination, int default_port, struct timeval
551
return sock;
552
}
553
554
+
555
+// --------------------------------------------------------------------------------------------------------------------
556
+// helpers to send/receive data in one call, in blocking mode, with a timeout
557
+
558
ssize_t recv_timeout(int sockfd, void *buf, size_t len, int flags, int timeout) {
559
for(;;) {
560
struct pollfd fd = {
@@ -289,3 +616,45 @@ ssize_t send_timeout(int sockfd, void *buf, size_t len, int flags, int timeout)
616
617
return send(sockfd, buf, len, flags);
618
}
619
+
620
+
621
+// --------------------------------------------------------------------------------------------------------------------
622
+// accept4() replacement for systems that do not have one
623
+
624
+#ifndef HAVE_ACCEPT4
625
+int accept4(int sock, struct sockaddr *addr, socklen_t *addrlen, int flags) {
626
+ int fd = accept(sock, addr, addrlen);
627
+ int newflags = 0;
628
+
629
+ if (fd < 0) return fd;
630
+
631
+ if (flags & SOCK_NONBLOCK) {
632
+ newflags |= O_NONBLOCK;
633
+ flags &= ~SOCK_NONBLOCK;
634
+ }
635
+
636
+#ifdef SOCK_CLOEXEC
637
+#ifdef O_CLOEXEC
638
+ if (flags & SOCK_CLOEXEC) {
639
+ newflags |= O_CLOEXEC;
640
+ flags &= ~SOCK_CLOEXEC;
641
+ }
642
+#endif
643
+#endif
644
+
645
+ if (flags) {
646
+ errno = -EINVAL;
647
+ return -1;
648
+ }
649
+
650
+ if (fcntl(fd, F_SETFL, newflags) < 0) {
651
+ int saved_errno = errno;
652
+ close(fd);
653
+ errno = saved_errno;
654
+ return -1;
655
+ }
656
+
657
+ return fd;
658
+}
659
+#endif
660
+
src/socket.h
+31
-4
@@ -1,14 +1,41 @@
1
-//
2
-// Created by costa on 24/12/2016.
3
-//
4
-
1
#ifndef NETDATA_SOCKET_H
2
#define NETDATA_SOCKET_H
3
4
+#ifndef MAX_LISTEN_FDS
5
+#define MAX_LISTEN_FDS 50
6
+#endif
7
+
8
+typedef struct listen_sockets {
9
+ const char *config_section; // the netdata configuration section to read settings from
10
+ int default_port; // the default port to use
11
+ int backlog; // the default listen backlog to use
12
+
13
+ size_t opened; // the number of sockets opened
14
+ size_t failed; // the number of sockets attempted to open, but failed
15
+ int fds[MAX_LISTEN_FDS]; // the open sockets
16
+ char *fds_names[MAX_LISTEN_FDS]; // descriptions for the open sockets
17
+} LISTEN_SOCKETS;
18
+
19
+extern int listen_sockets_setup(LISTEN_SOCKETS *sockets);
20
+extern void listen_sockets_close(LISTEN_SOCKETS *sockets);
21
+
22
extern int connect_to(const char *definition, int default_port, struct timeval *timeout);
23
extern int connect_to_one_of(const char *destination, int default_port, struct timeval *timeout, size_t *reconnects_counter, char *connected_to, size_t connected_to_size);
24
25
extern ssize_t recv_timeout(int sockfd, void *buf, size_t len, int flags, int timeout);
26
extern ssize_t send_timeout(int sockfd, void *buf, size_t len, int flags, int timeout);
27
28
+#ifndef HAVE_ACCEPT4
29
+extern int accept4(int sock, struct sockaddr *addr, socklen_t *addrlen, int flags);
30
+
31
+#ifndef SOCK_NONBLOCK
32
+#define SOCK_NONBLOCK 00004000
33
+#endif /* #ifndef SOCK_NONBLOCK */
34
+
35
+#ifndef SOCK_CLOEXEC
36
+#define SOCK_CLOEXEC 02000000
37
+#endif /* #ifndef SOCK_CLOEXEC */
38
+
39
+#endif /* #ifndef HAVE_ACCEPT4 */
40
+
41
#endif //NETDATA_SOCKET_H
src/web_server.c
+8
-358
@@ -1,25 +1,9 @@
1
#include "common.h"
2
3
-typedef struct listen_sockets {
4
- const char *config_section;
5
- size_t opened;
6
- size_t failed;
7
- int fds[MAX_LISTEN_FDS];
8
- char *fds_names[MAX_LISTEN_FDS];
9
- int default_port;
10
- int backlog;
11
- uint32_t flags;
12
-} LISTEN_SOCKETS;
13
-
3
static LISTEN_SOCKETS api_sockets = {
4
.config_section = CONFIG_SECTION_WEB,
16
- .opened = 0,
17
- .failed = 0,
18
- .fds = { [0 ... 99] = -1 },
19
- .fds_names = { [0 ... 99] = NULL },
20
- .default_port = LISTEN_PORT,
21
- .backlog = LISTEN_BACKLOG,
22
- .flags = 0
5
+ .default_port = API_LISTEN_PORT,
6
+ .backlog = API_LISTEN_BACKLOG
7
};
8
9
WEB_SERVER_MODE web_server_mode = WEB_SERVER_MODE_MULTI_THREADED;
@@ -61,42 +45,7 @@ static void log_allocations(void)
45
}
46
#endif /* NETDATA_INTERNAL_CHECKS */
47
64
-#ifndef HAVE_ACCEPT4
65
-int accept4(int sock, struct sockaddr *addr, socklen_t *addrlen, int flags) {
66
- int fd = accept(sock, addr, addrlen);
67
- int newflags = 0;
68
-
69
- if (fd < 0) return fd;
70
-
71
- if (flags & SOCK_NONBLOCK) {
72
- newflags |= O_NONBLOCK;
73
- flags &= ~SOCK_NONBLOCK;
74
- }
75
-
76
-#ifdef SOCK_CLOEXEC
77
-#ifdef O_CLOEXEC
78
- if (flags & SOCK_CLOEXEC) {
79
- newflags |= O_CLOEXEC;
80
- flags &= ~SOCK_CLOEXEC;
81
- }
82
-#endif
83
-#endif
84
-
85
- if (flags) {
86
- errno = -EINVAL;
87
- return -1;
88
- }
89
-
90
- if (fcntl(fd, F_SETFL, newflags) < 0) {
91
- int saved_errno = errno;
92
- close(fd);
93
- errno = saved_errno;
94
- return -1;
95
- }
96
-
97
- return fd;
98
-}
99
-#endif
48
+// --------------------------------------------------------------------------------------
49
50
WEB_SERVER_MODE web_server_mode_id(const char *mode) {
51
if(!strcmp(mode, "none"))
@@ -121,309 +70,10 @@ const char *web_server_mode_name(WEB_SERVER_MODE id) {
70
}
71
}
72
124
-int create_listen_socket4(int socktype, const char *ip, int port, int listen_backlog) {
125
- int sock;
126
- int sockopt = 1;
127
-
128
- debug(D_LISTENER, "IPv4 creating new listening socket on ip '%s' port %d", ip, port);
129
-
130
- sock = socket(AF_INET, socktype, 0);
131
- if(sock < 0) {
132
- error("IPv4 socket() on ip '%s' port %d failed.", ip, port);
133
- return -1;
134
- }
135
-
136
- /* avoid "address already in use" */
137
- if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&sockopt, sizeof(sockopt)) != 0)
138
- error("Cannot set SO_REUSEADDR on ip '%s' port's %d.", ip, port);
139
-
140
- struct sockaddr_in name;
141
- memset(&name, 0, sizeof(struct sockaddr_in));
142
- name.sin_family = AF_INET;
143
- name.sin_port = htons (port);
144
-
145
- int ret = inet_pton(AF_INET, ip, (void *)&name.sin_addr.s_addr);
146
- if(ret != 1) {
147
- error("Failed to convert IP '%s' to a valid IPv4 address.", ip);
148
- close(sock);
149
- return -1;
150
- }
151
-
152
- if(bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
153
- close(sock);
154
- error("IPv4 bind() on ip '%s' port %d failed.", ip, port);
155
- return -1;
156
- }
157
-
158
- if(listen(sock, listen_backlog) < 0) {
159
- close(sock);
160
- error("IPv4 listen() on ip '%s' port %d failed.", ip, port);
161
- return -1;
162
- }
163
-
164
- debug(D_LISTENER, "Listening on IPv4 ip '%s' port %d", ip, port);
165
- return sock;
166
-}
167
-
168
-int create_listen_socket6(int socktype, uint32_t scope_id, const char *ip, int port, int listen_backlog) {
169
- int sock = -1;
170
- int sockopt = 1;
171
- int ipv6only = 1;
172
-
173
- debug(D_LISTENER, "IPv6 creating new listening socket on ip '%s' port %d", ip, port);
174
-
175
- sock = socket(AF_INET6, socktype, 0);
176
- if (sock < 0) {
177
- error("IPv6 socket() on ip '%s' port %d failed.", ip, port);
178
- return -1;
179
- }
180
-
181
- /* avoid "address already in use" */
182
- if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&sockopt, sizeof(sockopt)) != 0)
183
- error("Cannot set SO_REUSEADDR on ip '%s' port's %d.", ip, port);
184
-
185
- /* IPv6 only */
186
- if(setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&ipv6only, sizeof(ipv6only)) != 0)
187
- error("Cannot set IPV6_V6ONLY on ip '%s' port's %d.", ip, port);
188
-
189
- struct sockaddr_in6 name;
190
- memset(&name, 0, sizeof(struct sockaddr_in6));
191
- name.sin6_family = AF_INET6;
192
- name.sin6_port = htons ((uint16_t) port);
193
- name.sin6_scope_id = scope_id;
194
-
195
- int ret = inet_pton(AF_INET6, ip, (void *)&name.sin6_addr.s6_addr);
196
- if(ret != 1) {
197
- error("Failed to convert IP '%s' to a valid IPv6 address.", ip);
198
- close(sock);
199
- return -1;
200
- }
201
-
202
- name.sin6_scope_id = scope_id;
203
-
204
- if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
205
- close(sock);
206
- error("IPv6 bind() on ip '%s' port %d failed.", ip, port);
207
- return -1;
208
- }
209
-
210
- if (listen(sock, listen_backlog) < 0) {
211
- close(sock);
212
- error("IPv6 listen() on ip '%s' port %d failed.", ip, port);
213
- return -1;
214
- }
215
-
216
- debug(D_LISTENER, "Listening on IPv6 ip '%s' port %d", ip, port);
217
- return sock;
218
-}
219
-
220
-static inline int add_listen_socket(LISTEN_SOCKETS *sockets, int fd, const char *protocol, const char *ip, int port) {
221
- if(sockets->opened >= MAX_LISTEN_FDS) {
222
- error("Too many listening sockets. Failed to add listening %s socket at ip '%s' port %d", protocol, ip, port);
223
- close(fd);
224
- return -1;
225
- }
226
-
227
- sockets->fds[sockets->opened] = fd;
228
-
229
- char buffer[100 + 1];
230
- snprintfz(buffer, 100, "%s:[%s]:%d", protocol, ip, port);
231
- sockets->fds_names[sockets->opened] = strdupz(buffer);
232
-
233
- sockets->opened++;
234
- return 0;
235
-}
236
-
237
-int is_listen_socket(LISTEN_SOCKETS *sockets, int fd) {
238
- size_t i;
239
- for(i = 0; i < sockets->opened ;i++)
240
- if(sockets->fds[i] == fd) return 1;
241
-
242
- return 0;
243
-}
244
-
245
-static inline void close_listen_sockets(LISTEN_SOCKETS *sockets) {
246
- size_t i;
247
- for(i = 0; i < sockets->opened ;i++) {
248
- close(sockets->fds[i]);
249
- sockets->fds[i] = -1;
250
-
251
- freez(sockets->fds_names[i]);
252
- sockets->fds_names[i] = NULL;
253
- }
254
-
255
- sockets->opened = 0;
256
-}
257
-
258
-static inline int bind_to_one(LISTEN_SOCKETS *sockets, const char *definition, int default_port, int listen_backlog) {
259
- int added = 0;
260
- struct addrinfo hints;
261
- struct addrinfo *result = NULL, *rp = NULL;
262
-
263
- char buffer[strlen(definition) + 1];
264
- strcpy(buffer, definition);
265
-
266
- char buffer2[10 + 1];
267
- snprintfz(buffer2, 10, "%d", default_port);
268
-
269
- char *ip = buffer, *port = buffer2, *interface = "";;
270
-
271
- int protocol = IPPROTO_TCP, socktype = SOCK_STREAM;
272
- const char *protocol_str = "tcp";
273
-
274
- if(strncmp(ip, "tcp:", 4) == 0) {
275
- ip += 4;
276
- protocol = IPPROTO_TCP;
277
- socktype = SOCK_STREAM;
278
- protocol_str = "tcp";
279
- }
280
- else if(strncmp(ip, "udp:", 4) == 0) {
281
- ip += 4;
282
- protocol = IPPROTO_UDP;
283
- socktype = SOCK_DGRAM;
284
- protocol_str = "udp";
285
- }
286
-
287
- char *e = ip;
288
- if(*e == '[') {
289
- e = ++ip;
290
- while(*e && *e != ']') e++;
291
- if(*e == ']') {
292
- *e = '\0';
293
- e++;
294
- }
295
- }
296
- else {
297
- while(*e && *e != ':' && *e != '%') e++;
298
- }
299
-
300
- if(*e == '%') {
301
- *e = '\0';
302
- e++;
303
- interface = e;
304
- while(*e && *e != ':') e++;
305
- }
306
-
307
- if(*e == ':') {
308
- port = e + 1;
309
- *e = '\0';
310
- }
311
-
312
- uint32_t scope_id = 0;
313
- if(*interface) {
314
- scope_id = if_nametoindex(interface);
315
- if(!scope_id)
316
- error("Cannot find a network interface named '%s'. Continuing with limiting the network interface", interface);
317
- }
318
-
319
- if(!*ip || *ip == '*' || !strcmp(ip, "any") || !strcmp(ip, "all"))
320
- ip = NULL;
321
-
322
- if(!*port)
323
- port = buffer2;
324
-
325
- memset(&hints, 0, sizeof(hints));
326
- hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
327
- hints.ai_socktype = socktype;
328
- hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
329
- hints.ai_protocol = protocol;
330
- hints.ai_canonname = NULL;
331
- hints.ai_addr = NULL;
332
- hints.ai_next = NULL;
333
-
334
- int r = getaddrinfo(ip, port, &hints, &result);
335
- if (r != 0) {
336
- error("getaddrinfo('%s', '%s'): %s\n", ip, port, gai_strerror(r));
337
- return -1;
338
- }
339
-
340
- for (rp = result; rp != NULL; rp = rp->ai_next) {
341
- int fd = -1;
342
-
343
- char rip[INET_ADDRSTRLEN + INET6_ADDRSTRLEN] = "INVALID";
344
- int rport = default_port;
345
-
346
- switch (rp->ai_addr->sa_family) {
347
- case AF_INET: {
348
- struct sockaddr_in *sin = (struct sockaddr_in *) rp->ai_addr;
349
- inet_ntop(AF_INET, &sin->sin_addr, rip, INET_ADDRSTRLEN);
350
- rport = ntohs(sin->sin_port);
351
- fd = create_listen_socket4(socktype, rip, rport, listen_backlog);
352
- break;
353
- }
354
-
355
- case AF_INET6: {
356
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) rp->ai_addr;
357
- inet_ntop(AF_INET6, &sin6->sin6_addr, rip, INET6_ADDRSTRLEN);
358
- rport = ntohs(sin6->sin6_port);
359
- fd = create_listen_socket6(socktype, scope_id, rip, rport, listen_backlog);
360
- break;
361
- }
362
-
363
- default:
364
- debug(D_LISTENER, "Unknown socket family %d", rp->ai_addr->sa_family);
365
- break;
366
- }
367
-
368
- if (fd == -1) {
369
- error("Cannot bind to ip '%s', port %d", rip, rport);
370
- sockets->failed++;
371
- }
372
- else {
373
- add_listen_socket(sockets, fd, protocol_str, rip, rport);
374
- added++;
375
- }
376
- }
377
-
378
- freeaddrinfo(result);
379
-
380
- return added;
381
-}
382
-
383
-int create_listen_sockets(LISTEN_SOCKETS *sockets) {
384
- sockets->backlog = (int) config_get_number(sockets->config_section, "listen backlog", LISTEN_BACKLOG);
385
-
386
- int old_port = sockets->default_port;
387
- sockets->default_port = (int) config_get_number(sockets->config_section, "default port", sockets->default_port);
388
- if(sockets->default_port < 1 || sockets->default_port > 65535) {
389
- error("Invalid listen port %d given. Defaulting to %d.", sockets->default_port, old_port);
390
- sockets->default_port = (int) config_set_number(sockets->config_section, "default port", old_port);
391
- }
392
- debug(D_OPTIONS, "Default listen port set to %d.", sockets->default_port);
393
-
394
- char *s = config_get(sockets->config_section, "bind to", "*");
395
- while(*s) {
396
- char *e = s;
397
-
398
- // skip separators, moving both s(tart) and e(nd)
399
- while(isspace(*e) || *e == ',') s = ++e;
400
-
401
- // move e(nd) to the first separator
402
- while(*e && !isspace(*e) && *e != ',') e++;
403
-
404
- // is there anything?
405
- if(!*s || s == e) break;
406
-
407
- char buf[e - s + 1];
408
- strncpyz(buf, s, e - s);
409
- bind_to_one(sockets, buf, sockets->default_port, sockets->backlog);
410
-
411
- s = e;
412
- }
413
-
414
- if(!sockets->opened)
415
- fatal("Cannot listen on any socket. Exiting...");
416
- else if(sockets->failed) {
417
- size_t i;
418
- for(i = 0; i < sockets->opened ;i++)
419
- info("Listen socket %s opened successfully.", sockets->fds_names[i]);
420
- }
421
-
422
- return (int)sockets->opened;
423
-}
73
+// --------------------------------------------------------------------------------------
74
425
-int create_api_listen_sockets(void) {
426
- return create_listen_sockets(&api_sockets);
75
+int api_listen_sockets_setup(void) {
76
+ return listen_sockets_setup(&api_sockets);
77
}
78
79
// --------------------------------------------------------------------------------------
@@ -532,7 +182,7 @@ void *socket_listen_main_multi_threaded(void *ptr) {
182
}
183
184
debug(D_WEB_CLIENT, "LISTENER: exit!");
535
- close_listen_sockets(&api_sockets);
185
+ listen_sockets_close(&api_sockets);
186
187
freez(fds);
188
@@ -704,7 +354,7 @@ void *socket_listen_main_single_threaded(void *ptr) {
354
}
355
356
debug(D_WEB_CLIENT, "LISTENER: exit!");
707
- close_listen_sockets(&api_sockets);
357
+ listen_sockets_close(&api_sockets);
358
359
static_thread->enabled = 0;
360
pthread_exit(NULL);
src/web_server.h
+6
-19
@@ -6,11 +6,12 @@
6
#define WEB_PATH_DATASOURCE "datasource"
7
#define WEB_PATH_GRAPH "graph"
8
9
-#define LISTEN_PORT 19999
10
-#define LISTEN_BACKLOG 100
9
+#ifndef API_LISTEN_PORT
10
+#define API_LISTEN_PORT 19999
11
+#endif
12
12
-#ifndef MAX_LISTEN_FDS
13
-#define MAX_LISTEN_FDS 100
13
+#ifndef API_LISTEN_BACKLOG
14
+#define API_LISTEN_BACKLOG 4096
15
#endif
16
17
typedef enum web_server_mode {
@@ -24,22 +25,8 @@ extern WEB_SERVER_MODE web_server_mode;
25
extern WEB_SERVER_MODE web_server_mode_id(const char *mode);
26
extern const char *web_server_mode_name(WEB_SERVER_MODE id);
27
27
-
28
extern void *socket_listen_main_multi_threaded(void *ptr);
29
extern void *socket_listen_main_single_threaded(void *ptr);
30
-extern int create_api_listen_sockets(void);
31
-
32
-#ifndef HAVE_ACCEPT4
33
-extern int accept4(int sock, struct sockaddr *addr, socklen_t *addrlen, int flags);
34
-
35
-#ifndef SOCK_NONBLOCK
36
-#define SOCK_NONBLOCK 00004000
37
-#endif /* #ifndef SOCK_NONBLOCK */
38
-
39
-#ifndef SOCK_CLOEXEC
40
-#define SOCK_CLOEXEC 02000000
41
-#endif /* #ifndef SOCK_CLOEXEC */
42
-
43
-#endif /* #ifndef HAVE_ACCEPT4 */
30
+extern int api_listen_sockets_setup(void);
31
32
#endif /* NETDATA_WEB_SERVER_H */