Merge branch 'ff/snmp' into collectd-4.10
[collectd.git] / src / network.c
1 /**
2  * collectd - src/network.c
3  * Copyright (C) 2005-2009  Florian octo Forster
4  * Copyright (C) 2009       Aman Gupta
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; only version 2.1 of the License is
9  * applicable.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * Authors:
21  *   Florian octo Forster <octo at verplant.org>
22  *   Aman Gupta <aman at tmm1.net>
23  **/
24
25 #define _BSD_SOURCE /* For struct ip_mreq */
26
27 #include "collectd.h"
28 #include "plugin.h"
29 #include "common.h"
30 #include "configfile.h"
31 #include "utils_fbhash.h"
32 #include "utils_avltree.h"
33 #include "utils_cache.h"
34 #include "utils_complain.h"
35
36 #include "network.h"
37
38 #if HAVE_PTHREAD_H
39 # include <pthread.h>
40 #endif
41 #if HAVE_SYS_SOCKET_H
42 # include <sys/socket.h>
43 #endif
44 #if HAVE_NETDB_H
45 # include <netdb.h>
46 #endif
47 #if HAVE_NETINET_IN_H
48 # include <netinet/in.h>
49 #endif
50 #if HAVE_ARPA_INET_H
51 # include <arpa/inet.h>
52 #endif
53 #if HAVE_POLL_H
54 # include <poll.h>
55 #endif
56 #if HAVE_NET_IF_H
57 # include <net/if.h>
58 #endif
59
60 #if HAVE_LIBGCRYPT
61 # include <pthread.h>
62 # include <gcrypt.h>
63 GCRY_THREAD_OPTION_PTHREAD_IMPL;
64 #endif
65
66 #ifndef IPV6_ADD_MEMBERSHIP
67 # ifdef IPV6_JOIN_GROUP
68 #  define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
69 # else
70 #  error "Neither IP_ADD_MEMBERSHIP nor IPV6_JOIN_GROUP is defined"
71 # endif
72 #endif /* !IP_ADD_MEMBERSHIP */
73
74 /*
75  * Maximum size required for encryption / signing:
76  *
77  *    42 bytes for the encryption header
78  * +  64 bytes for the username
79  * -----------
80  * = 106 bytes
81  */
82 #define BUFF_SIG_SIZE 106
83
84 /*
85  * Private data types
86  */
87 #define SECURITY_LEVEL_NONE     0
88 #if HAVE_LIBGCRYPT
89 # define SECURITY_LEVEL_SIGN    1
90 # define SECURITY_LEVEL_ENCRYPT 2
91 #endif
92 struct sockent_client
93 {
94         int fd;
95         struct sockaddr_storage *addr;
96         socklen_t                addrlen;
97 #if HAVE_LIBGCRYPT
98         int security_level;
99         char *username;
100         char *password;
101         gcry_cipher_hd_t cypher;
102         unsigned char password_hash[32];
103 #endif
104 };
105
106 struct sockent_server
107 {
108         int *fd;
109         size_t fd_num;
110 #if HAVE_LIBGCRYPT
111         int security_level;
112         char *auth_file;
113         fbhash_t *userdb;
114         gcry_cipher_hd_t cypher;
115 #endif
116 };
117
118 typedef struct sockent
119 {
120 #define SOCKENT_TYPE_CLIENT 1
121 #define SOCKENT_TYPE_SERVER 2
122         int type;
123
124         char *node;
125         char *service;
126         int interface;
127
128         union
129         {
130                 struct sockent_client client;
131                 struct sockent_server server;
132         } data;
133
134         struct sockent *next;
135 } sockent_t;
136
137 /*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
138  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
139  * +-------+-----------------------+-------------------------------+
140  * ! Ver.  !                       ! Length                        !
141  * +-------+-----------------------+-------------------------------+
142  */
143 struct part_header_s
144 {
145         uint16_t type;
146         uint16_t length;
147 };
148 typedef struct part_header_s part_header_t;
149
150 /*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
151  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
152  * +-------------------------------+-------------------------------+
153  * ! Type                          ! Length                        !
154  * +-------------------------------+-------------------------------+
155  * : (Length - 4) Bytes                                            :
156  * +---------------------------------------------------------------+
157  */
158 struct part_string_s
159 {
160         part_header_t *head;
161         char *value;
162 };
163 typedef struct part_string_s part_string_t;
164
165 /*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
166  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
167  * +-------------------------------+-------------------------------+
168  * ! Type                          ! Length                        !
169  * +-------------------------------+-------------------------------+
170  * : (Length - 4 == 2 || 4 || 8) Bytes                             :
171  * +---------------------------------------------------------------+
172  */
173 struct part_number_s
174 {
175         part_header_t *head;
176         uint64_t *value;
177 };
178 typedef struct part_number_s part_number_t;
179
180 /*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
181  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
182  * +-------------------------------+-------------------------------+
183  * ! Type                          ! Length                        !
184  * +-------------------------------+---------------+---------------+
185  * ! Num of values                 ! Type0         ! Type1         !
186  * +-------------------------------+---------------+---------------+
187  * ! Value0                                                        !
188  * !                                                               !
189  * +---------------------------------------------------------------+
190  * ! Value1                                                        !
191  * !                                                               !
192  * +---------------------------------------------------------------+
193  */
194 struct part_values_s
195 {
196         part_header_t *head;
197         uint16_t *num_values;
198         uint8_t  *values_types;
199         value_t  *values;
200 };
201 typedef struct part_values_s part_values_t;
202
203 /*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
204  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
205  * +-------------------------------+-------------------------------+
206  * ! Type                          ! Length                        !
207  * +-------------------------------+-------------------------------+
208  * ! Hash (Bits   0 -  31)                                         !
209  * : :                                                             :
210  * ! Hash (Bits 224 - 255)                                         !
211  * +---------------------------------------------------------------+
212  */
213 /* Minimum size */
214 #define PART_SIGNATURE_SHA256_SIZE 36
215 struct part_signature_sha256_s
216 {
217   part_header_t head;
218   unsigned char hash[32];
219   char *username;
220 };
221 typedef struct part_signature_sha256_s part_signature_sha256_t;
222
223 /*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
224  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
225  * +-------------------------------+-------------------------------+
226  * ! Type                          ! Length                        !
227  * +-------------------------------+-------------------------------+
228  * ! Original length               ! Padding (0 - 15 bytes)        !
229  * +-------------------------------+-------------------------------+
230  * ! Hash (Bits   0 -  31)                                         !
231  * : :                                                             :
232  * ! Hash (Bits 128 - 159)                                         !
233  * +---------------------------------------------------------------+
234  */
235 /* Minimum size */
236 #define PART_ENCRYPTION_AES256_SIZE 42
237 struct part_encryption_aes256_s
238 {
239   part_header_t head;
240   uint16_t username_length;
241   char *username;
242   unsigned char iv[16];
243   /* <encrypted> */
244   unsigned char hash[20];
245   /*   <payload /> */
246   /* </encrypted> */
247 };
248 typedef struct part_encryption_aes256_s part_encryption_aes256_t;
249
250 struct receive_list_entry_s
251 {
252   char *data;
253   int  data_len;
254   int  fd;
255   struct receive_list_entry_s *next;
256 };
257 typedef struct receive_list_entry_s receive_list_entry_t;
258
259 /*
260  * Private variables
261  */
262 static int network_config_ttl = 0;
263 static size_t network_config_packet_size = 1024;
264 static int network_config_forward = 0;
265 static int network_config_stats = 0;
266
267 static sockent_t *sending_sockets = NULL;
268
269 static receive_list_entry_t *receive_list_head = NULL;
270 static receive_list_entry_t *receive_list_tail = NULL;
271 static pthread_mutex_t       receive_list_lock = PTHREAD_MUTEX_INITIALIZER;
272 static pthread_cond_t        receive_list_cond = PTHREAD_COND_INITIALIZER;
273 static uint64_t              receive_list_length = 0;
274
275 static sockent_t     *listen_sockets = NULL;
276 static struct pollfd *listen_sockets_pollfd = NULL;
277 static size_t         listen_sockets_num = 0;
278
279 /* The receive and dispatch threads will run as long as `listen_loop' is set to
280  * zero. */
281 static int       listen_loop = 0;
282 static int       receive_thread_running = 0;
283 static pthread_t receive_thread_id;
284 static int       dispatch_thread_running = 0;
285 static pthread_t dispatch_thread_id;
286
287 /* Buffer in which to-be-sent network packets are constructed. */
288 static char            *send_buffer;
289 static char            *send_buffer_ptr;
290 static int              send_buffer_fill;
291 static value_list_t     send_buffer_vl = VALUE_LIST_STATIC;
292 static pthread_mutex_t  send_buffer_lock = PTHREAD_MUTEX_INITIALIZER;
293
294 /* XXX: These counters are incremented from one place only. The spot in which
295  * the values are incremented is either only reachable by one thread (the
296  * dispatch thread, for example) or locked by some lock (send_buffer_lock for
297  * example). Only if neither is true, the stats_lock is acquired. The counters
298  * are always read without holding a lock in the hope that writing 8 bytes to
299  * memory is an atomic operation. */
300 static uint64_t stats_octets_rx  = 0;
301 static uint64_t stats_octets_tx  = 0;
302 static uint64_t stats_packets_rx = 0;
303 static uint64_t stats_packets_tx = 0;
304 static uint64_t stats_values_dispatched = 0;
305 static uint64_t stats_values_not_dispatched = 0;
306 static uint64_t stats_values_sent = 0;
307 static uint64_t stats_values_not_sent = 0;
308 static pthread_mutex_t stats_lock = PTHREAD_MUTEX_INITIALIZER;
309
310 /*
311  * Private functions
312  */
313 static _Bool check_receive_okay (const value_list_t *vl) /* {{{ */
314 {
315   uint64_t time_sent = 0;
316   int status;
317
318   status = uc_meta_data_get_unsigned_int (vl,
319       "network:time_sent", &time_sent);
320
321   /* This is a value we already sent. Don't allow it to be received again in
322    * order to avoid looping. */
323   if ((status == 0) && (time_sent >= ((uint64_t) vl->time)))
324     return (false);
325
326   return (true);
327 } /* }}} _Bool check_receive_okay */
328
329 static _Bool check_send_okay (const value_list_t *vl) /* {{{ */
330 {
331   _Bool received = false;
332   int status;
333
334   if (network_config_forward != 0)
335     return (true);
336
337   if (vl->meta == NULL)
338     return (true);
339
340   status = meta_data_get_boolean (vl->meta, "network:received", &received);
341   if (status == -ENOENT)
342     return (true);
343   else if (status != 0)
344   {
345     ERROR ("network plugin: check_send_okay: meta_data_get_boolean failed "
346         "with status %i.", status);
347     return (true);
348   }
349
350   /* By default, only *send* value lists that were not *received* by the
351    * network plugin. */
352   return (!received);
353 } /* }}} _Bool check_send_okay */
354
355 static _Bool check_notify_received (const notification_t *n) /* {{{ */
356 {
357   notification_meta_t *ptr;
358
359   for (ptr = n->meta; ptr != NULL; ptr = ptr->next)
360     if ((strcmp ("network:received", ptr->name) == 0)
361         && (ptr->type == NM_TYPE_BOOLEAN))
362       return ((_Bool) ptr->nm_value.nm_boolean);
363
364   return (0);
365 } /* }}} _Bool check_notify_received */
366
367 static _Bool check_send_notify_okay (const notification_t *n) /* {{{ */
368 {
369   static c_complain_t complain_forwarding = C_COMPLAIN_INIT_STATIC;
370   _Bool received = 0;
371
372   if (n->meta == NULL)
373     return (1);
374
375   received = check_notify_received (n);
376
377   if (network_config_forward && received)
378   {
379     c_complain_once (LOG_ERR, &complain_forwarding,
380         "network plugin: A notification has been received via the network "
381         "forwarding if enabled. Forwarding of notifications is currently "
382         "not supported, because there is not loop-deteciton available. "
383         "Please contact the collectd mailing list if you need this "
384         "feature.");
385   }
386
387   /* By default, only *send* value lists that were not *received* by the
388    * network plugin. */
389   return (!received);
390 } /* }}} _Bool check_send_notify_okay */
391
392 static int network_dispatch_values (value_list_t *vl, /* {{{ */
393     const char *username)
394 {
395   int status;
396
397   if ((vl->time <= 0)
398       || (strlen (vl->host) <= 0)
399       || (strlen (vl->plugin) <= 0)
400       || (strlen (vl->type) <= 0))
401     return (-EINVAL);
402
403   if (!check_receive_okay (vl))
404   {
405 #if COLLECT_DEBUG
406     char name[6*DATA_MAX_NAME_LEN];
407     FORMAT_VL (name, sizeof (name), vl);
408     name[sizeof (name) - 1] = 0;
409     DEBUG ("network plugin: network_dispatch_values: "
410         "NOT dispatching %s.", name);
411 #endif
412     stats_values_not_dispatched++;
413     return (0);
414   }
415
416   assert (vl->meta == NULL);
417
418   vl->meta = meta_data_create ();
419   if (vl->meta == NULL)
420   {
421     ERROR ("network plugin: meta_data_create failed.");
422     return (-ENOMEM);
423   }
424
425   status = meta_data_add_boolean (vl->meta, "network:received", true);
426   if (status != 0)
427   {
428     ERROR ("network plugin: meta_data_add_boolean failed.");
429     meta_data_destroy (vl->meta);
430     vl->meta = NULL;
431     return (status);
432   }
433
434   if (username != NULL)
435   {
436     status = meta_data_add_string (vl->meta, "network:username", username);
437     if (status != 0)
438     {
439       ERROR ("network plugin: meta_data_add_string failed.");
440       meta_data_destroy (vl->meta);
441       vl->meta = NULL;
442       return (status);
443     }
444   }
445
446   plugin_dispatch_values_secure (vl);
447   stats_values_dispatched++;
448
449   meta_data_destroy (vl->meta);
450   vl->meta = NULL;
451
452   return (0);
453 } /* }}} int network_dispatch_values */
454
455 static int network_dispatch_notification (notification_t *n) /* {{{ */
456 {
457   int status;
458
459   assert (n->meta == NULL);
460
461   status = plugin_notification_meta_add_boolean (n, "network:received", 1);
462   if (status != 0)
463   {
464     ERROR ("network plugin: plugin_notification_meta_add_boolean failed.");
465     plugin_notification_meta_free (n->meta);
466     n->meta = NULL;
467     return (status);
468   }
469
470   status = plugin_dispatch_notification (n);
471
472   plugin_notification_meta_free (n->meta);
473   n->meta = NULL;
474
475   return (status);
476 } /* }}} int network_dispatch_notification */
477
478 #if HAVE_LIBGCRYPT
479 static gcry_cipher_hd_t network_get_aes256_cypher (sockent_t *se, /* {{{ */
480     const void *iv, size_t iv_size, const char *username)
481 {
482   gcry_error_t err;
483   gcry_cipher_hd_t *cyper_ptr;
484   unsigned char password_hash[32];
485
486   if (se->type == SOCKENT_TYPE_CLIENT)
487   {
488           cyper_ptr = &se->data.client.cypher;
489           memcpy (password_hash, se->data.client.password_hash,
490                           sizeof (password_hash));
491   }
492   else
493   {
494           char *secret;
495
496           cyper_ptr = &se->data.server.cypher;
497
498           if (username == NULL)
499                   return (NULL);
500
501           secret = fbh_get (se->data.server.userdb, username);
502           if (secret == NULL)
503                   return (NULL);
504
505           gcry_md_hash_buffer (GCRY_MD_SHA256,
506                           password_hash,
507                           secret, strlen (secret));
508
509           sfree (secret);
510   }
511
512   if (*cyper_ptr == NULL)
513   {
514     err = gcry_cipher_open (cyper_ptr,
515         GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB, /* flags = */ 0);
516     if (err != 0)
517     {
518       ERROR ("network plugin: gcry_cipher_open returned: %s",
519           gcry_strerror (err));
520       *cyper_ptr = NULL;
521       return (NULL);
522     }
523   }
524   else
525   {
526     gcry_cipher_reset (*cyper_ptr);
527   }
528   assert (*cyper_ptr != NULL);
529
530   err = gcry_cipher_setkey (*cyper_ptr,
531       password_hash, sizeof (password_hash));
532   if (err != 0)
533   {
534     ERROR ("network plugin: gcry_cipher_setkey returned: %s",
535         gcry_strerror (err));
536     gcry_cipher_close (*cyper_ptr);
537     *cyper_ptr = NULL;
538     return (NULL);
539   }
540
541   err = gcry_cipher_setiv (*cyper_ptr, iv, iv_size);
542   if (err != 0)
543   {
544     ERROR ("network plugin: gcry_cipher_setkey returned: %s",
545         gcry_strerror (err));
546     gcry_cipher_close (*cyper_ptr);
547     *cyper_ptr = NULL;
548     return (NULL);
549   }
550
551   return (*cyper_ptr);
552 } /* }}} int network_get_aes256_cypher */
553 #endif /* HAVE_LIBGCRYPT */
554
555 static int write_part_values (char **ret_buffer, int *ret_buffer_len,
556                 const data_set_t *ds, const value_list_t *vl)
557 {
558         char *packet_ptr;
559         int packet_len;
560         int num_values;
561
562         part_header_t pkg_ph;
563         uint16_t      pkg_num_values;
564         uint8_t      *pkg_values_types;
565         value_t      *pkg_values;
566
567         int offset;
568         int i;
569
570         num_values = vl->values_len;
571         packet_len = sizeof (part_header_t) + sizeof (uint16_t)
572                 + (num_values * sizeof (uint8_t))
573                 + (num_values * sizeof (value_t));
574
575         if (*ret_buffer_len < packet_len)
576                 return (-1);
577
578         pkg_values_types = (uint8_t *) malloc (num_values * sizeof (uint8_t));
579         if (pkg_values_types == NULL)
580         {
581                 ERROR ("network plugin: write_part_values: malloc failed.");
582                 return (-1);
583         }
584
585         pkg_values = (value_t *) malloc (num_values * sizeof (value_t));
586         if (pkg_values == NULL)
587         {
588                 free (pkg_values_types);
589                 ERROR ("network plugin: write_part_values: malloc failed.");
590                 return (-1);
591         }
592
593         pkg_ph.type = htons (TYPE_VALUES);
594         pkg_ph.length = htons (packet_len);
595
596         pkg_num_values = htons ((uint16_t) vl->values_len);
597
598         for (i = 0; i < num_values; i++)
599         {
600                 pkg_values_types[i] = (uint8_t) ds->ds[i].type;
601                 switch (ds->ds[i].type)
602                 {
603                         case DS_TYPE_COUNTER:
604                                 pkg_values[i].counter = htonll (vl->values[i].counter);
605                                 break;
606
607                         case DS_TYPE_GAUGE:
608                                 pkg_values[i].gauge = htond (vl->values[i].gauge);
609                                 break;
610
611                         case DS_TYPE_DERIVE:
612                                 pkg_values[i].derive = htonll (vl->values[i].derive);
613                                 break;
614
615                         case DS_TYPE_ABSOLUTE:
616                                 pkg_values[i].absolute = htonll (vl->values[i].absolute);
617                                 break;
618
619                         default:
620                                 free (pkg_values_types);
621                                 free (pkg_values);
622                                 ERROR ("network plugin: write_part_values: "
623                                                 "Unknown data source type: %i",
624                                                 ds->ds[i].type);
625                                 return (-1);
626                 } /* switch (ds->ds[i].type) */
627         } /* for (num_values) */
628
629         /*
630          * Use `memcpy' to write everything to the buffer, because the pointer
631          * may be unaligned and some architectures, such as SPARC, can't handle
632          * that.
633          */
634         packet_ptr = *ret_buffer;
635         offset = 0;
636         memcpy (packet_ptr + offset, &pkg_ph, sizeof (pkg_ph));
637         offset += sizeof (pkg_ph);
638         memcpy (packet_ptr + offset, &pkg_num_values, sizeof (pkg_num_values));
639         offset += sizeof (pkg_num_values);
640         memcpy (packet_ptr + offset, pkg_values_types, num_values * sizeof (uint8_t));
641         offset += num_values * sizeof (uint8_t);
642         memcpy (packet_ptr + offset, pkg_values, num_values * sizeof (value_t));
643         offset += num_values * sizeof (value_t);
644
645         assert (offset == packet_len);
646
647         *ret_buffer = packet_ptr + packet_len;
648         *ret_buffer_len -= packet_len;
649
650         free (pkg_values_types);
651         free (pkg_values);
652
653         return (0);
654 } /* int write_part_values */
655
656 static int write_part_number (char **ret_buffer, int *ret_buffer_len,
657                 int type, uint64_t value)
658 {
659         char *packet_ptr;
660         int packet_len;
661
662         part_header_t pkg_head;
663         uint64_t pkg_value;
664         
665         int offset;
666
667         packet_len = sizeof (pkg_head) + sizeof (pkg_value);
668
669         if (*ret_buffer_len < packet_len)
670                 return (-1);
671
672         pkg_head.type = htons (type);
673         pkg_head.length = htons (packet_len);
674         pkg_value = htonll (value);
675
676         packet_ptr = *ret_buffer;
677         offset = 0;
678         memcpy (packet_ptr + offset, &pkg_head, sizeof (pkg_head));
679         offset += sizeof (pkg_head);
680         memcpy (packet_ptr + offset, &pkg_value, sizeof (pkg_value));
681         offset += sizeof (pkg_value);
682
683         assert (offset == packet_len);
684
685         *ret_buffer = packet_ptr + packet_len;
686         *ret_buffer_len -= packet_len;
687
688         return (0);
689 } /* int write_part_number */
690
691 static int write_part_string (char **ret_buffer, int *ret_buffer_len,
692                 int type, const char *str, int str_len)
693 {
694         char *buffer;
695         int buffer_len;
696
697         uint16_t pkg_type;
698         uint16_t pkg_length;
699
700         int offset;
701
702         buffer_len = 2 * sizeof (uint16_t) + str_len + 1;
703         if (*ret_buffer_len < buffer_len)
704                 return (-1);
705
706         pkg_type = htons (type);
707         pkg_length = htons (buffer_len);
708
709         buffer = *ret_buffer;
710         offset = 0;
711         memcpy (buffer + offset, (void *) &pkg_type, sizeof (pkg_type));
712         offset += sizeof (pkg_type);
713         memcpy (buffer + offset, (void *) &pkg_length, sizeof (pkg_length));
714         offset += sizeof (pkg_length);
715         memcpy (buffer + offset, str, str_len);
716         offset += str_len;
717         memset (buffer + offset, '\0', 1);
718         offset += 1;
719
720         assert (offset == buffer_len);
721
722         *ret_buffer = buffer + buffer_len;
723         *ret_buffer_len -= buffer_len;
724
725         return (0);
726 } /* int write_part_string */
727
728 static int parse_part_values (void **ret_buffer, size_t *ret_buffer_len,
729                 value_t **ret_values, int *ret_num_values)
730 {
731         char *buffer = *ret_buffer;
732         size_t buffer_len = *ret_buffer_len;
733
734         uint16_t tmp16;
735         size_t exp_size;
736         int   i;
737
738         uint16_t pkg_length;
739         uint16_t pkg_type;
740         uint16_t pkg_numval;
741
742         uint8_t *pkg_types;
743         value_t *pkg_values;
744
745         if (buffer_len < 15)
746         {
747                 NOTICE ("network plugin: packet is too short: "
748                                 "buffer_len = %zu", buffer_len);
749                 return (-1);
750         }
751
752         memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
753         buffer += sizeof (tmp16);
754         pkg_type = ntohs (tmp16);
755
756         memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
757         buffer += sizeof (tmp16);
758         pkg_length = ntohs (tmp16);
759
760         memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
761         buffer += sizeof (tmp16);
762         pkg_numval = ntohs (tmp16);
763
764         assert (pkg_type == TYPE_VALUES);
765
766         exp_size = 3 * sizeof (uint16_t)
767                 + pkg_numval * (sizeof (uint8_t) + sizeof (value_t));
768         if (buffer_len < exp_size)
769         {
770                 WARNING ("network plugin: parse_part_values: "
771                                 "Packet too short: "
772                                 "Chunk of size %zu expected, "
773                                 "but buffer has only %zu bytes left.",
774                                 exp_size, buffer_len);
775                 return (-1);
776         }
777
778         if (pkg_length != exp_size)
779         {
780                 WARNING ("network plugin: parse_part_values: "
781                                 "Length and number of values "
782                                 "in the packet don't match.");
783                 return (-1);
784         }
785
786         pkg_types = (uint8_t *) malloc (pkg_numval * sizeof (uint8_t));
787         pkg_values = (value_t *) malloc (pkg_numval * sizeof (value_t));
788         if ((pkg_types == NULL) || (pkg_values == NULL))
789         {
790                 sfree (pkg_types);
791                 sfree (pkg_values);
792                 ERROR ("network plugin: parse_part_values: malloc failed.");
793                 return (-1);
794         }
795
796         memcpy ((void *) pkg_types, (void *) buffer, pkg_numval * sizeof (uint8_t));
797         buffer += pkg_numval * sizeof (uint8_t);
798         memcpy ((void *) pkg_values, (void *) buffer, pkg_numval * sizeof (value_t));
799         buffer += pkg_numval * sizeof (value_t);
800
801         for (i = 0; i < pkg_numval; i++)
802         {
803                 switch (pkg_types[i])
804                 {
805                   case DS_TYPE_COUNTER:
806                     pkg_values[i].counter = (counter_t) ntohll (pkg_values[i].counter);
807                     break;
808
809                   case DS_TYPE_GAUGE:
810                     pkg_values[i].gauge = (gauge_t) ntohd (pkg_values[i].gauge);
811                     break;
812
813                   case DS_TYPE_DERIVE:
814                     pkg_values[i].derive = (derive_t) ntohll (pkg_values[i].derive);
815                     break;
816
817                   case DS_TYPE_ABSOLUTE:
818                     pkg_values[i].absolute = (absolute_t) ntohll (pkg_values[i].absolute);
819                     break;
820
821                   default:
822                     NOTICE ("network plugin: parse_part_values: "
823                         "Don't know how to handle data source type %"PRIu8,
824                         pkg_types[i]);
825                     sfree (pkg_types);
826                     sfree (pkg_values);
827                     return (-1);
828                 } /* switch (pkg_types[i]) */
829         }
830
831         *ret_buffer     = buffer;
832         *ret_buffer_len = buffer_len - pkg_length;
833         *ret_num_values = pkg_numval;
834         *ret_values     = pkg_values;
835
836         sfree (pkg_types);
837
838         return (0);
839 } /* int parse_part_values */
840
841 static int parse_part_number (void **ret_buffer, size_t *ret_buffer_len,
842                 uint64_t *value)
843 {
844         char *buffer = *ret_buffer;
845         size_t buffer_len = *ret_buffer_len;
846
847         uint16_t tmp16;
848         uint64_t tmp64;
849         size_t exp_size = 2 * sizeof (uint16_t) + sizeof (uint64_t);
850
851         uint16_t pkg_length;
852
853         if (buffer_len < exp_size)
854         {
855                 WARNING ("network plugin: parse_part_number: "
856                                 "Packet too short: "
857                                 "Chunk of size %zu expected, "
858                                 "but buffer has only %zu bytes left.",
859                                 exp_size, buffer_len);
860                 return (-1);
861         }
862
863         memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
864         buffer += sizeof (tmp16);
865         /* pkg_type = ntohs (tmp16); */
866
867         memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
868         buffer += sizeof (tmp16);
869         pkg_length = ntohs (tmp16);
870
871         memcpy ((void *) &tmp64, buffer, sizeof (tmp64));
872         buffer += sizeof (tmp64);
873         *value = ntohll (tmp64);
874
875         *ret_buffer = buffer;
876         *ret_buffer_len = buffer_len - pkg_length;
877
878         return (0);
879 } /* int parse_part_number */
880
881 static int parse_part_string (void **ret_buffer, size_t *ret_buffer_len,
882                 char *output, int output_len)
883 {
884         char *buffer = *ret_buffer;
885         size_t buffer_len = *ret_buffer_len;
886
887         uint16_t tmp16;
888         size_t header_size = 2 * sizeof (uint16_t);
889
890         uint16_t pkg_length;
891
892         if (buffer_len < header_size)
893         {
894                 WARNING ("network plugin: parse_part_string: "
895                                 "Packet too short: "
896                                 "Chunk of at least size %zu expected, "
897                                 "but buffer has only %zu bytes left.",
898                                 header_size, buffer_len);
899                 return (-1);
900         }
901
902         memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
903         buffer += sizeof (tmp16);
904         /* pkg_type = ntohs (tmp16); */
905
906         memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
907         buffer += sizeof (tmp16);
908         pkg_length = ntohs (tmp16);
909
910         /* Check that packet fits in the input buffer */
911         if (pkg_length > buffer_len)
912         {
913                 WARNING ("network plugin: parse_part_string: "
914                                 "Packet too big: "
915                                 "Chunk of size %"PRIu16" received, "
916                                 "but buffer has only %zu bytes left.",
917                                 pkg_length, buffer_len);
918                 return (-1);
919         }
920
921         /* Check that pkg_length is in the valid range */
922         if (pkg_length <= header_size)
923         {
924                 WARNING ("network plugin: parse_part_string: "
925                                 "Packet too short: "
926                                 "Header claims this packet is only %hu "
927                                 "bytes long.", pkg_length);
928                 return (-1);
929         }
930
931         /* Check that the package data fits into the output buffer.
932          * The previous if-statement ensures that:
933          * `pkg_length > header_size' */
934         if ((output_len < 0)
935                         || ((size_t) output_len < ((size_t) pkg_length - header_size)))
936         {
937                 WARNING ("network plugin: parse_part_string: "
938                                 "Output buffer too small.");
939                 return (-1);
940         }
941
942         /* All sanity checks successfull, let's copy the data over */
943         output_len = pkg_length - header_size;
944         memcpy ((void *) output, (void *) buffer, output_len);
945         buffer += output_len;
946
947         /* For some very weird reason '\0' doesn't do the trick on SPARC in
948          * this statement. */
949         if (output[output_len - 1] != 0)
950         {
951                 WARNING ("network plugin: parse_part_string: "
952                                 "Received string does not end "
953                                 "with a NULL-byte.");
954                 return (-1);
955         }
956
957         *ret_buffer = buffer;
958         *ret_buffer_len = buffer_len - pkg_length;
959
960         return (0);
961 } /* int parse_part_string */
962
963 /* Forward declaration: parse_part_sign_sha256 and parse_part_encr_aes256 call
964  * parse_packet and vice versa. */
965 #define PP_SIGNED    0x01
966 #define PP_ENCRYPTED 0x02
967 static int parse_packet (sockent_t *se,
968                 void *buffer, size_t buffer_size, int flags,
969                 const char *username);
970
971 #define BUFFER_READ(p,s) do { \
972   memcpy ((p), buffer + buffer_offset, (s)); \
973   buffer_offset += (s); \
974 } while (0)
975
976 #if HAVE_LIBGCRYPT
977 static int parse_part_sign_sha256 (sockent_t *se, /* {{{ */
978     void **ret_buffer, size_t *ret_buffer_len, int flags)
979 {
980   static c_complain_t complain_no_users = C_COMPLAIN_INIT_STATIC;
981
982   char *buffer;
983   size_t buffer_len;
984   size_t buffer_offset;
985
986   size_t username_len;
987   char *secret;
988
989   part_signature_sha256_t pss;
990   uint16_t pss_head_length;
991   char hash[sizeof (pss.hash)];
992
993   gcry_md_hd_t hd;
994   gcry_error_t err;
995   unsigned char *hash_ptr;
996
997   buffer = *ret_buffer;
998   buffer_len = *ret_buffer_len;
999   buffer_offset = 0;
1000
1001   if (se->data.server.userdb == NULL)
1002   {
1003     c_complain (LOG_NOTICE, &complain_no_users,
1004         "network plugin: Received signed network packet but can't verify it "
1005         "because no user DB has been configured. Will accept it.");
1006     return (0);
1007   }
1008
1009   /* Check if the buffer has enough data for this structure. */
1010   if (buffer_len <= PART_SIGNATURE_SHA256_SIZE)
1011     return (-ENOMEM);
1012
1013   /* Read type and length header */
1014   BUFFER_READ (&pss.head.type, sizeof (pss.head.type));
1015   BUFFER_READ (&pss.head.length, sizeof (pss.head.length));
1016   pss_head_length = ntohs (pss.head.length);
1017
1018   /* Check if the `pss_head_length' is within bounds. */
1019   if ((pss_head_length <= PART_SIGNATURE_SHA256_SIZE)
1020       || (pss_head_length > buffer_len))
1021   {
1022     ERROR ("network plugin: HMAC-SHA-256 with invalid length received.");
1023     return (-1);
1024   }
1025
1026   /* Copy the hash. */
1027   BUFFER_READ (pss.hash, sizeof (pss.hash));
1028
1029   /* Calculate username length (without null byte) and allocate memory */
1030   username_len = pss_head_length - PART_SIGNATURE_SHA256_SIZE;
1031   pss.username = malloc (username_len + 1);
1032   if (pss.username == NULL)
1033     return (-ENOMEM);
1034
1035   /* Read the username */
1036   BUFFER_READ (pss.username, username_len);
1037   pss.username[username_len] = 0;
1038
1039   assert (buffer_offset == pss_head_length);
1040
1041   /* Query the password */
1042   secret = fbh_get (se->data.server.userdb, pss.username);
1043   if (secret == NULL)
1044   {
1045     ERROR ("network plugin: Unknown user: %s", pss.username);
1046     sfree (pss.username);
1047     return (-ENOENT);
1048   }
1049
1050   /* Create a hash device and check the HMAC */
1051   hd = NULL;
1052   err = gcry_md_open (&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
1053   if (err != 0)
1054   {
1055     ERROR ("network plugin: Creating HMAC-SHA-256 object failed: %s",
1056         gcry_strerror (err));
1057     sfree (secret);
1058     sfree (pss.username);
1059     return (-1);
1060   }
1061
1062   err = gcry_md_setkey (hd, secret, strlen (secret));
1063   if (err != 0)
1064   {
1065     ERROR ("network plugin: gcry_md_setkey failed: %s", gcry_strerror (err));
1066     gcry_md_close (hd);
1067     sfree (secret);
1068     sfree (pss.username);
1069     return (-1);
1070   }
1071
1072   gcry_md_write (hd,
1073       buffer     + PART_SIGNATURE_SHA256_SIZE,
1074       buffer_len - PART_SIGNATURE_SHA256_SIZE);
1075   hash_ptr = gcry_md_read (hd, GCRY_MD_SHA256);
1076   if (hash_ptr == NULL)
1077   {
1078     ERROR ("network plugin: gcry_md_read failed.");
1079     gcry_md_close (hd);
1080     sfree (secret);
1081     sfree (pss.username);
1082     return (-1);
1083   }
1084   memcpy (hash, hash_ptr, sizeof (hash));
1085
1086   /* Clean up */
1087   gcry_md_close (hd);
1088   hd = NULL;
1089
1090   if (memcmp (pss.hash, hash, sizeof (pss.hash)) != 0)
1091   {
1092     WARNING ("network plugin: Verifying HMAC-SHA-256 signature failed: "
1093         "Hash mismatch.");
1094   }
1095   else
1096   {
1097     parse_packet (se, buffer + buffer_offset, buffer_len - buffer_offset,
1098         flags | PP_SIGNED, pss.username);
1099   }
1100
1101   sfree (secret);
1102   sfree (pss.username);
1103
1104   *ret_buffer = buffer + buffer_len;
1105   *ret_buffer_len = 0;
1106
1107   return (0);
1108 } /* }}} int parse_part_sign_sha256 */
1109 /* #endif HAVE_LIBGCRYPT */
1110
1111 #else /* if !HAVE_LIBGCRYPT */
1112 static int parse_part_sign_sha256 (sockent_t *se, /* {{{ */
1113     void **ret_buffer, size_t *ret_buffer_size, int flags)
1114 {
1115   static int warning_has_been_printed = 0;
1116
1117   char *buffer;
1118   size_t buffer_size;
1119   size_t buffer_offset;
1120   uint16_t part_len;
1121
1122   part_signature_sha256_t pss;
1123
1124   buffer = *ret_buffer;
1125   buffer_size = *ret_buffer_size;
1126   buffer_offset = 0;
1127
1128   if (buffer_size <= PART_SIGNATURE_SHA256_SIZE)
1129     return (-ENOMEM);
1130
1131   BUFFER_READ (&pss.head.type, sizeof (pss.head.type));
1132   BUFFER_READ (&pss.head.length, sizeof (pss.head.length));
1133   part_len = ntohs (pss.head.length);
1134
1135   if ((part_len <= PART_SIGNATURE_SHA256_SIZE)
1136       || (part_len > buffer_size))
1137     return (-EINVAL);
1138
1139   if (warning_has_been_printed == 0)
1140   {
1141     WARNING ("network plugin: Received signed packet, but the network "
1142         "plugin was not linked with libgcrypt, so I cannot "
1143         "verify the signature. The packet will be accepted.");
1144     warning_has_been_printed = 1;
1145   }
1146
1147   parse_packet (se, buffer + part_len, buffer_size - part_len, flags,
1148       /* username = */ NULL);
1149
1150   *ret_buffer = buffer + buffer_size;
1151   *ret_buffer_size = 0;
1152
1153   return (0);
1154 } /* }}} int parse_part_sign_sha256 */
1155 #endif /* !HAVE_LIBGCRYPT */
1156
1157 #if HAVE_LIBGCRYPT
1158 static int parse_part_encr_aes256 (sockent_t *se, /* {{{ */
1159                 void **ret_buffer, size_t *ret_buffer_len,
1160                 int flags)
1161 {
1162   char  *buffer = *ret_buffer;
1163   size_t buffer_len = *ret_buffer_len;
1164   size_t payload_len;
1165   size_t part_size;
1166   size_t buffer_offset;
1167   uint16_t username_len;
1168   part_encryption_aes256_t pea;
1169   unsigned char hash[sizeof (pea.hash)];
1170
1171   gcry_cipher_hd_t cypher;
1172   gcry_error_t err;
1173
1174   /* Make sure at least the header if available. */
1175   if (buffer_len <= PART_ENCRYPTION_AES256_SIZE)
1176   {
1177     NOTICE ("network plugin: parse_part_encr_aes256: "
1178         "Discarding short packet.");
1179     return (-1);
1180   }
1181
1182   buffer_offset = 0;
1183
1184   /* Copy the unencrypted information into `pea'. */
1185   BUFFER_READ (&pea.head.type, sizeof (pea.head.type));
1186   BUFFER_READ (&pea.head.length, sizeof (pea.head.length));
1187
1188   /* Check the `part size'. */
1189   part_size = ntohs (pea.head.length);
1190   if ((part_size <= PART_ENCRYPTION_AES256_SIZE)
1191       || (part_size > buffer_len))
1192   {
1193     NOTICE ("network plugin: parse_part_encr_aes256: "
1194         "Discarding part with invalid size.");
1195     return (-1);
1196   }
1197
1198   /* Read the username */
1199   BUFFER_READ (&username_len, sizeof (username_len));
1200   username_len = ntohs (username_len);
1201
1202   if ((username_len <= 0)
1203       || (username_len > (part_size - (PART_ENCRYPTION_AES256_SIZE + 1))))
1204   {
1205     NOTICE ("network plugin: parse_part_encr_aes256: "
1206         "Discarding part with invalid username length.");
1207     return (-1);
1208   }
1209
1210   assert (username_len > 0);
1211   pea.username = malloc (username_len + 1);
1212   if (pea.username == NULL)
1213     return (-ENOMEM);
1214   BUFFER_READ (pea.username, username_len);
1215   pea.username[username_len] = 0;
1216
1217   /* Last but not least, the initialization vector */
1218   BUFFER_READ (pea.iv, sizeof (pea.iv));
1219
1220   /* Make sure we are at the right position */
1221   assert (buffer_offset == (username_len +
1222         PART_ENCRYPTION_AES256_SIZE - sizeof (pea.hash)));
1223
1224   cypher = network_get_aes256_cypher (se, pea.iv, sizeof (pea.iv),
1225       pea.username);
1226   if (cypher == NULL)
1227   {
1228     sfree (pea.username);
1229     return (-1);
1230   }
1231
1232   payload_len = part_size - (PART_ENCRYPTION_AES256_SIZE + username_len);
1233   assert (payload_len > 0);
1234
1235   /* Decrypt the packet in-place */
1236   err = gcry_cipher_decrypt (cypher,
1237       buffer    + buffer_offset,
1238       part_size - buffer_offset,
1239       /* in = */ NULL, /* in len = */ 0);
1240   if (err != 0)
1241   {
1242     sfree (pea.username);
1243     ERROR ("network plugin: gcry_cipher_decrypt returned: %s",
1244         gcry_strerror (err));
1245     return (-1);
1246   }
1247
1248   /* Read the hash */
1249   BUFFER_READ (pea.hash, sizeof (pea.hash));
1250
1251   /* Make sure we're at the right position - again */
1252   assert (buffer_offset == (username_len + PART_ENCRYPTION_AES256_SIZE));
1253   assert (buffer_offset == (part_size - payload_len));
1254
1255   /* Check hash sum */
1256   memset (hash, 0, sizeof (hash));
1257   gcry_md_hash_buffer (GCRY_MD_SHA1, hash,
1258       buffer + buffer_offset, payload_len);
1259   if (memcmp (hash, pea.hash, sizeof (hash)) != 0)
1260   {
1261     sfree (pea.username);
1262     ERROR ("network plugin: Decryption failed: Checksum mismatch.");
1263     return (-1);
1264   }
1265
1266   parse_packet (se, buffer + buffer_offset, payload_len,
1267       flags | PP_ENCRYPTED, pea.username);
1268
1269   /* XXX: Free pea.username?!? */
1270
1271   /* Update return values */
1272   *ret_buffer =     buffer     + part_size;
1273   *ret_buffer_len = buffer_len - part_size;
1274
1275   sfree (pea.username);
1276
1277   return (0);
1278 } /* }}} int parse_part_encr_aes256 */
1279 /* #endif HAVE_LIBGCRYPT */
1280
1281 #else /* if !HAVE_LIBGCRYPT */
1282 static int parse_part_encr_aes256 (sockent_t *se, /* {{{ */
1283     void **ret_buffer, size_t *ret_buffer_size, int flags)
1284 {
1285   static int warning_has_been_printed = 0;
1286
1287   char *buffer;
1288   size_t buffer_size;
1289   size_t buffer_offset;
1290
1291   part_header_t ph;
1292   size_t ph_length;
1293
1294   buffer = *ret_buffer;
1295   buffer_size = *ret_buffer_size;
1296   buffer_offset = 0;
1297
1298   /* parse_packet assures this minimum size. */
1299   assert (buffer_size >= (sizeof (ph.type) + sizeof (ph.length)));
1300
1301   BUFFER_READ (&ph.type, sizeof (ph.type));
1302   BUFFER_READ (&ph.length, sizeof (ph.length));
1303   ph_length = ntohs (ph.length);
1304
1305   if ((ph_length <= PART_ENCRYPTION_AES256_SIZE)
1306       || (ph_length > buffer_size))
1307   {
1308     ERROR ("network plugin: AES-256 encrypted part "
1309         "with invalid length received.");
1310     return (-1);
1311   }
1312
1313   if (warning_has_been_printed == 0)
1314   {
1315     WARNING ("network plugin: Received encrypted packet, but the network "
1316         "plugin was not linked with libgcrypt, so I cannot "
1317         "decrypt it. The part will be discarded.");
1318     warning_has_been_printed = 1;
1319   }
1320
1321   *ret_buffer += ph_length;
1322   *ret_buffer_size -= ph_length;
1323
1324   return (0);
1325 } /* }}} int parse_part_encr_aes256 */
1326 #endif /* !HAVE_LIBGCRYPT */
1327
1328 #undef BUFFER_READ
1329
1330 static int parse_packet (sockent_t *se, /* {{{ */
1331                 void *buffer, size_t buffer_size, int flags,
1332                 const char *username)
1333 {
1334         int status;
1335
1336         value_list_t vl = VALUE_LIST_INIT;
1337         notification_t n;
1338
1339 #if HAVE_LIBGCRYPT
1340         int packet_was_signed = (flags & PP_SIGNED);
1341         int packet_was_encrypted = (flags & PP_ENCRYPTED);
1342         int printed_ignore_warning = 0;
1343 #endif /* HAVE_LIBGCRYPT */
1344
1345
1346         memset (&vl, '\0', sizeof (vl));
1347         memset (&n, '\0', sizeof (n));
1348         status = 0;
1349
1350         while ((status == 0) && (0 < buffer_size)
1351                         && ((unsigned int) buffer_size > sizeof (part_header_t)))
1352         {
1353                 uint16_t pkg_length;
1354                 uint16_t pkg_type;
1355
1356                 memcpy ((void *) &pkg_type,
1357                                 (void *) buffer,
1358                                 sizeof (pkg_type));
1359                 memcpy ((void *) &pkg_length,
1360                                 (void *) (buffer + sizeof (pkg_type)),
1361                                 sizeof (pkg_length));
1362
1363                 pkg_length = ntohs (pkg_length);
1364                 pkg_type = ntohs (pkg_type);
1365
1366                 if (pkg_length > buffer_size)
1367                         break;
1368                 /* Ensure that this loop terminates eventually */
1369                 if (pkg_length < (2 * sizeof (uint16_t)))
1370                         break;
1371
1372                 if (pkg_type == TYPE_ENCR_AES256)
1373                 {
1374                         status = parse_part_encr_aes256 (se,
1375                                         &buffer, &buffer_size, flags);
1376                         if (status != 0)
1377                         {
1378                                 ERROR ("network plugin: Decrypting AES256 "
1379                                                 "part failed "
1380                                                 "with status %i.", status);
1381                                 break;
1382                         }
1383                 }
1384 #if HAVE_LIBGCRYPT
1385                 else if ((se->data.server.security_level == SECURITY_LEVEL_ENCRYPT)
1386                                 && (packet_was_encrypted == 0))
1387                 {
1388                         if (printed_ignore_warning == 0)
1389                         {
1390                                 INFO ("network plugin: Unencrypted packet or "
1391                                                 "part has been ignored.");
1392                                 printed_ignore_warning = 1;
1393                         }
1394                         buffer = ((char *) buffer) + pkg_length;
1395                         continue;
1396                 }
1397 #endif /* HAVE_LIBGCRYPT */
1398                 else if (pkg_type == TYPE_SIGN_SHA256)
1399                 {
1400                         status = parse_part_sign_sha256 (se,
1401                                         &buffer, &buffer_size, flags);
1402                         if (status != 0)
1403                         {
1404                                 ERROR ("network plugin: Verifying HMAC-SHA-256 "
1405                                                 "signature failed "
1406                                                 "with status %i.", status);
1407                                 break;
1408                         }
1409                 }
1410 #if HAVE_LIBGCRYPT
1411                 else if ((se->data.server.security_level == SECURITY_LEVEL_SIGN)
1412                                 && (packet_was_encrypted == 0)
1413                                 && (packet_was_signed == 0))
1414                 {
1415                         if (printed_ignore_warning == 0)
1416                         {
1417                                 INFO ("network plugin: Unsigned packet or "
1418                                                 "part has been ignored.");
1419                                 printed_ignore_warning = 1;
1420                         }
1421                         buffer = ((char *) buffer) + pkg_length;
1422                         continue;
1423                 }
1424 #endif /* HAVE_LIBGCRYPT */
1425                 else if (pkg_type == TYPE_VALUES)
1426                 {
1427                         status = parse_part_values (&buffer, &buffer_size,
1428                                         &vl.values, &vl.values_len);
1429                         if (status != 0)
1430                                 break;
1431
1432                         network_dispatch_values (&vl, username);
1433
1434                         sfree (vl.values);
1435                 }
1436                 else if (pkg_type == TYPE_TIME)
1437                 {
1438                         uint64_t tmp = 0;
1439                         status = parse_part_number (&buffer, &buffer_size,
1440                                         &tmp);
1441                         if (status == 0)
1442                         {
1443                                 vl.time = (time_t) tmp;
1444                                 n.time = (time_t) tmp;
1445                         }
1446                 }
1447                 else if (pkg_type == TYPE_INTERVAL)
1448                 {
1449                         uint64_t tmp = 0;
1450                         status = parse_part_number (&buffer, &buffer_size,
1451                                         &tmp);
1452                         if (status == 0)
1453                                 vl.interval = (int) tmp;
1454                 }
1455                 else if (pkg_type == TYPE_HOST)
1456                 {
1457                         status = parse_part_string (&buffer, &buffer_size,
1458                                         vl.host, sizeof (vl.host));
1459                         if (status == 0)
1460                                 sstrncpy (n.host, vl.host, sizeof (n.host));
1461                 }
1462                 else if (pkg_type == TYPE_PLUGIN)
1463                 {
1464                         status = parse_part_string (&buffer, &buffer_size,
1465                                         vl.plugin, sizeof (vl.plugin));
1466                         if (status == 0)
1467                                 sstrncpy (n.plugin, vl.plugin,
1468                                                 sizeof (n.plugin));
1469                 }
1470                 else if (pkg_type == TYPE_PLUGIN_INSTANCE)
1471                 {
1472                         status = parse_part_string (&buffer, &buffer_size,
1473                                         vl.plugin_instance,
1474                                         sizeof (vl.plugin_instance));
1475                         if (status == 0)
1476                                 sstrncpy (n.plugin_instance,
1477                                                 vl.plugin_instance,
1478                                                 sizeof (n.plugin_instance));
1479                 }
1480                 else if (pkg_type == TYPE_TYPE)
1481                 {
1482                         status = parse_part_string (&buffer, &buffer_size,
1483                                         vl.type, sizeof (vl.type));
1484                         if (status == 0)
1485                                 sstrncpy (n.type, vl.type, sizeof (n.type));
1486                 }
1487                 else if (pkg_type == TYPE_TYPE_INSTANCE)
1488                 {
1489                         status = parse_part_string (&buffer, &buffer_size,
1490                                         vl.type_instance,
1491                                         sizeof (vl.type_instance));
1492                         if (status == 0)
1493                                 sstrncpy (n.type_instance, vl.type_instance,
1494                                                 sizeof (n.type_instance));
1495                 }
1496                 else if (pkg_type == TYPE_MESSAGE)
1497                 {
1498                         status = parse_part_string (&buffer, &buffer_size,
1499                                         n.message, sizeof (n.message));
1500
1501                         if (status != 0)
1502                         {
1503                                 /* do nothing */
1504                         }
1505                         else if ((n.severity != NOTIF_FAILURE)
1506                                         && (n.severity != NOTIF_WARNING)
1507                                         && (n.severity != NOTIF_OKAY))
1508                         {
1509                                 INFO ("network plugin: "
1510                                                 "Ignoring notification with "
1511                                                 "unknown severity %i.",
1512                                                 n.severity);
1513                         }
1514                         else if (n.time <= 0)
1515                         {
1516                                 INFO ("network plugin: "
1517                                                 "Ignoring notification with "
1518                                                 "time == 0.");
1519                         }
1520                         else if (strlen (n.message) <= 0)
1521                         {
1522                                 INFO ("network plugin: "
1523                                                 "Ignoring notification with "
1524                                                 "an empty message.");
1525                         }
1526                         else
1527                         {
1528                                 network_dispatch_notification (&n);
1529                         }
1530                 }
1531                 else if (pkg_type == TYPE_SEVERITY)
1532                 {
1533                         uint64_t tmp = 0;
1534                         status = parse_part_number (&buffer, &buffer_size,
1535                                         &tmp);
1536                         if (status == 0)
1537                                 n.severity = (int) tmp;
1538                 }
1539                 else
1540                 {
1541                         DEBUG ("network plugin: parse_packet: Unknown part"
1542                                         " type: 0x%04hx", pkg_type);
1543                         buffer = ((char *) buffer) + pkg_length;
1544                 }
1545         } /* while (buffer_size > sizeof (part_header_t)) */
1546
1547         if (status == 0 && buffer_size > 0)
1548                 WARNING ("network plugin: parse_packet: Received truncated "
1549                                 "packet, try increasing `MaxPacketSize'");
1550
1551         return (status);
1552 } /* }}} int parse_packet */
1553
1554 static void free_sockent_client (struct sockent_client *sec) /* {{{ */
1555 {
1556   if (sec->fd >= 0)
1557   {
1558     close (sec->fd);
1559     sec->fd = -1;
1560   }
1561   sfree (sec->addr);
1562 #if HAVE_LIBGCRYPT
1563   sfree (sec->username);
1564   sfree (sec->password);
1565   if (sec->cypher != NULL)
1566     gcry_cipher_close (sec->cypher);
1567 #endif
1568 } /* }}} void free_sockent_client */
1569
1570 static void free_sockent_server (struct sockent_server *ses) /* {{{ */
1571 {
1572   size_t i;
1573
1574   for (i = 0; i < ses->fd_num; i++)
1575   {
1576     if (ses->fd[i] >= 0)
1577     {
1578       close (ses->fd[i]);
1579       ses->fd[i] = -1;
1580     }
1581   }
1582
1583   sfree (ses->fd);
1584 #if HAVE_LIBGCRYPT
1585   sfree (ses->auth_file);
1586   fbh_destroy (ses->userdb);
1587   if (ses->cypher != NULL)
1588     gcry_cipher_close (ses->cypher);
1589 #endif
1590 } /* }}} void free_sockent_server */
1591
1592 static void sockent_destroy (sockent_t *se) /* {{{ */
1593 {
1594   sockent_t *next;
1595
1596   DEBUG ("network plugin: sockent_destroy (se = %p);", (void *) se);
1597
1598   while (se != NULL)
1599   {
1600     next = se->next;
1601
1602     sfree (se->node);
1603     sfree (se->service);
1604
1605     if (se->type == SOCKENT_TYPE_CLIENT)
1606       free_sockent_client (&se->data.client);
1607     else
1608       free_sockent_server (&se->data.server);
1609
1610     sfree (se);
1611     se = next;
1612   }
1613 } /* }}} void sockent_destroy */
1614
1615 /*
1616  * int network_set_ttl
1617  *
1618  * Set the `IP_MULTICAST_TTL', `IP_TTL', `IPV6_MULTICAST_HOPS' or
1619  * `IPV6_UNICAST_HOPS', depending on which option is applicable.
1620  *
1621  * The `struct addrinfo' is used to destinguish between unicast and multicast
1622  * sockets.
1623  */
1624 static int network_set_ttl (const sockent_t *se, const struct addrinfo *ai)
1625 {
1626         DEBUG ("network plugin: network_set_ttl: network_config_ttl = %i;",
1627                         network_config_ttl);
1628
1629         assert (se->type == SOCKENT_TYPE_CLIENT);
1630
1631         if ((network_config_ttl < 1) || (network_config_ttl > 255))
1632                 return (-1);
1633
1634         if (ai->ai_family == AF_INET)
1635         {
1636                 struct sockaddr_in *addr = (struct sockaddr_in *) ai->ai_addr;
1637                 int optname;
1638
1639                 if (IN_MULTICAST (ntohl (addr->sin_addr.s_addr)))
1640                         optname = IP_MULTICAST_TTL;
1641                 else
1642                         optname = IP_TTL;
1643
1644                 if (setsockopt (se->data.client.fd, IPPROTO_IP, optname,
1645                                         &network_config_ttl,
1646                                         sizeof (network_config_ttl)) != 0)
1647                 {
1648                         char errbuf[1024];
1649                         ERROR ("network plugin: setsockopt (ipv4-ttl): %s",
1650                                         sstrerror (errno, errbuf, sizeof (errbuf)));
1651                         return (-1);
1652                 }
1653         }
1654         else if (ai->ai_family == AF_INET6)
1655         {
1656                 /* Useful example: http://gsyc.escet.urjc.es/~eva/IPv6-web/examples/mcast.html */
1657                 struct sockaddr_in6 *addr = (struct sockaddr_in6 *) ai->ai_addr;
1658                 int optname;
1659
1660                 if (IN6_IS_ADDR_MULTICAST (&addr->sin6_addr))
1661                         optname = IPV6_MULTICAST_HOPS;
1662                 else
1663                         optname = IPV6_UNICAST_HOPS;
1664
1665                 if (setsockopt (se->data.client.fd, IPPROTO_IPV6, optname,
1666                                         &network_config_ttl,
1667                                         sizeof (network_config_ttl)) != 0)
1668                 {
1669                         char errbuf[1024];
1670                         ERROR ("network plugin: setsockopt(ipv6-ttl): %s",
1671                                         sstrerror (errno, errbuf,
1672                                                 sizeof (errbuf)));
1673                         return (-1);
1674                 }
1675         }
1676
1677         return (0);
1678 } /* int network_set_ttl */
1679
1680 static int network_set_interface (const sockent_t *se, const struct addrinfo *ai) /* {{{ */
1681 {
1682         DEBUG ("network plugin: network_set_interface: interface index = %i;",
1683                         se->interface);
1684
1685         assert (se->type == SOCKENT_TYPE_CLIENT);
1686
1687         if (ai->ai_family == AF_INET)
1688         {
1689                 struct sockaddr_in *addr = (struct sockaddr_in *) ai->ai_addr;
1690
1691                 if (IN_MULTICAST (ntohl (addr->sin_addr.s_addr)))
1692                 {
1693 #if HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
1694                         /* If possible, use the "ip_mreqn" structure which has
1695                          * an "interface index" member. Using the interface
1696                          * index is preferred here, because of its similarity
1697                          * to the way IPv6 handles this. Unfortunately, it
1698                          * appears not to be portable. */
1699                         struct ip_mreqn mreq;
1700
1701                         memset (&mreq, 0, sizeof (mreq));
1702                         mreq.imr_multiaddr.s_addr = addr->sin_addr.s_addr;
1703                         mreq.imr_address.s_addr = ntohl (INADDR_ANY);
1704                         mreq.imr_ifindex = se->interface;
1705 #else
1706                         struct ip_mreq mreq;
1707
1708                         memset (&mreq, 0, sizeof (mreq));
1709                         mreq.imr_multiaddr.s_addr = addr->sin_addr.s_addr;
1710                         mreq.imr_interface.s_addr = ntohl (INADDR_ANY);
1711 #endif
1712
1713                         if (setsockopt (se->data.client.fd, IPPROTO_IP, IP_MULTICAST_IF,
1714                                                 &mreq, sizeof (mreq)) != 0)
1715                         {
1716                                 char errbuf[1024];
1717                                 ERROR ("network plugin: setsockopt (ipv4-multicast-if): %s",
1718                                                 sstrerror (errno, errbuf, sizeof (errbuf)));
1719                                 return (-1);
1720                         }
1721
1722                         return (0);
1723                 }
1724         }
1725         else if (ai->ai_family == AF_INET6)
1726         {
1727                 struct sockaddr_in6 *addr = (struct sockaddr_in6 *) ai->ai_addr;
1728
1729                 if (IN6_IS_ADDR_MULTICAST (&addr->sin6_addr))
1730                 {
1731                         if (setsockopt (se->data.client.fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1732                                                 &se->interface,
1733                                                 sizeof (se->interface)) != 0)
1734                         {
1735                                 char errbuf[1024];
1736                                 ERROR ("network plugin: setsockopt (ipv6-multicast-if): %s",
1737                                                 sstrerror (errno, errbuf,
1738                                                         sizeof (errbuf)));
1739                                 return (-1);
1740                         }
1741
1742                         return (0);
1743                 }
1744         }
1745
1746         /* else: Not a multicast interface. */
1747         if (se->interface != 0)
1748         {
1749 #if defined(HAVE_IF_INDEXTONAME) && HAVE_IF_INDEXTONAME && defined(SO_BINDTODEVICE)
1750                 char interface_name[IFNAMSIZ];
1751
1752                 if (if_indextoname (se->interface, interface_name) == NULL)
1753                         return (-1);
1754
1755                 DEBUG ("network plugin: Binding socket to interface %s", interface_name);
1756
1757                 if (setsockopt (se->data.client.fd, SOL_SOCKET, SO_BINDTODEVICE,
1758                                         interface_name,
1759                                         sizeof(interface_name)) == -1 )
1760                 {
1761                         char errbuf[1024];
1762                         ERROR ("network plugin: setsockopt (bind-if): %s",
1763                                         sstrerror (errno, errbuf, sizeof (errbuf)));
1764                         return (-1);
1765                 }
1766 /* #endif HAVE_IF_INDEXTONAME && SO_BINDTODEVICE */
1767
1768 #else
1769                 WARNING ("network plugin: Cannot set the interface on a unicast "
1770                         "socket because "
1771 # if !defined(SO_BINDTODEVICE)
1772                         "the \"SO_BINDTODEVICE\" socket option "
1773 # else
1774                         "the \"if_indextoname\" function "
1775 # endif
1776                         "is not available on your system.");
1777 #endif
1778
1779         }
1780
1781         return (0);
1782 } /* }}} network_set_interface */
1783
1784 static int network_bind_socket (int fd, const struct addrinfo *ai, const int interface_idx)
1785 {
1786 #if KERNEL_SOLARIS
1787         char loop   = 0;
1788 #else
1789         int loop = 0;
1790 #endif
1791         int yes  = 1;
1792
1793         /* allow multiple sockets to use the same PORT number */
1794         if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR,
1795                                 &yes, sizeof(yes)) == -1) {
1796                 char errbuf[1024];
1797                 ERROR ("network plugin: setsockopt (reuseaddr): %s",
1798                                 sstrerror (errno, errbuf, sizeof (errbuf)));
1799                 return (-1);
1800         }
1801
1802         DEBUG ("fd = %i; calling `bind'", fd);
1803
1804         if (bind (fd, ai->ai_addr, ai->ai_addrlen) == -1)
1805         {
1806                 char errbuf[1024];
1807                 ERROR ("bind: %s",
1808                                 sstrerror (errno, errbuf, sizeof (errbuf)));
1809                 return (-1);
1810         }
1811
1812         if (ai->ai_family == AF_INET)
1813         {
1814                 struct sockaddr_in *addr = (struct sockaddr_in *) ai->ai_addr;
1815                 if (IN_MULTICAST (ntohl (addr->sin_addr.s_addr)))
1816                 {
1817 #if HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
1818                         struct ip_mreqn mreq;
1819 #else
1820                         struct ip_mreq mreq;
1821 #endif
1822
1823                         DEBUG ("fd = %i; IPv4 multicast address found", fd);
1824
1825                         mreq.imr_multiaddr.s_addr = addr->sin_addr.s_addr;
1826 #if HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
1827                         /* Set the interface using the interface index if
1828                          * possible (available). Unfortunately, the struct
1829                          * ip_mreqn is not portable. */
1830                         mreq.imr_address.s_addr = ntohl (INADDR_ANY);
1831                         mreq.imr_ifindex = interface_idx;
1832 #else
1833                         mreq.imr_interface.s_addr = ntohl (INADDR_ANY);
1834 #endif
1835
1836                         if (setsockopt (fd, IPPROTO_IP, IP_MULTICAST_LOOP,
1837                                                 &loop, sizeof (loop)) == -1)
1838                         {
1839                                 char errbuf[1024];
1840                                 ERROR ("network plugin: setsockopt (multicast-loop): %s",
1841                                                 sstrerror (errno, errbuf,
1842                                                         sizeof (errbuf)));
1843                                 return (-1);
1844                         }
1845
1846                         if (setsockopt (fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
1847                                                 &mreq, sizeof (mreq)) == -1)
1848                         {
1849                                 char errbuf[1024];
1850                                 ERROR ("network plugin: setsockopt (add-membership): %s",
1851                                                 sstrerror (errno, errbuf,
1852                                                         sizeof (errbuf)));
1853                                 return (-1);
1854                         }
1855
1856                         return (0);
1857                 }
1858         }
1859         else if (ai->ai_family == AF_INET6)
1860         {
1861                 /* Useful example: http://gsyc.escet.urjc.es/~eva/IPv6-web/examples/mcast.html */
1862                 struct sockaddr_in6 *addr = (struct sockaddr_in6 *) ai->ai_addr;
1863                 if (IN6_IS_ADDR_MULTICAST (&addr->sin6_addr))
1864                 {
1865                         struct ipv6_mreq mreq;
1866
1867                         DEBUG ("fd = %i; IPv6 multicast address found", fd);
1868
1869                         memcpy (&mreq.ipv6mr_multiaddr,
1870                                         &addr->sin6_addr,
1871                                         sizeof (addr->sin6_addr));
1872
1873                         /* http://developer.apple.com/documentation/Darwin/Reference/ManPages/man4/ip6.4.html
1874                          * ipv6mr_interface may be set to zeroes to
1875                          * choose the default multicast interface or to
1876                          * the index of a particular multicast-capable
1877                          * interface if the host is multihomed.
1878                          * Membership is associ-associated with a
1879                          * single interface; programs running on
1880                          * multihomed hosts may need to join the same
1881                          * group on more than one interface.*/
1882                         mreq.ipv6mr_interface = interface_idx;
1883
1884                         if (setsockopt (fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
1885                                                 &loop, sizeof (loop)) == -1)
1886                         {
1887                                 char errbuf[1024];
1888                                 ERROR ("network plugin: setsockopt (ipv6-multicast-loop): %s",
1889                                                 sstrerror (errno, errbuf,
1890                                                         sizeof (errbuf)));
1891                                 return (-1);
1892                         }
1893
1894                         if (setsockopt (fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
1895                                                 &mreq, sizeof (mreq)) == -1)
1896                         {
1897                                 char errbuf[1024];
1898                                 ERROR ("network plugin: setsockopt (ipv6-add-membership): %s",
1899                                                 sstrerror (errno, errbuf,
1900                                                         sizeof (errbuf)));
1901                                 return (-1);
1902                         }
1903
1904                         return (0);
1905                 }
1906         }
1907
1908 #if defined(HAVE_IF_INDEXTONAME) && HAVE_IF_INDEXTONAME && defined(SO_BINDTODEVICE)
1909         /* if a specific interface was set, bind the socket to it. But to avoid
1910          * possible problems with multicast routing, only do that for non-multicast
1911          * addresses */
1912         if (interface_idx != 0)
1913         {
1914                 char interface_name[IFNAMSIZ];
1915
1916                 if (if_indextoname (interface_idx, interface_name) == NULL)
1917                         return (-1);
1918
1919                 DEBUG ("fd = %i; Binding socket to interface %s", fd, interface_name);
1920
1921                 if (setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE,
1922                                         interface_name,
1923                                         sizeof(interface_name)) == -1 )
1924                 {
1925                         char errbuf[1024];
1926                         ERROR ("network plugin: setsockopt (bind-if): %s",
1927                                         sstrerror (errno, errbuf, sizeof (errbuf)));
1928                         return (-1);
1929                 }
1930         }
1931 #endif /* HAVE_IF_INDEXTONAME && SO_BINDTODEVICE */
1932
1933         return (0);
1934 } /* int network_bind_socket */
1935
1936 /* Initialize a sockent structure. `type' must be either `SOCKENT_TYPE_CLIENT'
1937  * or `SOCKENT_TYPE_SERVER' */
1938 static int sockent_init (sockent_t *se, int type) /* {{{ */
1939 {
1940         if (se == NULL)
1941                 return (-1);
1942
1943         memset (se, 0, sizeof (*se));
1944
1945         se->type = SOCKENT_TYPE_CLIENT;
1946         se->node = NULL;
1947         se->service = NULL;
1948         se->interface = 0;
1949         se->next = NULL;
1950
1951         if (type == SOCKENT_TYPE_SERVER)
1952         {
1953                 se->type = SOCKENT_TYPE_SERVER;
1954                 se->data.server.fd = NULL;
1955 #if HAVE_LIBGCRYPT
1956                 se->data.server.security_level = SECURITY_LEVEL_NONE;
1957                 se->data.server.auth_file = NULL;
1958                 se->data.server.userdb = NULL;
1959                 se->data.server.cypher = NULL;
1960 #endif
1961         }
1962         else
1963         {
1964                 se->data.client.fd = -1;
1965                 se->data.client.addr = NULL;
1966 #if HAVE_LIBGCRYPT
1967                 se->data.client.security_level = SECURITY_LEVEL_NONE;
1968                 se->data.client.username = NULL;
1969                 se->data.client.password = NULL;
1970                 se->data.client.cypher = NULL;
1971 #endif
1972         }
1973
1974         return (0);
1975 } /* }}} int sockent_init */
1976
1977 /* Open the file descriptors for a initialized sockent structure. */
1978 static int sockent_open (sockent_t *se) /* {{{ */
1979 {
1980         struct addrinfo  ai_hints;
1981         struct addrinfo *ai_list, *ai_ptr;
1982         int              ai_return;
1983
1984         const char *node;
1985         const char *service;
1986
1987         if (se == NULL)
1988                 return (-1);
1989
1990         /* Set up the security structures. */
1991 #if HAVE_LIBGCRYPT /* {{{ */
1992         if (se->type == SOCKENT_TYPE_CLIENT)
1993         {
1994                 if (se->data.client.security_level > SECURITY_LEVEL_NONE)
1995                 {
1996                         if ((se->data.client.username == NULL)
1997                                         || (se->data.client.password == NULL))
1998                         {
1999                                 ERROR ("network plugin: Client socket with "
2000                                                 "security requested, but no "
2001                                                 "credentials are configured.");
2002                                 return (-1);
2003                         }
2004                         gcry_md_hash_buffer (GCRY_MD_SHA256,
2005                                         se->data.client.password_hash,
2006                                         se->data.client.password,
2007                                         strlen (se->data.client.password));
2008                 }
2009         }
2010         else /* (se->type == SOCKENT_TYPE_SERVER) */
2011         {
2012                 if (se->data.server.security_level > SECURITY_LEVEL_NONE)
2013                 {
2014                         if (se->data.server.auth_file == NULL)
2015                         {
2016                                 ERROR ("network plugin: Server socket with "
2017                                                 "security requested, but no "
2018                                                 "password file is configured.");
2019                                 return (-1);
2020                         }
2021                 }
2022                 if (se->data.server.auth_file != NULL)
2023                 {
2024                         se->data.server.userdb = fbh_create (se->data.server.auth_file);
2025                         if (se->data.server.userdb == NULL)
2026                         {
2027                                 ERROR ("network plugin: Reading password file "
2028                                                 "`%s' failed.",
2029                                                 se->data.server.auth_file);
2030                                 if (se->data.server.security_level > SECURITY_LEVEL_NONE)
2031                                         return (-1);
2032                         }
2033                 }
2034         }
2035 #endif /* }}} HAVE_LIBGCRYPT */
2036
2037         node = se->node;
2038         service = se->service;
2039
2040         if (service == NULL)
2041           service = NET_DEFAULT_PORT;
2042
2043         DEBUG ("network plugin: sockent_open: node = %s; service = %s;",
2044             node, service);
2045
2046         memset (&ai_hints, 0, sizeof (ai_hints));
2047         ai_hints.ai_flags  = 0;
2048 #ifdef AI_PASSIVE
2049         ai_hints.ai_flags |= AI_PASSIVE;
2050 #endif
2051 #ifdef AI_ADDRCONFIG
2052         ai_hints.ai_flags |= AI_ADDRCONFIG;
2053 #endif
2054         ai_hints.ai_family   = AF_UNSPEC;
2055         ai_hints.ai_socktype = SOCK_DGRAM;
2056         ai_hints.ai_protocol = IPPROTO_UDP;
2057
2058         ai_return = getaddrinfo (node, service, &ai_hints, &ai_list);
2059         if (ai_return != 0)
2060         {
2061                 ERROR ("network plugin: getaddrinfo (%s, %s) failed: %s",
2062                                 (se->node == NULL) ? "(null)" : se->node,
2063                                 (se->service == NULL) ? "(null)" : se->service,
2064                                 gai_strerror (ai_return));
2065                 return (-1);
2066         }
2067
2068         for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
2069         {
2070                 int status;
2071
2072                 if (se->type == SOCKENT_TYPE_SERVER) /* {{{ */
2073                 {
2074                         int *tmp;
2075
2076                         tmp = realloc (se->data.server.fd,
2077                                         sizeof (*tmp) * (se->data.server.fd_num + 1));
2078                         if (tmp == NULL)
2079                         {
2080                                 ERROR ("network plugin: realloc failed.");
2081                                 continue;
2082                         }
2083                         se->data.server.fd = tmp;
2084                         tmp = se->data.server.fd + se->data.server.fd_num;
2085
2086                         *tmp = socket (ai_ptr->ai_family, ai_ptr->ai_socktype,
2087                                         ai_ptr->ai_protocol);
2088                         if (*tmp < 0)
2089                         {
2090                                 char errbuf[1024];
2091                                 ERROR ("network plugin: socket(2) failed: %s",
2092                                                 sstrerror (errno, errbuf,
2093                                                         sizeof (errbuf)));
2094                                 continue;
2095                         }
2096
2097                         status = network_bind_socket (*tmp, ai_ptr, se->interface);
2098                         if (status != 0)
2099                         {
2100                                 close (*tmp);
2101                                 *tmp = -1;
2102                                 continue;
2103                         }
2104
2105                         se->data.server.fd_num++;
2106                         continue;
2107                 } /* }}} if (se->type == SOCKENT_TYPE_SERVER) */
2108                 else /* if (se->type == SOCKENT_TYPE_CLIENT) {{{ */
2109                 {
2110                         se->data.client.fd = socket (ai_ptr->ai_family,
2111                                         ai_ptr->ai_socktype,
2112                                         ai_ptr->ai_protocol);
2113                         if (se->data.client.fd < 0)
2114                         {
2115                                 char errbuf[1024];
2116                                 ERROR ("network plugin: socket(2) failed: %s",
2117                                                 sstrerror (errno, errbuf,
2118                                                         sizeof (errbuf)));
2119                                 continue;
2120                         }
2121
2122                         se->data.client.addr = malloc (sizeof (*se->data.client.addr));
2123                         if (se->data.client.addr == NULL)
2124                         {
2125                                 ERROR ("network plugin: malloc failed.");
2126                                 close (se->data.client.fd);
2127                                 se->data.client.fd = -1;
2128                                 continue;
2129                         }
2130
2131                         memset (se->data.client.addr, 0, sizeof (*se->data.client.addr));
2132                         assert (sizeof (*se->data.client.addr) >= ai_ptr->ai_addrlen);
2133                         memcpy (se->data.client.addr, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
2134                         se->data.client.addrlen = ai_ptr->ai_addrlen;
2135
2136                         network_set_ttl (se, ai_ptr);
2137                         network_set_interface (se, ai_ptr);
2138
2139                         /* We don't open more than one write-socket per
2140                          * node/service pair.. */
2141                         break;
2142                 } /* }}} if (se->type == SOCKENT_TYPE_CLIENT) */
2143         } /* for (ai_list) */
2144
2145         freeaddrinfo (ai_list);
2146
2147         /* Check if all went well. */
2148         if (se->type == SOCKENT_TYPE_SERVER)
2149         {
2150                 if (se->data.server.fd_num <= 0)
2151                         return (-1);
2152         }
2153         else /* if (se->type == SOCKENT_TYPE_CLIENT) */
2154         {
2155                 if (se->data.client.fd < 0)
2156                         return (-1);
2157         }
2158
2159         return (0);
2160 } /* }}} int sockent_open */
2161
2162 /* Add a sockent to the global list of sockets */
2163 static int sockent_add (sockent_t *se) /* {{{ */
2164 {
2165         sockent_t *last_ptr;
2166
2167         if (se == NULL)
2168                 return (-1);
2169
2170         if (se->type == SOCKENT_TYPE_SERVER)
2171         {
2172                 struct pollfd *tmp;
2173                 size_t i;
2174
2175                 tmp = realloc (listen_sockets_pollfd,
2176                                 sizeof (*tmp) * (listen_sockets_num
2177                                         + se->data.server.fd_num));
2178                 if (tmp == NULL)
2179                 {
2180                         ERROR ("network plugin: realloc failed.");
2181                         return (-1);
2182                 }
2183                 listen_sockets_pollfd = tmp;
2184                 tmp = listen_sockets_pollfd + listen_sockets_num;
2185
2186                 for (i = 0; i < se->data.server.fd_num; i++)
2187                 {
2188                         memset (tmp + i, 0, sizeof (*tmp));
2189                         tmp[i].fd = se->data.server.fd[i];
2190                         tmp[i].events = POLLIN | POLLPRI;
2191                         tmp[i].revents = 0;
2192                 }
2193
2194                 listen_sockets_num += se->data.server.fd_num;
2195
2196                 if (listen_sockets == NULL)
2197                 {
2198                         listen_sockets = se;
2199                         return (0);
2200                 }
2201                 last_ptr = listen_sockets;
2202         }
2203         else /* if (se->type == SOCKENT_TYPE_CLIENT) */
2204         {
2205                 if (sending_sockets == NULL)
2206                 {
2207                         sending_sockets = se;
2208                         return (0);
2209                 }
2210                 last_ptr = sending_sockets;
2211         }
2212
2213         while (last_ptr->next != NULL)
2214                 last_ptr = last_ptr->next;
2215         last_ptr->next = se;
2216
2217         return (0);
2218 } /* }}} int sockent_add */
2219
2220 static void *dispatch_thread (void __attribute__((unused)) *arg) /* {{{ */
2221 {
2222   while (42)
2223   {
2224     receive_list_entry_t *ent;
2225     sockent_t *se;
2226
2227     /* Lock and wait for more data to come in */
2228     pthread_mutex_lock (&receive_list_lock);
2229     while ((listen_loop == 0)
2230         && (receive_list_head == NULL))
2231       pthread_cond_wait (&receive_list_cond, &receive_list_lock);
2232
2233     /* Remove the head entry and unlock */
2234     ent = receive_list_head;
2235     if (ent != NULL)
2236       receive_list_head = ent->next;
2237     receive_list_length--;
2238     pthread_mutex_unlock (&receive_list_lock);
2239
2240     /* Check whether we are supposed to exit. We do NOT check `listen_loop'
2241      * because we dispatch all missing packets before shutting down. */
2242     if (ent == NULL)
2243       break;
2244
2245     /* Look for the correct `sockent_t' */
2246     se = listen_sockets;
2247     while (se != NULL)
2248     {
2249       size_t i;
2250
2251       for (i = 0; i < se->data.server.fd_num; i++)
2252         if (se->data.server.fd[i] == ent->fd)
2253           break;
2254
2255       if (i < se->data.server.fd_num)
2256         break;
2257
2258       se = se->next;
2259     }
2260
2261     if (se == NULL)
2262     {
2263       ERROR ("network plugin: Got packet from FD %i, but can't "
2264           "find an appropriate socket entry.",
2265           ent->fd);
2266       sfree (ent->data);
2267       sfree (ent);
2268       continue;
2269     }
2270
2271     parse_packet (se, ent->data, ent->data_len, /* flags = */ 0,
2272         /* username = */ NULL);
2273     sfree (ent->data);
2274     sfree (ent);
2275   } /* while (42) */
2276
2277   return (NULL);
2278 } /* }}} void *dispatch_thread */
2279
2280 static int network_receive (void) /* {{{ */
2281 {
2282         char buffer[network_config_packet_size];
2283         int  buffer_len;
2284
2285         int i;
2286         int status;
2287
2288         receive_list_entry_t *private_list_head;
2289         receive_list_entry_t *private_list_tail;
2290         uint64_t              private_list_length;
2291
2292         assert (listen_sockets_num > 0);
2293
2294         private_list_head = NULL;
2295         private_list_tail = NULL;
2296         private_list_length = 0;
2297
2298         while (listen_loop == 0)
2299         {
2300                 status = poll (listen_sockets_pollfd, listen_sockets_num, -1);
2301
2302                 if (status <= 0)
2303                 {
2304                         char errbuf[1024];
2305                         if (errno == EINTR)
2306                                 continue;
2307                         ERROR ("poll failed: %s",
2308                                         sstrerror (errno, errbuf, sizeof (errbuf)));
2309                         return (-1);
2310                 }
2311
2312                 for (i = 0; (i < listen_sockets_num) && (status > 0); i++)
2313                 {
2314                         receive_list_entry_t *ent;
2315
2316                         if ((listen_sockets_pollfd[i].revents
2317                                                 & (POLLIN | POLLPRI)) == 0)
2318                                 continue;
2319                         status--;
2320
2321                         buffer_len = recv (listen_sockets_pollfd[i].fd,
2322                                         buffer, sizeof (buffer),
2323                                         0 /* no flags */);
2324                         if (buffer_len < 0)
2325                         {
2326                                 char errbuf[1024];
2327                                 ERROR ("recv failed: %s",
2328                                                 sstrerror (errno, errbuf,
2329                                                         sizeof (errbuf)));
2330                                 return (-1);
2331                         }
2332
2333                         stats_octets_rx += ((uint64_t) buffer_len);
2334                         stats_packets_rx++;
2335
2336                         /* TODO: Possible performance enhancement: Do not free
2337                          * these entries in the dispatch thread but put them in
2338                          * another list, so we don't have to allocate more and
2339                          * more of these structures. */
2340                         ent = malloc (sizeof (receive_list_entry_t));
2341                         if (ent == NULL)
2342                         {
2343                                 ERROR ("network plugin: malloc failed.");
2344                                 return (-1);
2345                         }
2346                         memset (ent, 0, sizeof (receive_list_entry_t));
2347                         ent->data = malloc (network_config_packet_size);
2348                         if (ent->data == NULL)
2349                         {
2350                                 sfree (ent);
2351                                 ERROR ("network plugin: malloc failed.");
2352                                 return (-1);
2353                         }
2354                         ent->fd = listen_sockets_pollfd[i].fd;
2355                         ent->next = NULL;
2356
2357                         memcpy (ent->data, buffer, buffer_len);
2358                         ent->data_len = buffer_len;
2359
2360                         if (private_list_head == NULL)
2361                                 private_list_head = ent;
2362                         else
2363                                 private_list_tail->next = ent;
2364                         private_list_tail = ent;
2365                         private_list_length++;
2366
2367                         /* Do not block here. Blocking here has led to
2368                          * insufficient performance in the past. */
2369                         if (pthread_mutex_trylock (&receive_list_lock) == 0)
2370                         {
2371                                 assert (((receive_list_head == NULL) && (receive_list_length == 0))
2372                                                 || ((receive_list_head != NULL) && (receive_list_length != 0)));
2373
2374                                 if (receive_list_head == NULL)
2375                                         receive_list_head = private_list_head;
2376                                 else
2377                                         receive_list_tail->next = private_list_head;
2378                                 receive_list_tail = private_list_tail;
2379                                 receive_list_length += private_list_length;
2380
2381                                 pthread_cond_signal (&receive_list_cond);
2382                                 pthread_mutex_unlock (&receive_list_lock);
2383
2384                                 private_list_head = NULL;
2385                                 private_list_tail = NULL;
2386                                 private_list_length = 0;
2387                         }
2388                 } /* for (listen_sockets_pollfd) */
2389         } /* while (listen_loop == 0) */
2390
2391         /* Make sure everything is dispatched before exiting. */
2392         if (private_list_head != NULL)
2393         {
2394                 pthread_mutex_lock (&receive_list_lock);
2395
2396                 if (receive_list_head == NULL)
2397                         receive_list_head = private_list_head;
2398                 else
2399                         receive_list_tail->next = private_list_head;
2400                 receive_list_tail = private_list_tail;
2401                 receive_list_length += private_list_length;
2402
2403                 private_list_head = NULL;
2404                 private_list_tail = NULL;
2405                 private_list_length = 0;
2406
2407                 pthread_cond_signal (&receive_list_cond);
2408                 pthread_mutex_unlock (&receive_list_lock);
2409         }
2410
2411         return (0);
2412 } /* }}} int network_receive */
2413
2414 static void *receive_thread (void __attribute__((unused)) *arg)
2415 {
2416         return (network_receive () ? (void *) 1 : (void *) 0);
2417 } /* void *receive_thread */
2418
2419 static void network_init_buffer (void)
2420 {
2421         memset (send_buffer, 0, network_config_packet_size);
2422         send_buffer_ptr = send_buffer;
2423         send_buffer_fill = 0;
2424
2425         memset (&send_buffer_vl, 0, sizeof (send_buffer_vl));
2426 } /* int network_init_buffer */
2427
2428 static void networt_send_buffer_plain (const sockent_t *se, /* {{{ */
2429                 const char *buffer, size_t buffer_size)
2430 {
2431         int status;
2432
2433         while (42)
2434         {
2435                 status = sendto (se->data.client.fd, buffer, buffer_size,
2436                     /* flags = */ 0,
2437                     (struct sockaddr *) se->data.client.addr,
2438                     se->data.client.addrlen);
2439                 if (status < 0)
2440                 {
2441                         char errbuf[1024];
2442                         if (errno == EINTR)
2443                                 continue;
2444                         ERROR ("network plugin: sendto failed: %s",
2445                                         sstrerror (errno, errbuf,
2446                                                 sizeof (errbuf)));
2447                         break;
2448                 }
2449
2450                 break;
2451         } /* while (42) */
2452 } /* }}} void networt_send_buffer_plain */
2453
2454 #if HAVE_LIBGCRYPT
2455 #define BUFFER_ADD(p,s) do { \
2456   memcpy (buffer + buffer_offset, (p), (s)); \
2457   buffer_offset += (s); \
2458 } while (0)
2459
2460 static void networt_send_buffer_signed (const sockent_t *se, /* {{{ */
2461                 const char *in_buffer, size_t in_buffer_size)
2462 {
2463   part_signature_sha256_t ps;
2464   char buffer[BUFF_SIG_SIZE + in_buffer_size];
2465   size_t buffer_offset;
2466   size_t username_len;
2467
2468   gcry_md_hd_t hd;
2469   gcry_error_t err;
2470   unsigned char *hash;
2471
2472   hd = NULL;
2473   err = gcry_md_open (&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
2474   if (err != 0)
2475   {
2476     ERROR ("network plugin: Creating HMAC object failed: %s",
2477         gcry_strerror (err));
2478     return;
2479   }
2480
2481   err = gcry_md_setkey (hd, se->data.client.password,
2482       strlen (se->data.client.password));
2483   if (err != 0)
2484   {
2485     ERROR ("network plugin: gcry_md_setkey failed: %s",
2486         gcry_strerror (err));
2487     gcry_md_close (hd);
2488     return;
2489   }
2490
2491   username_len = strlen (se->data.client.username);
2492   if (username_len > (BUFF_SIG_SIZE - PART_SIGNATURE_SHA256_SIZE))
2493   {
2494     ERROR ("network plugin: Username too long: %s",
2495         se->data.client.username);
2496     return;
2497   }
2498
2499   memcpy (buffer + PART_SIGNATURE_SHA256_SIZE,
2500       se->data.client.username, username_len);
2501   memcpy (buffer + PART_SIGNATURE_SHA256_SIZE + username_len,
2502       in_buffer, in_buffer_size);
2503
2504   /* Initialize the `ps' structure. */
2505   memset (&ps, 0, sizeof (ps));
2506   ps.head.type = htons (TYPE_SIGN_SHA256);
2507   ps.head.length = htons (PART_SIGNATURE_SHA256_SIZE + username_len);
2508
2509   /* Calculate the hash value. */
2510   gcry_md_write (hd, buffer + PART_SIGNATURE_SHA256_SIZE,
2511       username_len + in_buffer_size);
2512   hash = gcry_md_read (hd, GCRY_MD_SHA256);
2513   if (hash == NULL)
2514   {
2515     ERROR ("network plugin: gcry_md_read failed.");
2516     gcry_md_close (hd);
2517     return;
2518   }
2519   memcpy (ps.hash, hash, sizeof (ps.hash));
2520
2521   /* Add the header */
2522   buffer_offset = 0;
2523
2524   BUFFER_ADD (&ps.head.type, sizeof (ps.head.type));
2525   BUFFER_ADD (&ps.head.length, sizeof (ps.head.length));
2526   BUFFER_ADD (ps.hash, sizeof (ps.hash));
2527
2528   assert (buffer_offset == PART_SIGNATURE_SHA256_SIZE);
2529
2530   gcry_md_close (hd);
2531   hd = NULL;
2532
2533   buffer_offset = PART_SIGNATURE_SHA256_SIZE + username_len + in_buffer_size;
2534   networt_send_buffer_plain (se, buffer, buffer_offset);
2535 } /* }}} void networt_send_buffer_signed */
2536
2537 static void networt_send_buffer_encrypted (sockent_t *se, /* {{{ */
2538                 const char *in_buffer, size_t in_buffer_size)
2539 {
2540   part_encryption_aes256_t pea;
2541   char buffer[BUFF_SIG_SIZE + in_buffer_size];
2542   size_t buffer_size;
2543   size_t buffer_offset;
2544   size_t header_size;
2545   size_t username_len;
2546   gcry_error_t err;
2547   gcry_cipher_hd_t cypher;
2548
2549   /* Initialize the header fields */
2550   memset (&pea, 0, sizeof (pea));
2551   pea.head.type = htons (TYPE_ENCR_AES256);
2552
2553   pea.username = se->data.client.username;
2554
2555   username_len = strlen (pea.username);
2556   if ((PART_ENCRYPTION_AES256_SIZE + username_len) > BUFF_SIG_SIZE)
2557   {
2558     ERROR ("network plugin: Username too long: %s", pea.username);
2559     return;
2560   }
2561
2562   buffer_size = PART_ENCRYPTION_AES256_SIZE + username_len + in_buffer_size;
2563   header_size = PART_ENCRYPTION_AES256_SIZE + username_len
2564     - sizeof (pea.hash);
2565
2566   assert (buffer_size <= sizeof (buffer));
2567   DEBUG ("network plugin: networt_send_buffer_encrypted: "
2568       "buffer_size = %zu;", buffer_size);
2569
2570   pea.head.length = htons ((uint16_t) (PART_ENCRYPTION_AES256_SIZE
2571         + username_len + in_buffer_size));
2572   pea.username_length = htons ((uint16_t) username_len);
2573
2574   /* Chose a random initialization vector. */
2575   gcry_randomize ((void *) &pea.iv, sizeof (pea.iv), GCRY_STRONG_RANDOM);
2576
2577   /* Create hash of the payload */
2578   gcry_md_hash_buffer (GCRY_MD_SHA1, pea.hash, in_buffer, in_buffer_size);
2579
2580   /* Initialize the buffer */
2581   buffer_offset = 0;
2582   memset (buffer, 0, sizeof (buffer));
2583
2584
2585   BUFFER_ADD (&pea.head.type, sizeof (pea.head.type));
2586   BUFFER_ADD (&pea.head.length, sizeof (pea.head.length));
2587   BUFFER_ADD (&pea.username_length, sizeof (pea.username_length));
2588   BUFFER_ADD (pea.username, username_len);
2589   BUFFER_ADD (pea.iv, sizeof (pea.iv));
2590   assert (buffer_offset == header_size);
2591   BUFFER_ADD (pea.hash, sizeof (pea.hash));
2592   BUFFER_ADD (in_buffer, in_buffer_size);
2593
2594   assert (buffer_offset == buffer_size);
2595
2596   cypher = network_get_aes256_cypher (se, pea.iv, sizeof (pea.iv),
2597       se->data.client.password);
2598   if (cypher == NULL)
2599     return;
2600
2601   /* Encrypt the buffer in-place */
2602   err = gcry_cipher_encrypt (cypher,
2603       buffer      + header_size,
2604       buffer_size - header_size,
2605       /* in = */ NULL, /* in len = */ 0);
2606   if (err != 0)
2607   {
2608     ERROR ("network plugin: gcry_cipher_encrypt returned: %s",
2609         gcry_strerror (err));
2610     return;
2611   }
2612
2613   /* Send it out without further modifications */
2614   networt_send_buffer_plain (se, buffer, buffer_size);
2615 } /* }}} void networt_send_buffer_encrypted */
2616 #undef BUFFER_ADD
2617 #endif /* HAVE_LIBGCRYPT */
2618
2619 static void network_send_buffer (char *buffer, size_t buffer_len) /* {{{ */
2620 {
2621   sockent_t *se;
2622
2623   DEBUG ("network plugin: network_send_buffer: buffer_len = %zu", buffer_len);
2624
2625   for (se = sending_sockets; se != NULL; se = se->next)
2626   {
2627 #if HAVE_LIBGCRYPT
2628     if (se->data.client.security_level == SECURITY_LEVEL_ENCRYPT)
2629       networt_send_buffer_encrypted (se, buffer, buffer_len);
2630     else if (se->data.client.security_level == SECURITY_LEVEL_SIGN)
2631       networt_send_buffer_signed (se, buffer, buffer_len);
2632     else /* if (se->data.client.security_level == SECURITY_LEVEL_NONE) */
2633 #endif /* HAVE_LIBGCRYPT */
2634       networt_send_buffer_plain (se, buffer, buffer_len);
2635   } /* for (sending_sockets) */
2636 } /* }}} void network_send_buffer */
2637
2638 static int add_to_buffer (char *buffer, int buffer_size, /* {{{ */
2639                 value_list_t *vl_def,
2640                 const data_set_t *ds, const value_list_t *vl)
2641 {
2642         char *buffer_orig = buffer;
2643
2644         if (strcmp (vl_def->host, vl->host) != 0)
2645         {
2646                 if (write_part_string (&buffer, &buffer_size, TYPE_HOST,
2647                                         vl->host, strlen (vl->host)) != 0)
2648                         return (-1);
2649                 sstrncpy (vl_def->host, vl->host, sizeof (vl_def->host));
2650         }
2651
2652         if (vl_def->time != vl->time)
2653         {
2654                 if (write_part_number (&buffer, &buffer_size, TYPE_TIME,
2655                                         (uint64_t) vl->time))
2656                         return (-1);
2657                 vl_def->time = vl->time;
2658         }
2659
2660         if (vl_def->interval != vl->interval)
2661         {
2662                 if (write_part_number (&buffer, &buffer_size, TYPE_INTERVAL,
2663                                         (uint64_t) vl->interval))
2664                         return (-1);
2665                 vl_def->interval = vl->interval;
2666         }
2667
2668         if (strcmp (vl_def->plugin, vl->plugin) != 0)
2669         {
2670                 if (write_part_string (&buffer, &buffer_size, TYPE_PLUGIN,
2671                                         vl->plugin, strlen (vl->plugin)) != 0)
2672                         return (-1);
2673                 sstrncpy (vl_def->plugin, vl->plugin, sizeof (vl_def->plugin));
2674         }
2675
2676         if (strcmp (vl_def->plugin_instance, vl->plugin_instance) != 0)
2677         {
2678                 if (write_part_string (&buffer, &buffer_size, TYPE_PLUGIN_INSTANCE,
2679                                         vl->plugin_instance,
2680                                         strlen (vl->plugin_instance)) != 0)
2681                         return (-1);
2682                 sstrncpy (vl_def->plugin_instance, vl->plugin_instance, sizeof (vl_def->plugin_instance));
2683         }
2684
2685         if (strcmp (vl_def->type, vl->type) != 0)
2686         {
2687                 if (write_part_string (&buffer, &buffer_size, TYPE_TYPE,
2688                                         vl->type, strlen (vl->type)) != 0)
2689                         return (-1);
2690                 sstrncpy (vl_def->type, ds->type, sizeof (vl_def->type));
2691         }
2692
2693         if (strcmp (vl_def->type_instance, vl->type_instance) != 0)
2694         {
2695                 if (write_part_string (&buffer, &buffer_size, TYPE_TYPE_INSTANCE,
2696                                         vl->type_instance,
2697                                         strlen (vl->type_instance)) != 0)
2698                         return (-1);
2699                 sstrncpy (vl_def->type_instance, vl->type_instance, sizeof (vl_def->type_instance));
2700         }
2701         
2702         if (write_part_values (&buffer, &buffer_size, ds, vl) != 0)
2703                 return (-1);
2704
2705         return (buffer - buffer_orig);
2706 } /* }}} int add_to_buffer */
2707
2708 static void flush_buffer (void)
2709 {
2710         DEBUG ("network plugin: flush_buffer: send_buffer_fill = %i",
2711                         send_buffer_fill);
2712
2713         network_send_buffer (send_buffer, (size_t) send_buffer_fill);
2714
2715         stats_octets_tx += ((uint64_t) send_buffer_fill);
2716         stats_packets_tx++;
2717
2718         network_init_buffer ();
2719 }
2720
2721 static int network_write (const data_set_t *ds, const value_list_t *vl,
2722                 user_data_t __attribute__((unused)) *user_data)
2723 {
2724         int status;
2725
2726         if (!check_send_okay (vl))
2727         {
2728 #if COLLECT_DEBUG
2729           char name[6*DATA_MAX_NAME_LEN];
2730           FORMAT_VL (name, sizeof (name), vl);
2731           name[sizeof (name) - 1] = 0;
2732           DEBUG ("network plugin: network_write: "
2733               "NOT sending %s.", name);
2734 #endif
2735           /* Counter is not protected by another lock and may be reached by
2736            * multiple threads */
2737           pthread_mutex_lock (&stats_lock);
2738           stats_values_not_sent++;
2739           pthread_mutex_unlock (&stats_lock);
2740           return (0);
2741         }
2742
2743         uc_meta_data_add_unsigned_int (vl,
2744             "network:time_sent", (uint64_t) vl->time);
2745
2746         pthread_mutex_lock (&send_buffer_lock);
2747
2748         status = add_to_buffer (send_buffer_ptr,
2749                         network_config_packet_size - (send_buffer_fill + BUFF_SIG_SIZE),
2750                         &send_buffer_vl,
2751                         ds, vl);
2752         if (status >= 0)
2753         {
2754                 /* status == bytes added to the buffer */
2755                 send_buffer_fill += status;
2756                 send_buffer_ptr  += status;
2757
2758                 stats_values_sent++;
2759         }
2760         else
2761         {
2762                 flush_buffer ();
2763
2764                 status = add_to_buffer (send_buffer_ptr,
2765                                 network_config_packet_size - (send_buffer_fill + BUFF_SIG_SIZE),
2766                                 &send_buffer_vl,
2767                                 ds, vl);
2768
2769                 if (status >= 0)
2770                 {
2771                         send_buffer_fill += status;
2772                         send_buffer_ptr  += status;
2773
2774                         stats_values_sent++;
2775                 }
2776         }
2777
2778         if (status < 0)
2779         {
2780                 ERROR ("network plugin: Unable to append to the "
2781                                 "buffer for some weird reason");
2782         }
2783         else if ((network_config_packet_size - send_buffer_fill) < 15)
2784         {
2785                 flush_buffer ();
2786         }
2787
2788         pthread_mutex_unlock (&send_buffer_lock);
2789
2790         return ((status < 0) ? -1 : 0);
2791 } /* int network_write */
2792
2793 static int network_config_set_boolean (const oconfig_item_t *ci, /* {{{ */
2794     int *retval)
2795 {
2796   if ((ci->values_num != 1)
2797       || ((ci->values[0].type != OCONFIG_TYPE_BOOLEAN)
2798         && (ci->values[0].type != OCONFIG_TYPE_STRING)))
2799   {
2800     ERROR ("network plugin: The `%s' config option needs "
2801         "exactly one boolean argument.", ci->key);
2802     return (-1);
2803   }
2804
2805   if (ci->values[0].type == OCONFIG_TYPE_BOOLEAN)
2806   {
2807     if (ci->values[0].value.boolean)
2808       *retval = 1;
2809     else
2810       *retval = 0;
2811   }
2812   else
2813   {
2814     char *str = ci->values[0].value.string;
2815
2816     if (IS_TRUE (str))
2817       *retval = 1;
2818     else if (IS_FALSE (str))
2819       *retval = 0;
2820     else
2821     {
2822       ERROR ("network plugin: Cannot parse string value `%s' of the `%s' "
2823           "option as boolean value.",
2824           str, ci->key);
2825       return (-1);
2826     }
2827   }
2828
2829   return (0);
2830 } /* }}} int network_config_set_boolean */
2831
2832 static int network_config_set_ttl (const oconfig_item_t *ci) /* {{{ */
2833 {
2834   int tmp;
2835   if ((ci->values_num != 1)
2836       || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
2837   {
2838     WARNING ("network plugin: The `TimeToLive' config option needs exactly "
2839         "one numeric argument.");
2840     return (-1);
2841   }
2842
2843   tmp = (int) ci->values[0].value.number;
2844   if ((tmp > 0) && (tmp <= 255))
2845     network_config_ttl = tmp;
2846
2847   return (0);
2848 } /* }}} int network_config_set_ttl */
2849
2850 static int network_config_set_interface (const oconfig_item_t *ci, /* {{{ */
2851     int *interface)
2852 {
2853   if ((ci->values_num != 1)
2854       || (ci->values[0].type != OCONFIG_TYPE_STRING))
2855   {
2856     WARNING ("network plugin: The `Interface' config option needs exactly "
2857         "one string argument.");
2858     return (-1);
2859   }
2860
2861   if (interface == NULL)
2862     return (-1);
2863
2864   *interface = if_nametoindex (ci->values[0].value.string);
2865
2866   return (0);
2867 } /* }}} int network_config_set_interface */
2868
2869 static int network_config_set_buffer_size (const oconfig_item_t *ci) /* {{{ */
2870 {
2871   int tmp;
2872   if ((ci->values_num != 1)
2873       || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
2874   {
2875     WARNING ("network plugin: The `MaxPacketSize' config option needs exactly "
2876         "one numeric argument.");
2877     return (-1);
2878   }
2879
2880   tmp = (int) ci->values[0].value.number;
2881   if ((tmp >= 1024) && (tmp <= 65535))
2882     network_config_packet_size = tmp;
2883
2884   return (0);
2885 } /* }}} int network_config_set_buffer_size */
2886
2887 #if HAVE_LIBGCRYPT
2888 static int network_config_set_string (const oconfig_item_t *ci, /* {{{ */
2889     char **ret_string)
2890 {
2891   char *tmp;
2892   if ((ci->values_num != 1)
2893       || (ci->values[0].type != OCONFIG_TYPE_STRING))
2894   {
2895     WARNING ("network plugin: The `%s' config option needs exactly "
2896         "one string argument.", ci->key);
2897     return (-1);
2898   }
2899
2900   tmp = strdup (ci->values[0].value.string);
2901   if (tmp == NULL)
2902     return (-1);
2903
2904   sfree (*ret_string);
2905   *ret_string = tmp;
2906
2907   return (0);
2908 } /* }}} int network_config_set_string */
2909 #endif /* HAVE_LIBGCRYPT */
2910
2911 #if HAVE_LIBGCRYPT
2912 static int network_config_set_security_level (oconfig_item_t *ci, /* {{{ */
2913     int *retval)
2914 {
2915   char *str;
2916   if ((ci->values_num != 1)
2917       || (ci->values[0].type != OCONFIG_TYPE_STRING))
2918   {
2919     WARNING ("network plugin: The `SecurityLevel' config option needs exactly "
2920         "one string argument.");
2921     return (-1);
2922   }
2923
2924   str = ci->values[0].value.string;
2925   if (strcasecmp ("Encrypt", str) == 0)
2926     *retval = SECURITY_LEVEL_ENCRYPT;
2927   else if (strcasecmp ("Sign", str) == 0)
2928     *retval = SECURITY_LEVEL_SIGN;
2929   else if (strcasecmp ("None", str) == 0)
2930     *retval = SECURITY_LEVEL_NONE;
2931   else
2932   {
2933     WARNING ("network plugin: Unknown security level: %s.", str);
2934     return (-1);
2935   }
2936
2937   return (0);
2938 } /* }}} int network_config_set_security_level */
2939 #endif /* HAVE_LIBGCRYPT */
2940
2941 static int network_config_add_listen (const oconfig_item_t *ci) /* {{{ */
2942 {
2943   sockent_t *se;
2944   int status;
2945   int i;
2946
2947   if ((ci->values_num < 1) || (ci->values_num > 2)
2948       || (ci->values[0].type != OCONFIG_TYPE_STRING)
2949       || ((ci->values_num > 1) && (ci->values[1].type != OCONFIG_TYPE_STRING)))
2950   {
2951     ERROR ("network plugin: The `%s' config option needs "
2952         "one or two string arguments.", ci->key);
2953     return (-1);
2954   }
2955
2956   se = malloc (sizeof (*se));
2957   if (se == NULL)
2958   {
2959     ERROR ("network plugin: malloc failed.");
2960     return (-1);
2961   }
2962   sockent_init (se, SOCKENT_TYPE_SERVER);
2963
2964   se->node = strdup (ci->values[0].value.string);
2965   if (ci->values_num >= 2)
2966     se->service = strdup (ci->values[1].value.string);
2967
2968   for (i = 0; i < ci->children_num; i++)
2969   {
2970     oconfig_item_t *child = ci->children + i;
2971
2972 #if HAVE_LIBGCRYPT
2973     if (strcasecmp ("AuthFile", child->key) == 0)
2974       network_config_set_string (child, &se->data.server.auth_file);
2975     else if (strcasecmp ("SecurityLevel", child->key) == 0)
2976       network_config_set_security_level (child,
2977           &se->data.server.security_level);
2978     else
2979 #endif /* HAVE_LIBGCRYPT */
2980     if (strcasecmp ("Interface", child->key) == 0)
2981       network_config_set_interface (child,
2982           &se->interface);
2983     else
2984     {
2985       WARNING ("network plugin: Option `%s' is not allowed here.",
2986           child->key);
2987     }
2988   }
2989
2990 #if HAVE_LIBGCRYPT
2991   if ((se->data.server.security_level > SECURITY_LEVEL_NONE)
2992       && (se->data.server.auth_file == NULL))
2993   {
2994     ERROR ("network plugin: A security level higher than `none' was "
2995         "requested, but no AuthFile option was given. Cowardly refusing to "
2996         "open this socket!");
2997     sockent_destroy (se);
2998     return (-1);
2999   }
3000 #endif /* HAVE_LIBGCRYPT */
3001
3002   status = sockent_open (se);
3003   if (status != 0)
3004   {
3005     ERROR ("network plugin: network_config_add_listen: sockent_open failed.");
3006     sockent_destroy (se);
3007     return (-1);
3008   }
3009
3010   status = sockent_add (se);
3011   if (status != 0)
3012   {
3013     ERROR ("network plugin: network_config_add_listen: sockent_add failed.");
3014     sockent_destroy (se);
3015     return (-1);
3016   }
3017
3018   return (0);
3019 } /* }}} int network_config_add_listen */
3020
3021 static int network_config_add_server (const oconfig_item_t *ci) /* {{{ */
3022 {
3023   sockent_t *se;
3024   int status;
3025   int i;
3026
3027   if ((ci->values_num < 1) || (ci->values_num > 2)
3028       || (ci->values[0].type != OCONFIG_TYPE_STRING)
3029       || ((ci->values_num > 1) && (ci->values[1].type != OCONFIG_TYPE_STRING)))
3030   {
3031     ERROR ("network plugin: The `%s' config option needs "
3032         "one or two string arguments.", ci->key);
3033     return (-1);
3034   }
3035
3036   se = malloc (sizeof (*se));
3037   if (se == NULL)
3038   {
3039     ERROR ("network plugin: malloc failed.");
3040     return (-1);
3041   }
3042   sockent_init (se, SOCKENT_TYPE_CLIENT);
3043
3044   se->node = strdup (ci->values[0].value.string);
3045   if (ci->values_num >= 2)
3046     se->service = strdup (ci->values[1].value.string);
3047
3048   for (i = 0; i < ci->children_num; i++)
3049   {
3050     oconfig_item_t *child = ci->children + i;
3051
3052 #if HAVE_LIBGCRYPT
3053     if (strcasecmp ("Username", child->key) == 0)
3054       network_config_set_string (child, &se->data.client.username);
3055     else if (strcasecmp ("Password", child->key) == 0)
3056       network_config_set_string (child, &se->data.client.password);
3057     else if (strcasecmp ("SecurityLevel", child->key) == 0)
3058       network_config_set_security_level (child,
3059           &se->data.client.security_level);
3060     else
3061 #endif /* HAVE_LIBGCRYPT */
3062     if (strcasecmp ("Interface", child->key) == 0)
3063       network_config_set_interface (child,
3064           &se->interface);
3065     else
3066     {
3067       WARNING ("network plugin: Option `%s' is not allowed here.",
3068           child->key);
3069     }
3070   }
3071
3072 #if HAVE_LIBGCRYPT
3073   if ((se->data.client.security_level > SECURITY_LEVEL_NONE)
3074       && ((se->data.client.username == NULL)
3075         || (se->data.client.password == NULL)))
3076   {
3077     ERROR ("network plugin: A security level higher than `none' was "
3078         "requested, but no Username or Password option was given. "
3079         "Cowardly refusing to open this socket!");
3080     sockent_destroy (se);
3081     return (-1);
3082   }
3083 #endif /* HAVE_LIBGCRYPT */
3084
3085   status = sockent_open (se);
3086   if (status != 0)
3087   {
3088     ERROR ("network plugin: network_config_add_server: sockent_open failed.");
3089     sockent_destroy (se);
3090     return (-1);
3091   }
3092
3093   status = sockent_add (se);
3094   if (status != 0)
3095   {
3096     ERROR ("network plugin: network_config_add_server: sockent_add failed.");
3097     sockent_destroy (se);
3098     return (-1);
3099   }
3100
3101   return (0);
3102 } /* }}} int network_config_add_server */
3103
3104 static int network_config (oconfig_item_t *ci) /* {{{ */
3105 {
3106   int i;
3107
3108   for (i = 0; i < ci->children_num; i++)
3109   {
3110     oconfig_item_t *child = ci->children + i;
3111
3112     if (strcasecmp ("Listen", child->key) == 0)
3113       network_config_add_listen (child);
3114     else if (strcasecmp ("Server", child->key) == 0)
3115       network_config_add_server (child);
3116     else if (strcasecmp ("TimeToLive", child->key) == 0)
3117       network_config_set_ttl (child);
3118     else if (strcasecmp ("MaxPacketSize", child->key) == 0)
3119       network_config_set_buffer_size (child);
3120     else if (strcasecmp ("Forward", child->key) == 0)
3121       network_config_set_boolean (child, &network_config_forward);
3122     else if (strcasecmp ("ReportStats", child->key) == 0)
3123       network_config_set_boolean (child, &network_config_stats);
3124     else if (strcasecmp ("CacheFlush", child->key) == 0)
3125       /* no op for backwards compatibility only */;
3126     else
3127     {
3128       WARNING ("network plugin: Option `%s' is not allowed here.",
3129           child->key);
3130     }
3131   }
3132
3133   return (0);
3134 } /* }}} int network_config */
3135
3136 static int network_notification (const notification_t *n,
3137     user_data_t __attribute__((unused)) *user_data)
3138 {
3139   char  buffer[network_config_packet_size];
3140   char *buffer_ptr = buffer;
3141   int   buffer_free = sizeof (buffer);
3142   int   status;
3143
3144   if (!check_send_notify_okay (n))
3145     return (0);
3146
3147   memset (buffer, 0, sizeof (buffer));
3148
3149   status = write_part_number (&buffer_ptr, &buffer_free, TYPE_TIME,
3150       (uint64_t) n->time);
3151   if (status != 0)
3152     return (-1);
3153
3154   status = write_part_number (&buffer_ptr, &buffer_free, TYPE_SEVERITY,
3155       (uint64_t) n->severity);
3156   if (status != 0)
3157     return (-1);
3158
3159   if (strlen (n->host) > 0)
3160   {
3161     status = write_part_string (&buffer_ptr, &buffer_free, TYPE_HOST,
3162         n->host, strlen (n->host));
3163     if (status != 0)
3164       return (-1);
3165   }
3166
3167   if (strlen (n->plugin) > 0)
3168   {
3169     status = write_part_string (&buffer_ptr, &buffer_free, TYPE_PLUGIN,
3170         n->plugin, strlen (n->plugin));
3171     if (status != 0)
3172       return (-1);
3173   }
3174
3175   if (strlen (n->plugin_instance) > 0)
3176   {
3177     status = write_part_string (&buffer_ptr, &buffer_free,
3178         TYPE_PLUGIN_INSTANCE,
3179         n->plugin_instance, strlen (n->plugin_instance));
3180     if (status != 0)
3181       return (-1);
3182   }
3183
3184   if (strlen (n->type) > 0)
3185   {
3186     status = write_part_string (&buffer_ptr, &buffer_free, TYPE_TYPE,
3187         n->type, strlen (n->type));
3188     if (status != 0)
3189       return (-1);
3190   }
3191
3192   if (strlen (n->type_instance) > 0)
3193   {
3194     status = write_part_string (&buffer_ptr, &buffer_free, TYPE_TYPE_INSTANCE,
3195         n->type_instance, strlen (n->type_instance));
3196     if (status != 0)
3197       return (-1);
3198   }
3199
3200   status = write_part_string (&buffer_ptr, &buffer_free, TYPE_MESSAGE,
3201       n->message, strlen (n->message));
3202   if (status != 0)
3203     return (-1);
3204
3205   network_send_buffer (buffer, sizeof (buffer) - buffer_free);
3206
3207   return (0);
3208 } /* int network_notification */
3209
3210 static int network_shutdown (void)
3211 {
3212         listen_loop++;
3213
3214         /* Kill the listening thread */
3215         if (receive_thread_running != 0)
3216         {
3217                 INFO ("network plugin: Stopping receive thread.");
3218                 pthread_kill (receive_thread_id, SIGTERM);
3219                 pthread_join (receive_thread_id, NULL /* no return value */);
3220                 memset (&receive_thread_id, 0, sizeof (receive_thread_id));
3221                 receive_thread_running = 0;
3222         }
3223
3224         /* Shutdown the dispatching thread */
3225         if (dispatch_thread_running != 0)
3226         {
3227                 INFO ("network plugin: Stopping dispatch thread.");
3228                 pthread_mutex_lock (&receive_list_lock);
3229                 pthread_cond_broadcast (&receive_list_cond);
3230                 pthread_mutex_unlock (&receive_list_lock);
3231                 pthread_join (dispatch_thread_id, /* ret = */ NULL);
3232                 dispatch_thread_running = 0;
3233         }
3234
3235         sockent_destroy (listen_sockets);
3236
3237         if (send_buffer_fill > 0)
3238                 flush_buffer ();
3239
3240         sfree (send_buffer);
3241
3242         /* TODO: Close `sending_sockets' */
3243
3244         plugin_unregister_config ("network");
3245         plugin_unregister_init ("network");
3246         plugin_unregister_write ("network");
3247         plugin_unregister_shutdown ("network");
3248
3249         return (0);
3250 } /* int network_shutdown */
3251
3252 static int network_stats_read (void) /* {{{ */
3253 {
3254         uint64_t copy_octets_rx;
3255         uint64_t copy_octets_tx;
3256         uint64_t copy_packets_rx;
3257         uint64_t copy_packets_tx;
3258         uint64_t copy_values_dispatched;
3259         uint64_t copy_values_not_dispatched;
3260         uint64_t copy_values_sent;
3261         uint64_t copy_values_not_sent;
3262         uint64_t copy_receive_list_length;
3263         value_list_t vl = VALUE_LIST_INIT;
3264         value_t values[2];
3265
3266         copy_octets_rx = stats_octets_rx;
3267         copy_octets_tx = stats_octets_tx;
3268         copy_packets_rx = stats_packets_rx;
3269         copy_packets_tx = stats_packets_tx;
3270         copy_values_dispatched = stats_values_dispatched;
3271         copy_values_not_dispatched = stats_values_not_dispatched;
3272         copy_values_sent = stats_values_sent;
3273         copy_values_not_sent = stats_values_not_sent;
3274         copy_receive_list_length = receive_list_length;
3275
3276         /* Initialize `vl' */
3277         vl.values = values;
3278         vl.values_len = 2;
3279         vl.time = 0;
3280         vl.interval = interval_g;
3281         sstrncpy (vl.host, hostname_g, sizeof (vl.host));
3282         sstrncpy (vl.plugin, "network", sizeof (vl.plugin));
3283
3284         /* Octets received / sent */
3285         vl.values[0].counter = (counter_t) copy_octets_rx;
3286         vl.values[1].counter = (counter_t) copy_octets_tx;
3287         sstrncpy (vl.type, "if_octets", sizeof (vl.type));
3288         plugin_dispatch_values_secure (&vl);
3289
3290         /* Packets received / send */
3291         vl.values[0].counter = (counter_t) copy_packets_rx;
3292         vl.values[1].counter = (counter_t) copy_packets_tx;
3293         sstrncpy (vl.type, "if_packets", sizeof (vl.type));
3294         plugin_dispatch_values_secure (&vl);
3295
3296         /* Values (not) dispatched and (not) send */
3297         sstrncpy (vl.type, "total_values", sizeof (vl.type));
3298         vl.values_len = 1;
3299
3300         vl.values[0].derive = (derive_t) copy_values_dispatched;
3301         sstrncpy (vl.type_instance, "dispatch-accepted",
3302                         sizeof (vl.type_instance));
3303         plugin_dispatch_values_secure (&vl);
3304
3305         vl.values[0].derive = (derive_t) copy_values_not_dispatched;
3306         sstrncpy (vl.type_instance, "dispatch-rejected",
3307                         sizeof (vl.type_instance));
3308         plugin_dispatch_values_secure (&vl);
3309
3310         vl.values[0].derive = (derive_t) copy_values_sent;
3311         sstrncpy (vl.type_instance, "send-accepted",
3312                         sizeof (vl.type_instance));
3313         plugin_dispatch_values_secure (&vl);
3314
3315         vl.values[0].derive = (derive_t) copy_values_not_sent;
3316         sstrncpy (vl.type_instance, "send-rejected",
3317                         sizeof (vl.type_instance));
3318         plugin_dispatch_values_secure (&vl);
3319
3320         /* Receive queue length */
3321         vl.values[0].gauge = (gauge_t) copy_receive_list_length;
3322         sstrncpy (vl.type, "queue_length", sizeof (vl.type));
3323         vl.type_instance[0] = 0;
3324         plugin_dispatch_values_secure (&vl);
3325
3326         return (0);
3327 } /* }}} int network_stats_read */
3328
3329 static int network_init (void)
3330 {
3331         static _Bool have_init = false;
3332
3333         /* Check if we were already initialized. If so, just return - there's
3334          * nothing more to do (for now, that is). */
3335         if (have_init)
3336                 return (0);
3337         have_init = true;
3338
3339 #if HAVE_LIBGCRYPT
3340         gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
3341         gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0);
3342         gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
3343 #endif
3344
3345         if (network_config_stats != 0)
3346                 plugin_register_read ("network", network_stats_read);
3347
3348         plugin_register_shutdown ("network", network_shutdown);
3349
3350         send_buffer = malloc (network_config_packet_size);
3351         if (send_buffer == NULL)
3352         {
3353                 ERROR ("network plugin: malloc failed.");
3354                 return (-1);
3355         }
3356         network_init_buffer ();
3357
3358         /* setup socket(s) and so on */
3359         if (sending_sockets != NULL)
3360         {
3361                 plugin_register_write ("network", network_write,
3362                                 /* user_data = */ NULL);
3363                 plugin_register_notification ("network", network_notification,
3364                                 /* user_data = */ NULL);
3365         }
3366
3367         /* If no threads need to be started, return here. */
3368         if ((listen_sockets_num == 0)
3369                         || ((dispatch_thread_running != 0)
3370                                 && (receive_thread_running != 0)))
3371                 return (0);
3372
3373         if (dispatch_thread_running == 0)
3374         {
3375                 int status;
3376                 status = pthread_create (&dispatch_thread_id,
3377                                 NULL /* no attributes */,
3378                                 dispatch_thread,
3379                                 NULL /* no argument */);
3380                 if (status != 0)
3381                 {
3382                         char errbuf[1024];
3383                         ERROR ("network: pthread_create failed: %s",
3384                                         sstrerror (errno, errbuf,
3385                                                 sizeof (errbuf)));
3386                 }
3387                 else
3388                 {
3389                         dispatch_thread_running = 1;
3390                 }
3391         }
3392
3393         if (receive_thread_running == 0)
3394         {
3395                 int status;
3396                 status = pthread_create (&receive_thread_id,
3397                                 NULL /* no attributes */,
3398                                 receive_thread,
3399                                 NULL /* no argument */);
3400                 if (status != 0)
3401                 {
3402                         char errbuf[1024];
3403                         ERROR ("network: pthread_create failed: %s",
3404                                         sstrerror (errno, errbuf,
3405                                                 sizeof (errbuf)));
3406                 }
3407                 else
3408                 {
3409                         receive_thread_running = 1;
3410                 }
3411         }
3412
3413         return (0);
3414 } /* int network_init */
3415
3416 /* 
3417  * The flush option of the network plugin cannot flush individual identifiers.
3418  * All the values are added to a buffer and sent when the buffer is full, the
3419  * requested value may or may not be in there, it's not worth finding out. We
3420  * just send the buffer if `flush'  is called - if the requested value was in
3421  * there, good. If not, well, then there is nothing to flush.. -octo
3422  */
3423 static int network_flush (int timeout,
3424                 const char __attribute__((unused)) *identifier,
3425                 user_data_t __attribute__((unused)) *user_data)
3426 {
3427         pthread_mutex_lock (&send_buffer_lock);
3428
3429         if (send_buffer_fill > 0)
3430           flush_buffer ();
3431
3432         pthread_mutex_unlock (&send_buffer_lock);
3433
3434         return (0);
3435 } /* int network_flush */
3436
3437 void module_register (void)
3438 {
3439         plugin_register_complex_config ("network", network_config);
3440         plugin_register_init   ("network", network_init);
3441         plugin_register_flush   ("network", network_flush,
3442                         /* user_data = */ NULL);
3443 } /* void module_register */
3444
3445 /* vim: set fdm=marker : */