src/{common,network}.[ch]: Updated copyright information.
[collectd.git] / src / network.c
1 /**
2  * collectd - src/network.c
3  * Copyright (C) 2005-2008  Florian octo Forster
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; only version 2 of the License is applicable.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Authors:
19  *   Florian octo Forster <octo at verplant.org>
20  **/
21
22 #include "collectd.h"
23 #include "plugin.h"
24 #include "common.h"
25 #include "configfile.h"
26 #include "utils_avltree.h"
27
28 #include "network.h"
29
30 #if HAVE_PTHREAD_H
31 # include <pthread.h>
32 #endif
33 #if HAVE_SYS_SOCKET_H
34 # include <sys/socket.h>
35 #endif
36 #if HAVE_NETDB_H
37 # include <netdb.h>
38 #endif
39 #if HAVE_NETINET_IN_H
40 # include <netinet/in.h>
41 #endif
42 #if HAVE_ARPA_INET_H
43 # include <arpa/inet.h>
44 #endif
45 #if HAVE_POLL_H
46 # include <poll.h>
47 #endif
48
49 /* 1500 - 40 - 8  =  Ethernet packet - IPv6 header - UDP header */
50 /* #define BUFF_SIZE 1452 */
51
52 #ifndef IPV6_ADD_MEMBERSHIP
53 # ifdef IPV6_JOIN_GROUP
54 #  define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
55 # else
56 #  error "Neither IP_ADD_MEMBERSHIP nor IPV6_JOIN_GROUP is defined"
57 # endif
58 #endif /* !IP_ADD_MEMBERSHIP */
59
60 #define BUFF_SIZE 1024
61
62 /*
63  * Private data types
64  */
65 typedef struct sockent
66 {
67         int                      fd;
68         struct sockaddr_storage *addr;
69         socklen_t                addrlen;
70         struct sockent          *next;
71 } sockent_t;
72
73 /*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
74  *  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
75  * +-------+-----------------------+-------------------------------+
76  * ! Ver.  !                       ! Length                        !
77  * +-------+-----------------------+-------------------------------+
78  */
79 struct part_header_s
80 {
81         uint16_t type;
82         uint16_t length;
83 };
84 typedef struct part_header_s part_header_t;
85
86 /*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
87  *  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
88  * +-------------------------------+-------------------------------+
89  * ! Type                          ! Length                        !
90  * +-------------------------------+-------------------------------+
91  * : (Length - 4) Bytes                                            :
92  * +---------------------------------------------------------------+
93  */
94 struct part_string_s
95 {
96         part_header_t *head;
97         char *value;
98 };
99 typedef struct part_string_s part_string_t;
100
101 /*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
102  *  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
103  * +-------------------------------+-------------------------------+
104  * ! Type                          ! Length                        !
105  * +-------------------------------+-------------------------------+
106  * : (Length - 4 == 2 || 4 || 8) Bytes                             :
107  * +---------------------------------------------------------------+
108  */
109 struct part_number_s
110 {
111         part_header_t *head;
112         uint64_t *value;
113 };
114 typedef struct part_number_s part_number_t;
115
116 /*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
117  *  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
118  * +-------------------------------+-------------------------------+
119  * ! Type                          ! Length                        !
120  * +-------------------------------+---------------+---------------+
121  * ! Num of values                 ! Type0         ! Type1         !
122  * +-------------------------------+---------------+---------------+
123  * ! Value0                                                        !
124  * !                                                               !
125  * +---------------------------------------------------------------+
126  * ! Value1                                                        !
127  * !                                                               !
128  * +---------------------------------------------------------------+
129  */
130 struct part_values_s
131 {
132         part_header_t *head;
133         uint16_t *num_values;
134         uint8_t  *values_types;
135         value_t  *values;
136 };
137 typedef struct part_values_s part_values_t;
138
139 /*
140  * Private variables
141  */
142 static const char *config_keys[] =
143 {
144         "CacheFlush",
145         "Listen",
146         "Server",
147         "TimeToLive",
148         "Forward"
149 };
150 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
151
152 static int network_config_ttl = 0;
153 static int network_config_forward = 0;
154
155 static sockent_t *sending_sockets = NULL;
156
157 static struct pollfd *listen_sockets = NULL;
158 static int listen_sockets_num = 0;
159 static pthread_t listen_thread = 0;
160 static int listen_loop = 0;
161
162 static char         send_buffer[BUFF_SIZE];
163 static char        *send_buffer_ptr;
164 static int          send_buffer_fill;
165 static value_list_t send_buffer_vl = VALUE_LIST_STATIC;
166 static char         send_buffer_type[DATA_MAX_NAME_LEN];
167 static pthread_mutex_t send_buffer_lock = PTHREAD_MUTEX_INITIALIZER;
168
169 static c_avl_tree_t      *cache_tree = NULL;
170 static pthread_mutex_t  cache_lock = PTHREAD_MUTEX_INITIALIZER;
171 static time_t           cache_flush_last;
172 static int              cache_flush_interval = 1800;
173
174 /*
175  * Private functions
176  */
177 static int cache_flush (void)
178 {
179         char **keys = NULL;
180         int    keys_num = 0;
181
182         char **tmp;
183         int    i;
184
185         char   *key;
186         time_t *value;
187         c_avl_iterator_t *iter;
188
189         time_t curtime = time (NULL);
190
191         iter = c_avl_get_iterator (cache_tree);
192         while (c_avl_iterator_next (iter, (void *) &key, (void *) &value) == 0)
193         {
194                 if ((curtime - *value) <= cache_flush_interval)
195                         continue;
196                 tmp = (char **) realloc (keys,
197                                 (keys_num + 1) * sizeof (char *));
198                 if (tmp == NULL)
199                 {
200                         sfree (keys);
201                         c_avl_iterator_destroy (iter);
202                         ERROR ("network plugin: cache_flush: realloc"
203                                         " failed.");
204                         return (-1);
205                 }
206                 keys = tmp;
207                 keys[keys_num] = key;
208                 keys_num++;
209         } /* while (c_avl_iterator_next) */
210         c_avl_iterator_destroy (iter);
211
212         for (i = 0; i < keys_num; i++)
213         {
214                 if (c_avl_remove (cache_tree, keys[i], (void *) &key,
215                                         (void *) &value) != 0)
216                 {
217                         WARNING ("network plugin: cache_flush: c_avl_remove"
218                                         " (%s) failed.", keys[i]);
219                         continue;
220                 }
221
222                 sfree (key);
223                 sfree (value);
224         }
225
226         sfree (keys);
227
228         DEBUG ("network plugin: cache_flush: Removed %i %s",
229                         keys_num, (keys_num == 1) ? "entry" : "entries");
230         cache_flush_last = curtime;
231         return (0);
232 } /* int cache_flush */
233
234 static int cache_check (const char *type, const value_list_t *vl)
235 {
236         char key[1024];
237         time_t *value = NULL;
238         int retval = -1;
239
240         if (cache_tree == NULL)
241                 return (-1);
242
243         if (format_name (key, sizeof (key), vl->host, vl->plugin,
244                                 vl->plugin_instance, type, vl->type_instance))
245                 return (-1);
246
247         pthread_mutex_lock (&cache_lock);
248
249         if (c_avl_get (cache_tree, key, (void *) &value) == 0)
250         {
251                 if (*value < vl->time)
252                 {
253                         *value = vl->time;
254                         retval = 0;
255                 }
256                 else
257                 {
258                         DEBUG ("network plugin: cache_check: *value = %i >= vl->time = %i",
259                                         (int) *value, (int) vl->time);
260                         retval = 1;
261                 }
262         }
263         else
264         {
265                 char *key_copy = strdup (key);
266                 value = malloc (sizeof (time_t));
267                 if ((key_copy != NULL) && (value != NULL))
268                 {
269                         *value = vl->time;
270                         c_avl_insert (cache_tree, key_copy, value);
271                         retval = 0;
272                 }
273                 else
274                 {
275                         sfree (key_copy);
276                         sfree (value);
277                 }
278         }
279
280         if ((time (NULL) - cache_flush_last) > cache_flush_interval)
281                 cache_flush ();
282
283         pthread_mutex_unlock (&cache_lock);
284
285         DEBUG ("network plugin: cache_check: key = %s; time = %i; retval = %i",
286                         key, (int) vl->time, retval);
287
288         return (retval);
289 } /* int cache_check */
290
291 static int write_part_values (char **ret_buffer, int *ret_buffer_len,
292                 const data_set_t *ds, const value_list_t *vl)
293 {
294         part_values_t pv;
295         int i;
296
297         i = 6 + (9 * vl->values_len);
298         if (*ret_buffer_len < i)
299                 return (-1);
300         *ret_buffer_len -= i;
301
302         pv.head = (part_header_t *) *ret_buffer;
303         pv.num_values = (uint16_t *) (pv.head + 1);
304         pv.values_types = (uint8_t *) (pv.num_values + 1);
305         pv.values = (value_t *) (pv.values_types + vl->values_len);
306         *ret_buffer = (void *) (pv.values + vl->values_len);
307
308         pv.head->type = htons (TYPE_VALUES);
309         pv.head->length = htons (6 + (9 * vl->values_len));
310         *pv.num_values = htons ((uint16_t) vl->values_len);
311         
312         for (i = 0; i < vl->values_len; i++)
313         {
314                 if (ds->ds[i].type == DS_TYPE_COUNTER)
315                 {
316                         pv.values_types[i] = DS_TYPE_COUNTER;
317                         pv.values[i].counter = htonll (vl->values[i].counter);
318                 }
319                 else
320                 {
321                         pv.values_types[i] = DS_TYPE_GAUGE;
322                         pv.values[i].gauge = vl->values[i].gauge;
323                 }
324         } /* for (values) */
325
326         return (0);
327 } /* int write_part_values */
328
329 static int write_part_number (char **ret_buffer, int *ret_buffer_len,
330                 int type, uint64_t value)
331 {
332         part_number_t pn;
333
334         if (*ret_buffer_len < 12)
335                 return (-1);
336
337         pn.head = (part_header_t *) *ret_buffer;
338         pn.value = (uint64_t *) (pn.head + 1);
339
340         pn.head->type = htons (type);
341         pn.head->length = htons (12);
342         *pn.value = htonll (value);
343
344         *ret_buffer = (char *) (pn.value + 1);
345         *ret_buffer_len -= 12;
346
347         return (0);
348 } /* int write_part_number */
349
350 static int write_part_string (char **ret_buffer, int *ret_buffer_len,
351                 int type, const char *str, int str_len)
352 {
353         part_string_t ps;
354         int len;
355
356         len = 4 + str_len + 1;
357         if (*ret_buffer_len < len)
358                 return (-1);
359         *ret_buffer_len -= len;
360
361         ps.head = (part_header_t *) *ret_buffer;
362         ps.value = (char *) (ps.head + 1);
363
364         ps.head->type = htons ((uint16_t) type);
365         ps.head->length = htons ((uint16_t) str_len + 5);
366         if (str_len > 0)
367                 memcpy (ps.value, str, str_len);
368         ps.value[str_len] = '\0';
369         *ret_buffer = (void *) (ps.value + (str_len + 1));
370
371         return (0);
372 } /* int write_part_string */
373
374 static int parse_part_values (void **ret_buffer, int *ret_buffer_len,
375                 value_t **ret_values, int *ret_num_values)
376 {
377         char *buffer = *ret_buffer;
378         int   buffer_len = *ret_buffer_len;
379         part_values_t pv;
380         int   i;
381
382         uint16_t h_length;
383         uint16_t h_type;
384         uint16_t h_num;
385
386         if (buffer_len < (15))
387         {
388                 DEBUG ("network plugin: packet is too short: buffer_len = %i",
389                                 buffer_len);
390                 return (-1);
391         }
392
393         pv.head = (part_header_t *) buffer;
394         h_length = ntohs (pv.head->length);
395         h_type = ntohs (pv.head->type);
396
397         assert (h_type == TYPE_VALUES);
398
399         pv.num_values = (uint16_t *) (pv.head + 1);
400         h_num = ntohs (*pv.num_values);
401
402         if (h_num != ((h_length - 6) / 9))
403         {
404                 DEBUG ("`length' and `num of values' don't match");
405                 return (-1);
406         }
407
408         pv.values_types = (uint8_t *) (pv.num_values + 1);
409         pv.values = (value_t *) (pv.values_types + h_num);
410
411         for (i = 0; i < h_num; i++)
412                 if (pv.values_types[i] == DS_TYPE_COUNTER)
413                         pv.values[i].counter = ntohll (pv.values[i].counter);
414
415         *ret_buffer     = (void *) (pv.values + h_num);
416         *ret_buffer_len = buffer_len - h_length;
417         *ret_num_values = h_num;
418         *ret_values     = pv.values;
419
420         return (0);
421 } /* int parse_part_values */
422
423 static int parse_part_number (void **ret_buffer, int *ret_buffer_len,
424                 uint64_t *value)
425 {
426         part_number_t pn;
427         uint16_t len;
428
429         pn.head = (part_header_t *) *ret_buffer;
430         pn.value = (uint64_t *) (pn.head + 1);
431
432         len = ntohs (pn.head->length);
433         if (len != 12)
434                 return (-1);
435         if (len > *ret_buffer_len)
436                 return (-1);
437         *value = ntohll (*pn.value);
438
439         *ret_buffer = (void *) (pn.value + 1);
440         *ret_buffer_len -= len;
441
442         return (0);
443 } /* int parse_part_number */
444
445 static int parse_part_string (void **ret_buffer, int *ret_buffer_len,
446                 char *output, int output_len)
447 {
448         char *buffer = *ret_buffer;
449         int   buffer_len = *ret_buffer_len;
450         part_string_t ps;
451
452         uint16_t h_length;
453         uint16_t h_type;
454
455         DEBUG ("network plugin: parse_part_string: ret_buffer = %p;"
456                         " ret_buffer_len = %i; output = %p; output_len = %i;",
457                         *ret_buffer, *ret_buffer_len,
458                         (void *) output, output_len);
459
460         ps.head = (part_header_t *) buffer;
461
462         h_length = ntohs (ps.head->length);
463         h_type = ntohs (ps.head->type);
464
465         DEBUG ("network plugin: parse_part_string: length = %hu; type = %hu;",
466                         h_length, h_type);
467
468         if (buffer_len < h_length)
469         {
470                 DEBUG ("packet is too short");
471                 return (-1);
472         }
473         assert ((h_type == TYPE_HOST)
474                         || (h_type == TYPE_PLUGIN)
475                         || (h_type == TYPE_PLUGIN_INSTANCE)
476                         || (h_type == TYPE_TYPE)
477                         || (h_type == TYPE_TYPE_INSTANCE)
478                         || (h_type == TYPE_MESSAGE));
479
480         ps.value = buffer + 4;
481         if (ps.value[h_length - 5] != '\0')
482         {
483                 DEBUG ("String does not end with a nullbyte");
484                 return (-1);
485         }
486
487         if (output_len < (h_length - 4))
488         {
489                 DEBUG ("output buffer is too small");
490                 return (-1);
491         }
492         strcpy (output, ps.value);
493
494         DEBUG ("network plugin: parse_part_string: output = %s", output);
495
496         *ret_buffer = (void *) (buffer + h_length);
497         *ret_buffer_len = buffer_len - h_length;
498
499         return (0);
500 } /* int parse_part_string */
501
502 static int parse_packet (void *buffer, int buffer_len)
503 {
504         part_header_t *header;
505         int status;
506
507         value_list_t vl = VALUE_LIST_INIT;
508         char type[DATA_MAX_NAME_LEN];
509         notification_t n;
510
511         DEBUG ("network plugin: parse_packet: buffer = %p; buffer_len = %i;",
512                         buffer, buffer_len);
513
514         memset (&vl, '\0', sizeof (vl));
515         memset (&type, '\0', sizeof (type));
516         memset (&n, '\0', sizeof (n));
517         status = 0;
518
519         while ((status == 0) && (0 < buffer_len)
520                         && ((unsigned int) buffer_len > sizeof (part_header_t)))
521         {
522                 header = (part_header_t *) buffer;
523
524                 if (ntohs (header->length) > buffer_len)
525                         break;
526                 /* Assure that this loop terminates eventually */
527                 if (ntohs (header->length) < 4)
528                         break;
529
530                 if (ntohs (header->type) == TYPE_VALUES)
531                 {
532                         status = parse_part_values (&buffer, &buffer_len,
533                                         &vl.values, &vl.values_len);
534
535                         if (status != 0)
536                         {
537                                 DEBUG ("parse_part_values failed.");
538                                 break;
539                         }
540
541                         if ((vl.time > 0)
542                                         && (strlen (vl.host) > 0)
543                                         && (strlen (vl.plugin) > 0)
544                                         && (strlen (type) > 0)
545                                         && (cache_check (type, &vl) == 0))
546                         {
547                                 DEBUG ("network plugin: parse_packet:"
548                                                 " dispatching values");
549                                 plugin_dispatch_values (type, &vl);
550                         }
551                         else
552                         {
553                                 DEBUG ("network plugin: parse_packet:"
554                                                 " NOT dispatching values");
555                         }
556                 }
557                 else if (ntohs (header->type) == TYPE_TIME)
558                 {
559                         uint64_t tmp = 0;
560                         status = parse_part_number (&buffer, &buffer_len, &tmp);
561                         if (status == 0)
562                         {
563                                 vl.time = (time_t) tmp;
564                                 n.time = (time_t) tmp;
565                         }
566                 }
567                 else if (ntohs (header->type) == TYPE_INTERVAL)
568                 {
569                         uint64_t tmp = 0;
570                         status = parse_part_number (&buffer, &buffer_len, &tmp);
571                         if (status == 0)
572                                 vl.interval = (int) tmp;
573                 }
574                 else if (ntohs (header->type) == TYPE_HOST)
575                 {
576                         status = parse_part_string (&buffer, &buffer_len,
577                                         vl.host, sizeof (vl.host));
578                         strncpy (n.host, vl.host, sizeof (n.host));
579                         n.host[sizeof (n.host) - 1] = '\0';
580                         DEBUG ("network plugin: parse_packet: vl.host = %s",
581                                         vl.host);
582                 }
583                 else if (ntohs (header->type) == TYPE_PLUGIN)
584                 {
585                         status = parse_part_string (&buffer, &buffer_len,
586                                         vl.plugin, sizeof (vl.plugin));
587                         strncpy (n.plugin, vl.plugin, sizeof (n.plugin));
588                         n.plugin[sizeof (n.plugin) - 1] = '\0';
589                         DEBUG ("network plugin: parse_packet: vl.plugin = %s",
590                                         vl.plugin);
591                 }
592                 else if (ntohs (header->type) == TYPE_PLUGIN_INSTANCE)
593                 {
594                         status = parse_part_string (&buffer, &buffer_len,
595                                         vl.plugin_instance,
596                                         sizeof (vl.plugin_instance));
597                         strncpy (n.plugin_instance, vl.plugin_instance,
598                                         sizeof (n.plugin_instance));
599                         n.plugin_instance[sizeof (n.plugin_instance) - 1] = '\0';
600                         DEBUG ("network plugin: parse_packet: "
601                                         "vl.plugin_instance = %s",
602                                         vl.plugin_instance);
603                 }
604                 else if (ntohs (header->type) == TYPE_TYPE)
605                 {
606                         status = parse_part_string (&buffer, &buffer_len,
607                                         type, sizeof (type));
608                         strncpy (n.type, type, sizeof (n.type));
609                         n.type[sizeof (n.type) - 1] = '\0';
610                         DEBUG ("network plugin: parse_packet: type = %s",
611                                         type);
612                 }
613                 else if (ntohs (header->type) == TYPE_TYPE_INSTANCE)
614                 {
615                         status = parse_part_string (&buffer, &buffer_len,
616                                         vl.type_instance,
617                                         sizeof (vl.type_instance));
618                         strncpy (n.type_instance, vl.type_instance,
619                                         sizeof (n.type_instance));
620                         n.type_instance[sizeof (n.type_instance) - 1] = '\0';
621                         DEBUG ("network plugin: parse_packet: "
622                                         "vl.type_instance = %s",
623                                         vl.type_instance);
624                 }
625                 else if (ntohs (header->type) == TYPE_MESSAGE)
626                 {
627                         status = parse_part_string (&buffer, &buffer_len,
628                                         n.message, sizeof (n.message));
629                         DEBUG ("network plugin: parse_packet: n.message = %s",
630                                         n.message);
631
632                         if ((n.severity != NOTIF_FAILURE)
633                                         && (n.severity != NOTIF_WARNING)
634                                         && (n.severity != NOTIF_OKAY))
635                         {
636                                 INFO ("network plugin: "
637                                                 "Ignoring notification with "
638                                                 "unknown severity %s.",
639                                                 n.severity);
640                         }
641                         else if (n.time <= 0)
642                         {
643                                 INFO ("network plugin: "
644                                                 "Ignoring notification with "
645                                                 "time == 0.");
646                         }
647                         else if (strlen (n.message) <= 0)
648                         {
649                                 INFO ("network plugin: "
650                                                 "Ignoring notification with "
651                                                 "an empty message.");
652                         }
653                         else
654                         {
655                                 /*
656                                  * TODO: Let this do a separate thread so that
657                                  * no packets are lost if this takes too long.
658                                  */
659                                 plugin_dispatch_notification (&n);
660                         }
661                 }
662                 else if (ntohs (header->type) == TYPE_SEVERITY)
663                 {
664                         uint64_t tmp = 0;
665                         status = parse_part_number (&buffer, &buffer_len, &tmp);
666                         if (status == 0)
667                                 n.severity = (int) tmp;
668                 }
669                 else
670                 {
671                         DEBUG ("network plugin: parse_packet: Unknown part"
672                                         " type: 0x%0hx", ntohs (header->type));
673                         buffer = ((char *) buffer) + ntohs (header->length);
674                 }
675         } /* while (buffer_len > sizeof (part_header_t)) */
676
677         return (0);
678 } /* int parse_packet */
679
680 static void free_sockent (sockent_t *se)
681 {
682         sockent_t *next;
683         while (se != NULL)
684         {
685                 next = se->next;
686                 free (se->addr);
687                 free (se);
688                 se = next;
689         }
690 } /* void free_sockent */
691
692 /*
693  * int network_set_ttl
694  *
695  * Set the `IP_MULTICAST_TTL', `IP_TTL', `IPV6_MULTICAST_HOPS' or
696  * `IPV6_UNICAST_HOPS', depending on which option is applicable.
697  *
698  * The `struct addrinfo' is used to destinguish between unicast and multicast
699  * sockets.
700  */
701 static int network_set_ttl (const sockent_t *se, const struct addrinfo *ai)
702 {
703         if ((network_config_ttl < 1) || (network_config_ttl > 255))
704                 return (-1);
705
706         DEBUG ("ttl = %i", network_config_ttl);
707
708         if (ai->ai_family == AF_INET)
709         {
710                 struct sockaddr_in *addr = (struct sockaddr_in *) ai->ai_addr;
711                 int optname;
712
713                 if (IN_MULTICAST (ntohl (addr->sin_addr.s_addr)))
714                         optname = IP_MULTICAST_TTL;
715                 else
716                         optname = IP_TTL;
717
718                 if (setsockopt (se->fd, IPPROTO_IP, optname,
719                                         &network_config_ttl,
720                                         sizeof (network_config_ttl)) == -1)
721                 {
722                         char errbuf[1024];
723                         ERROR ("setsockopt: %s",
724                                         sstrerror (errno, errbuf, sizeof (errbuf)));
725                         return (-1);
726                 }
727         }
728         else if (ai->ai_family == AF_INET6)
729         {
730                 /* Useful example: http://gsyc.escet.urjc.es/~eva/IPv6-web/examples/mcast.html */
731                 struct sockaddr_in6 *addr = (struct sockaddr_in6 *) ai->ai_addr;
732                 int optname;
733
734                 if (IN6_IS_ADDR_MULTICAST (&addr->sin6_addr))
735                         optname = IPV6_MULTICAST_HOPS;
736                 else
737                         optname = IPV6_UNICAST_HOPS;
738
739                 if (setsockopt (se->fd, IPPROTO_IPV6, optname,
740                                         &network_config_ttl,
741                                         sizeof (network_config_ttl)) == -1)
742                 {
743                         char errbuf[1024];
744                         ERROR ("setsockopt: %s",
745                                         sstrerror (errno, errbuf,
746                                                 sizeof (errbuf)));
747                         return (-1);
748                 }
749         }
750
751         return (0);
752 } /* int network_set_ttl */
753
754 static int network_bind_socket (const sockent_t *se, const struct addrinfo *ai)
755 {
756         int loop = 0;
757         int yes  = 1;
758
759         /* allow multiple sockets to use the same PORT number */
760         if (setsockopt(se->fd, SOL_SOCKET, SO_REUSEADDR,
761                                 &yes, sizeof(yes)) == -1) {
762                 char errbuf[1024];
763                 ERROR ("setsockopt: %s", 
764                                 sstrerror (errno, errbuf, sizeof (errbuf)));
765                 return (-1);
766         }
767
768         DEBUG ("fd = %i; calling `bind'", se->fd);
769
770         if (bind (se->fd, ai->ai_addr, ai->ai_addrlen) == -1)
771         {
772                 char errbuf[1024];
773                 ERROR ("bind: %s",
774                                 sstrerror (errno, errbuf, sizeof (errbuf)));
775                 return (-1);
776         }
777
778         if (ai->ai_family == AF_INET)
779         {
780                 struct sockaddr_in *addr = (struct sockaddr_in *) ai->ai_addr;
781                 if (IN_MULTICAST (ntohl (addr->sin_addr.s_addr)))
782                 {
783                         struct ip_mreq mreq;
784
785                         DEBUG ("fd = %i; IPv4 multicast address found", se->fd);
786
787                         mreq.imr_multiaddr.s_addr = addr->sin_addr.s_addr;
788                         mreq.imr_interface.s_addr = htonl (INADDR_ANY);
789
790                         if (setsockopt (se->fd, IPPROTO_IP, IP_MULTICAST_LOOP,
791                                                 &loop, sizeof (loop)) == -1)
792                         {
793                                 char errbuf[1024];
794                                 ERROR ("setsockopt: %s",
795                                                 sstrerror (errno, errbuf,
796                                                         sizeof (errbuf)));
797                                 return (-1);
798                         }
799
800                         if (setsockopt (se->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
801                                                 &mreq, sizeof (mreq)) == -1)
802                         {
803                                 char errbuf[1024];
804                                 ERROR ("setsockopt: %s",
805                                                 sstrerror (errno, errbuf,
806                                                         sizeof (errbuf)));
807                                 return (-1);
808                         }
809                 }
810         }
811         else if (ai->ai_family == AF_INET6)
812         {
813                 /* Useful example: http://gsyc.escet.urjc.es/~eva/IPv6-web/examples/mcast.html */
814                 struct sockaddr_in6 *addr = (struct sockaddr_in6 *) ai->ai_addr;
815                 if (IN6_IS_ADDR_MULTICAST (&addr->sin6_addr))
816                 {
817                         struct ipv6_mreq mreq;
818
819                         DEBUG ("fd = %i; IPv6 multicast address found", se->fd);
820
821                         memcpy (&mreq.ipv6mr_multiaddr,
822                                         &addr->sin6_addr,
823                                         sizeof (addr->sin6_addr));
824
825                         /* http://developer.apple.com/documentation/Darwin/Reference/ManPages/man4/ip6.4.html
826                          * ipv6mr_interface may be set to zeroes to
827                          * choose the default multicast interface or to
828                          * the index of a particular multicast-capable
829                          * interface if the host is multihomed.
830                          * Membership is associ-associated with a
831                          * single interface; programs running on
832                          * multihomed hosts may need to join the same
833                          * group on more than one interface.*/
834                         mreq.ipv6mr_interface = 0;
835
836                         if (setsockopt (se->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
837                                                 &loop, sizeof (loop)) == -1)
838                         {
839                                 char errbuf[1024];
840                                 ERROR ("setsockopt: %s",
841                                                 sstrerror (errno, errbuf,
842                                                         sizeof (errbuf)));
843                                 return (-1);
844                         }
845
846                         if (setsockopt (se->fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
847                                                 &mreq, sizeof (mreq)) == -1)
848                         {
849                                 char errbuf[1024];
850                                 ERROR ("setsockopt: %s",
851                                                 sstrerror (errno, errbuf,
852                                                         sizeof (errbuf)));
853                                 return (-1);
854                         }
855                 }
856         }
857
858         return (0);
859 } /* int network_bind_socket */
860
861 static sockent_t *network_create_socket (const char *node,
862                 const char *service,
863                 int listen)
864 {
865         struct addrinfo  ai_hints;
866         struct addrinfo *ai_list, *ai_ptr;
867         int              ai_return;
868
869         sockent_t *se_head = NULL;
870         sockent_t *se_tail = NULL;
871
872         DEBUG ("node = %s, service = %s", node, service);
873
874         memset (&ai_hints, '\0', sizeof (ai_hints));
875         ai_hints.ai_flags    = 0;
876 #ifdef AI_PASSIVE
877         ai_hints.ai_flags |= AI_PASSIVE;
878 #endif
879 #ifdef AI_ADDRCONFIG
880         ai_hints.ai_flags |= AI_ADDRCONFIG;
881 #endif
882         ai_hints.ai_family   = AF_UNSPEC;
883         ai_hints.ai_socktype = SOCK_DGRAM;
884         ai_hints.ai_protocol = IPPROTO_UDP;
885
886         ai_return = getaddrinfo (node, service, &ai_hints, &ai_list);
887         if (ai_return != 0)
888         {
889                 char errbuf[1024];
890                 ERROR ("getaddrinfo (%s, %s): %s",
891                                 (node == NULL) ? "(null)" : node,
892                                 (service == NULL) ? "(null)" : service,
893                                 (ai_return == EAI_SYSTEM)
894                                 ? sstrerror (errno, errbuf, sizeof (errbuf))
895                                 : gai_strerror (ai_return));
896                 return (NULL);
897         }
898
899         for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
900         {
901                 sockent_t *se;
902
903                 if ((se = (sockent_t *) malloc (sizeof (sockent_t))) == NULL)
904                 {
905                         char errbuf[1024];
906                         ERROR ("malloc: %s",
907                                         sstrerror (errno, errbuf,
908                                                 sizeof (errbuf)));
909                         continue;
910                 }
911
912                 if ((se->addr = (struct sockaddr_storage *) malloc (sizeof (struct sockaddr_storage))) == NULL)
913                 {
914                         char errbuf[1024];
915                         ERROR ("malloc: %s",
916                                         sstrerror (errno, errbuf,
917                                                 sizeof (errbuf)));
918                         free (se);
919                         continue;
920                 }
921
922                 assert (sizeof (struct sockaddr_storage) >= ai_ptr->ai_addrlen);
923                 memset (se->addr, '\0', sizeof (struct sockaddr_storage));
924                 memcpy (se->addr, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
925                 se->addrlen = ai_ptr->ai_addrlen;
926
927                 se->fd   = socket (ai_ptr->ai_family,
928                                 ai_ptr->ai_socktype,
929                                 ai_ptr->ai_protocol);
930                 se->next = NULL;
931
932                 if (se->fd == -1)
933                 {
934                         char errbuf[1024];
935                         ERROR ("socket: %s",
936                                         sstrerror (errno, errbuf,
937                                                 sizeof (errbuf)));
938                         free (se->addr);
939                         free (se);
940                         continue;
941                 }
942
943                 if (listen != 0)
944                 {
945                         if (network_bind_socket (se, ai_ptr) != 0)
946                         {
947                                 close (se->fd);
948                                 free (se->addr);
949                                 free (se);
950                                 continue;
951                         }
952                 }
953                 else /* listen == 0 */
954                 {
955                         network_set_ttl (se, ai_ptr);
956                 }
957
958                 if (se_tail == NULL)
959                 {
960                         se_head = se;
961                         se_tail = se;
962                 }
963                 else
964                 {
965                         se_tail->next = se;
966                         se_tail = se;
967                 }
968
969                 /* We don't open more than one write-socket per node/service pair.. */
970                 if (listen == 0)
971                         break;
972         }
973
974         freeaddrinfo (ai_list);
975
976         return (se_head);
977 } /* sockent_t *network_create_socket */
978
979 static sockent_t *network_create_default_socket (int listen)
980 {
981         sockent_t *se_ptr  = NULL;
982         sockent_t *se_head = NULL;
983         sockent_t *se_tail = NULL;
984
985         se_ptr = network_create_socket (NET_DEFAULT_V6_ADDR,
986                         NET_DEFAULT_PORT, listen);
987
988         /* Don't send to the same machine in IPv6 and IPv4 if both are available. */
989         if ((listen == 0) && (se_ptr != NULL))
990                 return (se_ptr);
991
992         if (se_ptr != NULL)
993         {
994                 se_head = se_ptr;
995                 se_tail = se_ptr;
996                 while (se_tail->next != NULL)
997                         se_tail = se_tail->next;
998         }
999
1000         se_ptr = network_create_socket (NET_DEFAULT_V4_ADDR, NET_DEFAULT_PORT, listen);
1001
1002         if (se_tail == NULL)
1003                 return (se_ptr);
1004
1005         se_tail->next = se_ptr;
1006         return (se_head);
1007 } /* sockent_t *network_create_default_socket */
1008
1009 static int network_add_listen_socket (const char *node, const char *service)
1010 {
1011         sockent_t *se;
1012         sockent_t *se_ptr;
1013         int se_num = 0;
1014
1015         if (service == NULL)
1016                 service = NET_DEFAULT_PORT;
1017
1018         if (node == NULL)
1019                 se = network_create_default_socket (1 /* listen == true */);
1020         else
1021                 se = network_create_socket (node, service, 1 /* listen == true */);
1022
1023         if (se == NULL)
1024                 return (-1);
1025
1026         for (se_ptr = se; se_ptr != NULL; se_ptr = se_ptr->next)
1027                 se_num++;
1028
1029         listen_sockets = (struct pollfd *) realloc (listen_sockets,
1030                         (listen_sockets_num + se_num)
1031                         * sizeof (struct pollfd));
1032
1033         for (se_ptr = se; se_ptr != NULL; se_ptr = se_ptr->next)
1034         {
1035                 listen_sockets[listen_sockets_num].fd = se_ptr->fd;
1036                 listen_sockets[listen_sockets_num].events = POLLIN | POLLPRI;
1037                 listen_sockets[listen_sockets_num].revents = 0;
1038                 listen_sockets_num++;
1039         } /* for (se) */
1040
1041         free_sockent (se);
1042         return (0);
1043 } /* int network_add_listen_socket */
1044
1045 static int network_add_sending_socket (const char *node, const char *service)
1046 {
1047         sockent_t *se;
1048         sockent_t *se_ptr;
1049
1050         if (service == NULL)
1051                 service = NET_DEFAULT_PORT;
1052
1053         if (node == NULL)
1054                 se = network_create_default_socket (0 /* listen == false */);
1055         else
1056                 se = network_create_socket (node, service, 0 /* listen == false */);
1057
1058         if (se == NULL)
1059                 return (-1);
1060
1061         if (sending_sockets == NULL)
1062         {
1063                 sending_sockets = se;
1064                 return (0);
1065         }
1066
1067         for (se_ptr = sending_sockets; se_ptr->next != NULL; se_ptr = se_ptr->next)
1068                 /* seek end */;
1069
1070         se_ptr->next = se;
1071         return (0);
1072 } /* int network_get_listen_socket */
1073
1074 static int network_receive (void)
1075 {
1076         char buffer[BUFF_SIZE];
1077         int  buffer_len;
1078
1079         int i;
1080         int status;
1081
1082         if (listen_sockets_num == 0)
1083                 network_add_listen_socket (NULL, NULL);
1084
1085         if (listen_sockets_num == 0)
1086         {
1087                 ERROR ("network: Failed to open a listening socket.");
1088                 return (-1);
1089         }
1090
1091         while (listen_loop == 0)
1092         {
1093                 status = poll (listen_sockets, listen_sockets_num, -1);
1094
1095                 if (status <= 0)
1096                 {
1097                         char errbuf[1024];
1098                         if (errno == EINTR)
1099                                 continue;
1100                         ERROR ("poll failed: %s",
1101                                         sstrerror (errno, errbuf, sizeof (errbuf)));
1102                         return (-1);
1103                 }
1104
1105                 for (i = 0; (i < listen_sockets_num) && (status > 0); i++)
1106                 {
1107                         if ((listen_sockets[i].revents & (POLLIN | POLLPRI)) == 0)
1108                                 continue;
1109                         status--;
1110
1111                         buffer_len = recv (listen_sockets[i].fd,
1112                                         buffer, sizeof (buffer),
1113                                         0 /* no flags */);
1114                         if (buffer_len < 0)
1115                         {
1116                                 char errbuf[1024];
1117                                 ERROR ("recv failed: %s",
1118                                                 sstrerror (errno, errbuf,
1119                                                         sizeof (errbuf)));
1120                                 return (-1);
1121                         }
1122
1123                         parse_packet (buffer, buffer_len);
1124                 } /* for (listen_sockets) */
1125         } /* while (listen_loop == 0) */
1126
1127         return (0);
1128 }
1129
1130 static void *receive_thread (void *arg)
1131 {
1132         return (network_receive () ? (void *) 1 : (void *) 0);
1133 } /* void *receive_thread */
1134
1135 static void network_send_buffer (const char *buffer, int buffer_len)
1136 {
1137         sockent_t *se;
1138         int status;
1139
1140         DEBUG ("network plugin: network_send_buffer: buffer_len = %i", buffer_len);
1141
1142         for (se = sending_sockets; se != NULL; se = se->next)
1143         {
1144                 while (42)
1145                 {
1146                         status = sendto (se->fd, buffer, buffer_len, 0 /* no flags */,
1147                                         (struct sockaddr *) se->addr, se->addrlen);
1148                         if (status < 0)
1149                         {
1150                                 char errbuf[1024];
1151                                 if (errno == EINTR)
1152                                         continue;
1153                                 ERROR ("network plugin: sendto failed: %s",
1154                                                 sstrerror (errno, errbuf,
1155                                                         sizeof (errbuf)));
1156                                 break;
1157                         }
1158
1159                         break;
1160                 } /* while (42) */
1161         } /* for (sending_sockets) */
1162 } /* void network_send_buffer */
1163
1164 static int add_to_buffer (char *buffer, int buffer_size,
1165                 value_list_t *vl_def, char *type_def,
1166                 const data_set_t *ds, const value_list_t *vl)
1167 {
1168         char *buffer_orig = buffer;
1169
1170         if (strcmp (vl_def->host, vl->host) != 0)
1171         {
1172                 if (write_part_string (&buffer, &buffer_size, TYPE_HOST,
1173                                         vl->host, strlen (vl->host)) != 0)
1174                         return (-1);
1175                 strcpy (vl_def->host, vl->host);
1176         }
1177
1178         if (vl_def->time != vl->time)
1179         {
1180                 if (write_part_number (&buffer, &buffer_size, TYPE_TIME,
1181                                         (uint64_t) vl->time))
1182                         return (-1);
1183                 vl_def->time = vl->time;
1184         }
1185
1186         if (vl_def->interval != vl->interval)
1187         {
1188                 if (write_part_number (&buffer, &buffer_size, TYPE_INTERVAL,
1189                                         (uint64_t) vl->interval))
1190                         return (-1);
1191                 vl_def->interval = vl->interval;
1192         }
1193
1194         if (strcmp (vl_def->plugin, vl->plugin) != 0)
1195         {
1196                 if (write_part_string (&buffer, &buffer_size, TYPE_PLUGIN,
1197                                         vl->plugin, strlen (vl->plugin)) != 0)
1198                         return (-1);
1199                 strcpy (vl_def->plugin, vl->plugin);
1200         }
1201
1202         if (strcmp (vl_def->plugin_instance, vl->plugin_instance) != 0)
1203         {
1204                 if (write_part_string (&buffer, &buffer_size, TYPE_PLUGIN_INSTANCE,
1205                                         vl->plugin_instance,
1206                                         strlen (vl->plugin_instance)) != 0)
1207                         return (-1);
1208                 strcpy (vl_def->plugin_instance, vl->plugin_instance);
1209         }
1210
1211         if (strcmp (type_def, ds->type) != 0)
1212         {
1213                 if (write_part_string (&buffer, &buffer_size, TYPE_TYPE,
1214                                         ds->type, strlen (ds->type)) != 0)
1215                         return (-1);
1216                 strcpy (type_def, ds->type);
1217         }
1218
1219         if (strcmp (vl_def->type_instance, vl->type_instance) != 0)
1220         {
1221                 if (write_part_string (&buffer, &buffer_size, TYPE_TYPE_INSTANCE,
1222                                         vl->type_instance,
1223                                         strlen (vl->type_instance)) != 0)
1224                         return (-1);
1225                 strcpy (vl_def->type_instance, vl->type_instance);
1226         }
1227         
1228         if (write_part_values (&buffer, &buffer_size, ds, vl) != 0)
1229                 return (-1);
1230
1231         return (buffer - buffer_orig);
1232 } /* int add_to_buffer */
1233
1234 static void flush_buffer (void)
1235 {
1236         DEBUG ("network plugin: flush_buffer: send_buffer_fill = %i",
1237                         send_buffer_fill);
1238
1239         network_send_buffer (send_buffer, send_buffer_fill);
1240         send_buffer_ptr  = send_buffer;
1241         send_buffer_fill = 0;
1242         memset (&send_buffer_vl, '\0', sizeof (send_buffer_vl));
1243         memset (send_buffer_type, '\0', sizeof (send_buffer_type));
1244 }
1245
1246 static int network_write (const data_set_t *ds, const value_list_t *vl)
1247 {
1248         int status;
1249
1250         /* If the value is already in the cache, we have received it via the
1251          * network. We write it again if forwarding is activated. It's then in
1252          * the cache and should we receive it again we will ignore it. */
1253         status = cache_check (ds->type, vl);
1254         if ((network_config_forward == 0)
1255                         && (status != 0))
1256                 return (0);
1257
1258         pthread_mutex_lock (&send_buffer_lock);
1259
1260         status = add_to_buffer (send_buffer_ptr,
1261                         sizeof (send_buffer) - send_buffer_fill,
1262                         &send_buffer_vl, send_buffer_type,
1263                         ds, vl);
1264         if (status >= 0)
1265         {
1266                 /* status == bytes added to the buffer */
1267                 send_buffer_fill += status;
1268                 send_buffer_ptr  += status;
1269         }
1270         else
1271         {
1272                 flush_buffer ();
1273
1274                 status = add_to_buffer (send_buffer_ptr,
1275                                 sizeof (send_buffer) - send_buffer_fill,
1276                                 &send_buffer_vl, send_buffer_type,
1277                                 ds, vl);
1278
1279                 if (status >= 0)
1280                 {
1281                         send_buffer_fill += status;
1282                         send_buffer_ptr  += status;
1283                 }
1284         }
1285
1286         if (status < 0)
1287         {
1288                 ERROR ("network plugin: Unable to append to the "
1289                                 "buffer for some weird reason");
1290         }
1291         else if ((sizeof (send_buffer) - send_buffer_fill) < 15)
1292         {
1293                 flush_buffer ();
1294         }
1295
1296         pthread_mutex_unlock (&send_buffer_lock);
1297
1298         return ((status < 0) ? -1 : 0);
1299 } /* int network_write */
1300
1301 static int network_config (const char *key, const char *val)
1302 {
1303         char *node;
1304         char *service;
1305
1306         char *fields[3];
1307         int   fields_num;
1308
1309         if ((strcasecmp ("Listen", key) == 0)
1310                         || (strcasecmp ("Server", key) == 0))
1311         {
1312                 char *val_cpy = strdup (val);
1313                 if (val_cpy == NULL)
1314                         return (1);
1315
1316                 service = NET_DEFAULT_PORT;
1317                 fields_num = strsplit (val_cpy, fields, 3);
1318                 if ((fields_num != 1)
1319                                 && (fields_num != 2))
1320                         return (1);
1321                 else if (fields_num == 2)
1322                 {
1323                         if ((service = strchr (fields[1], '.')) != NULL)
1324                                 *service = '\0';
1325                         service = fields[1];
1326                 }
1327                 node = fields[0];
1328
1329                 if (strcasecmp ("Listen", key) == 0)
1330                         network_add_listen_socket (node, service);
1331                 else
1332                         network_add_sending_socket (node, service);
1333         }
1334         else if (strcasecmp ("TimeToLive", key) == 0)
1335         {
1336                 int tmp = atoi (val);
1337                 if ((tmp > 0) && (tmp < 256))
1338                         network_config_ttl = tmp;
1339                 else
1340                         return (1);
1341         }
1342         else if (strcasecmp ("Forward", key) == 0)
1343         {
1344                 if ((strcasecmp ("true", val) == 0)
1345                                 || (strcasecmp ("yes", val) == 0)
1346                                 || (strcasecmp ("on", val) == 0))
1347                         network_config_forward = 1;
1348                 else
1349                         network_config_forward = 0;
1350         }
1351         else if (strcasecmp ("CacheFlush", key) == 0)
1352         {
1353                 int tmp = atoi (val);
1354                 if (tmp > 0)
1355                         cache_flush_interval = tmp;
1356                 else return (1);
1357         }
1358         else
1359         {
1360                 return (-1);
1361         }
1362         return (0);
1363 } /* int network_config */
1364
1365 static int network_notification (const notification_t *n)
1366 {
1367   char  buffer[BUFF_SIZE];
1368   char *buffer_ptr = buffer;
1369   int   buffer_free = sizeof (buffer);
1370   int   status;
1371
1372   memset (buffer, '\0', sizeof (buffer));
1373
1374
1375   status = write_part_number (&buffer_ptr, &buffer_free, TYPE_TIME,
1376       (uint64_t) n->time);
1377   if (status != 0)
1378     return (-1);
1379
1380   status = write_part_number (&buffer_ptr, &buffer_free, TYPE_SEVERITY,
1381       (uint64_t) n->severity);
1382   if (status != 0)
1383     return (-1);
1384
1385   if (strlen (n->host) > 0)
1386   {
1387     status = write_part_string (&buffer_ptr, &buffer_free, TYPE_HOST,
1388         n->host, strlen (n->host));
1389     if (status != 0)
1390       return (-1);
1391   }
1392
1393   if (strlen (n->plugin) > 0)
1394   {
1395     status = write_part_string (&buffer_ptr, &buffer_free, TYPE_PLUGIN,
1396         n->plugin, strlen (n->plugin));
1397     if (status != 0)
1398       return (-1);
1399   }
1400
1401   if (strlen (n->plugin_instance) > 0)
1402   {
1403     status = write_part_string (&buffer_ptr, &buffer_free,
1404         TYPE_PLUGIN_INSTANCE,
1405         n->plugin_instance, strlen (n->plugin_instance));
1406     if (status != 0)
1407       return (-1);
1408   }
1409
1410   if (strlen (n->type) > 0)
1411   {
1412     status = write_part_string (&buffer_ptr, &buffer_free, TYPE_TYPE,
1413         n->type, strlen (n->type));
1414     if (status != 0)
1415       return (-1);
1416   }
1417
1418   if (strlen (n->type_instance) > 0)
1419   {
1420     status = write_part_string (&buffer_ptr, &buffer_free, TYPE_TYPE_INSTANCE,
1421         n->type_instance, strlen (n->type_instance));
1422     if (status != 0)
1423       return (-1);
1424   }
1425
1426   status = write_part_string (&buffer_ptr, &buffer_free, TYPE_MESSAGE,
1427       n->message, strlen (n->message));
1428   if (status != 0)
1429     return (-1);
1430
1431   network_send_buffer (buffer, sizeof (buffer) - buffer_free);
1432
1433   return (0);
1434 } /* int network_notification */
1435
1436 static int network_shutdown (void)
1437 {
1438         listen_loop++;
1439
1440         if (listen_thread != (pthread_t) 0)
1441         {
1442                 pthread_kill (listen_thread, SIGTERM);
1443                 pthread_join (listen_thread, NULL /* no return value */);
1444                 listen_thread = (pthread_t) 0;
1445         }
1446
1447         if (send_buffer_fill > 0)
1448                 flush_buffer ();
1449
1450         if (cache_tree != NULL)
1451         {
1452                 void *key;
1453                 void *value;
1454
1455                 while (c_avl_pick (cache_tree, &key, &value) == 0)
1456                 {
1457                         sfree (key);
1458                         sfree (value);
1459                 }
1460                 c_avl_destroy (cache_tree);
1461                 cache_tree = NULL;
1462         }
1463
1464         /* TODO: Close `sending_sockets' */
1465
1466         plugin_unregister_config ("network");
1467         plugin_unregister_init ("network");
1468         plugin_unregister_write ("network");
1469         plugin_unregister_shutdown ("network");
1470
1471         return (0);
1472 } /* int network_shutdown */
1473
1474 static int network_init (void)
1475 {
1476         plugin_register_shutdown ("network", network_shutdown);
1477
1478         send_buffer_ptr  = send_buffer;
1479         send_buffer_fill = 0;
1480         memset (&send_buffer_vl, '\0', sizeof (send_buffer_vl));
1481         memset (send_buffer_type, '\0', sizeof (send_buffer_type));
1482
1483         cache_tree = c_avl_create ((int (*) (const void *, const void *)) strcmp);
1484         cache_flush_last = time (NULL);
1485
1486         /* setup socket(s) and so on */
1487         if (sending_sockets != NULL)
1488         {
1489                 plugin_register_write ("network", network_write);
1490                 plugin_register_notification ("network", network_notification);
1491         }
1492
1493         if ((listen_sockets_num != 0) && (listen_thread == 0))
1494         {
1495                 int status;
1496
1497                 status = pthread_create (&listen_thread, NULL /* no attributes */,
1498                                 receive_thread, NULL /* no argument */);
1499
1500                 if (status != 0)
1501                 {
1502                         char errbuf[1024];
1503                         ERROR ("network: pthread_create failed: %s",
1504                                         sstrerror (errno, errbuf,
1505                                                 sizeof (errbuf)));
1506                 }
1507         }
1508         return (0);
1509 } /* int network_init */
1510
1511 void module_register (void)
1512 {
1513         plugin_register_config ("network", network_config,
1514                         config_keys, config_keys_num);
1515         plugin_register_init   ("network", network_init);
1516 } /* void module_register */