@cryptotaxi247 / netdata-1 / commits / 4add90417

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 */