Many build fixes that turned up with GCC 4.6.
[collectd.git] / src / network.c
index b1b9e39..95f5464 100644 (file)
@@ -31,6 +31,7 @@
 #include "utils_fbhash.h"
 #include "utils_avltree.h"
 #include "utils_cache.h"
+#include "utils_complain.h"
 
 #include "network.h"
 
@@ -350,7 +351,8 @@ static _Bool check_send_okay (const value_list_t *vl) /* {{{ */
   return (!received);
 } /* }}} _Bool check_send_okay */
 
-static int network_dispatch_values (value_list_t *vl) /* {{{ */
+static int network_dispatch_values (value_list_t *vl, /* {{{ */
+    const char *username)
 {
   int status;
 
@@ -391,6 +393,18 @@ static int network_dispatch_values (value_list_t *vl) /* {{{ */
     return (status);
   }
 
+  if (username != NULL)
+  {
+    status = meta_data_add_string (vl->meta, "network:username", username);
+    if (status != 0)
+    {
+      ERROR ("network plugin: meta_data_add_string failed.");
+      meta_data_destroy (vl->meta);
+      vl->meta = NULL;
+      return (status);
+    }
+  }
+
   plugin_dispatch_values (vl);
   stats_values_dispatched++;
 
@@ -744,11 +758,11 @@ static int parse_part_values (void **ret_buffer, size_t *ret_buffer_len,
                    break;
 
                  default:
-                   sfree (pkg_types);
-                   sfree (pkg_values);
                    NOTICE ("network plugin: parse_part_values: "
                        "Don't know how to handle data source type %"PRIu8,
                        pkg_types[i]);
+                   sfree (pkg_types);
+                   sfree (pkg_values);
                    return (-1);
                } /* switch (pkg_types[i]) */
        }
@@ -774,7 +788,6 @@ static int parse_part_number (void **ret_buffer, size_t *ret_buffer_len,
        size_t exp_size = 2 * sizeof (uint16_t) + sizeof (uint64_t);
 
        uint16_t pkg_length;
-       uint16_t pkg_type;
 
        if ((buffer_len < 0) || ((size_t) buffer_len < exp_size))
        {
@@ -788,7 +801,7 @@ static int parse_part_number (void **ret_buffer, size_t *ret_buffer_len,
 
        memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
        buffer += sizeof (tmp16);
-       pkg_type = ntohs (tmp16);
+       /* pkg_type = ntohs (tmp16); */
 
        memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
        buffer += sizeof (tmp16);
@@ -814,7 +827,6 @@ static int parse_part_string (void **ret_buffer, size_t *ret_buffer_len,
        size_t header_size = 2 * sizeof (uint16_t);
 
        uint16_t pkg_length;
-       uint16_t pkg_type;
 
        if ((buffer_len < 0) || (buffer_len < header_size))
        {
@@ -828,7 +840,7 @@ static int parse_part_string (void **ret_buffer, size_t *ret_buffer_len,
 
        memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
        buffer += sizeof (tmp16);
-       pkg_type = ntohs (tmp16);
+       /* pkg_type = ntohs (tmp16); */
 
        memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
        buffer += sizeof (tmp16);
@@ -892,7 +904,8 @@ static int parse_part_string (void **ret_buffer, size_t *ret_buffer_len,
 #define PP_SIGNED    0x01
 #define PP_ENCRYPTED 0x02
 static int parse_packet (sockent_t *se,
-               void *buffer, size_t buffer_size, int flags);
+               void *buffer, size_t buffer_size, int flags,
+               const char *username);
 
 #define BUFFER_READ(p,s) do { \
   memcpy ((p), buffer + buffer_offset, (s)); \
@@ -903,6 +916,8 @@ static int parse_packet (sockent_t *se,
 static int parse_part_sign_sha256 (sockent_t *se, /* {{{ */
     void **ret_buffer, size_t *ret_buffer_len, int flags)
 {
+  static c_complain_t complain_no_users = C_COMPLAIN_INIT_STATIC;
+
   char *buffer;
   size_t buffer_len;
   size_t buffer_offset;
@@ -924,8 +939,9 @@ static int parse_part_sign_sha256 (sockent_t *se, /* {{{ */
 
   if (se->data.server.userdb == NULL)
   {
-    NOTICE ("network plugin: Received signed network packet but can't verify "
-        "it because no user DB has been configured. Will accept it.");
+    c_complain (LOG_NOTICE, &complain_no_users,
+        "network plugin: Received signed network packet but can't verify it "
+        "because no user DB has been configured. Will accept it.");
     return (0);
   }
 
@@ -987,6 +1003,8 @@ static int parse_part_sign_sha256 (sockent_t *se, /* {{{ */
   {
     ERROR ("network plugin: gcry_md_setkey failed: %s", gcry_strerror (err));
     gcry_md_close (hd);
+    sfree (secret);
+    sfree (pss.username);
     return (-1);
   }
 
@@ -1008,9 +1026,6 @@ static int parse_part_sign_sha256 (sockent_t *se, /* {{{ */
   gcry_md_close (hd);
   hd = NULL;
 
-  sfree (secret);
-  sfree (pss.username);
-
   if (memcmp (pss.hash, hash, sizeof (pss.hash)) != 0)
   {
     WARNING ("network plugin: Verifying HMAC-SHA-256 signature failed: "
@@ -1019,9 +1034,12 @@ static int parse_part_sign_sha256 (sockent_t *se, /* {{{ */
   else
   {
     parse_packet (se, buffer + buffer_offset, buffer_len - buffer_offset,
-        flags | PP_SIGNED);
+        flags | PP_SIGNED, pss.username);
   }
 
+  sfree (secret);
+  sfree (pss.username);
+
   *ret_buffer = buffer + buffer_len;
   *ret_buffer_len = 0;
 
@@ -1065,7 +1083,8 @@ static int parse_part_sign_sha256 (sockent_t *se, /* {{{ */
     warning_has_been_printed = 1;
   }
 
-  parse_packet (se, buffer + part_len, buffer_size - part_len, flags);
+  parse_packet (se, buffer + part_len, buffer_size - part_len, flags,
+      /* username = */ NULL);
 
   *ret_buffer = buffer + buffer_size;
   *ret_buffer_size = 0;
@@ -1144,7 +1163,10 @@ static int parse_part_encr_aes256 (sockent_t *se, /* {{{ */
   cypher = network_get_aes256_cypher (se, pea.iv, sizeof (pea.iv),
       pea.username);
   if (cypher == NULL)
+  {
+    sfree (pea.username);
     return (-1);
+  }
 
   payload_len = part_size - (PART_ENCRYPTION_AES256_SIZE + username_len);
   assert (payload_len > 0);
@@ -1156,6 +1178,7 @@ static int parse_part_encr_aes256 (sockent_t *se, /* {{{ */
       /* in = */ NULL, /* in len = */ 0);
   if (err != 0)
   {
+    sfree (pea.username);
     ERROR ("network plugin: gcry_cipher_decrypt returned: %s",
         gcry_strerror (err));
     return (-1);
@@ -1174,17 +1197,22 @@ static int parse_part_encr_aes256 (sockent_t *se, /* {{{ */
       buffer + buffer_offset, payload_len);
   if (memcmp (hash, pea.hash, sizeof (hash)) != 0)
   {
+    sfree (pea.username);
     ERROR ("network plugin: Decryption failed: Checksum mismatch.");
     return (-1);
   }
 
   parse_packet (se, buffer + buffer_offset, payload_len,
-      flags | PP_ENCRYPTED);
+      flags | PP_ENCRYPTED, pea.username);
+
+  /* XXX: Free pea.username?!? */
 
   /* Update return values */
   *ret_buffer =     buffer     + part_size;
   *ret_buffer_len = buffer_len - part_size;
 
+  sfree (pea.username);
+
   return (0);
 } /* }}} int parse_part_encr_aes256 */
 /* #endif HAVE_LIBGCRYPT */
@@ -1239,7 +1267,8 @@ static int parse_part_encr_aes256 (sockent_t *se, /* {{{ */
 #undef BUFFER_READ
 
 static int parse_packet (sockent_t *se, /* {{{ */
-               void *buffer, size_t buffer_size, int flags)
+               void *buffer, size_t buffer_size, int flags,
+               const char *username)
 {
        int status;
 
@@ -1339,7 +1368,7 @@ static int parse_packet (sockent_t *se, /* {{{ */
                        if (status != 0)
                                break;
 
-                       network_dispatch_values (&vl);
+                       network_dispatch_values (&vl, username);
 
                        sfree (vl.values);
                }
@@ -1553,7 +1582,7 @@ static int network_set_ttl (const sockent_t *se, const struct addrinfo *ai)
 
                if (setsockopt (se->data.client.fd, IPPROTO_IP, optname,
                                        &network_config_ttl,
-                                       sizeof (network_config_ttl)) == -1)
+                                       sizeof (network_config_ttl)) != 0)
                {
                        char errbuf[1024];
                        ERROR ("setsockopt: %s",
@@ -1574,7 +1603,7 @@ static int network_set_ttl (const sockent_t *se, const struct addrinfo *ai)
 
                if (setsockopt (se->data.client.fd, IPPROTO_IPV6, optname,
                                        &network_config_ttl,
-                                       sizeof (network_config_ttl)) == -1)
+                                       sizeof (network_config_ttl)) != 0)
                {
                        char errbuf[1024];
                        ERROR ("setsockopt: %s",
@@ -1600,22 +1629,28 @@ static int network_set_interface (const sockent_t *se, const struct addrinfo *ai
 
                if (IN_MULTICAST (ntohl (addr->sin_addr.s_addr)))
                {
-#if KERNEL_LINUX
+#if HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
+                       /* If possible, use the "ip_mreqn" structure which has
+                        * an "interface index" member. Using the interface
+                        * index is preferred here, because of its similarity
+                        * to the way IPv6 handles this. Unfortunately, it
+                        * appears not to be portable. */
                        struct ip_mreqn mreq;
-#else
-                       struct ip_mreq mreq;
-#endif
 
+                       memset (&mreq, 0, sizeof (mreq));
                        mreq.imr_multiaddr.s_addr = addr->sin_addr.s_addr;
-#if KERNEL_LINUX
                        mreq.imr_address.s_addr = ntohl (INADDR_ANY);
                        mreq.imr_ifindex = se->interface;
 #else
+                       struct ip_mreq mreq;
+
+                       memset (&mreq, 0, sizeof (mreq));
+                       mreq.imr_multiaddr.s_addr = addr->sin_addr.s_addr;
                        mreq.imr_interface.s_addr = ntohl (INADDR_ANY);
 #endif
 
                        if (setsockopt (se->data.client.fd, IPPROTO_IP, IP_MULTICAST_IF,
-                                               &mreq, sizeof (mreq)) == -1)
+                                               &mreq, sizeof (mreq)) != 0)
                        {
                                char errbuf[1024];
                                ERROR ("setsockopt: %s",
@@ -1634,7 +1669,7 @@ static int network_set_interface (const sockent_t *se, const struct addrinfo *ai
                {
                        if (setsockopt (se->data.client.fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
                                                &se->interface,
-                                               sizeof (se->interface)) == -1)
+                                               sizeof (se->interface)) != 0)
                        {
                                char errbuf[1024];
                                ERROR ("setsockopt: %s",
@@ -1647,7 +1682,8 @@ static int network_set_interface (const sockent_t *se, const struct addrinfo *ai
                }
        }
 
-#if KERNEL_LINUX
+       /* else: Not a multicast interface. */
+#if defined(HAVE_IF_INDEXTONAME) && HAVE_IF_INDEXTONAME && defined(SO_BINDTODEVICE)
        if (se->interface != 0)
        {
                char interface_name[IFNAMSIZ];
@@ -1667,6 +1703,17 @@ static int network_set_interface (const sockent_t *se, const struct addrinfo *ai
                        return (-1);
                }
        }
+/* #endif HAVE_IF_INDEXTONAME && SO_BINDTODEVICE */
+
+#else
+       WARNING ("network plugin: Cannot set the interface on a unicast "
+                       "socket because "
+# if !defined(SO_BINDTODEVICE)
+                       "the the \"SO_BINDTODEVICE\" socket option "
+# else
+                       "the \"if_indextoname\" function "
+# endif
+                       "is not available on your system.");
 #endif
 
        return (0);
@@ -1701,7 +1748,7 @@ static int network_bind_socket (int fd, const struct addrinfo *ai, const int int
                struct sockaddr_in *addr = (struct sockaddr_in *) ai->ai_addr;
                if (IN_MULTICAST (ntohl (addr->sin_addr.s_addr)))
                {
-#if KERNEL_LINUX
+#if HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
                        struct ip_mreqn mreq;
 #else
                        struct ip_mreq mreq;
@@ -1710,7 +1757,10 @@ static int network_bind_socket (int fd, const struct addrinfo *ai, const int int
                        DEBUG ("fd = %i; IPv4 multicast address found", fd);
 
                        mreq.imr_multiaddr.s_addr = addr->sin_addr.s_addr;
-#if KERNEL_LINUX
+#if HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
+                       /* Set the interface using the interface index if
+                        * possible (available). Unfortunately, the struct
+                        * ip_mreqn is not portable. */
                        mreq.imr_address.s_addr = ntohl (INADDR_ANY);
                        mreq.imr_ifindex = interface_idx;
 #else
@@ -1789,7 +1839,7 @@ static int network_bind_socket (int fd, const struct addrinfo *ai, const int int
                }
        }
 
-#if KERNEL_LINUX
+#if defined(HAVE_IF_INDEXTONAME) && HAVE_IF_INDEXTONAME && defined(SO_BINDTODEVICE)
        /* if a specific interface was set, bind the socket to it. But to avoid
         * possible problems with multicast routing, only do that for non-multicast
         * addresses */
@@ -1812,7 +1862,7 @@ static int network_bind_socket (int fd, const struct addrinfo *ai, const int int
                        return (-1);
                }
        }
-#endif
+#endif /* HAVE_IF_INDEXTONAME && SO_BINDTODEVICE */
 
        return (0);
 } /* int network_bind_socket */
@@ -2152,7 +2202,8 @@ static void *dispatch_thread (void __attribute__((unused)) *arg) /* {{{ */
       continue;
     }
 
-    parse_packet (se, ent->data, ent->data_len, /* flags = */ 0);
+    parse_packet (se, ent->data, ent->data_len, /* flags = */ 0,
+       /* username = */ NULL);
     sfree (ent->data);
     sfree (ent);
   } /* while (42) */