2 * collectd - src/libcollectdclient/network.c
3 * Copyright (C) 2005-2012 Florian octo Forster
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
24 * Florian octo Forster <octo at collectd.org>
36 #include <sys/types.h>
37 #include <sys/socket.h>
41 # include <netinet/in.h>
44 #include "collectd/network.h"
45 #include "collectd/network_buffer.h"
52 lcc_server_t *servers;
61 lcc_security_level_t security_level;
69 lcc_network_buffer_t *buffer;
77 static int server_close_socket (lcc_server_t *srv) /* {{{ */
92 } /* }}} int server_close_socket */
94 static void int_server_destroy (lcc_server_t *srv) /* {{{ */
101 server_close_socket (srv);
107 free (srv->username);
108 free (srv->password);
111 int_server_destroy (next);
112 } /* }}} void int_server_destroy */
114 static int server_open_socket (lcc_server_t *srv) /* {{{ */
116 struct addrinfo ai_hints = { 0 };
117 struct addrinfo *ai_list = NULL;
118 struct addrinfo *ai_ptr;
125 server_close_socket (srv);
128 ai_hints.ai_flags |= AI_ADDRCONFIG;
130 ai_hints.ai_family = AF_UNSPEC;
131 ai_hints.ai_socktype = SOCK_DGRAM;
133 status = getaddrinfo (srv->node, srv->service, &ai_hints, &ai_list);
136 assert (ai_list != NULL);
138 for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
140 srv->fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
144 if (ai_ptr->ai_family == AF_INET)
146 struct sockaddr_in *addr = (struct sockaddr_in *) ai_ptr->ai_addr;
149 if (IN_MULTICAST (ntohl (addr->sin_addr.s_addr)))
150 optname = IP_MULTICAST_TTL;
154 status = setsockopt (srv->fd, IPPROTO_IP, optname,
155 &srv->ttl, sizeof (srv->ttl));
157 else if (ai_ptr->ai_family == AF_INET6)
159 /* Useful example: http://gsyc.escet.urjc.es/~eva/IPv6-web/examples/mcast.html */
160 struct sockaddr_in6 *addr = (struct sockaddr_in6 *) ai_ptr->ai_addr;
163 if (IN6_IS_ADDR_MULTICAST (&addr->sin6_addr))
164 optname = IPV6_MULTICAST_HOPS;
166 optname = IPV6_UNICAST_HOPS;
168 status = setsockopt (srv->fd, IPPROTO_IPV6, optname,
169 &srv->ttl, sizeof (srv->ttl));
173 /* setsockopt failed. */
179 srv->sa = malloc (ai_ptr->ai_addrlen);
187 memcpy (srv->sa, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
188 srv->sa_len = ai_ptr->ai_addrlen;
192 freeaddrinfo (ai_list);
197 } /* }}} int server_open_socket */
199 static int server_send_buffer (lcc_server_t *srv) /* {{{ */
201 char buffer[LCC_NETWORK_BUFFER_SIZE_DEFAULT];
207 status = server_open_socket (srv);
212 memset (buffer, 0, sizeof (buffer));
213 buffer_size = sizeof (buffer);
215 lcc_network_buffer_finalize (srv->buffer);
216 status = lcc_network_buffer_get (srv->buffer, buffer, &buffer_size);
217 lcc_network_buffer_initialize (srv->buffer);
222 if (buffer_size > sizeof (buffer))
223 buffer_size = sizeof (buffer);
227 assert (srv->fd >= 0);
228 assert (srv->sa != NULL);
229 status = (int) sendto (srv->fd, buffer, buffer_size, /* flags = */ 0,
230 srv->sa, srv->sa_len);
231 if ((status < 0) && ((errno == EINTR) || (errno == EAGAIN)))
240 } /* }}} int server_send_buffer */
242 static int server_value_add (lcc_server_t *srv, /* {{{ */
243 const lcc_value_list_t *vl)
247 status = lcc_network_buffer_add_value (srv->buffer, vl);
251 server_send_buffer (srv);
252 return (lcc_network_buffer_add_value (srv->buffer, vl));
253 } /* }}} int server_value_add */
258 lcc_network_t *lcc_network_create (void) /* {{{ */
262 net = malloc (sizeof (*net));
265 memset (net, 0, sizeof (*net));
270 } /* }}} lcc_network_t *lcc_network_create */
272 void lcc_network_destroy (lcc_network_t *net) /* {{{ */
276 int_server_destroy (net->servers);
278 } /* }}} void lcc_network_destroy */
280 lcc_server_t *lcc_server_create (lcc_network_t *net, /* {{{ */
281 const char *node, const char *service)
285 if ((net == NULL) || (node == NULL))
288 service = NET_DEFAULT_PORT;
290 srv = malloc (sizeof (*srv));
293 memset (srv, 0, sizeof (*srv));
296 srv->security_level = NONE;
297 srv->username = NULL;
298 srv->password = NULL;
301 srv->node = strdup (node);
302 if (srv->node == NULL)
308 srv->service = strdup (service);
309 if (srv->service == NULL)
316 srv->buffer = lcc_network_buffer_create (/* size = */ 0);
317 if (srv->buffer == NULL)
325 if (net->servers == NULL)
331 lcc_server_t *last = net->servers;
333 while (last->next != NULL)
340 } /* }}} lcc_server_t *lcc_server_create */
342 int lcc_server_destroy (lcc_network_t *net, lcc_server_t *srv) /* {{{ */
344 if ((net == NULL) || (srv == NULL))
347 if (net->servers == srv)
349 net->servers = srv->next;
354 lcc_server_t *prev = net->servers;
356 while ((prev != NULL) && (prev->next != srv))
362 prev->next = srv->next;
366 int_server_destroy (srv);
369 } /* }}} int lcc_server_destroy */
371 int lcc_server_set_ttl (lcc_server_t *srv, uint8_t ttl) /* {{{ */
376 srv->ttl = (int) ttl;
379 } /* }}} int lcc_server_set_ttl */
381 int lcc_server_set_security_level (lcc_server_t *srv, /* {{{ */
382 lcc_security_level_t level,
383 const char *username, const char *password)
385 return (lcc_network_buffer_set_security_level (srv->buffer,
386 level, username, password));
387 } /* }}} int lcc_server_set_security_level */
389 int lcc_network_values_send (lcc_network_t *net, /* {{{ */
390 const lcc_value_list_t *vl)
394 if ((net == NULL) || (vl == NULL))
397 for (srv = net->servers; srv != NULL; srv = srv->next)
398 server_value_add (srv, vl);
401 } /* }}} int lcc_network_values_send */
403 /* vim: set sw=2 sts=2 et fdm=marker : */