X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fnetwork.c;h=22e911a87b8e4d4fe89d805abc9c9559ce2463c6;hb=44d73d6556833bcfbc4678a01731aafee95c3caf;hp=b86d5a255b1f9f5897ab20d4c9d660d846a58392;hpb=7e9a722fa5d169d5efd1afcdfff5676fd3bcfcc0;p=collectd.git diff --git a/src/network.c b/src/network.c index b86d5a25..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,29 +23,33 @@ #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" /* 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 { @@ -58,6 +62,63 @@ 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; @@ -153,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) { @@ -210,12 +281,18 @@ 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) { @@ -251,10 +328,14 @@ static int network_connect_default (void) ret = 0; - if (network_create_socket (NET_DEFAULT_V4_ADDR, NET_DEFAULT_PORT) > 0) + if (network_create_socket (NET_DEFAULT_V6_ADDR, NET_DEFAULT_PORT) > 0) ret++; - if (network_create_socket (NET_DEFAULT_V6_ADDR, NET_DEFAULT_PORT) > 0) + /* 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) @@ -275,38 +356,32 @@ static int network_get_listen_socket (void) if (socklist_head == NULL) network_connect_default (); - while (1) + 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) - { - if (se->mode != operating_mode) - continue; + if (se->mode != operating_mode) + continue; - FD_SET (se->fd, &readfds); - if (se->fd >= max_fd) - max_fd = se->fd + 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); - } + 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) @@ -349,6 +424,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)); @@ -440,8 +516,6 @@ int network_send (char *type, char *inst, char *value) if (se->mode != operating_mode) continue; - DBG ("fd = %i", se->fd); - while (1) { status = sendto (se->fd, buf, buflen, 0, @@ -457,6 +531,7 @@ int network_send (char *type, char *inst, char *value) else { syslog (LOG_ERR, "sendto: %s", strerror (errno)); + ret = -1; break; } }