From: Florian Forster Date: Tue, 17 Aug 2010 08:04:30 +0000 (+0200) Subject: libcollectdclient: Add initial network interface. X-Git-Tag: collectd-5.2.0~18^2~13 X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=bd9b7a4bde9fba106488d9b1781bca913c1f282a;p=collectd.git libcollectdclient: Add initial network interface. Still incomplete though. --- diff --git a/src/libcollectdclient/Makefile.am b/src/libcollectdclient/Makefile.am index da76f7c7..ae9590d4 100644 --- a/src/libcollectdclient/Makefile.am +++ b/src/libcollectdclient/Makefile.am @@ -10,5 +10,5 @@ nodist_pkgconfig_DATA = libcollectdclient.pc BUILT_SOURCES = collectd/lcc_features.h -libcollectdclient_la_SOURCES = client.c network_buffer.c +libcollectdclient_la_SOURCES = client.c network.c network_buffer.c libcollectdclient_la_LDFLAGS = -version-info 0:0:0 diff --git a/src/libcollectdclient/network.c b/src/libcollectdclient/network.c new file mode 100644 index 00000000..55f2aff6 --- /dev/null +++ b/src/libcollectdclient/network.c @@ -0,0 +1,427 @@ +/** + * collectd - src/libcollectdclient/network.h + * Copyright (C) 2005-2010 Florian octo Forster + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; only version 2.1 of the License is + * applicable. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Florian octo Forster + **/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "collectd/network.h" +#include "collectd/network_buffer.h" + +/* + * Private data types + */ +struct lcc_network_s +{ + lcc_server_t *servers; +}; + +struct lcc_server_s +{ + char *node; + char *service; + + int ttl; + lcc_security_level_t security_level; + char *username; + char *password; + + int fd; + struct sockaddr *sa; + socklen_t sa_len; + + lcc_network_buffer_t *buffer; + + lcc_server_t *next; +}; + +/* + * Private functions + */ +static int server_close_socket (lcc_server_t *srv) /* {{{ */ +{ + if (srv == NULL) + return (EINVAL); + + if (srv->fd < 0) + return (0); + + close (srv->fd); + free (srv->sa); + srv->sa = NULL; + srv->sa_len = 0; + + return (0); +} /* }}} int server_close_socket */ + +static void int_server_destroy (lcc_server_t *srv) /* {{{ */ +{ + lcc_server_t *next; + + if (srv == NULL) + return; + + server_close_socket (srv); + + next = srv->next; + + if (srv->fd >= 0) + { + close (srv->fd); + srv->fd = -1; + } + + free (srv->node); + free (srv->service); + free (srv->username); + free (srv->password); + free (srv); + + int_server_destroy (next); +} /* }}} void int_server_destroy */ + +static int server_open_socket (lcc_server_t *srv) /* {{{ */ +{ + struct addrinfo ai_hints = { 0 }; + struct addrinfo *ai_list = NULL; + struct addrinfo *ai_ptr; + int status; + + if (srv == NULL) + return (EINVAL); + + if (srv->fd >= 0) + server_close_socket (srv); + +#ifdef AI_ADDRCONFIG + ai_hints.ai_flags |= AI_ADDRCONFIG; +#endif + ai_hints.ai_family = AF_UNSPEC; + ai_hints.ai_socktype = SOCK_DGRAM; + + status = getaddrinfo (srv->node, srv->service, &ai_hints, &ai_list); + if (status != 0) + return (status); + assert (ai_list != NULL); + + for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) + { + srv->fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol); + if (srv->fd < 0) + continue; + + if (ai_ptr->ai_family == AF_INET) + { + + struct sockaddr_in *addr = (struct sockaddr_in *) ai_ptr->ai_addr; + int optname; + + if (IN_MULTICAST (ntohl (addr->sin_addr.s_addr))) + optname = IP_MULTICAST_TTL; + else + optname = IP_TTL; + + setsockopt (srv->fd, IPPROTO_IP, optname, + &srv->ttl, + sizeof (srv->ttl)); + } + else if (ai_ptr->ai_family == AF_INET6) + { + /* Useful example: http://gsyc.escet.urjc.es/~eva/IPv6-web/examples/mcast.html */ + struct sockaddr_in6 *addr = (struct sockaddr_in6 *) ai_ptr->ai_addr; + int optname; + + if (IN6_IS_ADDR_MULTICAST (&addr->sin6_addr)) + optname = IPV6_MULTICAST_HOPS; + else + optname = IPV6_UNICAST_HOPS; + + setsockopt (srv->fd, IPPROTO_IPV6, optname, + &srv->ttl, + sizeof (srv->ttl)); + } + + srv->sa = malloc (ai_ptr->ai_addrlen); + if (srv->sa == NULL) + { + close (srv->fd); + srv->fd = -1; + continue; + } + + memcpy (srv->sa, ai_ptr->ai_addr, ai_ptr->ai_addrlen); + srv->sa_len = ai_ptr->ai_addrlen; + break; + } + + freeaddrinfo (ai_list); + + if (srv->fd < 0) + return (-1); + return (0); +} /* }}} int server_open_socket */ + +static int server_send_buffer (lcc_server_t *srv) /* {{{ */ +{ + char buffer[LCC_NETWORK_BUFFER_SIZE_DEFAULT]; + size_t buffer_size; + int status; + + if (srv->fd < 0) + { + status = server_open_socket (srv); + if (status != 0) + return (status); + } + + memset (buffer, 0, sizeof (buffer)); + buffer_size = sizeof (buffer); + + lcc_network_buffer_finalize (srv->buffer); + status = lcc_network_buffer_get (srv->buffer, buffer, &buffer_size); + lcc_network_buffer_initialize (srv->buffer); + + if (status != 0) + return (status); + + if (buffer_size > sizeof (buffer)) + buffer_size = sizeof (buffer); + + while (42) + { + assert (srv->fd >= 0); + assert (srv->sa != NULL); + status = (int) sendto (srv->fd, buffer, buffer_size, /* flags = */ 0, + srv->sa, srv->sa_len); + if ((status < 0) && ((errno == EINTR) || (errno == EAGAIN))) + continue; + + break; + } + + if (status < 0) + return (status); + return (0); +} /* }}} int server_send_buffer */ + +static int server_value_add (lcc_server_t *srv, /* {{{ */ + const lcc_value_list_t *vl) +{ + int status; + + status = lcc_network_buffer_add_value (srv->buffer, vl); + if (status == 0) + return (0); + + server_send_buffer (srv); + return (lcc_network_buffer_add_value (srv->buffer, vl)); +} /* }}} int server_value_add */ + +/* + * Public functions + */ +lcc_network_t *lcc_network_create (void) /* {{{ */ +{ + lcc_network_t *net; + + net = malloc (sizeof (*net)); + if (net == NULL) + return (NULL); + memset (net, 0, sizeof (*net)); + + net->servers = NULL; + + return (net); +} /* }}} lcc_network_t *lcc_network_create */ + +void lcc_network_destroy (lcc_network_t *net) /* {{{ */ +{ + if (net == NULL) + return; + int_server_destroy (net->servers); + free (net); +} /* }}} void lcc_network_destroy */ + +lcc_server_t *lcc_server_create (lcc_network_t *net, /* {{{ */ + const char *node, const char *service) +{ + lcc_server_t *srv; + + if ((net == NULL) || (node == NULL)) + return (NULL); + if (service == NULL) + service = NET_DEFAULT_PORT; + + srv = malloc (sizeof (*srv)); + if (srv == NULL) + return (NULL); + memset (srv, 0, sizeof (*srv)); + + srv->fd = -1; + srv->security_level = NONE; + srv->username = NULL; + srv->password = NULL; + srv->next = NULL; + + srv->node = strdup (node); + if (srv->node == NULL) + { + free (srv); + return (NULL); + } + + srv->service = strdup (service); + if (srv->service == NULL) + { + free (srv->node); + free (srv); + return (NULL); + } + + srv->buffer = lcc_network_buffer_create (/* size = */ 0); + if (srv->buffer == NULL) + { + free (srv->service); + free (srv->node); + free (srv); + return (NULL); + } + + if (net->servers == NULL) + { + net->servers = srv; + } + else + { + lcc_server_t *last = net->servers; + + while (last->next != NULL) + last = last->next; + + last->next = srv; + } + + return (srv); +} /* }}} lcc_server_t *lcc_server_create */ + +int lcc_server_destroy (lcc_network_t *net, lcc_server_t *srv) /* {{{ */ +{ + if ((net == NULL) || (srv == NULL)) + return (EINVAL); + + if (net->servers == srv) + { + net->servers = srv->next; + srv->next = NULL; + } + else + { + lcc_server_t *prev = net->servers; + + while ((prev != NULL) && (prev->next != srv)) + prev = prev->next; + + if (prev == NULL) + return (ENOENT); + + prev->next = srv->next; + srv->next = NULL; + } + + int_server_destroy (srv); + + return (0); +} /* }}} int lcc_server_destroy */ + +int lcc_server_set_ttl (lcc_server_t *srv, uint8_t ttl) /* {{{ */ +{ + if (srv == NULL) + return (EINVAL); + + srv->ttl = (int) ttl; + + return (0); +} /* }}} int lcc_server_set_ttl */ + +int lcc_server_set_security_level (lcc_server_t *srv, /* {{{ */ + lcc_security_level_t level) +{ + if ((srv == NULL) + || ((level != NONE) && (level != SIGN) && (level != ENCRYPT))) + return (EINVAL); + + srv->security_level = level; + + return (0); +} /* }}} int lcc_server_set_security_level */ + +int lcc_server_set_credentials (lcc_server_t *srv, /* {{{ */ + const char *username, const char *password) +{ + char *tmp_username; + char *tmp_password; + + if ((srv == NULL) || (username == NULL) || (password == NULL)) + return (EINVAL); + + tmp_username = strdup (username); + if (tmp_username == NULL) + return (ENOMEM); + + tmp_password = strdup (password); + if (tmp_password == NULL) + { + free (tmp_username); + return (ENOMEM); + } + + free (srv->username); + free (srv->password); + + srv->username = tmp_username; + srv->password = tmp_password; + + return (0); +} /* }}} int lcc_server_set_credentials */ + +int lcc_network_values_send (lcc_network_t *net, /* {{{ */ + const lcc_value_list_t *vl) +{ + lcc_server_t *srv; + + if ((net == NULL) || (vl == NULL)) + return (EINVAL); + + for (srv = net->servers; srv != NULL; srv = srv->next) + server_value_add (srv, vl); + + return (0); +} /* }}} int lcc_network_values_send */ + +/* vim: set sw=2 sts=2 et fdm=marker : */