2 * collectd - src/libcollectdclient/network.h
3 * Copyright (C) 2005-2010 Florian octo Forster
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation; only version 2.1 of the License is
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * Florian octo Forster <octo at verplant.org>
30 #include <sys/types.h>
31 #include <sys/socket.h>
34 #include "collectd/network.h"
35 #include "collectd/network_buffer.h"
42 lcc_server_t *servers;
51 lcc_security_level_t security_level;
59 lcc_network_buffer_t *buffer;
67 static int server_close_socket (lcc_server_t *srv) /* {{{ */
81 } /* }}} int server_close_socket */
83 static void int_server_destroy (lcc_server_t *srv) /* {{{ */
90 server_close_socket (srv);
102 free (srv->username);
103 free (srv->password);
106 int_server_destroy (next);
107 } /* }}} void int_server_destroy */
109 static int server_open_socket (lcc_server_t *srv) /* {{{ */
111 struct addrinfo ai_hints = { 0 };
112 struct addrinfo *ai_list = NULL;
113 struct addrinfo *ai_ptr;
120 server_close_socket (srv);
123 ai_hints.ai_flags |= AI_ADDRCONFIG;
125 ai_hints.ai_family = AF_UNSPEC;
126 ai_hints.ai_socktype = SOCK_DGRAM;
128 status = getaddrinfo (srv->node, srv->service, &ai_hints, &ai_list);
131 assert (ai_list != NULL);
133 for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
135 srv->fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
139 if (ai_ptr->ai_family == AF_INET)
142 struct sockaddr_in *addr = (struct sockaddr_in *) ai_ptr->ai_addr;
145 if (IN_MULTICAST (ntohl (addr->sin_addr.s_addr)))
146 optname = IP_MULTICAST_TTL;
150 setsockopt (srv->fd, IPPROTO_IP, optname,
154 else if (ai_ptr->ai_family == AF_INET6)
156 /* Useful example: http://gsyc.escet.urjc.es/~eva/IPv6-web/examples/mcast.html */
157 struct sockaddr_in6 *addr = (struct sockaddr_in6 *) ai_ptr->ai_addr;
160 if (IN6_IS_ADDR_MULTICAST (&addr->sin6_addr))
161 optname = IPV6_MULTICAST_HOPS;
163 optname = IPV6_UNICAST_HOPS;
165 setsockopt (srv->fd, IPPROTO_IPV6, optname,
170 srv->sa = malloc (ai_ptr->ai_addrlen);
178 memcpy (srv->sa, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
179 srv->sa_len = ai_ptr->ai_addrlen;
183 freeaddrinfo (ai_list);
188 } /* }}} int server_open_socket */
190 static int server_send_buffer (lcc_server_t *srv) /* {{{ */
192 char buffer[LCC_NETWORK_BUFFER_SIZE_DEFAULT];
198 status = server_open_socket (srv);
203 memset (buffer, 0, sizeof (buffer));
204 buffer_size = sizeof (buffer);
206 lcc_network_buffer_finalize (srv->buffer);
207 status = lcc_network_buffer_get (srv->buffer, buffer, &buffer_size);
208 lcc_network_buffer_initialize (srv->buffer);
213 if (buffer_size > sizeof (buffer))
214 buffer_size = sizeof (buffer);
218 assert (srv->fd >= 0);
219 assert (srv->sa != NULL);
220 status = (int) sendto (srv->fd, buffer, buffer_size, /* flags = */ 0,
221 srv->sa, srv->sa_len);
222 if ((status < 0) && ((errno == EINTR) || (errno == EAGAIN)))
231 } /* }}} int server_send_buffer */
233 static int server_value_add (lcc_server_t *srv, /* {{{ */
234 const lcc_value_list_t *vl)
238 status = lcc_network_buffer_add_value (srv->buffer, vl);
242 server_send_buffer (srv);
243 return (lcc_network_buffer_add_value (srv->buffer, vl));
244 } /* }}} int server_value_add */
249 lcc_network_t *lcc_network_create (void) /* {{{ */
253 net = malloc (sizeof (*net));
256 memset (net, 0, sizeof (*net));
261 } /* }}} lcc_network_t *lcc_network_create */
263 void lcc_network_destroy (lcc_network_t *net) /* {{{ */
267 int_server_destroy (net->servers);
269 } /* }}} void lcc_network_destroy */
271 lcc_server_t *lcc_server_create (lcc_network_t *net, /* {{{ */
272 const char *node, const char *service)
276 if ((net == NULL) || (node == NULL))
279 service = NET_DEFAULT_PORT;
281 srv = malloc (sizeof (*srv));
284 memset (srv, 0, sizeof (*srv));
287 srv->security_level = NONE;
288 srv->username = NULL;
289 srv->password = NULL;
292 srv->node = strdup (node);
293 if (srv->node == NULL)
299 srv->service = strdup (service);
300 if (srv->service == NULL)
307 srv->buffer = lcc_network_buffer_create (/* size = */ 0);
308 if (srv->buffer == NULL)
316 if (net->servers == NULL)
322 lcc_server_t *last = net->servers;
324 while (last->next != NULL)
331 } /* }}} lcc_server_t *lcc_server_create */
333 int lcc_server_destroy (lcc_network_t *net, lcc_server_t *srv) /* {{{ */
335 if ((net == NULL) || (srv == NULL))
338 if (net->servers == srv)
340 net->servers = srv->next;
345 lcc_server_t *prev = net->servers;
347 while ((prev != NULL) && (prev->next != srv))
353 prev->next = srv->next;
357 int_server_destroy (srv);
360 } /* }}} int lcc_server_destroy */
362 int lcc_server_set_ttl (lcc_server_t *srv, uint8_t ttl) /* {{{ */
367 srv->ttl = (int) ttl;
370 } /* }}} int lcc_server_set_ttl */
372 int lcc_server_set_security_level (lcc_server_t *srv, /* {{{ */
373 lcc_security_level_t level)
376 || ((level != NONE) && (level != SIGN) && (level != ENCRYPT)))
379 srv->security_level = level;
382 } /* }}} int lcc_server_set_security_level */
384 int lcc_server_set_credentials (lcc_server_t *srv, /* {{{ */
385 const char *username, const char *password)
390 if ((srv == NULL) || (username == NULL) || (password == NULL))
393 tmp_username = strdup (username);
394 if (tmp_username == NULL)
397 tmp_password = strdup (password);
398 if (tmp_password == NULL)
404 free (srv->username);
405 free (srv->password);
407 srv->username = tmp_username;
408 srv->password = tmp_password;
411 } /* }}} int lcc_server_set_credentials */
413 int lcc_network_values_send (lcc_network_t *net, /* {{{ */
414 const lcc_value_list_t *vl)
418 if ((net == NULL) || (vl == NULL))
421 for (srv = net->servers; srv != NULL; srv = srv->next)
422 server_value_add (srv, vl);
425 } /* }}} int lcc_network_values_send */
427 /* vim: set sw=2 sts=2 et fdm=marker : */