]> arthur.barton.de Git - netdata.git/blob - src/socket.c
added more fping alarms; added the ability to have alarms that never send CLEAR notif...
[netdata.git] / src / socket.c
1 #include "common.h"
2
3 // connect_to()
4 //
5 // definition format:
6 //
7 //    [PROTOCOL:]IP[%INTERFACE][:PORT]
8 //
9 // PROTOCOL  = tcp or udp
10 // IP        = IPv4 or IPv6 IP or hostname, optionally enclosed in [] (required for IPv6)
11 // INTERFACE = for IPv6 only, the network interface to use
12 // PORT      = port number or service name
13
14 int connect_to(const char *definition, int default_port, struct timeval *timeout) {
15     struct addrinfo hints;
16     struct addrinfo *ai_head = NULL, *ai = NULL;
17
18     char buffer[strlen(definition) + 1];
19     strcpy(buffer, definition);
20
21     char default_service[10 + 1];
22     snprintfz(default_service, 10, "%d", default_port);
23
24     char *host = buffer, *service = default_service, *interface = "";
25     int protocol = IPPROTO_TCP, socktype = SOCK_STREAM;
26     uint32_t scope_id = 0;
27
28     if(strncmp(host, "tcp:", 4) == 0) {
29         host += 4;
30         protocol = IPPROTO_TCP;
31         socktype = SOCK_STREAM;
32     }
33     else if(strncmp(host, "udp:", 4) == 0) {
34         host += 4;
35         protocol = IPPROTO_UDP;
36         socktype = SOCK_DGRAM;
37     }
38
39     char *e = host;
40     if(*e == '[') {
41         e = ++host;
42         while(*e && *e != ']') e++;
43         if(*e == ']') {
44             *e = '\0';
45             e++;
46         }
47     }
48     else {
49         while(*e && *e != ':' && *e != '%') e++;
50     }
51
52     if(*e == '%') {
53         *e = '\0';
54         e++;
55         interface = e;
56         while(*e && *e != ':') e++;
57     }
58
59     if(*e == ':') {
60         *e = '\0';
61         e++;
62         service = e;
63     }
64
65     debug(D_CONNECT_TO, "Attempting connection to host = '%s', service = '%s', interface = '%s', protocol = %d (tcp = %d, udp = %d)", host, service, interface, protocol, IPPROTO_TCP, IPPROTO_UDP);
66
67     if(!*host) {
68         error("Definition '%s' does not specify a host.", definition);
69         return -1;
70     }
71
72     if(*interface) {
73         scope_id = if_nametoindex(interface);
74         if(!scope_id)
75             error("Cannot find a network interface named '%s'. Continuing with limiting the network interface", interface);
76     }
77
78     if(!*service)
79         service = default_service;
80
81     memset(&hints, 0, sizeof(hints));
82     hints.ai_family   = PF_UNSPEC;   /* Allow IPv4 or IPv6 */
83     hints.ai_socktype = socktype;
84     hints.ai_protocol = protocol;
85
86     int ai_err = getaddrinfo(host, service, &hints, &ai_head);
87     if (ai_err != 0) {
88         error("Cannot resolve host '%s', port '%s': %s", host, service, gai_strerror(ai_err));
89         return -1;
90     }
91
92     int fd = -1;
93     for (ai = ai_head; ai != NULL && fd == -1; ai = ai->ai_next) {
94
95         if (ai->ai_family == PF_INET6) {
96             struct sockaddr_in6 *pSadrIn6 = (struct sockaddr_in6 *) ai->ai_addr;
97             if(pSadrIn6->sin6_scope_id == 0) {
98                 pSadrIn6->sin6_scope_id = scope_id;
99             }
100         }
101
102         char hostBfr[NI_MAXHOST + 1];
103         char servBfr[NI_MAXSERV + 1];
104
105         getnameinfo(ai->ai_addr,
106                 ai->ai_addrlen,
107                 hostBfr,
108                 sizeof(hostBfr),
109                 servBfr,
110                 sizeof(servBfr),
111                 NI_NUMERICHOST | NI_NUMERICSERV);
112
113         debug(D_CONNECT_TO, "Address info: host = '%s', service = '%s', ai_flags = 0x%02X, ai_family = %d (PF_INET = %d, PF_INET6 = %d), ai_socktype = %d (SOCK_STREAM = %d, SOCK_DGRAM = %d), ai_protocol = %d (IPPROTO_TCP = %d, IPPROTO_UDP = %d), ai_addrlen = %lu (sockaddr_in = %lu, sockaddr_in6 = %lu)",
114                 hostBfr,
115                 servBfr,
116                 (unsigned int)ai->ai_flags,
117                 ai->ai_family,
118                 PF_INET,
119                 PF_INET6,
120                 ai->ai_socktype,
121                 SOCK_STREAM,
122                 SOCK_DGRAM,
123                 ai->ai_protocol,
124                 IPPROTO_TCP,
125                 IPPROTO_UDP,
126                 (unsigned long)ai->ai_addrlen,
127                 (unsigned long)sizeof(struct sockaddr_in),
128                 (unsigned long)sizeof(struct sockaddr_in6));
129
130         switch (ai->ai_addr->sa_family) {
131             case PF_INET: {
132                 struct sockaddr_in *pSadrIn = (struct sockaddr_in *)ai->ai_addr;
133                 debug(D_CONNECT_TO, "ai_addr = sin_family: %d (AF_INET = %d, AF_INET6 = %d), sin_addr: '%s', sin_port: '%s'",
134                         pSadrIn->sin_family,
135                         AF_INET,
136                         AF_INET6,
137                         hostBfr,
138                         servBfr);
139                 break;
140             }
141
142             case PF_INET6: {
143                 struct sockaddr_in6 *pSadrIn6 = (struct sockaddr_in6 *) ai->ai_addr;
144                 debug(D_CONNECT_TO,"ai_addr = sin6_family: %d (AF_INET = %d, AF_INET6 = %d), sin6_addr: '%s', sin6_port: '%s', sin6_flowinfo: %u, sin6_scope_id: %u",
145                         pSadrIn6->sin6_family,
146                         AF_INET,
147                         AF_INET6,
148                         hostBfr,
149                         servBfr,
150                         pSadrIn6->sin6_flowinfo,
151                         pSadrIn6->sin6_scope_id);
152                 break;
153             }
154
155             default: {
156                 debug(D_CONNECT_TO, "Unknown protocol family %d.", ai->ai_family);
157                 continue;
158             }
159         }
160
161         fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
162         if(fd != -1) {
163             if(setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)timeout, sizeof(struct timeval)) < 0)
164                 error("Failed to set timeout on the socket to ip '%s' port '%s'", hostBfr, servBfr);
165
166             if(connect(fd, ai->ai_addr, ai->ai_addrlen) < 0) {
167                 error("Failed to connect to '%s', port '%s'", hostBfr, servBfr);
168                 close(fd);
169                 fd = -1;
170             }
171
172             debug(D_CONNECT_TO, "Connected to '%s' on port '%s'.", hostBfr, servBfr);
173         }
174     }
175
176     freeaddrinfo(ai_head);
177
178     return fd;
179 }