network: Add missing freeaddrinfo on error path.
[collectd.git] / src / network.c
index e28316d..613caa7 100644 (file)
@@ -27,8 +27,8 @@
 
 #include "collectd.h"
 
-#include "common.h"
 #include "plugin.h"
+#include "utils/common/common.h"
 #include "utils_cache.h"
 #include "utils_complain.h"
 #include "utils_fbhash.h"
@@ -51,7 +51,7 @@
 #include <net/if.h>
 #endif
 
-#if HAVE_LIBGCRYPT
+#if HAVE_GCRYPT_H
 #if defined __APPLE__
 /* default xcode compiler throws warnings even when deprecated functionality
  * is not used. -Werror breaks the build because of erroneous warnings.
@@ -96,7 +96,7 @@ GCRY_THREAD_OPTION_PTHREAD_IMPL;
  * Private data types
  */
 #define SECURITY_LEVEL_NONE 0
-#if HAVE_LIBGCRYPT
+#if HAVE_GCRYPT_H
 #define SECURITY_LEVEL_SIGN 1
 #define SECURITY_LEVEL_ENCRYPT 2
 #endif
@@ -104,7 +104,7 @@ struct sockent_client {
   int fd;
   struct sockaddr_storage *addr;
   socklen_t addrlen;
-#if HAVE_LIBGCRYPT
+#if HAVE_GCRYPT_H
   int security_level;
   char *username;
   char *password;
@@ -113,12 +113,13 @@ struct sockent_client {
 #endif
   cdtime_t next_resolve_reconnect;
   cdtime_t resolve_interval;
+  struct sockaddr_storage *bind_addr;
 };
 
 struct sockent_server {
   int *fd;
   size_t fd_num;
-#if HAVE_LIBGCRYPT
+#if HAVE_GCRYPT_H
   int security_level;
   char *auth_file;
   fbhash_t *userdb;
@@ -141,6 +142,7 @@ typedef struct sockent {
   } data;
 
   struct sockent *next;
+  pthread_mutex_t lock;
 } sockent_t;
 
 /*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
@@ -261,30 +263,30 @@ typedef struct receive_list_entry_s receive_list_entry_t;
 /*
  * Private variables
  */
-static int network_config_ttl = 0;
+static int network_config_ttl;
 /* Ethernet - (IPv6 + UDP) = 1500 - (40 + 8) = 1452 */
 static size_t network_config_packet_size = 1452;
-static _Bool network_config_forward = 0;
-static _Bool network_config_stats = 0;
+static bool network_config_forward;
+static bool network_config_stats;
 
-static sockent_t *sending_sockets = NULL;
+static sockent_t *sending_sockets;
 
-static receive_list_entry_t *receive_list_head = NULL;
-static receive_list_entry_t *receive_list_tail = NULL;
+static receive_list_entry_t *receive_list_head;
+static receive_list_entry_t *receive_list_tail;
 static pthread_mutex_t receive_list_lock = PTHREAD_MUTEX_INITIALIZER;
 static pthread_cond_t receive_list_cond = PTHREAD_COND_INITIALIZER;
-static uint64_t receive_list_length = 0;
+static uint64_t receive_list_length;
 
-static sockent_t *listen_sockets = NULL;
-static struct pollfd *listen_sockets_pollfd = NULL;
-static size_t listen_sockets_num = 0;
+static sockent_t *listen_sockets;
+static struct pollfd *listen_sockets_pollfd;
+static size_t listen_sockets_num;
 
 /* The receive and dispatch threads will run as long as `listen_loop' is set to
  * zero. */
-static int listen_loop = 0;
-static int receive_thread_running = 0;
+static int listen_loop;
+static int receive_thread_running;
 static pthread_t receive_thread_id;
-static int dispatch_thread_running = 0;
+static int dispatch_thread_running;
 static pthread_t dispatch_thread_id;
 
 /* Buffer in which to-be-sent network packets are constructed. */
@@ -301,20 +303,20 @@ static pthread_mutex_t send_buffer_lock = PTHREAD_MUTEX_INITIALIZER;
  * example). Only if neither is true, the stats_lock is acquired. The counters
  * are always read without holding a lock in the hope that writing 8 bytes to
  * memory is an atomic operation. */
-static derive_t stats_octets_rx = 0;
-static derive_t stats_octets_tx = 0;
-static derive_t stats_packets_rx = 0;
-static derive_t stats_packets_tx = 0;
-static derive_t stats_values_dispatched = 0;
-static derive_t stats_values_not_dispatched = 0;
-static derive_t stats_values_sent = 0;
-static derive_t stats_values_not_sent = 0;
+static derive_t stats_octets_rx;
+static derive_t stats_octets_tx;
+static derive_t stats_packets_rx;
+static derive_t stats_packets_tx;
+static derive_t stats_values_dispatched;
+static derive_t stats_values_not_dispatched;
+static derive_t stats_values_sent;
+static derive_t stats_values_not_sent;
 static pthread_mutex_t stats_lock = PTHREAD_MUTEX_INITIALIZER;
 
 /*
  * Private functions
  */
-static _Bool check_receive_okay(const value_list_t *vl) /* {{{ */
+static bool check_receive_okay(const value_list_t *vl) /* {{{ */
 {
   uint64_t time_sent = 0;
   int status;
@@ -324,54 +326,54 @@ static _Bool check_receive_okay(const value_list_t *vl) /* {{{ */
   /* This is a value we already sent. Don't allow it to be received again in
    * order to avoid looping. */
   if ((status == 0) && (time_sent >= ((uint64_t)vl->time)))
-    return (0);
+    return 0;
 
-  return (1);
-} /* }}} _Bool check_receive_okay */
+  return 1;
+} /* }}} bool check_receive_okay */
 
-static _Bool check_send_okay(const value_list_t *vl) /* {{{ */
+static bool check_send_okay(const value_list_t *vl) /* {{{ */
 {
-  _Bool received = 0;
+  bool received = 0;
   int status;
 
   if (network_config_forward)
-    return (1);
+    return 1;
 
   if (vl->meta == NULL)
-    return (1);
+    return 1;
 
   status = meta_data_get_boolean(vl->meta, "network:received", &received);
   if (status == -ENOENT)
-    return (1);
+    return 1;
   else if (status != 0) {
     ERROR("network plugin: check_send_okay: meta_data_get_boolean failed "
           "with status %i.",
           status);
-    return (1);
+    return 1;
   }
 
   /* By default, only *send* value lists that were not *received* by the
    * network plugin. */
-  return (!received);
-} /* }}} _Bool check_send_okay */
+  return !received;
+} /* }}} bool check_send_okay */
 
-static _Bool check_notify_received(const notification_t *n) /* {{{ */
+static bool check_notify_received(const notification_t *n) /* {{{ */
 {
   for (notification_meta_t *ptr = n->meta; ptr != NULL; ptr = ptr->next)
     if ((strcmp("network:received", ptr->name) == 0) &&
         (ptr->type == NM_TYPE_BOOLEAN))
-      return ((_Bool)ptr->nm_value.nm_boolean);
+      return (bool)ptr->nm_value.nm_boolean;
 
-  return (0);
-} /* }}} _Bool check_notify_received */
+  return 0;
+} /* }}} bool check_notify_received */
 
-static _Bool check_send_notify_okay(const notification_t *n) /* {{{ */
+static bool check_send_notify_okay(const notification_t *n) /* {{{ */
 {
   static c_complain_t complain_forwarding = C_COMPLAIN_INIT_STATIC;
-  _Bool received = 0;
+  bool received = 0;
 
   if (n->meta == NULL)
-    return (1);
+    return 1;
 
   received = check_notify_received(n);
 
@@ -380,15 +382,15 @@ static _Bool check_send_notify_okay(const notification_t *n) /* {{{ */
         LOG_ERR, &complain_forwarding,
         "network plugin: A notification has been received via the network "
         "and forwarding is enabled. Forwarding of notifications is currently "
-        "not supported, because there is not loop-deteciton available. "
+        "not supported, because there is not loop-detection available. "
         "Please contact the collectd mailing list if you need this "
         "feature.");
   }
 
   /* By default, only *send* value lists that were not *received* by the
    * network plugin. */
-  return (!received);
-} /* }}} _Bool check_send_notify_okay */
+  return !received;
+} /* }}} bool check_send_notify_okay */
 
 static int network_dispatch_values(value_list_t *vl, /* {{{ */
                                    const char *username) {
@@ -396,19 +398,19 @@ static int network_dispatch_values(value_list_t *vl, /* {{{ */
 
   if ((vl->time == 0) || (strlen(vl->host) == 0) || (strlen(vl->plugin) == 0) ||
       (strlen(vl->type) == 0))
-    return (-EINVAL);
+    return -EINVAL;
 
   if (!check_receive_okay(vl)) {
 #if COLLECT_DEBUG
     char name[6 * DATA_MAX_NAME_LEN];
     FORMAT_VL(name, sizeof(name), vl);
-    name[sizeof(name) - 1] = 0;
+    name[sizeof(name) - 1] = '\0';
     DEBUG("network plugin: network_dispatch_values: "
           "NOT dispatching %s.",
           name);
 #endif
     stats_values_not_dispatched++;
-    return (0);
+    return 0;
   }
 
   assert(vl->meta == NULL);
@@ -416,7 +418,7 @@ static int network_dispatch_values(value_list_t *vl, /* {{{ */
   vl->meta = meta_data_create();
   if (vl->meta == NULL) {
     ERROR("network plugin: meta_data_create failed.");
-    return (-ENOMEM);
+    return -ENOMEM;
   }
 
   status = meta_data_add_boolean(vl->meta, "network:received", 1);
@@ -424,7 +426,7 @@ static int network_dispatch_values(value_list_t *vl, /* {{{ */
     ERROR("network plugin: meta_data_add_boolean failed.");
     meta_data_destroy(vl->meta);
     vl->meta = NULL;
-    return (status);
+    return status;
   }
 
   if (username != NULL) {
@@ -433,7 +435,7 @@ static int network_dispatch_values(value_list_t *vl, /* {{{ */
       ERROR("network plugin: meta_data_add_string failed.");
       meta_data_destroy(vl->meta);
       vl->meta = NULL;
-      return (status);
+      return status;
     }
   }
 
@@ -443,7 +445,7 @@ static int network_dispatch_values(value_list_t *vl, /* {{{ */
   meta_data_destroy(vl->meta);
   vl->meta = NULL;
 
-  return (0);
+  return 0;
 } /* }}} int network_dispatch_values */
 
 static int network_dispatch_notification(notification_t *n) /* {{{ */
@@ -457,7 +459,7 @@ static int network_dispatch_notification(notification_t *n) /* {{{ */
     ERROR("network plugin: plugin_notification_meta_add_boolean failed.");
     plugin_notification_meta_free(n->meta);
     n->meta = NULL;
-    return (status);
+    return status;
   }
 
   status = plugin_dispatch_notification(n);
@@ -465,10 +467,10 @@ static int network_dispatch_notification(notification_t *n) /* {{{ */
   plugin_notification_meta_free(n->meta);
   n->meta = NULL;
 
-  return (status);
+  return status;
 } /* }}} int network_dispatch_notification */
 
-#if HAVE_LIBGCRYPT
+#if HAVE_GCRYPT_H
 static int network_init_gcrypt(void) /* {{{ */
 {
   gcry_error_t err;
@@ -477,7 +479,7 @@ static int network_init_gcrypt(void) /* {{{ */
    * Because you can't know in a library whether another library has
    * already initialized the library */
   if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P))
-    return (0);
+    return 0;
 
 /* http://www.gnupg.org/documentation/manuals/gcrypt/Multi_002dThreading.html
  * To ensure thread-safety, it's important to set GCRYCTL_SET_THREAD_CBS
@@ -491,7 +493,7 @@ static int network_init_gcrypt(void) /* {{{ */
   if (err) {
     ERROR("network plugin: gcry_control (GCRYCTL_SET_THREAD_CBS) failed: %s",
           gcry_strerror(err));
-    return (-1);
+    return -1;
   }
 #endif
 
@@ -501,11 +503,11 @@ static int network_init_gcrypt(void) /* {{{ */
   if (err) {
     ERROR("network plugin: gcry_control (GCRYCTL_INIT_SECMEM) failed: %s",
           gcry_strerror(err));
-    return (-1);
+    return -1;
   }
 
   gcry_control(GCRYCTL_INITIALIZATION_FINISHED);
-  return (0);
+  return 0;
 } /* }}} int network_init_gcrypt */
 
 static gcry_cipher_hd_t network_get_aes256_cypher(sockent_t *se, /* {{{ */
@@ -525,11 +527,11 @@ static gcry_cipher_hd_t network_get_aes256_cypher(sockent_t *se, /* {{{ */
     cyper_ptr = &se->data.server.cypher;
 
     if (username == NULL)
-      return (NULL);
+      return NULL;
 
     secret = fbh_get(se->data.server.userdb, username);
     if (secret == NULL)
-      return (NULL);
+      return NULL;
 
     gcry_md_hash_buffer(GCRY_MD_SHA256, password_hash, secret, strlen(secret));
 
@@ -543,7 +545,7 @@ static gcry_cipher_hd_t network_get_aes256_cypher(sockent_t *se, /* {{{ */
       ERROR("network plugin: gcry_cipher_open returned: %s",
             gcry_strerror(err));
       *cyper_ptr = NULL;
-      return (NULL);
+      return NULL;
     }
   } else {
     gcry_cipher_reset(*cyper_ptr);
@@ -556,7 +558,7 @@ static gcry_cipher_hd_t network_get_aes256_cypher(sockent_t *se, /* {{{ */
           gcry_strerror(err));
     gcry_cipher_close(*cyper_ptr);
     *cyper_ptr = NULL;
-    return (NULL);
+    return NULL;
   }
 
   err = gcry_cipher_setiv(*cyper_ptr, iv, iv_size);
@@ -565,12 +567,12 @@ static gcry_cipher_hd_t network_get_aes256_cypher(sockent_t *se, /* {{{ */
           gcry_strerror(err));
     gcry_cipher_close(*cyper_ptr);
     *cyper_ptr = NULL;
-    return (NULL);
+    return NULL;
   }
 
-  return (*cyper_ptr);
+  return *cyper_ptr;
 } /* }}} int network_get_aes256_cypher */
-#endif /* HAVE_LIBGCRYPT */
+#endif /* HAVE_GCRYPT_H */
 
 static int write_part_values(char **ret_buffer, size_t *ret_buffer_len,
                              const data_set_t *ds, const value_list_t *vl) {
@@ -590,19 +592,19 @@ static int write_part_values(char **ret_buffer, size_t *ret_buffer_len,
                (num_values * sizeof(uint8_t)) + (num_values * sizeof(value_t));
 
   if (*ret_buffer_len < packet_len)
-    return (-1);
+    return -1;
 
   pkg_values_types = malloc(num_values * sizeof(*pkg_values_types));
   if (pkg_values_types == NULL) {
     ERROR("network plugin: write_part_values: malloc failed.");
-    return (-1);
+    return -1;
   }
 
   pkg_values = malloc(num_values * sizeof(*pkg_values));
   if (pkg_values == NULL) {
     free(pkg_values_types);
     ERROR("network plugin: write_part_values: malloc failed.");
-    return (-1);
+    return -1;
   }
 
   pkg_ph.type = htons(TYPE_VALUES);
@@ -635,7 +637,7 @@ static int write_part_values(char **ret_buffer, size_t *ret_buffer_len,
       ERROR("network plugin: write_part_values: "
             "Unknown data source type: %i",
             ds->ds[i].type);
-      return (-1);
+      return -1;
     } /* switch (ds->ds[i].type) */
   }   /* for (num_values) */
 
@@ -663,7 +665,7 @@ static int write_part_values(char **ret_buffer, size_t *ret_buffer_len,
   free(pkg_values_types);
   free(pkg_values);
 
-  return (0);
+  return 0;
 } /* int write_part_values */
 
 static int write_part_number(char **ret_buffer, size_t *ret_buffer_len,
@@ -679,7 +681,7 @@ static int write_part_number(char **ret_buffer, size_t *ret_buffer_len,
   packet_len = sizeof(pkg_head) + sizeof(pkg_value);
 
   if (*ret_buffer_len < packet_len)
-    return (-1);
+    return -1;
 
   pkg_head.type = htons(type);
   pkg_head.length = htons(packet_len);
@@ -697,7 +699,7 @@ static int write_part_number(char **ret_buffer, size_t *ret_buffer_len,
   *ret_buffer = packet_ptr + packet_len;
   *ret_buffer_len -= packet_len;
 
-  return (0);
+  return 0;
 } /* int write_part_number */
 
 static int write_part_string(char **ret_buffer, size_t *ret_buffer_len,
@@ -712,7 +714,7 @@ static int write_part_string(char **ret_buffer, size_t *ret_buffer_len,
 
   buffer_len = 2 * sizeof(uint16_t) + str_len + 1;
   if (*ret_buffer_len < buffer_len)
-    return (-1);
+    return -1;
 
   pkg_type = htons(type);
   pkg_length = htons(buffer_len);
@@ -733,7 +735,7 @@ static int write_part_string(char **ret_buffer, size_t *ret_buffer_len,
   *ret_buffer = buffer + buffer_len;
   *ret_buffer_len -= buffer_len;
 
-  return (0);
+  return 0;
 } /* int write_part_string */
 
 static int parse_part_values(void **ret_buffer, size_t *ret_buffer_len,
@@ -753,9 +755,9 @@ static int parse_part_values(void **ret_buffer, size_t *ret_buffer_len,
 
   if (buffer_len < 15) {
     NOTICE("network plugin: packet is too short: "
-           "buffer_len = %zu",
+           "buffer_len = %" PRIsz,
            buffer_len);
-    return (-1);
+    return -1;
   }
 
   memcpy((void *)&tmp16, buffer, sizeof(tmp16));
@@ -777,10 +779,10 @@ static int parse_part_values(void **ret_buffer, size_t *ret_buffer_len,
   if (buffer_len < exp_size) {
     WARNING("network plugin: parse_part_values: "
             "Packet too short: "
-            "Chunk of size %zu expected, "
-            "but buffer has only %zu bytes left.",
+            "Chunk of size %" PRIsz " expected, "
+            "but buffer has only %" PRIsz " bytes left.",
             exp_size, buffer_len);
-    return (-1);
+    return -1;
   }
   assert(pkg_numval <= ((buffer_len - 6) / 9));
 
@@ -788,7 +790,7 @@ static int parse_part_values(void **ret_buffer, size_t *ret_buffer_len,
     WARNING("network plugin: parse_part_values: "
             "Length and number of values "
             "in the packet don't match.");
-    return (-1);
+    return -1;
   }
 
   pkg_types = calloc(pkg_numval, sizeof(*pkg_types));
@@ -797,7 +799,7 @@ static int parse_part_values(void **ret_buffer, size_t *ret_buffer_len,
     sfree(pkg_types);
     sfree(pkg_values);
     ERROR("network plugin: parse_part_values: calloc failed.");
-    return (-1);
+    return -1;
   }
 
   memcpy(pkg_types, buffer, pkg_numval * sizeof(*pkg_types));
@@ -829,7 +831,7 @@ static int parse_part_values(void **ret_buffer, size_t *ret_buffer_len,
              pkg_types[i]);
       sfree(pkg_types);
       sfree(pkg_values);
-      return (-1);
+      return -1;
     } /* switch (pkg_types[i]) */
   }
 
@@ -840,7 +842,7 @@ static int parse_part_values(void **ret_buffer, size_t *ret_buffer_len,
 
   sfree(pkg_types);
 
-  return (0);
+  return 0;
 } /* int parse_part_values */
 
 static int parse_part_number(void **ret_buffer, size_t *ret_buffer_len,
@@ -857,10 +859,10 @@ static int parse_part_number(void **ret_buffer, size_t *ret_buffer_len,
   if (buffer_len < exp_size) {
     WARNING("network plugin: parse_part_number: "
             "Packet too short: "
-            "Chunk of size %zu expected, "
-            "but buffer has only %zu bytes left.",
+            "Chunk of size %" PRIsz " expected, "
+            "but buffer has only %" PRIsz " bytes left.",
             exp_size, buffer_len);
-    return (-1);
+    return -1;
   }
 
   memcpy((void *)&tmp16, buffer, sizeof(tmp16));
@@ -878,7 +880,7 @@ static int parse_part_number(void **ret_buffer, size_t *ret_buffer_len,
   *ret_buffer = buffer;
   *ret_buffer_len = buffer_len - pkg_length;
 
-  return (0);
+  return 0;
 } /* int parse_part_number */
 
 static int parse_part_string(void **ret_buffer, size_t *ret_buffer_len,
@@ -893,15 +895,15 @@ static int parse_part_string(void **ret_buffer, size_t *ret_buffer_len,
   size_t payload_size;
 
   if (output_len == 0)
-    return (EINVAL);
+    return EINVAL;
 
   if (buffer_len < header_size) {
     WARNING("network plugin: parse_part_string: "
             "Packet too short: "
-            "Chunk of at least size %zu expected, "
-            "but buffer has only %zu bytes left.",
+            "Chunk of at least size %" PRIsz " expected, "
+            "but buffer has only %" PRIsz " bytes left.",
             header_size, buffer_len);
-    return (-1);
+    return -1;
   }
 
   memcpy((void *)&tmp16, buffer, sizeof(tmp16));
@@ -918,9 +920,9 @@ static int parse_part_string(void **ret_buffer, size_t *ret_buffer_len,
     WARNING("network plugin: parse_part_string: "
             "Packet too big: "
             "Chunk of size %" PRIu16 " received, "
-            "but buffer has only %zu bytes left.",
+            "but buffer has only %" PRIsz " bytes left.",
             pkg_length, buffer_len);
-    return (-1);
+    return -1;
   }
 
   /* Check that pkg_length is in the valid range */
@@ -930,7 +932,7 @@ static int parse_part_string(void **ret_buffer, size_t *ret_buffer_len,
             "Header claims this packet is only %hu "
             "bytes long.",
             pkg_length);
-    return (-1);
+    return -1;
   }
 
   /* Check that the package data fits into the output buffer.
@@ -939,11 +941,11 @@ static int parse_part_string(void **ret_buffer, size_t *ret_buffer_len,
   if (output_len < payload_size) {
     WARNING("network plugin: parse_part_string: "
             "Buffer too small: "
-            "Output buffer holds %zu bytes, "
+            "Output buffer holds %" PRIsz " bytes, "
             "which is too small to hold the received "
-            "%zu byte string.",
+            "%" PRIsz " byte string.",
             output_len, payload_size);
-    return (-1);
+    return -1;
   }
 
   /* All sanity checks successfull, let's copy the data over */
@@ -956,13 +958,13 @@ static int parse_part_string(void **ret_buffer, size_t *ret_buffer_len,
     WARNING("network plugin: parse_part_string: "
             "Received string does not end "
             "with a NULL-byte.");
-    return (-1);
+    return -1;
   }
 
   *ret_buffer = buffer;
   *ret_buffer_len = buffer_len - pkg_length;
 
-  return (0);
+  return 0;
 } /* int parse_part_string */
 
 /* Forward declaration: parse_part_sign_sha256 and parse_part_encr_aes256 call
@@ -978,7 +980,7 @@ static int parse_packet(sockent_t *se, void *buffer, size_t buffer_size,
     buffer_offset += (s);                                                      \
   } while (0)
 
-#if HAVE_LIBGCRYPT
+#if HAVE_GCRYPT_H
 static int parse_part_sign_sha256(sockent_t *se, /* {{{ */
                                   void **ret_buffer, size_t *ret_buffer_len,
                                   int flags) {
@@ -1005,7 +1007,7 @@ static int parse_part_sign_sha256(sockent_t *se, /* {{{ */
 
   /* Check if the buffer has enough data for this structure. */
   if (buffer_len <= PART_SIGNATURE_SHA256_SIZE)
-    return (-ENOMEM);
+    return -ENOMEM;
 
   /* Read type and length header */
   BUFFER_READ(&pss.head.type, sizeof(pss.head.type));
@@ -1016,7 +1018,7 @@ static int parse_part_sign_sha256(sockent_t *se, /* {{{ */
   if ((pss_head_length <= PART_SIGNATURE_SHA256_SIZE) ||
       (pss_head_length > buffer_len)) {
     ERROR("network plugin: HMAC-SHA-256 with invalid length received.");
-    return (-1);
+    return -1;
   }
 
   if (se->data.server.userdb == NULL) {
@@ -1028,7 +1030,7 @@ static int parse_part_sign_sha256(sockent_t *se, /* {{{ */
     *ret_buffer = buffer + pss_head_length;
     *ret_buffer_len -= pss_head_length;
 
-    return (0);
+    return 0;
   }
 
   /* Copy the hash. */
@@ -1038,7 +1040,7 @@ static int parse_part_sign_sha256(sockent_t *se, /* {{{ */
   username_len = pss_head_length - PART_SIGNATURE_SHA256_SIZE;
   pss.username = malloc(username_len + 1);
   if (pss.username == NULL)
-    return (-ENOMEM);
+    return -ENOMEM;
 
   /* Read the username */
   BUFFER_READ(pss.username, username_len);
@@ -1051,7 +1053,7 @@ static int parse_part_sign_sha256(sockent_t *se, /* {{{ */
   if (secret == NULL) {
     ERROR("network plugin: Unknown user: %s", pss.username);
     sfree(pss.username);
-    return (-ENOENT);
+    return -ENOENT;
   }
 
   /* Create a hash device and check the HMAC */
@@ -1062,7 +1064,7 @@ static int parse_part_sign_sha256(sockent_t *se, /* {{{ */
           gcry_strerror(err));
     sfree(secret);
     sfree(pss.username);
-    return (-1);
+    return -1;
   }
 
   err = gcry_md_setkey(hd, secret, strlen(secret));
@@ -1071,7 +1073,7 @@ static int parse_part_sign_sha256(sockent_t *se, /* {{{ */
     gcry_md_close(hd);
     sfree(secret);
     sfree(pss.username);
-    return (-1);
+    return -1;
   }
 
   gcry_md_write(hd, buffer + PART_SIGNATURE_SHA256_SIZE,
@@ -1082,7 +1084,7 @@ static int parse_part_sign_sha256(sockent_t *se, /* {{{ */
     gcry_md_close(hd);
     sfree(secret);
     sfree(pss.username);
-    return (-1);
+    return -1;
   }
   memcpy(hash, hash_ptr, sizeof(hash));
 
@@ -1105,15 +1107,15 @@ static int parse_part_sign_sha256(sockent_t *se, /* {{{ */
   *ret_buffer = buffer + buffer_len;
   *ret_buffer_len = 0;
 
-  return (0);
+  return 0;
 } /* }}} int parse_part_sign_sha256 */
-/* #endif HAVE_LIBGCRYPT */
+  /* #endif HAVE_GCRYPT_H */
 
-#else  /* if !HAVE_LIBGCRYPT */
+#else  /* if !HAVE_GCRYPT_H */
 static int parse_part_sign_sha256(sockent_t *se, /* {{{ */
                                   void **ret_buffer, size_t *ret_buffer_size,
                                   int flags) {
-  static int warning_has_been_printed = 0;
+  static int warning_has_been_printed;
 
   char *buffer;
   size_t buffer_size;
@@ -1127,14 +1129,14 @@ static int parse_part_sign_sha256(sockent_t *se, /* {{{ */
   buffer_offset = 0;
 
   if (buffer_size <= PART_SIGNATURE_SHA256_SIZE)
-    return (-ENOMEM);
+    return -ENOMEM;
 
   BUFFER_READ(&pss.head.type, sizeof(pss.head.type));
   BUFFER_READ(&pss.head.length, sizeof(pss.head.length));
   part_len = ntohs(pss.head.length);
 
   if ((part_len <= PART_SIGNATURE_SHA256_SIZE) || (part_len > buffer_size))
-    return (-EINVAL);
+    return -EINVAL;
 
   if (warning_has_been_printed == 0) {
     WARNING("network plugin: Received signed packet, but the network "
@@ -1149,11 +1151,11 @@ static int parse_part_sign_sha256(sockent_t *se, /* {{{ */
   *ret_buffer = buffer + buffer_size;
   *ret_buffer_size = 0;
 
-  return (0);
+  return 0;
 } /* }}} int parse_part_sign_sha256 */
-#endif /* !HAVE_LIBGCRYPT */
+#endif /* !HAVE_GCRYPT_H */
 
-#if HAVE_LIBGCRYPT
+#if HAVE_GCRYPT_H
 static int parse_part_encr_aes256(sockent_t *se, /* {{{ */
                                   void **ret_buffer, size_t *ret_buffer_len,
                                   int flags) {
@@ -1173,7 +1175,7 @@ static int parse_part_encr_aes256(sockent_t *se, /* {{{ */
   if (buffer_len <= PART_ENCRYPTION_AES256_SIZE) {
     NOTICE("network plugin: parse_part_encr_aes256: "
            "Discarding short packet.");
-    return (-1);
+    return -1;
   }
 
   buffer_offset = 0;
@@ -1187,7 +1189,7 @@ static int parse_part_encr_aes256(sockent_t *se, /* {{{ */
   if ((part_size <= PART_ENCRYPTION_AES256_SIZE) || (part_size > buffer_len)) {
     NOTICE("network plugin: parse_part_encr_aes256: "
            "Discarding part with invalid size.");
-    return (-1);
+    return -1;
   }
 
   /* Read the username */
@@ -1198,13 +1200,13 @@ static int parse_part_encr_aes256(sockent_t *se, /* {{{ */
       (username_len > (part_size - (PART_ENCRYPTION_AES256_SIZE + 1)))) {
     NOTICE("network plugin: parse_part_encr_aes256: "
            "Discarding part with invalid username length.");
-    return (-1);
+    return -1;
   }
 
   assert(username_len > 0);
   pea.username = malloc(username_len + 1);
   if (pea.username == NULL)
-    return (-ENOMEM);
+    return -ENOMEM;
   BUFFER_READ(pea.username, username_len);
   pea.username[username_len] = 0;
 
@@ -1219,7 +1221,7 @@ static int parse_part_encr_aes256(sockent_t *se, /* {{{ */
   if (cypher == NULL) {
     ERROR("network plugin: Failed to get cypher. Username: %s", pea.username);
     sfree(pea.username);
-    return (-1);
+    return -1;
   }
 
   payload_len = part_size - (PART_ENCRYPTION_AES256_SIZE + username_len);
@@ -1233,7 +1235,7 @@ static int parse_part_encr_aes256(sockent_t *se, /* {{{ */
     ERROR("network plugin: gcry_cipher_decrypt returned: %s. Username: %s",
           gcry_strerror(err), pea.username);
     sfree(pea.username);
-    return (-1);
+    return -1;
   }
 
   /* Read the hash */
@@ -1248,7 +1250,7 @@ static int parse_part_encr_aes256(sockent_t *se, /* {{{ */
   if (memcmp(hash, pea.hash, sizeof(hash)) != 0) {
     ERROR("network plugin: Checksum mismatch. Username: %s", pea.username);
     sfree(pea.username);
-    return (-1);
+    return -1;
   }
 
   parse_packet(se, buffer + buffer_offset, payload_len, flags | PP_ENCRYPTED,
@@ -1260,15 +1262,15 @@ static int parse_part_encr_aes256(sockent_t *se, /* {{{ */
 
   sfree(pea.username);
 
-  return (0);
+  return 0;
 } /* }}} int parse_part_encr_aes256 */
-/* #endif HAVE_LIBGCRYPT */
+  /* #endif HAVE_GCRYPT_H */
 
-#else  /* if !HAVE_LIBGCRYPT */
+#else  /* if !HAVE_GCRYPT_H */
 static int parse_part_encr_aes256(sockent_t *se, /* {{{ */
                                   void **ret_buffer, size_t *ret_buffer_size,
                                   int flags) {
-  static int warning_has_been_printed = 0;
+  static int warning_has_been_printed;
 
   char *buffer;
   size_t buffer_size;
@@ -1291,7 +1293,7 @@ static int parse_part_encr_aes256(sockent_t *se, /* {{{ */
   if ((ph_length <= PART_ENCRYPTION_AES256_SIZE) || (ph_length > buffer_size)) {
     ERROR("network plugin: AES-256 encrypted part "
           "with invalid length received.");
-    return (-1);
+    return -1;
   }
 
   if (warning_has_been_printed == 0) {
@@ -1304,9 +1306,9 @@ static int parse_part_encr_aes256(sockent_t *se, /* {{{ */
   *ret_buffer = (void *)(((char *)*ret_buffer) + ph_length);
   *ret_buffer_size -= ph_length;
 
-  return (0);
+  return 0;
 } /* }}} int parse_part_encr_aes256 */
-#endif /* !HAVE_LIBGCRYPT */
+#endif /* !HAVE_GCRYPT_H */
 
 #undef BUFFER_READ
 
@@ -1318,11 +1320,11 @@ static int parse_packet(sockent_t *se, /* {{{ */
   value_list_t vl = VALUE_LIST_INIT;
   notification_t n = {0};
 
-#if HAVE_LIBGCRYPT
+#if HAVE_GCRYPT_H
   int packet_was_signed = (flags & PP_SIGNED);
   int packet_was_encrypted = (flags & PP_ENCRYPTED);
   int printed_ignore_warning = 0;
-#endif /* HAVE_LIBGCRYPT */
+#endif /* HAVE_GCRYPT_H */
 
   memset(&vl, '\0', sizeof(vl));
   status = 0;
@@ -1355,7 +1357,7 @@ static int parse_packet(sockent_t *se, /* {{{ */
         break;
       }
     }
-#if HAVE_LIBGCRYPT
+#if HAVE_GCRYPT_H
     else if ((se->data.server.security_level == SECURITY_LEVEL_ENCRYPT) &&
              (packet_was_encrypted == 0)) {
       if (printed_ignore_warning == 0) {
@@ -1367,7 +1369,7 @@ static int parse_packet(sockent_t *se, /* {{{ */
       buffer_size -= (size_t)pkg_length;
       continue;
     }
-#endif /* HAVE_LIBGCRYPT */
+#endif /* HAVE_GCRYPT_H */
     else if (pkg_type == TYPE_SIGN_SHA256) {
       status = parse_part_sign_sha256(se, &buffer, &buffer_size, flags);
       if (status != 0) {
@@ -1378,7 +1380,7 @@ static int parse_packet(sockent_t *se, /* {{{ */
         break;
       }
     }
-#if HAVE_LIBGCRYPT
+#if HAVE_GCRYPT_H
     else if ((se->data.server.security_level == SECURITY_LEVEL_SIGN) &&
              (packet_was_encrypted == 0) && (packet_was_signed == 0)) {
       if (printed_ignore_warning == 0) {
@@ -1390,7 +1392,7 @@ static int parse_packet(sockent_t *se, /* {{{ */
       buffer_size -= (size_t)pkg_length;
       continue;
     }
-#endif /* HAVE_LIBGCRYPT */
+#endif /* HAVE_GCRYPT_H */
     else if (pkg_type == TYPE_VALUES) {
       status =
           parse_part_values(&buffer, &buffer_size, &vl.values, &vl.values_len);
@@ -1491,7 +1493,7 @@ static int parse_packet(sockent_t *se, /* {{{ */
     WARNING("network plugin: parse_packet: Received truncated "
             "packet, try increasing `MaxPacketSize'");
 
-  return (status);
+  return status;
 } /* }}} int parse_packet */
 
 static void free_sockent_client(struct sockent_client *sec) /* {{{ */
@@ -1501,7 +1503,8 @@ static void free_sockent_client(struct sockent_client *sec) /* {{{ */
     sec->fd = -1;
   }
   sfree(sec->addr);
-#if HAVE_LIBGCRYPT
+  sfree(sec->bind_addr);
+#if HAVE_GCRYPT_H
   sfree(sec->username);
   sfree(sec->password);
   if (sec->cypher != NULL)
@@ -1519,7 +1522,7 @@ static void free_sockent_server(struct sockent_server *ses) /* {{{ */
   }
 
   sfree(ses->fd);
-#if HAVE_LIBGCRYPT
+#if HAVE_GCRYPT_H
   sfree(ses->auth_file);
   fbh_destroy(ses->userdb);
   if (ses->cypher != NULL)
@@ -1538,6 +1541,7 @@ static void sockent_destroy(sockent_t *se) /* {{{ */
 
     sfree(se->node);
     sfree(se->service);
+    pthread_mutex_destroy(&se->lock);
 
     if (se->type == SOCKENT_TYPE_CLIENT)
       free_sockent_client(&se->data.client);
@@ -1565,7 +1569,7 @@ static int network_set_ttl(const sockent_t *se, const struct addrinfo *ai) {
   assert(se->type == SOCKENT_TYPE_CLIENT);
 
   if ((network_config_ttl < 1) || (network_config_ttl > 255))
-    return (-1);
+    return -1;
 
   if (ai->ai_family == AF_INET) {
     struct sockaddr_in *addr = (struct sockaddr_in *)ai->ai_addr;
@@ -1578,10 +1582,8 @@ 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)) != 0) {
-      char errbuf[1024];
-      ERROR("network plugin: setsockopt (ipv4-ttl): %s",
-            sstrerror(errno, errbuf, sizeof(errbuf)));
-      return (-1);
+      ERROR("network plugin: setsockopt (ipv4-ttl): %s", STRERRNO);
+      return -1;
     }
   } else if (ai->ai_family == AF_INET6) {
     /* Useful example:
@@ -1596,14 +1598,12 @@ 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)) != 0) {
-      char errbuf[1024];
-      ERROR("network plugin: setsockopt(ipv6-ttl): %s",
-            sstrerror(errno, errbuf, sizeof(errbuf)));
-      return (-1);
+      ERROR("network plugin: setsockopt(ipv6-ttl): %s", STRERRNO);
+      return -1;
     }
   }
 
-  return (0);
+  return 0;
 } /* int network_set_ttl */
 
 static int network_set_interface(const sockent_t *se,
@@ -1634,13 +1634,11 @@ static int network_set_interface(const sockent_t *se,
 
       if (setsockopt(se->data.client.fd, IPPROTO_IP, IP_MULTICAST_IF, &mreq,
                      sizeof(mreq)) != 0) {
-        char errbuf[1024];
-        ERROR("network plugin: setsockopt (ipv4-multicast-if): %s",
-              sstrerror(errno, errbuf, sizeof(errbuf)));
-        return (-1);
+        ERROR("network plugin: setsockopt (ipv4-multicast-if): %s", STRERRNO);
+        return -1;
       }
 
-      return (0);
+      return 0;
     }
   } else if (ai->ai_family == AF_INET6) {
     struct sockaddr_in6 *addr = (struct sockaddr_in6 *)ai->ai_addr;
@@ -1648,13 +1646,11 @@ static int network_set_interface(const sockent_t *se,
     if (IN6_IS_ADDR_MULTICAST(&addr->sin6_addr)) {
       if (setsockopt(se->data.client.fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
                      &se->interface, sizeof(se->interface)) != 0) {
-        char errbuf[1024];
-        ERROR("network plugin: setsockopt (ipv6-multicast-if): %s",
-              sstrerror(errno, errbuf, sizeof(errbuf)));
-        return (-1);
+        ERROR("network plugin: setsockopt (ipv6-multicast-if): %s", STRERRNO);
+        return -1;
       }
 
-      return (0);
+      return 0;
     }
   }
 
@@ -1665,18 +1661,16 @@ static int network_set_interface(const sockent_t *se,
     char interface_name[IFNAMSIZ];
 
     if (if_indextoname(se->interface, interface_name) == NULL)
-      return (-1);
+      return -1;
 
     DEBUG("network plugin: Binding socket to interface %s", interface_name);
 
     if (setsockopt(se->data.client.fd, SOL_SOCKET, SO_BINDTODEVICE,
                    interface_name, sizeof(interface_name)) == -1) {
-      char errbuf[1024];
-      ERROR("network plugin: setsockopt (bind-if): %s",
-            sstrerror(errno, errbuf, sizeof(errbuf)));
-      return (-1);
+      ERROR("network plugin: setsockopt (bind-if): %s", STRERRNO);
+      return -1;
     }
-/* #endif HAVE_IF_INDEXTONAME && SO_BINDTODEVICE */
+      /* #endif HAVE_IF_INDEXTONAME && SO_BINDTODEVICE */
 
 #else
     WARNING("network plugin: Cannot set the interface on a unicast "
@@ -1690,9 +1684,45 @@ static int network_set_interface(const sockent_t *se,
 #endif
   }
 
-  return (0);
+  return 0;
 } /* }}} network_set_interface */
 
+static int network_bind_socket_to_addr(sockent_t *se,
+                                       const struct addrinfo *ai) {
+
+  if (se->data.client.bind_addr == NULL)
+    return 0;
+
+  DEBUG("network_plugin: fd %i: bind socket to address", se->data.client.fd);
+  char pbuffer[64];
+
+  if (ai->ai_family == AF_INET) {
+    struct sockaddr_in *addr =
+        (struct sockaddr_in *)(se->data.client.bind_addr);
+    inet_ntop(AF_INET, &(addr->sin_addr), pbuffer, 64);
+    DEBUG("network_plugin: binding client socket to ipv4 address: %s", pbuffer);
+    if (bind(se->data.client.fd, (struct sockaddr *)addr, sizeof(*addr)) ==
+        -1) {
+      ERROR("network plugin: failed to bind client socket (ipv4) to %s: %s",
+            pbuffer, STRERRNO);
+      return -1;
+    }
+  } else if (ai->ai_family == AF_INET6) {
+    struct sockaddr_in6 *addr =
+        (struct sockaddr_in6 *)(se->data.client.bind_addr);
+    inet_ntop(AF_INET6, &(addr->sin6_addr), pbuffer, 64);
+    DEBUG("network_plugin: binding client socket to ipv6 address: %s", pbuffer);
+    if (bind(se->data.client.fd, (struct sockaddr *)addr, sizeof(*addr)) ==
+        -1) {
+      ERROR("network plugin: failed to bind client socket (ipv6) to %s: %s",
+            pbuffer, STRERRNO);
+      return -1;
+    }
+  }
+
+  return 0;
+} /* int network_bind_socket_to_addr */
+
 static int network_bind_socket(int fd, const struct addrinfo *ai,
                                const int interface_idx) {
 #if KERNEL_SOLARIS
@@ -1700,22 +1730,18 @@ static int network_bind_socket(int fd, const struct addrinfo *ai,
 #else
   int loop = 0;
 #endif
-  int yes = 1;
 
   /* allow multiple sockets to use the same PORT number */
-  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) {
-    char errbuf[1024];
-    ERROR("network plugin: setsockopt (reuseaddr): %s",
-          sstrerror(errno, errbuf, sizeof(errbuf)));
-    return (-1);
+  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) == -1) {
+    ERROR("network plugin: setsockopt (reuseaddr): %s", STRERRNO);
+    return -1;
   }
 
   DEBUG("fd = %i; calling `bind'", fd);
 
   if (bind(fd, ai->ai_addr, ai->ai_addrlen) == -1) {
-    char errbuf[1024];
-    ERROR("bind: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
-    return (-1);
+    ERROR("bind: %s", STRERRNO);
+    return -1;
   }
 
   if (ai->ai_family == AF_INET) {
@@ -1742,21 +1768,17 @@ static int network_bind_socket(int fd, const struct addrinfo *ai,
 
       if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) ==
           -1) {
-        char errbuf[1024];
-        ERROR("network plugin: setsockopt (multicast-loop): %s",
-              sstrerror(errno, errbuf, sizeof(errbuf)));
-        return (-1);
+        ERROR("network plugin: setsockopt (multicast-loop): %s", STRERRNO);
+        return -1;
       }
 
       if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) ==
           -1) {
-        char errbuf[1024];
-        ERROR("network plugin: setsockopt (add-membership): %s",
-              sstrerror(errno, errbuf, sizeof(errbuf)));
-        return (-1);
+        ERROR("network plugin: setsockopt (add-membership): %s", STRERRNO);
+        return -1;
       }
 
-      return (0);
+      return 0;
     }
   } else if (ai->ai_family == AF_INET6) {
     /* Useful example:
@@ -1782,21 +1804,17 @@ static int network_bind_socket(int fd, const struct addrinfo *ai,
 
       if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop,
                      sizeof(loop)) == -1) {
-        char errbuf[1024];
-        ERROR("network plugin: setsockopt (ipv6-multicast-loop): %s",
-              sstrerror(errno, errbuf, sizeof(errbuf)));
-        return (-1);
+        ERROR("network plugin: setsockopt (ipv6-multicast-loop): %s", STRERRNO);
+        return -1;
       }
 
       if (setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq,
                      sizeof(mreq)) == -1) {
-        char errbuf[1024];
-        ERROR("network plugin: setsockopt (ipv6-add-membership): %s",
-              sstrerror(errno, errbuf, sizeof(errbuf)));
-        return (-1);
+        ERROR("network plugin: setsockopt (ipv6-add-membership): %s", STRERRNO);
+        return -1;
       }
 
-      return (0);
+      return 0;
     }
   }
 
@@ -1809,21 +1827,19 @@ static int network_bind_socket(int fd, const struct addrinfo *ai,
     char interface_name[IFNAMSIZ];
 
     if (if_indextoname(interface_idx, interface_name) == NULL)
-      return (-1);
+      return -1;
 
     DEBUG("fd = %i; Binding socket to interface %s", fd, interface_name);
 
     if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, interface_name,
                    sizeof(interface_name)) == -1) {
-      char errbuf[1024];
-      ERROR("network plugin: setsockopt (bind-if): %s",
-            sstrerror(errno, errbuf, sizeof(errbuf)));
-      return (-1);
+      ERROR("network plugin: setsockopt (bind-if): %s", STRERRNO);
+      return -1;
     }
   }
 #endif /* HAVE_IF_INDEXTONAME && SO_BINDTODEVICE */
 
-  return (0);
+  return 0;
 } /* int network_bind_socket */
 
 /* Initialize a sockent structure. `type' must be either `SOCKENT_TYPE_CLIENT'
@@ -1833,22 +1849,23 @@ static sockent_t *sockent_create(int type) /* {{{ */
   sockent_t *se;
 
   if ((type != SOCKENT_TYPE_CLIENT) && (type != SOCKENT_TYPE_SERVER))
-    return (NULL);
+    return NULL;
 
   se = calloc(1, sizeof(*se));
   if (se == NULL)
-    return (NULL);
+    return NULL;
 
   se->type = type;
   se->node = NULL;
   se->service = NULL;
   se->interface = 0;
   se->next = NULL;
+  pthread_mutex_init(&se->lock, NULL);
 
   if (type == SOCKENT_TYPE_SERVER) {
     se->data.server.fd = NULL;
     se->data.server.fd_num = 0;
-#if HAVE_LIBGCRYPT
+#if HAVE_GCRYPT_H
     se->data.server.security_level = SECURITY_LEVEL_NONE;
     se->data.server.auth_file = NULL;
     se->data.server.userdb = NULL;
@@ -1857,9 +1874,10 @@ static sockent_t *sockent_create(int type) /* {{{ */
   } else {
     se->data.client.fd = -1;
     se->data.client.addr = NULL;
+    se->data.client.bind_addr = NULL;
     se->data.client.resolve_interval = 0;
     se->data.client.next_resolve_reconnect = 0;
-#if HAVE_LIBGCRYPT
+#if HAVE_GCRYPT_H
     se->data.client.security_level = SECURITY_LEVEL_NONE;
     se->data.client.username = NULL;
     se->data.client.password = NULL;
@@ -1867,18 +1885,18 @@ static sockent_t *sockent_create(int type) /* {{{ */
 #endif
   }
 
-  return (se);
+  return se;
 } /* }}} sockent_t *sockent_create */
 
 static int sockent_init_crypto(sockent_t *se) /* {{{ */
 {
-#if HAVE_LIBGCRYPT /* {{{ */
+#if HAVE_GCRYPT_H /* {{{ */
   if (se->type == SOCKENT_TYPE_CLIENT) {
     if (se->data.client.security_level > SECURITY_LEVEL_NONE) {
       if (network_init_gcrypt() < 0) {
         ERROR("network plugin: Cannot configure client socket with "
               "security: Failed to initialize crypto library.");
-        return (-1);
+        return -1;
       }
 
       if ((se->data.client.username == NULL) ||
@@ -1886,7 +1904,7 @@ static int sockent_init_crypto(sockent_t *se) /* {{{ */
         ERROR("network plugin: Client socket with "
               "security requested, but no "
               "credentials are configured.");
-        return (-1);
+        return -1;
       }
       gcry_md_hash_buffer(GCRY_MD_SHA256, se->data.client.password_hash,
                           se->data.client.password,
@@ -1898,26 +1916,26 @@ static int sockent_init_crypto(sockent_t *se) /* {{{ */
         (se->data.server.auth_file == NULL)) {
       ERROR("network plugin: Server socket with security requested, "
             "but no \"AuthFile\" is configured.");
-      return (-1);
+      return -1;
     }
     if (se->data.server.auth_file != NULL) {
       if (network_init_gcrypt() < 0) {
         ERROR("network plugin: Cannot configure server socket with security: "
               "Failed to initialize crypto library.");
-        return (-1);
+        return -1;
       }
 
       se->data.server.userdb = fbh_create(se->data.server.auth_file);
       if (se->data.server.userdb == NULL) {
         ERROR("network plugin: Reading password file \"%s\" failed.",
               se->data.server.auth_file);
-        return (-1);
+        return -1;
       }
     }
   }
-#endif /* }}} HAVE_LIBGCRYPT */
+#endif /* }}} HAVE_GCRYPT_H */
 
-  return (0);
+  return 0;
 } /* }}} int sockent_init_crypto */
 
 static int sockent_client_disconnect(sockent_t *se) /* {{{ */
@@ -1925,7 +1943,7 @@ static int sockent_client_disconnect(sockent_t *se) /* {{{ */
   struct sockent_client *client;
 
   if ((se == NULL) || (se->type != SOCKENT_TYPE_CLIENT))
-    return (EINVAL);
+    return EINVAL;
 
   client = &se->data.client;
   if (client->fd >= 0) /* connected */
@@ -1934,10 +1952,12 @@ static int sockent_client_disconnect(sockent_t *se) /* {{{ */
     client->fd = -1;
   }
 
+  DEBUG("network plugin: free (se = %p, addr = %p);", (void *)se,
+        (void *)client->addr);
   sfree(client->addr);
   client->addrlen = 0;
 
-  return (0);
+  return 0;
 } /* }}} int sockent_client_disconnect */
 
 static int sockent_client_connect(sockent_t *se) /* {{{ */
@@ -1947,11 +1967,11 @@ static int sockent_client_connect(sockent_t *se) /* {{{ */
   struct sockent_client *client;
   struct addrinfo *ai_list;
   int status;
-  _Bool reconnect = 0;
+  bool reconnect = false;
   cdtime_t now;
 
   if ((se == NULL) || (se->type != SOCKENT_TYPE_CLIENT))
-    return (EINVAL);
+    return EINVAL;
 
   client = &se->data.client;
 
@@ -1961,11 +1981,11 @@ static int sockent_client_connect(sockent_t *se) /* {{{ */
           "next_resolve_reconnect = %lf",
           CDTIME_T_TO_DOUBLE(client->resolve_interval),
           CDTIME_T_TO_DOUBLE(client->next_resolve_reconnect));
-    reconnect = 1;
+    reconnect = true;
   }
 
   if (client->fd >= 0 && !reconnect) /* already connected and not stale*/
-    return (0);
+    return 0;
 
   struct addrinfo ai_hints = {.ai_family = AF_UNSPEC,
                               .ai_flags = AI_ADDRCONFIG,
@@ -1980,7 +2000,7 @@ static int sockent_client_connect(sockent_t *se) /* {{{ */
         LOG_ERR, &complaint, "network plugin: getaddrinfo (%s, %s) failed: %s",
         (se->node == NULL) ? "(null)" : se->node,
         (se->service == NULL) ? "(null)" : se->service, gai_strerror(status));
-    return (-1);
+    return -1;
   } else {
     c_release(LOG_NOTICE, &complaint,
               "network plugin: Successfully resolved \"%s\".", se->node);
@@ -1994,9 +2014,7 @@ static int sockent_client_connect(sockent_t *se) /* {{{ */
     client->fd =
         socket(ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
     if (client->fd < 0) {
-      char errbuf[1024];
-      ERROR("network plugin: socket(2) failed: %s",
-            sstrerror(errno, errbuf, sizeof(errbuf)));
+      ERROR("network plugin: socket(2) failed: %s", STRERRNO);
       continue;
     }
 
@@ -2007,6 +2025,8 @@ static int sockent_client_connect(sockent_t *se) /* {{{ */
       client->fd = -1;
       continue;
     }
+    DEBUG("network plugin: alloc (se = %p, addr = %p);", (void *)se,
+          (void *)client->addr);
 
     assert(sizeof(*client->addr) >= ai_ptr->ai_addrlen);
     memcpy(client->addr, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
@@ -2014,6 +2034,7 @@ static int sockent_client_connect(sockent_t *se) /* {{{ */
 
     network_set_ttl(se, ai_ptr);
     network_set_interface(se, ai_ptr);
+    network_bind_socket_to_addr(se, ai_ptr);
 
     /* We don't open more than one write-socket per
      * node/service pair.. */
@@ -2022,11 +2043,11 @@ static int sockent_client_connect(sockent_t *se) /* {{{ */
 
   freeaddrinfo(ai_list);
   if (client->fd < 0)
-    return (-1);
+    return -1;
 
   if (client->resolve_interval > 0)
     client->next_resolve_reconnect = now + client->resolve_interval;
-  return (0);
+  return 0;
 } /* }}} int sockent_client_connect */
 
 /* Open the file descriptors for a initialized sockent structure. */
@@ -2039,7 +2060,7 @@ static int sockent_server_listen(sockent_t *se) /* {{{ */
   const char *service;
 
   if (se == NULL)
-    return (-1);
+    return -1;
 
   assert(se->data.server.fd == NULL);
   assert(se->data.server.fd_num == 0);
@@ -2063,7 +2084,7 @@ static int sockent_server_listen(sockent_t *se) /* {{{ */
     ERROR("network plugin: getaddrinfo (%s, %s) failed: %s",
           (se->node == NULL) ? "(null)" : se->node,
           (se->service == NULL) ? "(null)" : se->service, gai_strerror(status));
-    return (-1);
+    return -1;
   }
 
   for (struct addrinfo *ai_ptr = ai_list; ai_ptr != NULL;
@@ -2081,9 +2102,7 @@ static int sockent_server_listen(sockent_t *se) /* {{{ */
 
     *tmp = socket(ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
     if (*tmp < 0) {
-      char errbuf[1024];
-      ERROR("network plugin: socket(2) failed: %s",
-            sstrerror(errno, errbuf, sizeof(errbuf)));
+      ERROR("network plugin: socket(2) failed: %s", STRERRNO);
       continue;
     }
 
@@ -2101,8 +2120,8 @@ static int sockent_server_listen(sockent_t *se) /* {{{ */
   freeaddrinfo(ai_list);
 
   if (se->data.server.fd_num == 0)
-    return (-1);
-  return (0);
+    return -1;
+  return 0;
 } /* }}} int sockent_server_listen */
 
 /* Add a sockent to the global list of sockets */
@@ -2111,7 +2130,7 @@ static int sockent_add(sockent_t *se) /* {{{ */
   sockent_t *last_ptr;
 
   if (se == NULL)
-    return (-1);
+    return -1;
 
   if (se->type == SOCKENT_TYPE_SERVER) {
     struct pollfd *tmp;
@@ -2120,7 +2139,7 @@ static int sockent_add(sockent_t *se) /* {{{ */
                   sizeof(*tmp) * (listen_sockets_num + se->data.server.fd_num));
     if (tmp == NULL) {
       ERROR("network plugin: realloc failed.");
-      return (-1);
+      return -1;
     }
     listen_sockets_pollfd = tmp;
     tmp = listen_sockets_pollfd + listen_sockets_num;
@@ -2136,14 +2155,14 @@ static int sockent_add(sockent_t *se) /* {{{ */
 
     if (listen_sockets == NULL) {
       listen_sockets = se;
-      return (0);
+      return 0;
     }
     last_ptr = listen_sockets;
   } else /* if (se->type == SOCKENT_TYPE_CLIENT) */
   {
     if (sending_sockets == NULL) {
       sending_sockets = se;
-      return (0);
+      return 0;
     }
     last_ptr = sending_sockets;
   }
@@ -2152,7 +2171,7 @@ static int sockent_add(sockent_t *se) /* {{{ */
     last_ptr = last_ptr->next;
   last_ptr->next = se;
 
-  return (0);
+  return 0;
 } /* }}} int sockent_add */
 
 static void *dispatch_thread(void __attribute__((unused)) * arg) /* {{{ */
@@ -2208,7 +2227,7 @@ static void *dispatch_thread(void __attribute__((unused)) * arg) /* {{{ */
     sfree(ent);
   } /* while (42) */
 
-  return (NULL);
+  return NULL;
 } /* }}} void *dispatch_thread */
 
 static int network_receive(void) /* {{{ */
@@ -2231,11 +2250,9 @@ static int network_receive(void) /* {{{ */
   while (listen_loop == 0) {
     status = poll(listen_sockets_pollfd, listen_sockets_num, -1);
     if (status <= 0) {
-      char errbuf[1024];
       if (errno == EINTR)
         continue;
-      ERROR("network plugin: poll(2) failed: %s",
-            sstrerror(errno, errbuf, sizeof(errbuf)));
+      ERROR("network plugin: poll(2) failed: %s", STRERRNO);
       break;
     }
 
@@ -2249,10 +2266,8 @@ static int network_receive(void) /* {{{ */
       buffer_len = recv(listen_sockets_pollfd[i].fd, buffer, sizeof(buffer),
                         0 /* no flags */);
       if (buffer_len < 0) {
-        char errbuf[1024];
         status = (errno != 0) ? errno : -1;
-        ERROR("network plugin: recv(2) failed: %s",
-              sstrerror(errno, errbuf, sizeof(errbuf)));
+        ERROR("network plugin: recv(2) failed: %s", STRERRNO);
         break;
       }
 
@@ -2333,11 +2348,11 @@ static int network_receive(void) /* {{{ */
     pthread_mutex_unlock(&receive_list_lock);
   }
 
-  return (status);
+  return status;
 } /* }}} int network_receive */
 
 static void *receive_thread(void __attribute__((unused)) * arg) {
-  return (network_receive() ? (void *)1 : (void *)0);
+  return network_receive() ? (void *)1 : (void *)0;
 } /* void *receive_thread */
 
 static void network_init_buffer(void) {
@@ -2362,13 +2377,11 @@ static void network_send_buffer_plain(sockent_t *se, /* {{{ */
                     /* flags = */ 0, (struct sockaddr *)se->data.client.addr,
                     se->data.client.addrlen);
     if (status < 0) {
-      char errbuf[1024];
-
       if ((errno == EINTR) || (errno == EAGAIN))
         continue;
 
       ERROR("network plugin: sendto failed: %s. Closing sending socket.",
-            sstrerror(errno, errbuf, sizeof(errbuf)));
+            STRERRNO);
       sockent_client_disconnect(se);
       return;
     }
@@ -2377,7 +2390,7 @@ static void network_send_buffer_plain(sockent_t *se, /* {{{ */
   } /* while (42) */
 } /* }}} void network_send_buffer_plain */
 
-#if HAVE_LIBGCRYPT
+#if HAVE_GCRYPT_H
 #define BUFFER_ADD(p, s)                                                       \
   do {                                                                         \
     memcpy(buffer + buffer_offset, (p), (s));                                  \
@@ -2480,7 +2493,7 @@ static void network_send_buffer_encrypted(sockent_t *se, /* {{{ */
 
   assert(buffer_size <= sizeof(buffer));
   DEBUG("network plugin: network_send_buffer_encrypted: "
-        "buffer_size = %zu;",
+        "buffer_size = %" PRIsz ";",
         buffer_size);
 
   pea.head.length = htons(
@@ -2527,21 +2540,24 @@ static void network_send_buffer_encrypted(sockent_t *se, /* {{{ */
   network_send_buffer_plain(se, buffer, buffer_size);
 } /* }}} void network_send_buffer_encrypted */
 #undef BUFFER_ADD
-#endif /* HAVE_LIBGCRYPT */
+#endif /* HAVE_GCRYPT_H */
 
 static void network_send_buffer(char *buffer, size_t buffer_len) /* {{{ */
 {
-  DEBUG("network plugin: network_send_buffer: buffer_len = %zu", buffer_len);
+  DEBUG("network plugin: network_send_buffer: buffer_len = %" PRIsz,
+        buffer_len);
 
   for (sockent_t *se = sending_sockets; se != NULL; se = se->next) {
-#if HAVE_LIBGCRYPT
+    pthread_mutex_lock(&se->lock);
+#if HAVE_GCRYPT_H
     if (se->data.client.security_level == SECURITY_LEVEL_ENCRYPT)
       network_send_buffer_encrypted(se, buffer, buffer_len);
     else if (se->data.client.security_level == SECURITY_LEVEL_SIGN)
       network_send_buffer_signed(se, buffer, buffer_len);
     else /* if (se->data.client.security_level == SECURITY_LEVEL_NONE) */
-#endif   /* HAVE_LIBGCRYPT */
+#endif   /* HAVE_GCRYPT_H */
       network_send_buffer_plain(se, buffer, buffer_len);
+    pthread_mutex_unlock(&se->lock);
   } /* for (sending_sockets) */
 } /* }}} void network_send_buffer */
 
@@ -2553,28 +2569,28 @@ static int add_to_buffer(char *buffer, size_t buffer_size, /* {{{ */
   if (strcmp(vl_def->host, vl->host) != 0) {
     if (write_part_string(&buffer, &buffer_size, TYPE_HOST, vl->host,
                           strlen(vl->host)) != 0)
-      return (-1);
+      return -1;
     sstrncpy(vl_def->host, vl->host, sizeof(vl_def->host));
   }
 
   if (vl_def->time != vl->time) {
     if (write_part_number(&buffer, &buffer_size, TYPE_TIME_HR,
                           (uint64_t)vl->time))
-      return (-1);
+      return -1;
     vl_def->time = vl->time;
   }
 
   if (vl_def->interval != vl->interval) {
     if (write_part_number(&buffer, &buffer_size, TYPE_INTERVAL_HR,
                           (uint64_t)vl->interval))
-      return (-1);
+      return -1;
     vl_def->interval = vl->interval;
   }
 
   if (strcmp(vl_def->plugin, vl->plugin) != 0) {
     if (write_part_string(&buffer, &buffer_size, TYPE_PLUGIN, vl->plugin,
                           strlen(vl->plugin)) != 0)
-      return (-1);
+      return -1;
     sstrncpy(vl_def->plugin, vl->plugin, sizeof(vl_def->plugin));
   }
 
@@ -2582,7 +2598,7 @@ static int add_to_buffer(char *buffer, size_t buffer_size, /* {{{ */
     if (write_part_string(&buffer, &buffer_size, TYPE_PLUGIN_INSTANCE,
                           vl->plugin_instance,
                           strlen(vl->plugin_instance)) != 0)
-      return (-1);
+      return -1;
     sstrncpy(vl_def->plugin_instance, vl->plugin_instance,
              sizeof(vl_def->plugin_instance));
   }
@@ -2590,22 +2606,22 @@ static int add_to_buffer(char *buffer, size_t buffer_size, /* {{{ */
   if (strcmp(vl_def->type, vl->type) != 0) {
     if (write_part_string(&buffer, &buffer_size, TYPE_TYPE, vl->type,
                           strlen(vl->type)) != 0)
-      return (-1);
+      return -1;
     sstrncpy(vl_def->type, ds->type, sizeof(vl_def->type));
   }
 
   if (strcmp(vl_def->type_instance, vl->type_instance) != 0) {
     if (write_part_string(&buffer, &buffer_size, TYPE_TYPE_INSTANCE,
                           vl->type_instance, strlen(vl->type_instance)) != 0)
-      return (-1);
+      return -1;
     sstrncpy(vl_def->type_instance, vl->type_instance,
              sizeof(vl_def->type_instance));
   }
 
   if (write_part_values(&buffer, &buffer_size, ds, vl) != 0)
-    return (-1);
+    return -1;
 
-  return (buffer - buffer_orig);
+  return buffer - buffer_orig;
 } /* }}} int add_to_buffer */
 
 static void flush_buffer(void) {
@@ -2633,7 +2649,7 @@ static int network_write(const data_set_t *ds, const value_list_t *vl,
 #if COLLECT_DEBUG
     char name[6 * DATA_MAX_NAME_LEN];
     FORMAT_VL(name, sizeof(name), vl);
-    name[sizeof(name) - 1] = 0;
+    name[sizeof(name) - 1] = '\0';
     DEBUG("network plugin: network_write: "
           "NOT sending %s.",
           name);
@@ -2643,17 +2659,17 @@ static int network_write(const data_set_t *ds, const value_list_t *vl,
     pthread_mutex_lock(&stats_lock);
     stats_values_not_sent++;
     pthread_mutex_unlock(&stats_lock);
-    return (0);
+    return 0;
   }
 
   uc_meta_data_add_unsigned_int(vl, "network:time_sent", (uint64_t)vl->time);
 
   pthread_mutex_lock(&send_buffer_lock);
 
-  status =
-      add_to_buffer(send_buffer_ptr, network_config_packet_size -
-                                         (send_buffer_fill + BUFF_SIG_SIZE),
-                    &send_buffer_vl, ds, vl);
+  status = add_to_buffer(send_buffer_ptr,
+                         network_config_packet_size -
+                             (send_buffer_fill + BUFF_SIG_SIZE),
+                         &send_buffer_vl, ds, vl);
   if (status >= 0) {
     /* status == bytes added to the buffer */
     send_buffer_fill += status;
@@ -2664,10 +2680,10 @@ static int network_write(const data_set_t *ds, const value_list_t *vl,
   } else {
     flush_buffer();
 
-    status =
-        add_to_buffer(send_buffer_ptr, network_config_packet_size -
-                                           (send_buffer_fill + BUFF_SIG_SIZE),
-                      &send_buffer_vl, ds, vl);
+    status = add_to_buffer(send_buffer_ptr,
+                           network_config_packet_size -
+                               (send_buffer_fill + BUFF_SIG_SIZE),
+                           &send_buffer_vl, ds, vl);
 
     if (status >= 0) {
       send_buffer_fill += status;
@@ -2686,7 +2702,7 @@ static int network_write(const data_set_t *ds, const value_list_t *vl,
 
   pthread_mutex_unlock(&send_buffer_lock);
 
-  return ((status < 0) ? -1 : 0);
+  return (status < 0) ? -1 : 0;
 } /* int network_write */
 
 static int network_config_set_ttl(const oconfig_item_t *ci) /* {{{ */
@@ -2694,15 +2710,15 @@ static int network_config_set_ttl(const oconfig_item_t *ci) /* {{{ */
   int tmp = 0;
 
   if (cf_util_get_int(ci, &tmp) != 0)
-    return (-1);
+    return -1;
   else if ((tmp > 0) && (tmp <= 255))
     network_config_ttl = tmp;
   else {
     WARNING("network plugin: The `TimeToLive' must be between 1 and 255.");
-    return (-1);
+    return -1;
   }
 
-  return (0);
+  return 0;
 } /* }}} int network_config_set_ttl */
 
 static int network_config_set_interface(const oconfig_item_t *ci, /* {{{ */
@@ -2710,37 +2726,89 @@ static int network_config_set_interface(const oconfig_item_t *ci, /* {{{ */
   char if_name[256];
 
   if (cf_util_get_string_buffer(ci, if_name, sizeof(if_name)) != 0)
-    return (-1);
+    return -1;
 
   *interface = if_nametoindex(if_name);
-  return (0);
+  return 0;
 } /* }}} int network_config_set_interface */
 
+static int
+network_config_set_bind_address(const oconfig_item_t *ci,
+                                struct sockaddr_storage **bind_address) {
+  if ((*bind_address) != NULL) {
+    ERROR("network_plugin: only a single bind address is allowed");
+    return -1;
+  }
+
+  char addr_text[256];
+
+  if (cf_util_get_string_buffer(ci, addr_text, sizeof(addr_text)) != 0)
+    return -1;
+
+  int ret;
+  struct addrinfo *res = NULL;
+  struct addrinfo ai_hints = {.ai_family = AF_UNSPEC,
+                              .ai_flags = AI_NUMERICHOST,
+                              .ai_protocol = IPPROTO_UDP,
+                              .ai_socktype = SOCK_DGRAM};
+
+  ret = getaddrinfo(addr_text, NULL, &ai_hints, &res);
+  if (ret) {
+    ERROR("network plugin: Bind address option has invalid address set: %s",
+          gai_strerror(ret));
+    return -1;
+  }
+
+  *bind_address = malloc(sizeof(**bind_address));
+  if (*bind_address == NULL) {
+    ERROR("network plugin: network_config_set_bind_address: malloc failed.");
+    freeaddrinfo(res);
+    return -1;
+  }
+  (*bind_address)->ss_family = res->ai_family;
+  if (res->ai_family == AF_INET) {
+    struct sockaddr_in *addr = (struct sockaddr_in *)(*bind_address);
+    inet_pton(AF_INET, addr_text, &(addr->sin_addr));
+  } else if (res->ai_family == AF_INET6) {
+    struct sockaddr_in6 *addr = (struct sockaddr_in6 *)(*bind_address);
+    inet_pton(AF_INET6, addr_text, &(addr->sin6_addr));
+  } else {
+    ERROR("network plugin: %s is an unknown address format %d\n", addr_text,
+          res->ai_family);
+    sfree(*bind_address);
+    freeaddrinfo(res);
+    return -1;
+  }
+
+  freeaddrinfo(res);
+  return 0;
+} /* int network_config_set_bind_address */
+
 static int network_config_set_buffer_size(const oconfig_item_t *ci) /* {{{ */
 {
   int tmp = 0;
 
   if (cf_util_get_int(ci, &tmp) != 0)
-    return (-1);
+    return -1;
   else if ((tmp >= 1024) && (tmp <= 65535))
     network_config_packet_size = tmp;
   else {
     WARNING(
         "network plugin: The `MaxPacketSize' must be between 1024 and 65535.");
-    return (-1);
+    return -1;
   }
 
-  return (0);
+  return 0;
 } /* }}} int network_config_set_buffer_size */
 
-#if HAVE_LIBGCRYPT
+#if HAVE_GCRYPT_H
 static int network_config_set_security_level(oconfig_item_t *ci, /* {{{ */
                                              int *retval) {
   char *str;
   if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
     WARNING("network plugin: The `SecurityLevel' config option needs exactly "
             "one string argument.");
-    return (-1);
+    return -1;
   }
 
   str = ci->values[0].value.string;
@@ -2752,12 +2820,12 @@ static int network_config_set_security_level(oconfig_item_t *ci, /* {{{ */
     *retval = SECURITY_LEVEL_NONE;
   else {
     WARNING("network plugin: Unknown security level: %s.", str);
-    return (-1);
+    return -1;
   }
 
-  return (0);
+  return 0;
 } /* }}} int network_config_set_security_level */
-#endif /* HAVE_LIBGCRYPT */
+#endif /* HAVE_GCRYPT_H */
 
 static int network_config_add_listen(const oconfig_item_t *ci) /* {{{ */
 {
@@ -2770,13 +2838,13 @@ static int network_config_add_listen(const oconfig_item_t *ci) /* {{{ */
     ERROR("network plugin: The `%s' config option needs "
           "one or two string arguments.",
           ci->key);
-    return (-1);
+    return -1;
   }
 
   se = sockent_create(SOCKENT_TYPE_SERVER);
   if (se == NULL) {
     ERROR("network plugin: sockent_create failed.");
-    return (-1);
+    return -1;
   }
 
   se->node = strdup(ci->values[0].value.string);
@@ -2786,13 +2854,13 @@ static int network_config_add_listen(const oconfig_item_t *ci) /* {{{ */
   for (int i = 0; i < ci->children_num; i++) {
     oconfig_item_t *child = ci->children + i;
 
-#if HAVE_LIBGCRYPT
+#if HAVE_GCRYPT_H
     if (strcasecmp("AuthFile", child->key) == 0)
       cf_util_get_string(child, &se->data.server.auth_file);
     else if (strcasecmp("SecurityLevel", child->key) == 0)
       network_config_set_security_level(child, &se->data.server.security_level);
     else
-#endif /* HAVE_LIBGCRYPT */
+#endif /* HAVE_GCRYPT_H */
         if (strcasecmp("Interface", child->key) == 0)
       network_config_set_interface(child, &se->interface);
     else {
@@ -2800,23 +2868,23 @@ static int network_config_add_listen(const oconfig_item_t *ci) /* {{{ */
     }
   }
 
-#if HAVE_LIBGCRYPT
+#if HAVE_GCRYPT_H
   if ((se->data.server.security_level > SECURITY_LEVEL_NONE) &&
       (se->data.server.auth_file == NULL)) {
     ERROR("network plugin: A security level higher than `none' was "
           "requested, but no AuthFile option was given. Cowardly refusing to "
           "open this socket!");
     sockent_destroy(se);
-    return (-1);
+    return -1;
   }
-#endif /* HAVE_LIBGCRYPT */
+#endif /* HAVE_GCRYPT_H */
 
   status = sockent_init_crypto(se);
   if (status != 0) {
     ERROR("network plugin: network_config_add_listen: sockent_init_crypto() "
           "failed.");
     sockent_destroy(se);
-    return (-1);
+    return -1;
   }
 
   status = sockent_server_listen(se);
@@ -2824,17 +2892,17 @@ static int network_config_add_listen(const oconfig_item_t *ci) /* {{{ */
     ERROR("network plugin: network_config_add_listen: sockent_server_listen "
           "failed.");
     sockent_destroy(se);
-    return (-1);
+    return -1;
   }
 
   status = sockent_add(se);
   if (status != 0) {
     ERROR("network plugin: network_config_add_listen: sockent_add failed.");
     sockent_destroy(se);
-    return (-1);
+    return -1;
   }
 
-  return (0);
+  return 0;
 } /* }}} int network_config_add_listen */
 
 static int network_config_add_server(const oconfig_item_t *ci) /* {{{ */
@@ -2848,13 +2916,13 @@ static int network_config_add_server(const oconfig_item_t *ci) /* {{{ */
     ERROR("network plugin: The `%s' config option needs "
           "one or two string arguments.",
           ci->key);
-    return (-1);
+    return -1;
   }
 
   se = sockent_create(SOCKENT_TYPE_CLIENT);
   if (se == NULL) {
     ERROR("network plugin: sockent_create failed.");
-    return (-1);
+    return -1;
   }
 
   se->node = strdup(ci->values[0].value.string);
@@ -2864,7 +2932,7 @@ static int network_config_add_server(const oconfig_item_t *ci) /* {{{ */
   for (int i = 0; i < ci->children_num; i++) {
     oconfig_item_t *child = ci->children + i;
 
-#if HAVE_LIBGCRYPT
+#if HAVE_GCRYPT_H
     if (strcasecmp("Username", child->key) == 0)
       cf_util_get_string(child, &se->data.client.username);
     else if (strcasecmp("Password", child->key) == 0)
@@ -2872,9 +2940,11 @@ static int network_config_add_server(const oconfig_item_t *ci) /* {{{ */
     else if (strcasecmp("SecurityLevel", child->key) == 0)
       network_config_set_security_level(child, &se->data.client.security_level);
     else
-#endif /* HAVE_LIBGCRYPT */
+#endif /* HAVE_GCRYPT_H */
         if (strcasecmp("Interface", child->key) == 0)
       network_config_set_interface(child, &se->interface);
+    else if (strcasecmp("BindAddress", child->key) == 0)
+      network_config_set_bind_address(child, &se->data.client.bind_addr);
     else if (strcasecmp("ResolveInterval", child->key) == 0)
       cf_util_get_cdtime(child, &se->data.client.resolve_interval);
     else {
@@ -2882,7 +2952,7 @@ static int network_config_add_server(const oconfig_item_t *ci) /* {{{ */
     }
   }
 
-#if HAVE_LIBGCRYPT
+#if HAVE_GCRYPT_H
   if ((se->data.client.security_level > SECURITY_LEVEL_NONE) &&
       ((se->data.client.username == NULL) ||
        (se->data.client.password == NULL))) {
@@ -2890,16 +2960,16 @@ static int network_config_add_server(const oconfig_item_t *ci) /* {{{ */
           "requested, but no Username or Password option was given. "
           "Cowardly refusing to open this socket!");
     sockent_destroy(se);
-    return (-1);
+    return -1;
   }
-#endif /* HAVE_LIBGCRYPT */
+#endif /* HAVE_GCRYPT_H */
 
   status = sockent_init_crypto(se);
   if (status != 0) {
     ERROR("network plugin: network_config_add_server: sockent_init_crypto() "
           "failed.");
     sockent_destroy(se);
-    return (-1);
+    return -1;
   }
 
   /* No call to sockent_client_connect() here -- it is called from
@@ -2909,10 +2979,10 @@ static int network_config_add_server(const oconfig_item_t *ci) /* {{{ */
   if (status != 0) {
     ERROR("network plugin: network_config_add_server: sockent_add failed.");
     sockent_destroy(se);
-    return (-1);
+    return -1;
   }
 
-  return (0);
+  return 0;
 } /* }}} int network_config_add_server */
 
 static int network_config(oconfig_item_t *ci) /* {{{ */
@@ -2944,7 +3014,7 @@ static int network_config(oconfig_item_t *ci) /* {{{ */
     }
   }
 
-  return (0);
+  return 0;
 } /* }}} int network_config */
 
 static int network_notification(const notification_t *n,
@@ -2956,63 +3026,63 @@ static int network_notification(const notification_t *n,
   int status;
 
   if (!check_send_notify_okay(n))
-    return (0);
+    return 0;
 
   memset(buffer, 0, sizeof(buffer));
 
   status = write_part_number(&buffer_ptr, &buffer_free, TYPE_TIME_HR,
                              (uint64_t)n->time);
   if (status != 0)
-    return (-1);
+    return -1;
 
   status = write_part_number(&buffer_ptr, &buffer_free, TYPE_SEVERITY,
                              (uint64_t)n->severity);
   if (status != 0)
-    return (-1);
+    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);
+      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);
+      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);
+      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);
+      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);
+      return -1;
   }
 
   status = write_part_string(&buffer_ptr, &buffer_free, TYPE_MESSAGE,
                              n->message, strlen(n->message));
   if (status != 0)
-    return (-1);
+    return -1;
 
   network_send_buffer(buffer, sizeof(buffer) - buffer_free);
 
-  return (0);
+  return 0;
 } /* int network_notification */
 
 static int network_shutdown(void) {
@@ -3053,7 +3123,7 @@ static int network_shutdown(void) {
   plugin_unregister_write("network");
   plugin_unregister_shutdown("network");
 
-  return (0);
+  return 0;
 } /* int network_shutdown */
 
 static int network_stats_read(void) /* {{{ */
@@ -3124,17 +3194,17 @@ static int network_stats_read(void) /* {{{ */
   vl.type_instance[0] = 0;
   plugin_dispatch_values(&vl);
 
-  return (0);
+  return 0;
 } /* }}} int network_stats_read */
 
 static int network_init(void) {
-  static _Bool have_init = 0;
+  static bool have_init;
 
   /* Check if we were already initialized. If so, just return - there's
    * nothing more to do (for now, that is). */
   if (have_init)
-    return (0);
-  have_init = 1;
+    return 0;
+  have_init = true;
 
   if (network_config_stats)
     plugin_register_read("network", network_stats_read);
@@ -3144,7 +3214,7 @@ static int network_init(void) {
   send_buffer = malloc(network_config_packet_size);
   if (send_buffer == NULL) {
     ERROR("network plugin: malloc failed.");
-    return (-1);
+    return -1;
   }
   network_init_buffer();
 
@@ -3159,7 +3229,7 @@ static int network_init(void) {
   /* If no threads need to be started, return here. */
   if ((listen_sockets_num == 0) ||
       ((dispatch_thread_running != 0) && (receive_thread_running != 0)))
-    return (0);
+    return 0;
 
   if (dispatch_thread_running == 0) {
     int status;
@@ -3167,9 +3237,7 @@ static int network_init(void) {
                                   dispatch_thread, NULL /* no argument */,
                                   "network disp");
     if (status != 0) {
-      char errbuf[1024];
-      ERROR("network: pthread_create failed: %s",
-            sstrerror(errno, errbuf, sizeof(errbuf)));
+      ERROR("network: pthread_create failed: %s", STRERRNO);
     } else {
       dispatch_thread_running = 1;
     }
@@ -3181,15 +3249,13 @@ static int network_init(void) {
                                   receive_thread, NULL /* no argument */,
                                   "network recv");
     if (status != 0) {
-      char errbuf[1024];
-      ERROR("network: pthread_create failed: %s",
-            sstrerror(errno, errbuf, sizeof(errbuf)));
+      ERROR("network: pthread_create failed: %s", STRERRNO);
     } else {
       receive_thread_running = 1;
     }
   }
 
-  return (0);
+  return 0;
 } /* int network_init */
 
 /*
@@ -3209,14 +3275,14 @@ static int network_flush(cdtime_t timeout,
       cdtime_t now = cdtime();
       if ((send_buffer_last_update + timeout) > now) {
         pthread_mutex_unlock(&send_buffer_lock);
-        return (0);
+        return 0;
       }
     }
     flush_buffer();
   }
   pthread_mutex_unlock(&send_buffer_lock);
 
-  return (0);
+  return 0;
 } /* int network_flush */
 
 void module_register(void) {
@@ -3225,5 +3291,3 @@ void module_register(void) {
   plugin_register_flush("network", network_flush,
                         /* user_data = */ NULL);
 } /* void module_register */
-
-/* vim: set fdm=marker : */