allow netdata to listen at and connect to unix sockets; fixes #2656
Costa Tsaousis (ktsaou) committed
Aug 31, 2017 at 00:05 UTC
a91bfe3739c749e96b21d6d86b4099a3bfa088ac
3 files changed
+101
-10
src/common.h
+1
@@ -80,6 +80,7 @@
80
#include <sys/time.h>
81
#include <sys/types.h>
82
#include <sys/wait.h>
83
+#include <sys/un.h>
84
#include <time.h>
85
#include <unistd.h>
86
#include <uuid/uuid.h>
src/socket.c
+99
-9
@@ -80,6 +80,43 @@ int sock_enlarge_out(int fd) {
80
// --------------------------------------------------------------------------------------------------------------------
81
// listening sockets
82
83
+int create_listen_socket_unix(const char *path, int listen_backlog) {
84
+ int sock;
85
+
86
+ debug(D_LISTENER, "LISTENER: UNIX creating new listening socket on path '%s'", path);
87
+
88
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
89
+ if(sock < 0) {
90
+ error("LISTENER: UNIX socket() on path '%s' failed.", path);
91
+ return -1;
92
+ }
93
+
94
+ sock_setnonblock(sock);
95
+ sock_enlarge_in(sock);
96
+
97
+ struct sockaddr_un name;
98
+ memset(&name, 0, sizeof(struct sockaddr_un));
99
+ name.sun_family = AF_UNIX;
100
+ strncpy(name.sun_path, path, sizeof(name.sun_path)-1);
101
+
102
+ unlink(path);
103
+
104
+ if(bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
105
+ close(sock);
106
+ error("LISTENER: UNIX bind() on path '%s' failed.", path);
107
+ return -1;
108
+ }
109
+
110
+ if(listen(sock, listen_backlog) < 0) {
111
+ close(sock);
112
+ error("LISTENER: UNIX listen() on path '%s' failed.", path);
113
+ return -1;
114
+ }
115
+
116
+ debug(D_LISTENER, "LISTENER: Listening on UNIX path '%s'", path);
117
+ return sock;
118
+}
119
+
120
int create_listen_socket4(int socktype, const char *ip, int port, int listen_backlog) {
121
int sock;
122
@@ -186,7 +223,12 @@ static inline int listen_sockets_add(LISTEN_SOCKETS *sockets, int fd, int sockty
223
sockets->fds[sockets->opened] = fd;
224
225
char buffer[100 + 1];
189
- snprintfz(buffer, 100, "%s:[%s]:%d", protocol, ip, port);
226
+
227
+ if(port)
228
+ snprintfz(buffer, 100, "%s:[%s]:%d", protocol, ip, port);
229
+ else
230
+ snprintfz(buffer, 100, "%s:[%s]", protocol, ip);
231
+
232
sockets->fds_names[sockets->opened] = strdupz(buffer);
233
sockets->fds_types[sockets->opened] = socktype;
234
@@ -230,7 +272,7 @@ void listen_sockets_close(LISTEN_SOCKETS *sockets) {
272
sockets->failed = 0;
273
}
274
233
-static inline int bind_to_one(LISTEN_SOCKETS *sockets, const char *definition, int default_port, int listen_backlog) {
275
+static inline int bind_to_this(LISTEN_SOCKETS *sockets, const char *definition, int default_port, int listen_backlog) {
276
int added = 0;
277
struct addrinfo hints;
278
struct addrinfo *result = NULL, *rp = NULL;
@@ -258,6 +300,22 @@ static inline int bind_to_one(LISTEN_SOCKETS *sockets, const char *definition, i
300
socktype = SOCK_DGRAM;
301
protocol_str = "udp";
302
}
303
+ else if(strncmp(ip, "unix:", 5) == 0) {
304
+ char *path = ip + 5;
305
+ socktype = SOCK_STREAM;
306
+ protocol_str = "unix";
307
+
308
+ int fd = create_listen_socket_unix(path, listen_backlog);
309
+ if (fd == -1) {
310
+ error("LISTENER: Cannot create unix socket '%s'", path);
311
+ sockets->failed++;
312
+ }
313
+ else {
314
+ listen_sockets_add(sockets, fd, socktype, protocol_str, path, 0);
315
+ added++;
316
+ }
317
+ return added;
318
+ }
319
320
char *e = ip;
321
if(*e == '[') {
@@ -385,7 +443,7 @@ int listen_sockets_setup(LISTEN_SOCKETS *sockets) {
443
444
char buf[e - s + 1];
445
strncpyz(buf, s, e - s);
388
- bind_to_one(sockets, buf, sockets->default_port, sockets->backlog);
446
+ bind_to_this(sockets, buf, sockets->default_port, sockets->backlog);
447
448
s = e;
449
}
@@ -403,7 +461,35 @@ int listen_sockets_setup(LISTEN_SOCKETS *sockets) {
461
// --------------------------------------------------------------------------------------------------------------------
462
// connect to another host/port
463
406
-// _connect_to()
464
+// connect_to_this_unix()
465
+// path the path of the unix socket
466
+// timeout the timeout for establishing a connection
467
+
468
+static inline int connect_to_unix(const char *path, struct timeval *timeout) {
469
+ int fd = socket(AF_UNIX, SOCK_STREAM, 0);
470
+
471
+ if(timeout) {
472
+ if(setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *) timeout, sizeof(struct timeval)) < 0)
473
+ error("Failed to set timeout on UNIX socket '%s'", path);
474
+ }
475
+
476
+ struct sockaddr_un addr;
477
+ memset(&addr, 0, sizeof(addr));
478
+ addr.sun_family = AF_UNIX;
479
+ strncpy(addr.sun_path, path, sizeof(addr.sun_path)-1);
480
+
481
+ if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
482
+ error("Cannot connect to UNIX socket on path '%s'.", path);
483
+ close(fd);
484
+ return -1;
485
+ }
486
+
487
+ debug(D_CONNECT_TO, "Connected to UNIX socket on path '%s'.", path);
488
+
489
+ return fd;
490
+}
491
+
492
+// connect_to_this_ip46()
493
// protocol IPPROTO_TCP, IPPROTO_UDP
494
// socktype SOCK_STREAM, SOCK_DGRAM
495
// host the destination hostname or IP address (IPv4 or IPv6) to connect to
@@ -413,7 +499,7 @@ int listen_sockets_setup(LISTEN_SOCKETS *sockets) {
499
// service the service name or port to connect to
500
// timeout the timeout for establishing a connection
501
416
-static inline int _connect_to(int protocol, int socktype, const char *host, uint32_t scope_id, const char *service, struct timeval *timeout) {
502
+static inline int connect_to_this_ip46(int protocol, int socktype, const char *host, uint32_t scope_id, const char *service, struct timeval *timeout) {
503
struct addrinfo hints;
504
struct addrinfo *ai_head = NULL, *ai = NULL;
505
@@ -519,7 +605,7 @@ static inline int _connect_to(int protocol, int socktype, const char *host, uint
605
return fd;
606
}
607
522
-// connect_to()
608
+// connect_to_this()
609
//
610
// definition format:
611
//
@@ -530,7 +616,7 @@ static inline int _connect_to(int protocol, int socktype, const char *host, uint
616
// INTERFACE = for IPv6 only, the network interface to use
617
// PORT = port number or service name
618
533
-int connect_to(const char *definition, int default_port, struct timeval *timeout) {
619
+int connect_to_this(const char *definition, int default_port, struct timeval *timeout) {
620
char buffer[strlen(definition) + 1];
621
strcpy(buffer, definition);
622
@@ -551,6 +637,10 @@ int connect_to(const char *definition, int default_port, struct timeval *timeout
637
protocol = IPPROTO_UDP;
638
socktype = SOCK_DGRAM;
639
}
640
+ else if(strncmp(host, "unix:", 5) == 0) {
641
+ char *path = host + 5;
642
+ return connect_to_unix(path, timeout);
643
+ }
644
645
char *e = host;
646
if(*e == '[') {
@@ -595,7 +685,7 @@ int connect_to(const char *definition, int default_port, struct timeval *timeout
685
service = default_service;
686
687
598
- return _connect_to(protocol, socktype, host, scope_id, service, timeout);
688
+ return connect_to_this_ip46(protocol, socktype, host, scope_id, service, timeout);
689
}
690
691
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) {
@@ -617,7 +707,7 @@ int connect_to_one_of(const char *destination, int default_port, struct timeval
707
char buf[e - s + 1];
708
strncpyz(buf, s, e - s);
709
if(reconnects_counter) *reconnects_counter += 1;
620
- sock = connect_to(buf, default_port, timeout);
710
+ sock = connect_to_this(buf, default_port, timeout);
711
if(sock != -1) {
712
if(connected_to && connected_to_size) {
713
strncpy(connected_to, buf, connected_to_size);
src/socket.h
+1
-1
@@ -21,7 +21,7 @@ typedef struct listen_sockets {
21
extern int listen_sockets_setup(LISTEN_SOCKETS *sockets);
22
extern void listen_sockets_close(LISTEN_SOCKETS *sockets);
23
24
-extern int connect_to(const char *definition, int default_port, struct timeval *timeout);
24
+extern int connect_to_this(const char *definition, int default_port, struct timeval *timeout);
25
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);
26
27
extern ssize_t recv_timeout(int sockfd, void *buf, size_t len, int flags, int timeout);