Replace all calls to `strerror' with `sstrerror'
[collectd.git] / src / network.c
1 /**
2  * collectd - src/network.c
3  * Copyright (C) 2005-2007  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
27 #include "network.h"
28
29 #if HAVE_PTHREAD_H
30 # include <pthread.h>
31 #endif
32 #if HAVE_SYS_SOCKET_H
33 # include <sys/socket.h>
34 #endif
35 #if HAVE_NETDB_H
36 # include <netdb.h>
37 #endif
38 #if HAVE_NETINET_IN_H
39 # include <netinet/in.h>
40 #endif
41 #if HAVE_ARPA_INET_H
42 # include <arpa/inet.h>
43 #endif
44 #if HAVE_POLL_H
45 # include <poll.h>
46 #endif
47
48 /* 1500 - 40 - 8  =  Ethernet packet - IPv6 header - UDP header */
49 /* #define BUFF_SIZE 1452 */
50
51 #ifndef IPV6_ADD_MEMBERSHIP
52 # ifdef IPV6_JOIN_GROUP
53 #  define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
54 # else
55 #  error "Neither IP_ADD_MEMBERSHIP nor IPV6_JOIN_GROUP is defined"
56 # endif
57 #endif /* !IP_ADD_MEMBERSHIP */
58
59 #define BUFF_SIZE 1024
60
61 /*
62  * Private data types
63  */
64 typedef struct sockent
65 {
66         int                      fd;
67         struct sockaddr_storage *addr;
68         socklen_t                addrlen;
69         struct sockent          *next;
70 } sockent_t;
71
72 /*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
73  *  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
74  * +-------+-----------------------+-------------------------------+
75  * ! Ver.  !                       ! Length                        !
76  * +-------+-----------------------+-------------------------------+
77  */
78 struct part_header_s
79 {
80         uint16_t type;
81         uint16_t length;
82 };
83 typedef struct part_header_s part_header_t;
84
85 /*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
86  *  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
87  * +-------------------------------+-------------------------------+
88  * ! Type                          ! Length                        !
89  * +-------------------------------+-------------------------------+
90  * : (Length - 4) Bytes                                            :
91  * +---------------------------------------------------------------+
92  */
93 struct part_string_s
94 {
95         part_header_t *head;
96         char *value;
97 };
98 typedef struct part_string_s part_string_t;
99
100 /*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
101  *  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
102  * +-------------------------------+-------------------------------+
103  * ! Type                          ! Length                        !
104  * +-------------------------------+-------------------------------+
105  * : (Length - 4 == 2 || 4 || 8) Bytes                             :
106  * +---------------------------------------------------------------+
107  */
108 struct part_number_s
109 {
110         part_header_t *head;
111         uint64_t *value;
112 };
113 typedef struct part_number_s part_number_t;
114
115 /*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
116  *  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
117  * +-------------------------------+-------------------------------+
118  * ! Type                          ! Length                        !
119  * +-------------------------------+---------------+---------------+
120  * ! Num of values                 ! Type0         ! Type1         !
121  * +-------------------------------+---------------+---------------+
122  * ! Value0                                                        !
123  * !                                                               !
124  * +---------------------------------------------------------------+
125  * ! Value1                                                        !
126  * !                                                               !
127  * +---------------------------------------------------------------+
128  */
129 struct part_values_s
130 {
131         part_header_t *head;
132         uint16_t *num_values;
133         uint8_t  *values_types;
134         value_t  *values;
135 };
136 typedef struct part_values_s part_values_t;
137
138 /*
139  * Private variables
140  */
141 static const char *config_keys[] =
142 {
143         "Listen",
144         "Server",
145         "TimeToLive",
146         NULL
147 };
148 static int config_keys_num = 3;
149
150 static int network_config_ttl = 0;
151
152 static sockent_t *sending_sockets = NULL;
153
154 static struct pollfd *listen_sockets = NULL;
155 static int listen_sockets_num = 0;
156 static pthread_t listen_thread = 0;
157 static int listen_loop = 0;
158
159 static char         send_buffer[BUFF_SIZE];
160 static char        *send_buffer_ptr;
161 static int          send_buffer_fill;
162 static value_list_t send_buffer_vl = VALUE_LIST_INIT;
163 static char         send_buffer_type[DATA_MAX_NAME_LEN];
164
165 /*
166  * Private functions
167  */
168 static int write_part_values (char **ret_buffer, int *ret_buffer_len,
169                 const data_set_t *ds, const value_list_t *vl)
170 {
171         part_values_t pv;
172         int i;
173
174         i = 6 + (9 * vl->values_len);
175         if (*ret_buffer_len < i)
176                 return (-1);
177         *ret_buffer_len -= i;
178
179         pv.head = (part_header_t *) *ret_buffer;
180         pv.num_values = (uint16_t *) (pv.head + 1);
181         pv.values_types = (uint8_t *) (pv.num_values + 1);
182         pv.values = (value_t *) (pv.values_types + vl->values_len);
183         *ret_buffer = (void *) (pv.values + vl->values_len);
184
185         pv.head->type = htons (TYPE_VALUES);
186         pv.head->length = htons (6 + (9 * vl->values_len));
187         *pv.num_values = htons ((uint16_t) vl->values_len);
188         
189         for (i = 0; i < vl->values_len; i++)
190         {
191                 if (ds->ds[i].type == DS_TYPE_COUNTER)
192                 {
193                         pv.values_types[i] = DS_TYPE_COUNTER;
194                         pv.values[i].counter = htonll (vl->values[i].counter);
195                 }
196                 else
197                 {
198                         pv.values_types[i] = DS_TYPE_GAUGE;
199                         pv.values[i].gauge = vl->values[i].gauge;
200                 }
201         } /* for (values) */
202
203         return (0);
204 } /* int write_part_values */
205
206 static int write_part_number (char **ret_buffer, int *ret_buffer_len,
207                 int type, uint64_t value)
208 {
209         part_number_t pn;
210
211         if (*ret_buffer_len < 12)
212                 return (-1);
213
214         pn.head = (part_header_t *) *ret_buffer;
215         pn.value = (uint64_t *) (pn.head + 1);
216
217         pn.head->type = htons (type);
218         pn.head->length = htons (12);
219         *pn.value = htonll (value);
220
221         *ret_buffer = (char *) (pn.value + 1);
222         *ret_buffer_len -= 12;
223
224         return (0);
225 } /* int write_part_number */
226
227 static int write_part_string (char **ret_buffer, int *ret_buffer_len,
228                 int type, const char *str, int str_len)
229 {
230         part_string_t ps;
231         int len;
232
233         len = 4 + str_len + 1;
234         if (*ret_buffer_len < len)
235                 return (-1);
236         *ret_buffer_len -= len;
237
238         ps.head = (part_header_t *) *ret_buffer;
239         ps.value = (char *) (ps.head + 1);
240
241         ps.head->type = htons ((uint16_t) type);
242         ps.head->length = htons ((uint16_t) str_len + 5);
243         if (str_len > 0)
244                 memcpy (ps.value, str, str_len);
245         ps.value[str_len] = '\0';
246         *ret_buffer = (void *) (ps.value + (str_len + 1));
247
248         return (0);
249 } /* int write_part_string */
250
251 static int parse_part_values (void **ret_buffer, int *ret_buffer_len,
252                 value_t **ret_values, int *ret_num_values)
253 {
254         char *buffer = *ret_buffer;
255         int   buffer_len = *ret_buffer_len;
256         part_values_t pv;
257         int   i;
258
259         uint16_t h_length;
260         uint16_t h_type;
261         uint16_t h_num;
262
263         if (buffer_len < (15))
264         {
265                 DEBUG ("packet is too short: buffer_len = %i", buffer_len);
266                 return (-1);
267         }
268
269         pv.head = (part_header_t *) buffer;
270         h_length = ntohs (pv.head->length);
271         h_type = ntohs (pv.head->type);
272
273         assert (h_type == TYPE_VALUES);
274
275         pv.num_values = (uint16_t *) (pv.head + 1);
276         h_num = ntohs (*pv.num_values);
277
278         if (h_num != ((h_length - 6) / 9))
279         {
280                 DEBUG ("`length' and `num of values' don't match");
281                 return (-1);
282         }
283
284         pv.values_types = (uint8_t *) (pv.num_values + 1);
285         pv.values = (value_t *) (pv.values_types + h_num);
286
287         for (i = 0; i < h_num; i++)
288                 if (pv.values_types[i] == DS_TYPE_COUNTER)
289                         pv.values[i].counter = ntohll (pv.values[i].counter);
290
291         *ret_buffer     = (void *) (pv.values + h_num);
292         *ret_buffer_len = buffer_len - h_length;
293         *ret_num_values = h_num;
294         *ret_values     = pv.values;
295
296         return (0);
297 } /* int parse_part_values */
298
299 static int parse_part_number (void **ret_buffer, int *ret_buffer_len,
300                 uint64_t *value)
301 {
302         part_number_t pn;
303         uint16_t len;
304
305         pn.head = (part_header_t *) *ret_buffer;
306         pn.value = (uint64_t *) (pn.head + 1);
307
308         len = ntohs (pn.head->length);
309         if (len != 12)
310                 return (-1);
311         if (len > *ret_buffer_len)
312                 return (-1);
313         *value = ntohll (*pn.value);
314
315         *ret_buffer = (void *) (pn.value + 1);
316         *ret_buffer_len -= len;
317
318         return (0);
319 } /* int parse_part_number */
320
321 static int parse_part_string (void **ret_buffer, int *ret_buffer_len,
322                 char *output, int output_len)
323 {
324         char *buffer = *ret_buffer;
325         int   buffer_len = *ret_buffer_len;
326         part_string_t ps;
327
328         uint16_t h_length;
329         uint16_t h_type;
330
331         DEBUG ("ret_buffer = %p; ret_buffer_len = %i; output = %p; output_len = %i;",
332                         *ret_buffer, *ret_buffer_len,
333                         (void *) output, output_len);
334
335         ps.head = (part_header_t *) buffer;
336
337         h_length = ntohs (ps.head->length);
338         h_type = ntohs (ps.head->type);
339
340         DEBUG ("length = %hu; type = %hu;", h_length, h_type);
341
342         if (buffer_len < h_length)
343         {
344                 DEBUG ("packet is too short");
345                 return (-1);
346         }
347         assert ((h_type == TYPE_HOST)
348                         || (h_type == TYPE_PLUGIN)
349                         || (h_type == TYPE_PLUGIN_INSTANCE)
350                         || (h_type == TYPE_TYPE)
351                         || (h_type == TYPE_TYPE_INSTANCE));
352
353         ps.value = buffer + 4;
354         if (ps.value[h_length - 5] != '\0')
355         {
356                 DEBUG ("String does not end with a nullbyte");
357                 return (-1);
358         }
359
360         if (output_len < (h_length - 4))
361         {
362                 DEBUG ("output buffer is too small");
363                 return (-1);
364         }
365         strcpy (output, ps.value);
366
367         DEBUG ("output = %s", output);
368
369         *ret_buffer = (void *) (buffer + h_length);
370         *ret_buffer_len = buffer_len - h_length;
371
372         return (0);
373 } /* int parse_part_string */
374
375 static int parse_packet (void *buffer, int buffer_len)
376 {
377         part_header_t *header;
378         int status;
379
380         value_list_t vl = VALUE_LIST_INIT;
381         char type[DATA_MAX_NAME_LEN];
382
383         DEBUG ("buffer = %p; buffer_len = %i;", buffer, buffer_len);
384
385         memset (&vl, '\0', sizeof (vl));
386         memset (&type, '\0', sizeof (type));
387         status = 0;
388
389         while ((status == 0) && (buffer_len > sizeof (part_header_t)))
390         {
391                 header = (part_header_t *) buffer;
392
393                 if (ntohs (header->length) > buffer_len)
394                         break;
395
396                 if (header->type == htons (TYPE_VALUES))
397                 {
398                         status = parse_part_values (&buffer, &buffer_len,
399                                         &vl.values, &vl.values_len);
400
401                         if (status != 0)
402                         {
403                                 DEBUG ("parse_part_values failed.");
404                                 break;
405                         }
406
407                         if ((vl.time > 0)
408                                         && (strlen (vl.host) > 0)
409                                         && (strlen (vl.plugin) > 0)
410                                         && (strlen (type) > 0))
411                         {
412                                 DEBUG ("dispatching values");
413                                 plugin_dispatch_values (type, &vl);
414                         }
415                         else
416                         {
417                                 DEBUG ("NOT dispatching values");
418                         }
419                 }
420                 else if (header->type == ntohs (TYPE_TIME))
421                 {
422                         uint64_t tmp = 0;
423                         status = parse_part_number (&buffer, &buffer_len, &tmp);
424                         if (status == 0)
425                                 vl.time = (time_t) tmp;
426                 }
427                 else if (header->type == ntohs (TYPE_HOST))
428                 {
429                         status = parse_part_string (&buffer, &buffer_len,
430                                         vl.host, sizeof (vl.host));
431                 }
432                 else if (header->type == ntohs (TYPE_PLUGIN))
433                 {
434                         status = parse_part_string (&buffer, &buffer_len,
435                                         vl.plugin, sizeof (vl.plugin));
436                 }
437                 else if (header->type == ntohs (TYPE_PLUGIN_INSTANCE))
438                 {
439                         status = parse_part_string (&buffer, &buffer_len,
440                                         vl.plugin_instance, sizeof (vl.plugin_instance));
441                 }
442                 else if (header->type == ntohs (TYPE_TYPE))
443                 {
444                         status = parse_part_string (&buffer, &buffer_len,
445                                         type, sizeof (type));
446                 }
447                 else if (header->type == ntohs (TYPE_TYPE_INSTANCE))
448                 {
449                         status = parse_part_string (&buffer, &buffer_len,
450                                         vl.type_instance, sizeof (vl.type_instance));
451                 }
452                 else
453                 {
454                         DEBUG ("Unknown part type: 0x%0hx", header->type);
455                         buffer = ((char *) buffer) + header->length;
456                 }
457         } /* while (buffer_len > sizeof (part_header_t)) */
458
459         return (0);
460 } /* int parse_packet */
461
462 static void free_sockent (sockent_t *se)
463 {
464         sockent_t *next;
465         while (se != NULL)
466         {
467                 next = se->next;
468                 free (se->addr);
469                 free (se);
470                 se = next;
471         }
472 } /* void free_sockent */
473
474 /*
475  * int network_set_ttl
476  *
477  * Set the `IP_MULTICAST_TTL', `IP_TTL', `IPV6_MULTICAST_HOPS' or
478  * `IPV6_UNICAST_HOPS', depending on which option is applicable.
479  *
480  * The `struct addrinfo' is used to destinguish between unicast and multicast
481  * sockets.
482  */
483 static int network_set_ttl (const sockent_t *se, const struct addrinfo *ai)
484 {
485         if ((network_config_ttl < 1) || (network_config_ttl > 255))
486                 return (-1);
487
488         DEBUG ("ttl = %i", network_config_ttl);
489
490         if (ai->ai_family == AF_INET)
491         {
492                 struct sockaddr_in *addr = (struct sockaddr_in *) ai->ai_addr;
493                 int optname;
494
495                 if (IN_MULTICAST (ntohl (addr->sin_addr.s_addr)))
496                         optname = IP_MULTICAST_TTL;
497                 else
498                         optname = IP_TTL;
499
500                 if (setsockopt (se->fd, IPPROTO_IP, optname,
501                                         &network_config_ttl,
502                                         sizeof (network_config_ttl)) == -1)
503                 {
504                         char errbuf[1024];
505                         ERROR ("setsockopt: %s",
506                                         sstrerror (errno, errbuf, sizeof (errbuf)));
507                         return (-1);
508                 }
509         }
510         else if (ai->ai_family == AF_INET6)
511         {
512                 /* Useful example: http://gsyc.escet.urjc.es/~eva/IPv6-web/examples/mcast.html */
513                 struct sockaddr_in6 *addr = (struct sockaddr_in6 *) ai->ai_addr;
514                 int optname;
515
516                 if (IN6_IS_ADDR_MULTICAST (&addr->sin6_addr))
517                         optname = IPV6_MULTICAST_HOPS;
518                 else
519                         optname = IPV6_UNICAST_HOPS;
520
521                 if (setsockopt (se->fd, IPPROTO_IPV6, optname,
522                                         &network_config_ttl,
523                                         sizeof (network_config_ttl)) == -1)
524                 {
525                         char errbuf[1024];
526                         ERROR ("setsockopt: %s",
527                                         sstrerror (errno, errbuf,
528                                                 sizeof (errbuf)));
529                         return (-1);
530                 }
531         }
532
533         return (0);
534 } /* int network_set_ttl */
535
536 static int network_bind_socket (const sockent_t *se, const struct addrinfo *ai)
537 {
538         int loop = 1;
539
540         DEBUG ("fd = %i; calling `bind'", se->fd);
541
542         if (bind (se->fd, ai->ai_addr, ai->ai_addrlen) == -1)
543         {
544                 char errbuf[1024];
545                 ERROR ("bind: %s",
546                                 sstrerror (errno, errbuf, sizeof (errbuf)));
547                 return (-1);
548         }
549
550         if (ai->ai_family == AF_INET)
551         {
552                 struct sockaddr_in *addr = (struct sockaddr_in *) ai->ai_addr;
553                 if (IN_MULTICAST (ntohl (addr->sin_addr.s_addr)))
554                 {
555                         struct ip_mreq mreq;
556
557                         DEBUG ("fd = %i; IPv4 multicast address found", se->fd);
558
559                         mreq.imr_multiaddr.s_addr = addr->sin_addr.s_addr;
560                         mreq.imr_interface.s_addr = htonl (INADDR_ANY);
561
562                         if (setsockopt (se->fd, IPPROTO_IP, IP_MULTICAST_LOOP,
563                                                 &loop, sizeof (loop)) == -1)
564                         {
565                                 char errbuf[1024];
566                                 ERROR ("setsockopt: %s",
567                                                 sstrerror (errno, errbuf,
568                                                         sizeof (errbuf)));
569                                 return (-1);
570                         }
571
572                         if (setsockopt (se->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
573                                                 &mreq, sizeof (mreq)) == -1)
574                         {
575                                 char errbuf[1024];
576                                 ERROR ("setsockopt: %s",
577                                                 sstrerror (errno, errbuf,
578                                                         sizeof (errbuf)));
579                                 return (-1);
580                         }
581                 }
582         }
583         else if (ai->ai_family == AF_INET6)
584         {
585                 /* Useful example: http://gsyc.escet.urjc.es/~eva/IPv6-web/examples/mcast.html */
586                 struct sockaddr_in6 *addr = (struct sockaddr_in6 *) ai->ai_addr;
587                 if (IN6_IS_ADDR_MULTICAST (&addr->sin6_addr))
588                 {
589                         struct ipv6_mreq mreq;
590
591                         DEBUG ("fd = %i; IPv6 multicast address found", se->fd);
592
593                         memcpy (&mreq.ipv6mr_multiaddr,
594                                         &addr->sin6_addr,
595                                         sizeof (addr->sin6_addr));
596
597                         /* http://developer.apple.com/documentation/Darwin/Reference/ManPages/man4/ip6.4.html
598                          * ipv6mr_interface may be set to zeroes to
599                          * choose the default multicast interface or to
600                          * the index of a particular multicast-capable
601                          * interface if the host is multihomed.
602                          * Membership is associ-associated with a
603                          * single interface; programs running on
604                          * multihomed hosts may need to join the same
605                          * group on more than one interface.*/
606                         mreq.ipv6mr_interface = 0;
607
608                         if (setsockopt (se->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
609                                                 &loop, sizeof (loop)) == -1)
610                         {
611                                 char errbuf[1024];
612                                 ERROR ("setsockopt: %s",
613                                                 sstrerror (errno, errbuf,
614                                                         sizeof (errbuf)));
615                                 return (-1);
616                         }
617
618                         if (setsockopt (se->fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
619                                                 &mreq, sizeof (mreq)) == -1)
620                         {
621                                 char errbuf[1024];
622                                 ERROR ("setsockopt: %s",
623                                                 sstrerror (errno, errbuf,
624                                                         sizeof (errbuf)));
625                                 return (-1);
626                         }
627                 }
628         }
629
630         return (0);
631 } /* int network_bind_socket */
632
633 static sockent_t *network_create_socket (const char *node,
634                 const char *service,
635                 int listen)
636 {
637         struct addrinfo  ai_hints;
638         struct addrinfo *ai_list, *ai_ptr;
639         int              ai_return;
640
641         sockent_t *se_head = NULL;
642         sockent_t *se_tail = NULL;
643
644         DEBUG ("node = %s, service = %s", node, service);
645
646         memset (&ai_hints, '\0', sizeof (ai_hints));
647         ai_hints.ai_flags    = 0;
648 #ifdef AI_PASSIVE
649         ai_hints.ai_flags |= AI_PASSIVE;
650 #endif
651 #ifdef AI_ADDRCONFIG
652         ai_hints.ai_flags |= AI_ADDRCONFIG;
653 #endif
654         ai_hints.ai_family   = AF_UNSPEC;
655         ai_hints.ai_socktype = SOCK_DGRAM;
656         ai_hints.ai_protocol = IPPROTO_UDP;
657
658         ai_return = getaddrinfo (node, service, &ai_hints, &ai_list);
659         if (ai_return != 0)
660         {
661                 char errbuf[1024];
662                 ERROR ("getaddrinfo (%s, %s): %s",
663                                 (node == NULL) ? "(null)" : node,
664                                 (service == NULL) ? "(null)" : service,
665                                 (ai_return == EAI_SYSTEM)
666                                 ? sstrerror (errno, errbuf, sizeof (errbuf))
667                                 : gai_strerror (ai_return));
668                 return (NULL);
669         }
670
671         for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
672         {
673                 sockent_t *se;
674
675                 if ((se = (sockent_t *) malloc (sizeof (sockent_t))) == NULL)
676                 {
677                         char errbuf[1024];
678                         ERROR ("malloc: %s",
679                                         sstrerror (errno, errbuf,
680                                                 sizeof (errbuf)));
681                         continue;
682                 }
683
684                 if ((se->addr = (struct sockaddr_storage *) malloc (sizeof (struct sockaddr_storage))) == NULL)
685                 {
686                         char errbuf[1024];
687                         ERROR ("malloc: %s",
688                                         sstrerror (errno, errbuf,
689                                                 sizeof (errbuf)));
690                         free (se);
691                         continue;
692                 }
693
694                 assert (sizeof (struct sockaddr_storage) >= ai_ptr->ai_addrlen);
695                 memset (se->addr, '\0', sizeof (struct sockaddr_storage));
696                 memcpy (se->addr, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
697                 se->addrlen = ai_ptr->ai_addrlen;
698
699                 se->fd   = socket (ai_ptr->ai_family,
700                                 ai_ptr->ai_socktype,
701                                 ai_ptr->ai_protocol);
702                 se->next = NULL;
703
704                 if (se->fd == -1)
705                 {
706                         char errbuf[1024];
707                         ERROR ("socket: %s",
708                                         sstrerror (errno, errbuf,
709                                                 sizeof (errbuf)));
710                         free (se->addr);
711                         free (se);
712                         continue;
713                 }
714
715                 if (listen != 0)
716                 {
717                         if (network_bind_socket (se, ai_ptr) != 0)
718                         {
719                                 close (se->fd);
720                                 free (se->addr);
721                                 free (se);
722                                 continue;
723                         }
724                 }
725                 else /* listen == 0 */
726                 {
727                         network_set_ttl (se, ai_ptr);
728                 }
729
730                 if (se_tail == NULL)
731                 {
732                         se_head = se;
733                         se_tail = se;
734                 }
735                 else
736                 {
737                         se_tail->next = se;
738                         se_tail = se;
739                 }
740
741                 /* We don't open more than one write-socket per node/service pair.. */
742                 if (listen == 0)
743                         break;
744         }
745
746         freeaddrinfo (ai_list);
747
748         return (se_head);
749 } /* sockent_t *network_create_socket */
750
751 static sockent_t *network_create_default_socket (int listen)
752 {
753         sockent_t *se_ptr  = NULL;
754         sockent_t *se_head = NULL;
755         sockent_t *se_tail = NULL;
756
757         se_ptr = network_create_socket (NET_DEFAULT_V6_ADDR,
758                         NET_DEFAULT_PORT, listen);
759
760         /* Don't send to the same machine in IPv6 and IPv4 if both are available. */
761         if ((listen == 0) && (se_ptr != NULL))
762                 return (se_ptr);
763
764         if (se_ptr != NULL)
765         {
766                 se_head = se_ptr;
767                 se_tail = se_ptr;
768                 while (se_tail->next != NULL)
769                         se_tail = se_tail->next;
770         }
771
772         se_ptr = network_create_socket (NET_DEFAULT_V4_ADDR, NET_DEFAULT_PORT, listen);
773
774         if (se_tail == NULL)
775                 return (se_ptr);
776
777         se_tail->next = se_ptr;
778         return (se_head);
779 } /* sockent_t *network_create_default_socket */
780
781 static int network_add_listen_socket (const char *node, const char *service)
782 {
783         sockent_t *se;
784         sockent_t *se_ptr;
785         int se_num = 0;
786
787         if (service == NULL)
788                 service = NET_DEFAULT_PORT;
789
790         if (node == NULL)
791                 se = network_create_default_socket (1 /* listen == true */);
792         else
793                 se = network_create_socket (node, service, 1 /* listen == true */);
794
795         if (se == NULL)
796                 return (-1);
797
798         for (se_ptr = se; se_ptr != NULL; se_ptr = se_ptr->next)
799                 se_num++;
800
801         listen_sockets = (struct pollfd *) realloc (listen_sockets,
802                         (listen_sockets_num + se_num)
803                         * sizeof (struct pollfd));
804
805         for (se_ptr = se; se_ptr != NULL; se_ptr = se_ptr->next)
806         {
807                 listen_sockets[listen_sockets_num].fd = se_ptr->fd;
808                 listen_sockets[listen_sockets_num].events = POLLIN | POLLPRI;
809                 listen_sockets[listen_sockets_num].revents = 0;
810                 listen_sockets_num++;
811         } /* for (se) */
812
813         free_sockent (se);
814         return (0);
815 } /* int network_add_listen_socket */
816
817 static int network_add_sending_socket (const char *node, const char *service)
818 {
819         sockent_t *se;
820         sockent_t *se_ptr;
821
822         if (service == NULL)
823                 service = NET_DEFAULT_PORT;
824
825         if (node == NULL)
826                 se = network_create_default_socket (0 /* listen == false */);
827         else
828                 se = network_create_socket (node, service, 0 /* listen == false */);
829
830         if (se == NULL)
831                 return (-1);
832
833         if (sending_sockets == NULL)
834         {
835                 sending_sockets = se;
836                 return (0);
837         }
838
839         for (se_ptr = sending_sockets; se_ptr->next != NULL; se_ptr = se_ptr->next)
840                 /* seek end */;
841
842         se_ptr->next = se;
843         return (0);
844 } /* int network_get_listen_socket */
845
846 int network_receive (void)
847 {
848         char buffer[BUFF_SIZE];
849         int  buffer_len;
850
851         int i;
852         int status;
853
854         if (listen_sockets_num == 0)
855                 network_add_listen_socket (NULL, NULL);
856
857         if (listen_sockets_num == 0)
858         {
859                 ERROR ("network: Failed to open a listening socket.");
860                 return (-1);
861         }
862
863         while (listen_loop == 0)
864         {
865                 status = poll (listen_sockets, listen_sockets_num, -1);
866
867                 if (status <= 0)
868                 {
869                         char errbuf[1024];
870                         if (errno == EINTR)
871                                 continue;
872                         ERROR ("poll failed: %s",
873                                         sstrerror (errno, errbuf, sizeof (errbuf)));
874                         return (-1);
875                 }
876
877                 for (i = 0; (i < listen_sockets_num) && (status > 0); i++)
878                 {
879                         if ((listen_sockets[i].revents & (POLLIN | POLLPRI)) == 0)
880                                 continue;
881                         status--;
882
883                         buffer_len = recv (listen_sockets[i].fd,
884                                         buffer, sizeof (buffer),
885                                         0 /* no flags */);
886                         if (buffer_len < 0)
887                         {
888                                 char errbuf[1024];
889                                 ERROR ("recv failed: %s",
890                                                 sstrerror (errno, errbuf,
891                                                         sizeof (errbuf)));
892                                 return (-1);
893                         }
894
895                         parse_packet (buffer, buffer_len);
896                 } /* for (listen_sockets) */
897         } /* while (listen_loop == 0) */
898
899         return (0);
900 }
901
902 static void *receive_thread (void *arg)
903 {
904         return (network_receive () ? (void *) 1 : (void *) 0);
905 } /* void *receive_thread */
906
907 static void network_send_buffer (const char *buffer, int buffer_len)
908 {
909         sockent_t *se;
910         int status;
911
912         DEBUG ("buffer_len = %i", buffer_len);
913
914         for (se = sending_sockets; se != NULL; se = se->next)
915         {
916                 while (42)
917                 {
918                         status = sendto (se->fd, buffer, buffer_len, 0 /* no flags */,
919                                         (struct sockaddr *) se->addr, se->addrlen);
920                         if (status < 0)
921                         {
922                                 char errbuf[1024];
923                                 if (errno == EINTR)
924                                         continue;
925                                 ERROR ("network plugin: sendto failed: %s",
926                                                 sstrerror (errno, errbuf,
927                                                         sizeof (errbuf)));
928                                 break;
929                         }
930
931                         break;
932                 } /* while (42) */
933         } /* for (sending_sockets) */
934 } /* void network_send_buffer */
935
936 static int add_to_buffer (char *buffer, int buffer_size,
937                 value_list_t *vl_def, char *type_def,
938                 const data_set_t *ds, const value_list_t *vl)
939 {
940         if (strcmp (vl_def->host, vl->host) != 0)
941         {
942                 if (write_part_string (&buffer, &buffer_size, TYPE_HOST,
943                                         vl->host, strlen (vl->host)) != 0)
944                         return (-1);
945                 strcpy (vl_def->host, vl->host);
946                 DEBUG ("host = %s", vl->host);
947         }
948
949         if (vl_def->time != vl->time)
950         {
951                 if (write_part_number (&buffer, &buffer_size, TYPE_TIME,
952                                         (uint64_t) vl->time))
953                         return (-1);
954                 vl_def->time = vl->time;
955                 DEBUG ("time = %u", (unsigned int) vl->time);
956         }
957
958         if (strcmp (vl_def->plugin, vl->plugin) != 0)
959         {
960                 if (write_part_string (&buffer, &buffer_size, TYPE_PLUGIN,
961                                         vl->plugin, strlen (vl->plugin)) != 0)
962                         return (-1);
963                 strcpy (vl_def->plugin, vl->plugin);
964                 DEBUG ("plugin = %s", vl->plugin);
965         }
966
967         if (strcmp (vl_def->plugin_instance, vl->plugin_instance) != 0)
968         {
969                 if (write_part_string (&buffer, &buffer_size, TYPE_PLUGIN_INSTANCE,
970                                         vl->plugin_instance,
971                                         strlen (vl->plugin_instance)) != 0)
972                         return (-1);
973                 strcpy (vl_def->plugin_instance, vl->plugin_instance);
974                 DEBUG ("plugin_instance = %s", vl->plugin_instance);
975         }
976
977         if (strcmp (type_def, ds->type) != 0)
978         {
979                 if (write_part_string (&buffer, &buffer_size, TYPE_TYPE,
980                                         ds->type, strlen (ds->type)) != 0)
981                         return (-1);
982                 strcpy (type_def, ds->type);
983                 DEBUG ("type = %s", ds->type);
984         }
985
986         if (strcmp (vl_def->type_instance, vl->type_instance) != 0)
987         {
988                 if (write_part_string (&buffer, &buffer_size, TYPE_PLUGIN_INSTANCE,
989                                         vl->type_instance,
990                                         strlen (vl->type_instance)) != 0)
991                         return (-1);
992                 strcpy (vl_def->type_instance, vl->type_instance);
993                 DEBUG ("type_instance = %s", vl->type_instance);
994         }
995         
996         if (write_part_values (&buffer, &buffer_size, ds, vl) != 0)
997                 return (-1);
998
999         return (buffer_size);
1000 } /* int add_to_buffer */
1001
1002 static void flush_buffer (void)
1003 {
1004         network_send_buffer (send_buffer, send_buffer_fill);
1005         send_buffer_ptr  = send_buffer;
1006         send_buffer_fill = 0;
1007         memset (&send_buffer_vl, '\0', sizeof (send_buffer_vl));
1008         memset (send_buffer_type, '\0', sizeof (send_buffer_type));
1009 }
1010
1011 static int network_write (const data_set_t *ds, const value_list_t *vl)
1012 {
1013         int status;
1014         /* TODO: lock buffer */
1015         status = add_to_buffer (send_buffer_ptr,
1016                         sizeof (send_buffer) - send_buffer_fill,
1017                         &send_buffer_vl, send_buffer_type,
1018                         ds, vl);
1019         if (status >= 0)
1020         {
1021                 send_buffer_fill += status;
1022                 send_buffer_ptr  += status;
1023         }
1024         else
1025         {
1026                 flush_buffer ();
1027
1028                 status = add_to_buffer (send_buffer_ptr,
1029                                 sizeof (send_buffer) - send_buffer_fill,
1030                                 &send_buffer_vl, send_buffer_type,
1031                                 ds, vl);
1032
1033                 if (status >= 0)
1034                 {
1035                         send_buffer_fill += status;
1036                         send_buffer_ptr  += status;
1037                 }
1038         }
1039
1040         if (status < 0)
1041         {
1042                 ERROR ("network plugin: Unable to append to the "
1043                                 "buffer for some weird reason");
1044         }
1045         else if ((sizeof (send_buffer) - send_buffer_fill) < 15)
1046         {
1047                 flush_buffer ();
1048         }
1049         /* TODO: unlock buffer */
1050
1051         return ((status < 0) ? -1 : 0);
1052 } /* int network_write */
1053
1054 static int network_config (const char *key, const char *val)
1055 {
1056         char *node;
1057         char *service;
1058
1059         char *fields[3];
1060         int   fields_num;
1061
1062         if ((strcasecmp ("Listen", key) == 0)
1063                         || (strcasecmp ("Server", key) == 0))
1064         {
1065                 char *val_cpy = strdup (val);
1066                 if (val_cpy == NULL)
1067                         return (1);
1068
1069                 service = NET_DEFAULT_PORT;
1070                 fields_num = strsplit (val_cpy, fields, 3);
1071                 if ((fields_num != 1)
1072                                 && (fields_num != 2))
1073                         return (1);
1074                 else if (fields_num == 2)
1075                         service = fields[1];
1076                 node = fields[0];
1077
1078                 if (strcasecmp ("Listen", key) == 0)
1079                         network_add_listen_socket (node, service);
1080                 else
1081                         network_add_sending_socket (node, service);
1082         }
1083         else if (strcasecmp ("TimeToLive", key) == 0)
1084         {
1085                 int tmp = atoi (val);
1086                 if ((tmp > 0) && (tmp < 256))
1087                         network_config_ttl = tmp;
1088                 else
1089                         return (1);
1090         }
1091         else
1092         {
1093                 return (-1);
1094         }
1095         return (0);
1096 }
1097
1098 static int network_shutdown (void)
1099 {
1100         DEBUG ("Shutting down.");
1101
1102         listen_loop++;
1103
1104         pthread_kill (listen_thread, SIGTERM);
1105         pthread_join (listen_thread, NULL /* no return value */);
1106
1107         listen_thread = 0;
1108
1109         return (0);
1110 }
1111
1112 static int network_init (void)
1113 {
1114         plugin_register_shutdown ("network", network_shutdown);
1115
1116         send_buffer_ptr  = send_buffer;
1117         send_buffer_fill = 0;
1118         memset (&send_buffer_vl, '\0', sizeof (send_buffer_vl));
1119         memset (send_buffer_type, '\0', sizeof (send_buffer_type));
1120
1121         /* setup socket(s) and so on */
1122         if (sending_sockets != NULL)
1123                 plugin_register_write ("network", network_write);
1124
1125         if ((listen_sockets_num != 0) && (listen_thread == 0))
1126         {
1127                 int status;
1128
1129                 status = pthread_create (&listen_thread, NULL /* no attributes */,
1130                                 receive_thread, NULL /* no argument */);
1131
1132                 if (status != 0)
1133                 {
1134                         char errbuf[1024];
1135                         ERROR ("network: pthread_create failed: %s",
1136                                         sstrerror (errno, errbuf,
1137                                                 sizeof (errbuf)));
1138                 }
1139         }
1140         return (0);
1141 } /* int network_init */
1142
1143 void module_register (void)
1144 {
1145         plugin_register_config ("network", network_config,
1146                         config_keys, config_keys_num);
1147         plugin_register_init   ("network", network_init);
1148 }