X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fnetwork.c;h=22e911a87b8e4d4fe89d805abc9c9559ce2463c6;hb=44d73d6556833bcfbc4678a01731aafee95c3caf;hp=f42693e1c494f90359b1877c4148c8e4a5fef45e;hpb=66eb6c7178d61098864aa1dd3fb5e10c2afb67ee;p=collectd.git diff --git a/src/network.c b/src/network.c index f42693e1..22e911a8 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,47 +23,38 @@ #include #include #include -#include #include #include +#include #include #include #include #include -#include #include "network.h" #include "common.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 +#include "configfile.h" +#include "utils_debug.h" /* 1500 - 40 - 8 = Ethernet packet - IPv6 header - UDP header */ -#define BUFF_SIZE 1452 +/* #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; @@ -71,11 +62,70 @@ typedef struct sockent static sockent_t *socklist_head = NULL; -static int network_bind_socket (int fd, const struct addrinfo *ai, const sockent_t *se) +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; - if (bind (fd, ai->ai_addr, ai->ai_addrlen) == -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)); return (-1); @@ -88,6 +138,8 @@ static int network_bind_socket (int fd, const struct addrinfo *ai, const sockent { 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); @@ -114,6 +166,8 @@ static int network_bind_socket (int fd, const struct addrinfo *ai, const sockent { struct ipv6_mreq mreq; + DBG ("fd = %i; IPv6 multicast address found", se->fd); + memcpy (&mreq.ipv6mr_multiaddr, &addr->sin6_addr, sizeof (addr->sin6_addr)); @@ -127,7 +181,7 @@ static int network_bind_socket (int fd, const struct addrinfo *ai, const sockent * single interface; programs running on * multihomed hosts may need to join the same * group on more than one interface.*/ - mreq6.ipv6mr_interface = 0; + mreq.ipv6mr_interface = 0; if (setsockopt (se->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop, sizeof (loop)) == -1) @@ -160,18 +214,28 @@ 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) + { + syslog (LOG_WARNING, "network_create_socket: There is no point opening a socket when you are in mode `%s'.", + operating_mode == MODE_LOCAL ? "Local" : "Log"); return (-1); + } socklist_tail = socklist_head; while ((socklist_tail != NULL) && (socklist_tail->next != NULL)) 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) { @@ -199,11 +263,12 @@ int network_create_socket (const char *node, const char *service) continue; } - assert (sizeof (struct sockaddr_storage) >= ai_ptr->addrlen); + assert (sizeof (struct sockaddr_storage) >= ai_ptr->ai_addrlen); memset (se->addr, '\0', sizeof (struct sockaddr_storage)); - memcpy (se->addr, ai_ptr->ai_addr, ai_ptr->addrlen); - se->addrlen = ai_ptr->addrlen; + 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; @@ -216,16 +281,23 @@ int network_create_socket (const char *node, const char *service) } if (operating_mode == MODE_SERVER) - if (network_bind_socket (se->fd, ai_ptr, se->addr) != 0) + { + 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 { @@ -245,51 +317,84 @@ 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; - int max_fd; + int fd; + int max_fd; + int status; 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; + } - status = select (max_fd, &readfds, NULL, NULL, NULL); + if (max_fd == -1) + { + syslog (LOG_WARNING, "No listen sockets found!"); + return (-1); + } - if ((status == -1) && (errno == EINTR)) - continue; - else if (status == -1) - { + status = select (max_fd, &readfds, NULL, NULL, NULL); + + 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..?"); @@ -304,6 +409,7 @@ int network_receive (char **host, char **type, char **inst, char **value) char buffer[BUFF_SIZE]; struct sockaddr_storage addr; + socklen_t addrlen; int status; char *fields[4]; @@ -318,7 +424,8 @@ int network_receive (char **host, char **type, char **inst, char **value) if ((fd = network_get_listen_socket ()) < 0) return (-1); - if (recvfrom (fd, buffer, BUFF_SIZE, 0, (struct sockaddr *) &addr, sizeof (addr)) == -1) + addrlen = sizeof (addr); + if (recvfrom (fd, buffer, BUFF_SIZE, 0, (struct sockaddr *) &addr, &addrlen) == -1) { syslog (LOG_ERR, "recvfrom: %s", strerror (errno)); return (-1); @@ -330,7 +437,7 @@ int network_receive (char **host, char **type, char **inst, char **value) return (-1); } - status = getnameinfo ((struct sockaddr *) &addr, sizeof (addr), + status = getnameinfo ((struct sockaddr *) &addr, addrlen, *host, BUFF_SIZE, NULL, 0, 0); if (status != 0) { @@ -349,14 +456,14 @@ int network_receive (char **host, char **type, char **inst, char **value) if ((*type = strdup (fields[0])) == NULL) { - syslog (LOG_EMERG, "strdup: %s", strerror ()); + syslog (LOG_EMERG, "strdup: %s", strerror (errno)); free (*host); *host = NULL; return (-1); } if ((*inst = strdup (fields[1])) == NULL) { - syslog (LOG_EMERG, "strdup: %s", strerror ()); + syslog (LOG_EMERG, "strdup: %s", strerror (errno)); free (*host); *host = NULL; free (*type); *type = NULL; return (-1); @@ -364,7 +471,7 @@ int network_receive (char **host, char **type, char **inst, char **value) if ((*value = strdup (fields[2])) == NULL) { - syslog (LOG_EMERG, "strdup: %s", strerror ()); + syslog (LOG_EMERG, "strdup: %s", strerror (errno)); free (*host); *host = NULL; free (*type); *type = NULL; free (*inst); *inst = NULL; @@ -400,10 +507,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) { @@ -420,6 +531,7 @@ int network_send (char *type, char *inst, char *value) else { syslog (LOG_ERR, "sendto: %s", strerror (errno)); + ret = -1; break; } }