X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fnetwork.c;h=54f9bfa3b43456dd1d02fd0b2b1104ca5d211a86;hb=e864bcaff1a5205ab6fcdd34281544fe6a56c0fe;hp=546f5e2d142ad46d03548a5410d5c139ba361018;hpb=e723f7fb92d313a8fe56c1ee8763985fcc9bb722;p=collectd.git diff --git a/src/network.c b/src/network.c index 546f5e2d..54f9bfa3 100644 --- a/src/network.c +++ b/src/network.c @@ -1,6 +1,6 @@ /** * collectd - src/network.c - * Copyright (C) 2006 Florian octo Forster + * Copyright (C) 2005,2006 Florian octo Forster * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -23,48 +23,38 @@ #include #include #include -#include #include #include +#include #include #include #include #include -#include #include "network.h" #include "common.h" +#include "configfile.h" #include "utils_debug.h" -/* - * From RFC2365: - * - * The IPv4 Organization Local Scope -- 239.192.0.0/14 - * - * 239.192.0.0/14 is defined to be the IPv4 Organization Local Scope, and is - * the space from which an organization should allocate sub-ranges when - * defining scopes for private use. - * - * Port 25826 is not assigned as of 2005-09-12 - */ - -#define IPV4_MCAST_GROUP "239.192.74.66" -#define UDP_PORT 25826 - /* 1500 - 40 - 8 = Ethernet packet - IPv6 header - UDP header */ /* #define BUFF_SIZE 1452 */ +#ifndef IPV6_ADD_MEMBERSHIP +# ifdef IPV6_JOIN_GROUP +# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +# else +# error "Neither IP_ADD_MEMBERSHIP nor IPV6_JOIN_GROUP is defined" +# endif +#endif /* !IP_ADD_MEMBERSHIP */ + #define BUFF_SIZE 4096 -#ifdef HAVE_LIBRRD extern int operating_mode; -#else -static int operating_mode = MODE_CLIENT; -#endif typedef struct sockent { int fd; + int mode; struct sockaddr_storage *addr; socklen_t addrlen; struct sockent *next; @@ -72,10 +62,69 @@ typedef struct sockent static sockent_t *socklist_head = NULL; +static int network_set_ttl (const sockent_t *se, const struct addrinfo *ai) +{ + char *ttl_str; + int ttl_int; + + ttl_str = cf_get_option ("TimeToLive", NULL); + if (ttl_str == NULL) + return (-1); + + ttl_int = atoi (ttl_str); + if ((ttl_int < 1) || (ttl_int > 255)) + { + syslog (LOG_WARNING, "A TTL value of %i is invalid.", ttl_int); + return (-1); + } + + DBG ("ttl = %i", ttl_int); + + if (ai->ai_family == AF_INET) + { + struct sockaddr_in *addr = (struct sockaddr_in *) ai->ai_addr; + int optname; + + if (IN_MULTICAST (ntohl (addr->sin_addr.s_addr))) + optname = IP_MULTICAST_TTL; + else + optname = IP_TTL; + + if (setsockopt (se->fd, IPPROTO_IP, optname, + &ttl_int, sizeof (ttl_int)) == -1) + { + syslog (LOG_ERR, "setsockopt: %s", strerror (errno)); + return (-1); + } + } + else if (ai->ai_family == AF_INET6) + { + /* Useful example: http://gsyc.escet.urjc.es/~eva/IPv6-web/examples/mcast.html */ + struct sockaddr_in6 *addr = (struct sockaddr_in6 *) ai->ai_addr; + int optname; + + if (IN6_IS_ADDR_MULTICAST (&addr->sin6_addr)) + optname = IPV6_MULTICAST_HOPS; + else + optname = IPV6_UNICAST_HOPS; + + if (setsockopt (se->fd, IPPROTO_IPV6, optname, + &ttl_int, sizeof (ttl_int)) == -1) + { + syslog (LOG_ERR, "setsockopt: %s", strerror (errno)); + return (-1); + } + } + + return (0); +} + static int network_bind_socket (const sockent_t *se, const struct addrinfo *ai) { int loop = 1; + DBG ("fd = %i; calling `bind'", se->fd); + if (bind (se->fd, ai->ai_addr, ai->ai_addrlen) == -1) { syslog (LOG_ERR, "bind: %s", strerror (errno)); @@ -89,6 +138,8 @@ static int network_bind_socket (const sockent_t *se, const struct addrinfo *ai) { struct ip_mreq mreq; + DBG ("fd = %i; IPv4 multicast address found", se->fd); + mreq.imr_multiaddr.s_addr = addr->sin_addr.s_addr; mreq.imr_interface.s_addr = htonl (INADDR_ANY); @@ -115,6 +166,8 @@ static int network_bind_socket (const sockent_t *se, const struct addrinfo *ai) { struct ipv6_mreq mreq; + DBG ("fd = %i; IPv6 multicast address found", se->fd); + memcpy (&mreq.ipv6mr_multiaddr, &addr->sin6_addr, sizeof (addr->sin6_addr)); @@ -161,7 +214,7 @@ int network_create_socket (const char *node, const char *service) DBG ("node = %s, service = %s", node, service); - if (operating_mode == MODE_LOCAL) + if (operating_mode == MODE_LOCAL || operating_mode == MODE_LOG) return (-1); socklist_tail = socklist_head; @@ -169,10 +222,16 @@ int network_create_socket (const char *node, const char *service) socklist_tail = socklist_tail->next; memset (&ai_hints, '\0', sizeof (ai_hints)); - ai_hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + ai_hints.ai_flags = 0; +#ifdef AI_PASSIVE + ai_hints.ai_flags |= AI_PASSIVE; +#endif +#ifdef AI_ADDRCONFIG + ai_hints.ai_flags |= AI_ADDRCONFIG; +#endif ai_hints.ai_family = PF_UNSPEC; ai_hints.ai_socktype = SOCK_DGRAM; - ai_hints.ai_protocol = IPPROTO_UDP; /* XXX is this right here?!? */ + ai_hints.ai_protocol = IPPROTO_UDP; if ((ai_return = getaddrinfo (node, service, &ai_hints, &ai_list)) != 0) { @@ -205,6 +264,7 @@ int network_create_socket (const char *node, const char *service) memcpy (se->addr, ai_ptr->ai_addr, ai_ptr->ai_addrlen); se->addrlen = ai_ptr->ai_addrlen; + se->mode = operating_mode; se->fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol); se->next = NULL; @@ -217,16 +277,23 @@ int network_create_socket (const char *node, const char *service) } if (operating_mode == MODE_SERVER) + { if (network_bind_socket (se, ai_ptr) != 0) { free (se->addr); free (se); continue; } + } + else if (operating_mode == MODE_CLIENT) + { + network_set_ttl (se, ai_ptr); + } if (socklist_tail == NULL) { - socklist_head = socklist_tail = se; + socklist_head = se; + socklist_tail = se; } else { @@ -246,6 +313,33 @@ int network_create_socket (const char *node, const char *service) return (num_added); } +static int network_connect_default (void) +{ + int ret; + + if (socklist_head != NULL) + return (0); + + DBG ("socklist_head is NULL"); + + ret = 0; + + if (network_create_socket (NET_DEFAULT_V6_ADDR, NET_DEFAULT_PORT) > 0) + ret++; + + /* Don't use IPv4 and IPv6 in parallel by default.. */ + if ((operating_mode == MODE_CLIENT) && (ret != 0)) + return (ret); + + if (network_create_socket (NET_DEFAULT_V4_ADDR, NET_DEFAULT_PORT) > 0) + ret++; + + if (ret == 0) + ret = -1; + + return (ret); +} + static int network_get_listen_socket (void) { int fd; @@ -255,43 +349,48 @@ static int network_get_listen_socket (void) fd_set readfds; sockent_t *se; - while (1) + if (socklist_head == NULL) + network_connect_default (); + + FD_ZERO (&readfds); + max_fd = -1; + for (se = socklist_head; se != NULL; se = se->next) { - FD_ZERO (&readfds); - max_fd = -1; - for (se = socklist_head; se != NULL; se = se->next) - { - FD_SET (se->fd, &readfds); - if (se->fd >= max_fd) - max_fd = se->fd + 1; - } + if (se->mode != operating_mode) + continue; - if (max_fd == -1) - { - syslog (LOG_WARNING, "No listen sockets found!"); - return (-1); - } + FD_SET (se->fd, &readfds); + if (se->fd >= max_fd) + max_fd = se->fd + 1; + } + + if (max_fd == -1) + { + syslog (LOG_WARNING, "No listen sockets found!"); + return (-1); + } - status = select (max_fd, &readfds, NULL, NULL, NULL); + status = select (max_fd, &readfds, NULL, NULL, NULL); - if ((status == -1) && (errno == EINTR)) - continue; - else if (status == -1) - { + if (status == -1) + { + if (errno != EINTR) syslog (LOG_ERR, "select: %s", strerror (errno)); - return (-1); - } - else - break; - } /* while (true) */ + return (-1); + } fd = -1; for (se = socklist_head; se != NULL; se = se->next) + { + if (se->mode != operating_mode) + continue; + if (FD_ISSET (se->fd, &readfds)) { fd = se->fd; break; } + } if (fd == -1) syslog (LOG_WARNING, "No socket ready..?"); @@ -321,6 +420,7 @@ int network_receive (char **host, char **type, char **inst, char **value) if ((fd = network_get_listen_socket ()) < 0) return (-1); + addrlen = sizeof (addr); if (recvfrom (fd, buffer, BUFF_SIZE, 0, (struct sockaddr *) &addr, &addrlen) == -1) { syslog (LOG_ERR, "recvfrom: %s", strerror (errno)); @@ -403,10 +503,14 @@ int network_send (char *type, char *inst, char *value) buf[buflen] = '\0'; buflen++; + if (socklist_head == NULL) + network_connect_default (); + ret = 0; for (se = socklist_head; se != NULL; se = se->next) { - DBG ("fd = %i", se->fd); + if (se->mode != operating_mode) + continue; while (1) { @@ -423,6 +527,7 @@ int network_send (char *type, char *inst, char *value) else { syslog (LOG_ERR, "sendto: %s", strerror (errno)); + ret = -1; break; } }