]> arthur.barton.de Git - netdata.git/blobdiff - src/socket.c
dns_query_time plugin: makefiles and python.d.conf update
[netdata.git] / src / socket.c
index 6d60be772e506e1f59bb8e729a6769f6cb78c7e8..400c1ef4e2456020c5fb36794dc7c8cc449522ab 100644 (file)
@@ -7,7 +7,7 @@
 //    [PROTOCOL:]IP[%INTERFACE][:PORT]
 //
 // PROTOCOL  = tcp or udp
-// IP        = IPv4 or IPv6 IP or hostname, optionaly enclosed in [] (required for IPv6)
+// IP        = IPv4 or IPv6 IP or hostname, optionally enclosed in [] (required for IPv6)
 // INTERFACE = for IPv6 only, the network interface to use
 // PORT      = port number or service name
 
@@ -22,16 +22,18 @@ int connect_to(const char *definition, int default_port, struct timeval *timeout
     snprintfz(default_service, 10, "%d", default_port);
 
     char *host = buffer, *service = default_service, *interface = "";
-    int protocol = 0;
+    int protocol = IPPROTO_TCP, socktype = SOCK_STREAM;
     uint32_t scope_id = 0;
 
     if(strncmp(host, "tcp:", 4) == 0) {
         host += 4;
         protocol = IPPROTO_TCP;
+        socktype = SOCK_STREAM;
     }
     else if(strncmp(host, "udp:", 4) == 0) {
         host += 4;
         protocol = IPPROTO_UDP;
+        socktype = SOCK_DGRAM;
     }
 
     char *e = host;
@@ -76,14 +78,14 @@ int connect_to(const char *definition, int default_port, struct timeval *timeout
     if(!*service)
         service = default_service;
 
-    memset(&hints, 0, sizeof(struct addrinfo));
+    memset(&hints, 0, sizeof(hints));
     hints.ai_family   = PF_UNSPEC;   /* Allow IPv4 or IPv6 */
-    hints.ai_socktype = SOCK_DGRAM;  /* Datagram socket */
-    hints.ai_protocol = protocol;    /* The required protocol */
+    hints.ai_socktype = socktype;
+    hints.ai_protocol = protocol;
 
     int ai_err = getaddrinfo(host, service, &hints, &ai_head);
     if (ai_err != 0) {
-        error("Cannot resolve host '%s', port '%s': %s\n", host, service, gai_strerror(ai_err));
+        error("Cannot resolve host '%s', port '%s': %s", host, service, gai_strerror(ai_err));
         return -1;
     }
 
@@ -158,8 +160,10 @@ int connect_to(const char *definition, int default_port, struct timeval *timeout
 
         fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
         if(fd != -1) {
-            if(setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)timeout, sizeof(struct timeval)) < 0)
-                error("Failed to set timeout on the socket to ip '%s' port '%s'", hostBfr, servBfr);
+            if(timeout) {
+                if(setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *) timeout, sizeof(struct timeval)) < 0)
+                    error("Failed to set timeout on the socket to ip '%s' port '%s'", hostBfr, servBfr);
+            }
 
             if(connect(fd, ai->ai_addr, ai->ai_addrlen) < 0) {
                 error("Failed to connect to '%s', port '%s'", hostBfr, servBfr);
@@ -175,3 +179,98 @@ int connect_to(const char *definition, int default_port, struct timeval *timeout
 
     return fd;
 }
+
+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) {
+    int sock = -1;
+
+    const char *s = destination;
+    while(*s) {
+        const char *e = s;
+
+        // skip separators, moving both s(tart) and e(nd)
+        while(isspace(*e) || *e == ',') s = ++e;
+
+        // move e(nd) to the first separator
+        while(*e && !isspace(*e) && *e != ',') e++;
+
+        // is there anything?
+        if(!*s || s == e) break;
+
+        char buf[e - s + 1];
+        strncpyz(buf, s, e - s);
+        if(reconnects_counter) *reconnects_counter += 1;
+        sock = connect_to(buf, default_port, timeout);
+        if(sock != -1) {
+            if(connected_to && connected_to_size) {
+                strncpy(connected_to, buf, connected_to_size);
+                connected_to[connected_to_size - 1] = '\0';
+            }
+            break;
+        }
+        s = e;
+    }
+
+    return sock;
+}
+
+ssize_t recv_timeout(int sockfd, void *buf, size_t len, int flags, int timeout) {
+    for(;;) {
+        struct pollfd fd = {
+                .fd = sockfd,
+                .events = POLLIN,
+                .revents = 0
+        };
+
+        errno = 0;
+        int retval = poll(&fd, 1, timeout * 1000);
+
+        if(retval == -1) {
+            // failed
+
+            if(errno == EINTR || errno == EAGAIN)
+                continue;
+
+            return -1;
+        }
+
+        if(!retval) {
+            // timeout
+            return 0;
+        }
+
+        if(fd.events & POLLIN) break;
+    }
+
+    return recv(sockfd, buf, len, flags);
+}
+
+ssize_t send_timeout(int sockfd, void *buf, size_t len, int flags, int timeout) {
+    for(;;) {
+        struct pollfd fd = {
+                .fd = sockfd,
+                .events = POLLOUT,
+                .revents = 0
+        };
+
+        errno = 0;
+        int retval = poll(&fd, 1, timeout * 1000);
+
+        if(retval == -1) {
+            // failed
+
+            if(errno == EINTR || errno == EAGAIN)
+                continue;
+
+            return -1;
+        }
+
+        if(!retval) {
+            // timeout
+            return 0;
+        }
+
+        if(fd.events & POLLOUT) break;
+    }
+
+    return send(sockfd, buf, len, flags);
+}