Code

libcollectdclient: Add initial network interface.
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Tue, 17 Aug 2010 08:04:30 +0000 (10:04 +0200)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Tue, 17 Aug 2010 08:04:30 +0000 (10:04 +0200)
Still incomplete though.

src/libcollectdclient/Makefile.am
src/libcollectdclient/network.c [new file with mode: 0644]

index da76f7c7af6ff2c6c4866b9696b4cc06154e7803..ae9590d49ab8c3c3b752838891aba72072ce7631 100644 (file)
@@ -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 (file)
index 0000000..55f2aff
--- /dev/null
@@ -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 <octo at verplant.org>
+ **/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#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 : */