Replace all occurrences of `strcpy' with `sstrncpy'.
[collectd.git] / src / network.c
index 29e6708..022e46a 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/network.c
- * Copyright (C) 2005-2007  Florian octo Forster
+ * Copyright (C) 2005-2008  Florian octo Forster
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -183,7 +183,7 @@ static pthread_mutex_t send_buffer_lock = PTHREAD_MUTEX_INITIALIZER;
 
 static c_avl_tree_t      *cache_tree = NULL;
 static pthread_mutex_t  cache_lock = PTHREAD_MUTEX_INITIALIZER;
-static time_t           cache_flush_last;
+static time_t           cache_flush_last = 0;
 static int              cache_flush_interval = 1800;
 
 /*
@@ -425,33 +425,36 @@ static int write_part_number (char **ret_buffer, int *ret_buffer_len,
 static int write_part_string (char **ret_buffer, int *ret_buffer_len,
                int type, const char *str, int str_len)
 {
-       char *packet_ptr;
-       int packet_len;
+       char *buffer;
+       int buffer_len;
 
-       part_header_t pkg_head;
+       uint16_t pkg_type;
+       uint16_t pkg_length;
 
        int offset;
 
-       packet_len = sizeof (pkg_head) + str_len + 1;
-       if (*ret_buffer_len < packet_len)
+       buffer_len = 2 * sizeof (uint16_t) + str_len + 1;
+       if (*ret_buffer_len < buffer_len)
                return (-1);
 
-       pkg_head.type = htons (type);
-       pkg_head.length = htons (packet_len);
+       pkg_type = htons (type);
+       pkg_length = htons (buffer_len);
 
-       packet_ptr = *ret_buffer;
+       buffer = *ret_buffer;
        offset = 0;
-       memcpy (packet_ptr + offset, &pkg_head, sizeof (pkg_head));
-       offset += sizeof (pkg_head);
-       memcpy (packet_ptr + offset, str, str_len);
+       memcpy (buffer + offset, (void *) &pkg_type, sizeof (pkg_type));
+       offset += sizeof (pkg_type);
+       memcpy (buffer + offset, (void *) &pkg_length, sizeof (pkg_length));
+       offset += sizeof (pkg_length);
+       memcpy (buffer + offset, str, str_len);
        offset += str_len;
-       memset (packet_ptr + offset, '\0', 1);
+       memset (buffer + offset, '\0', 1);
        offset += 1;
 
-       assert (offset == packet_len);
+       assert (offset == buffer_len);
 
-       *ret_buffer = packet_ptr + packet_len;
-       *ret_buffer_len -= packet_len;
+       *ret_buffer = buffer + buffer_len;
+       *ret_buffer_len -= buffer_len;
 
        return (0);
 } /* int write_part_string */
@@ -482,11 +485,11 @@ static int parse_part_values (void **ret_buffer, int *ret_buffer_len,
 
        memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
        buffer += sizeof (tmp16);
-       pkg_length = ntohs (tmp16);
+       pkg_type = ntohs (tmp16);
 
        memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
        buffer += sizeof (tmp16);
-       pkg_type = ntohs (tmp16);
+       pkg_length = ntohs (tmp16);
 
        memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
        buffer += sizeof (tmp16);
@@ -572,11 +575,11 @@ static int parse_part_number (void **ret_buffer, int *ret_buffer_len,
 
        memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
        buffer += sizeof (tmp16);
-       pkg_length = ntohs (tmp16);
+       pkg_type = ntohs (tmp16);
 
        memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
        buffer += sizeof (tmp16);
-       pkg_type = ntohs (tmp16);
+       pkg_length = ntohs (tmp16);
 
        memcpy ((void *) &tmp64, buffer, sizeof (tmp64));
        buffer += sizeof (tmp64);
@@ -612,11 +615,11 @@ static int parse_part_string (void **ret_buffer, int *ret_buffer_len,
 
        memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
        buffer += sizeof (tmp16);
-       pkg_length = ntohs (tmp16);
+       pkg_type = ntohs (tmp16);
 
        memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
        buffer += sizeof (tmp16);
-       pkg_type = ntohs (tmp16);
+       pkg_length = ntohs (tmp16);
 
        /* Check that packet fits in the input buffer */
        if (pkg_length > buffer_len)
@@ -654,7 +657,9 @@ static int parse_part_string (void **ret_buffer, int *ret_buffer_len,
        memcpy ((void *) output, (void *) buffer, output_len);
        buffer += output_len;
 
-       if (output[output_len - 1] != '\0');
+       /* For some very weird reason '\0' doesn't do the trick on SPARC in
+        * this statement. */
+       if (output[output_len - 1] != 0)
        {
                WARNING ("network plugin: parse_part_string: "
                                "Received string does not end "
@@ -674,25 +679,28 @@ static int parse_packet (void *buffer, int buffer_len)
 
        value_list_t vl = VALUE_LIST_INIT;
        char type[DATA_MAX_NAME_LEN];
+       notification_t n;
 
        DEBUG ("network plugin: parse_packet: buffer = %p; buffer_len = %i;",
                        buffer, buffer_len);
 
        memset (&vl, '\0', sizeof (vl));
        memset (&type, '\0', sizeof (type));
+       memset (&n, '\0', sizeof (n));
        status = 0;
 
-       while ((status == 0) && (buffer_len > sizeof (part_header_t)))
+       while ((status == 0) && (0 < buffer_len)
+                       && ((unsigned int) buffer_len > sizeof (part_header_t)))
        {
                uint16_t pkg_length;
                uint16_t pkg_type;
 
-               memcpy ((void *) &pkg_length,
-                               (void *) buffer,
-                               sizeof (pkg_length));
                memcpy ((void *) &pkg_type,
-                               (void *) buffer + sizeof (pkg_length),
+                               (void *) buffer,
                                sizeof (pkg_type));
+               memcpy ((void *) &pkg_length,
+                               (void *) (buffer + sizeof (pkg_type)),
+                               sizeof (pkg_length));
 
                pkg_length = ntohs (pkg_length);
                pkg_type = ntohs (pkg_type);
@@ -730,14 +738,19 @@ static int parse_packet (void *buffer, int buffer_len)
                else if (pkg_type == TYPE_TIME)
                {
                        uint64_t tmp = 0;
-                       status = parse_part_number (&buffer, &buffer_len, &tmp);
+                       status = parse_part_number (&buffer, &buffer_len,
+                                       &tmp);
                        if (status == 0)
+                       {
                                vl.time = (time_t) tmp;
+                               n.time = (time_t) tmp;
+                       }
                }
                else if (pkg_type == TYPE_INTERVAL)
                {
                        uint64_t tmp = 0;
-                       status = parse_part_number (&buffer, &buffer_len, &tmp);
+                       status = parse_part_number (&buffer, &buffer_len,
+                                       &tmp);
                        if (status == 0)
                                vl.interval = (int) tmp;
                }
@@ -745,31 +758,85 @@ static int parse_packet (void *buffer, int buffer_len)
                {
                        status = parse_part_string (&buffer, &buffer_len,
                                        vl.host, sizeof (vl.host));
-                       DEBUG ("network plugin: parse_packet: vl.host = %s", vl.host);
+                       if (status == 0)
+                               sstrncpy (n.host, vl.host, sizeof (n.host));
                }
                else if (pkg_type == TYPE_PLUGIN)
                {
                        status = parse_part_string (&buffer, &buffer_len,
                                        vl.plugin, sizeof (vl.plugin));
-                       DEBUG ("network plugin: parse_packet: vl.plugin = %s", vl.plugin);
+                       if (status == 0)
+                               sstrncpy (n.plugin, vl.plugin,
+                                               sizeof (n.plugin));
                }
                else if (pkg_type == TYPE_PLUGIN_INSTANCE)
                {
                        status = parse_part_string (&buffer, &buffer_len,
-                                       vl.plugin_instance, sizeof (vl.plugin_instance));
-                       DEBUG ("network plugin: parse_packet: vl.plugin_instance = %s", vl.plugin_instance);
+                                       vl.plugin_instance,
+                                       sizeof (vl.plugin_instance));
+                       if (status == 0)
+                               sstrncpy (n.plugin_instance,
+                                               vl.plugin_instance,
+                                               sizeof (n.plugin_instance));
                }
                else if (pkg_type == TYPE_TYPE)
                {
                        status = parse_part_string (&buffer, &buffer_len,
                                        type, sizeof (type));
-                       DEBUG ("network plugin: parse_packet: type = %s", type);
+                       if (status == 0)
+                               sstrncpy (n.type, type, sizeof (n.type));
                }
                else if (pkg_type == TYPE_TYPE_INSTANCE)
                {
                        status = parse_part_string (&buffer, &buffer_len,
-                                       vl.type_instance, sizeof (vl.type_instance));
-                       DEBUG ("network plugin: parse_packet: vl.type_instance = %s", vl.type_instance);
+                                       vl.type_instance,
+                                       sizeof (vl.type_instance));
+                       if (status == 0)
+                               sstrncpy (n.type_instance, vl.type_instance,
+                                               sizeof (n.type_instance));
+               }
+               else if (pkg_type == TYPE_MESSAGE)
+               {
+                       status = parse_part_string (&buffer, &buffer_len,
+                                       n.message, sizeof (n.message));
+
+                       if (status != 0)
+                       {
+                               /* do nothing */
+                       }
+                       else if ((n.severity != NOTIF_FAILURE)
+                                       && (n.severity != NOTIF_WARNING)
+                                       && (n.severity != NOTIF_OKAY))
+                       {
+                               INFO ("network plugin: "
+                                               "Ignoring notification with "
+                                               "unknown severity %i.",
+                                               n.severity);
+                       }
+                       else if (n.time <= 0)
+                       {
+                               INFO ("network plugin: "
+                                               "Ignoring notification with "
+                                               "time == 0.");
+                       }
+                       else if (strlen (n.message) <= 0)
+                       {
+                               INFO ("network plugin: "
+                                               "Ignoring notification with "
+                                               "an empty message.");
+                       }
+                       else
+                       {
+                               plugin_dispatch_notification (&n);
+                       }
+               }
+               else if (pkg_type == TYPE_SEVERITY)
+               {
+                       uint64_t tmp = 0;
+                       status = parse_part_number (&buffer, &buffer_len,
+                                       &tmp);
+                       if (status == 0)
+                               n.severity = (int) tmp;
                }
                else
                {
@@ -859,6 +926,16 @@ static int network_set_ttl (const sockent_t *se, const struct addrinfo *ai)
 static int network_bind_socket (const sockent_t *se, const struct addrinfo *ai)
 {
        int loop = 0;
+       int yes  = 1;
+
+       /* allow multiple sockets to use the same PORT number */
+       if (setsockopt(se->fd, SOL_SOCKET, SO_REUSEADDR,
+                               &yes, sizeof(yes)) == -1) {
+                char errbuf[1024];
+                ERROR ("setsockopt: %s", 
+                                sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
+       }
 
        DEBUG ("fd = %i; calling `bind'", se->fd);
 
@@ -1328,7 +1405,7 @@ static int add_to_buffer (char *buffer, int buffer_size,
                if (write_part_string (&buffer, &buffer_size, TYPE_HOST,
                                        vl->host, strlen (vl->host)) != 0)
                        return (-1);
-               strcpy (vl_def->host, vl->host);
+               sstrncpy (vl_def->host, vl->host, sizeof (vl_def->host));
        }
 
        if (vl_def->time != vl->time)
@@ -1352,7 +1429,7 @@ static int add_to_buffer (char *buffer, int buffer_size,
                if (write_part_string (&buffer, &buffer_size, TYPE_PLUGIN,
                                        vl->plugin, strlen (vl->plugin)) != 0)
                        return (-1);
-               strcpy (vl_def->plugin, vl->plugin);
+               sstrncpy (vl_def->plugin, vl->plugin, sizeof (vl_def->plugin));
        }
 
        if (strcmp (vl_def->plugin_instance, vl->plugin_instance) != 0)
@@ -1361,7 +1438,7 @@ static int add_to_buffer (char *buffer, int buffer_size,
                                        vl->plugin_instance,
                                        strlen (vl->plugin_instance)) != 0)
                        return (-1);
-               strcpy (vl_def->plugin_instance, vl->plugin_instance);
+               sstrncpy (vl_def->plugin_instance, vl->plugin_instance, sizeof (vl_def->plugin_instance));
        }
 
        if (strcmp (type_def, ds->type) != 0)
@@ -1369,7 +1446,7 @@ static int add_to_buffer (char *buffer, int buffer_size,
                if (write_part_string (&buffer, &buffer_size, TYPE_TYPE,
                                        ds->type, strlen (ds->type)) != 0)
                        return (-1);
-               strcpy (type_def, ds->type);
+               sstrncpy (type_def, ds->type, sizeof (type_def));
        }
 
        if (strcmp (vl_def->type_instance, vl->type_instance) != 0)
@@ -1378,7 +1455,7 @@ static int add_to_buffer (char *buffer, int buffer_size,
                                        vl->type_instance,
                                        strlen (vl->type_instance)) != 0)
                        return (-1);
-               strcpy (vl_def->type_instance, vl->type_instance);
+               sstrncpy (vl_def->type_instance, vl->type_instance, sizeof (vl_def->type_instance));
        }
        
        if (write_part_values (&buffer, &buffer_size, ds, vl) != 0)
@@ -1518,6 +1595,77 @@ static int network_config (const char *key, const char *val)
        return (0);
 } /* int network_config */
 
+static int network_notification (const notification_t *n)
+{
+  char  buffer[BUFF_SIZE];
+  char *buffer_ptr = buffer;
+  int   buffer_free = sizeof (buffer);
+  int   status;
+
+  memset (buffer, '\0', sizeof (buffer));
+
+
+  status = write_part_number (&buffer_ptr, &buffer_free, TYPE_TIME,
+      (uint64_t) n->time);
+  if (status != 0)
+    return (-1);
+
+  status = write_part_number (&buffer_ptr, &buffer_free, TYPE_SEVERITY,
+      (uint64_t) n->severity);
+  if (status != 0)
+    return (-1);
+
+  if (strlen (n->host) > 0)
+  {
+    status = write_part_string (&buffer_ptr, &buffer_free, TYPE_HOST,
+       n->host, strlen (n->host));
+    if (status != 0)
+      return (-1);
+  }
+
+  if (strlen (n->plugin) > 0)
+  {
+    status = write_part_string (&buffer_ptr, &buffer_free, TYPE_PLUGIN,
+       n->plugin, strlen (n->plugin));
+    if (status != 0)
+      return (-1);
+  }
+
+  if (strlen (n->plugin_instance) > 0)
+  {
+    status = write_part_string (&buffer_ptr, &buffer_free,
+       TYPE_PLUGIN_INSTANCE,
+       n->plugin_instance, strlen (n->plugin_instance));
+    if (status != 0)
+      return (-1);
+  }
+
+  if (strlen (n->type) > 0)
+  {
+    status = write_part_string (&buffer_ptr, &buffer_free, TYPE_TYPE,
+       n->type, strlen (n->type));
+    if (status != 0)
+      return (-1);
+  }
+
+  if (strlen (n->type_instance) > 0)
+  {
+    status = write_part_string (&buffer_ptr, &buffer_free, TYPE_TYPE_INSTANCE,
+       n->type_instance, strlen (n->type_instance));
+    if (status != 0)
+      return (-1);
+  }
+
+  status = write_part_string (&buffer_ptr, &buffer_free, TYPE_MESSAGE,
+      n->message, strlen (n->message));
+  if (status != 0)
+    return (-1);
+
+  network_send_buffer (buffer, sizeof (buffer) - buffer_free);
+
+  return (0);
+} /* int network_notification */
+
 static int network_shutdown (void)
 {
        listen_loop++;
@@ -1558,11 +1706,19 @@ static int network_shutdown (void)
        plugin_unregister_write ("network");
        plugin_unregister_shutdown ("network");
 
+       /* Let the init function do it's move again ;) */
+       cache_flush_last = 0;
+
        return (0);
 } /* int network_shutdown */
 
 static int network_init (void)
 {
+       /* Check if we were already initialized. If so, just return - there's
+        * nothing more to do (for now, that is). */
+       if (cache_flush_last != 0)
+               return (0);
+
        plugin_register_shutdown ("network", network_shutdown);
 
        send_buffer_ptr  = send_buffer;
@@ -1575,7 +1731,10 @@ static int network_init (void)
 
        /* setup socket(s) and so on */
        if (sending_sockets != NULL)
+       {
                plugin_register_write ("network", network_write);
+               plugin_register_notification ("network", network_notification);
+       }
 
        if ((listen_sockets_num != 0) && (receive_thread_id == 0))
        {