X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fliboping.c;h=87aa654eb6b7f4fc21f2218caac6a9573d12cf02;hb=288bac33067ea6c88e2399a8b5ddae051aaaa547;hp=65b2ef529dd81cff07b7948f2d8f47eeb76e76c1;hpb=11970f14b437d4f8f62040f5913ecc4d5f4fbb53;p=liboping.git diff --git a/src/liboping.c b/src/liboping.c index 65b2ef5..87aa654 100644 --- a/src/liboping.c +++ b/src/liboping.c @@ -25,7 +25,6 @@ # include # include # include -# include # include # include # include @@ -33,6 +32,10 @@ # error "You don't have the standard C99 header files installed" #endif /* STDC_HEADERS */ +#ifdef HAVE_STDINT_H +# include +#endif + #if HAVE_UNISTD_H # include #endif @@ -61,6 +64,7 @@ #if HAVE_SYS_SOCKET_H # include #endif + #if HAVE_NETDB_H # include #endif @@ -141,7 +145,7 @@ struct pingobj /* Even though Posix requires "strerror_r" to return an "int", * some systems (e.g. the GNU libc) return a "char *" _and_ * ignore the second argument ... -tokkee */ -char *sstrerror (int errnum, char *buf, size_t buflen) +static char *sstrerror (int errnum, char *buf, size_t buflen) { buf[0] = 0; @@ -255,7 +259,8 @@ static uint16_t ping_icmp4_checksum (char *buf, size_t len) return (ret); } -static pinghost_t *ping_receive_ipv4 (pinghost_t *ph, char *buffer, size_t buffer_len) +static pinghost_t *ping_receive_ipv4 (pingobj_t *obj, char *buffer, + size_t buffer_len) { struct ip *ip_hdr; struct icmp *icmp_hdr; @@ -310,7 +315,9 @@ static pinghost_t *ping_receive_ipv4 (pinghost_t *ph, char *buffer, size_t buffe ident = ntohs (icmp_hdr->icmp_id); seq = ntohs (icmp_hdr->icmp_seq); - for (ptr = ph; ptr != NULL; ptr = ptr->next) + /* We have to iterate over all hosts, since ICMPv4 packets may + * be received on any raw v4 socket. */ + for (ptr = obj->head; ptr != NULL; ptr = ptr->next) { dprintf ("hostname = %s, ident = 0x%04x, seq = %i\n", ptr->hostname, ptr->ident, ((ptr->sequence - 1) & 0xFFFF)); @@ -339,6 +346,9 @@ static pinghost_t *ping_receive_ipv4 (pinghost_t *ph, char *buffer, size_t buffe ident, seq); } + if (ptr != NULL) + ptr->recv_ttl = ip_hdr->ip_ttl; + return (ptr); } @@ -358,7 +368,8 @@ static pinghost_t *ping_receive_ipv4 (pinghost_t *ph, char *buffer, size_t buffe # endif #endif -static pinghost_t *ping_receive_ipv6 (pinghost_t *ph, char *buffer, size_t buffer_len) +static pinghost_t *ping_receive_ipv6 (pingobj_t *obj, char *buffer, + size_t buffer_len) { struct icmp6_hdr *icmp_hdr; @@ -389,7 +400,9 @@ static pinghost_t *ping_receive_ipv6 (pinghost_t *ph, char *buffer, size_t buffe ident = ntohs (icmp_hdr->icmp6_id); seq = ntohs (icmp_hdr->icmp6_seq); - for (ptr = ph; ptr != NULL; ptr = ptr->next) + /* We have to iterate over all hosts, since ICMPv6 packets may + * be received on any raw v6 socket. */ + for (ptr = obj->head; ptr != NULL; ptr = ptr->next) { dprintf ("hostname = %s, ident = 0x%04x, seq = %i\n", ptr->hostname, ptr->ident, ((ptr->sequence - 1) & 0xFFFF)); @@ -421,11 +434,15 @@ static pinghost_t *ping_receive_ipv6 (pinghost_t *ph, char *buffer, size_t buffe return (ptr); } -static int ping_receive_one (int fd, pinghost_t *ph, struct timeval *now) +static int ping_receive_one (pingobj_t *obj, const pinghost_t *ph, + struct timeval *now) { + /* Note: 'ph' is not necessarily the host object for which we receive a + * reply. The right object will be returned by ping_receive_ipv*(). For + * now, we can only rely on ph->fd and ph->addrfamily. */ + struct timeval diff; pinghost_t *host = NULL; - int family; int recv_ttl; /* @@ -454,8 +471,11 @@ static int ping_receive_one (int fd, pinghost_t *ph, struct timeval *now) msghdr.msg_controllen = sizeof (control_buffer); /* flags; this is an output only field.. */ msghdr.msg_flags = 0; +#ifdef MSG_XPG4_2 + msghdr.msg_flags |= MSG_XPG4_2; +#endif - payload_buffer_len = recvmsg (fd, &msghdr, /* flags = */ 0); + payload_buffer_len = recvmsg (ph->fd, &msghdr, /* flags = */ 0); if (payload_buffer_len < 0) { #if WITH_DEBUG @@ -465,18 +485,19 @@ static int ping_receive_one (int fd, pinghost_t *ph, struct timeval *now) #endif return (-1); } - dprintf ("Read %zi bytes from fd = %i\n", payload_buffer_len, fd); + dprintf ("Read %zi bytes from fd = %i\n", payload_buffer_len, ph->fd); /* Iterate over all auxiliary data in msghdr */ - family = -1; recv_ttl = -1; for (cmsg = CMSG_FIRSTHDR (&msghdr); /* {{{ */ cmsg != NULL; cmsg = CMSG_NXTHDR (&msghdr, cmsg)) { - if (cmsg->cmsg_level == IPPROTO_IP) /* {{{ */ + if (ph->addrfamily == AF_INET) /* {{{ */ { - family = AF_INET; + if (cmsg->cmsg_level != IPPROTO_IP) + continue; + if (cmsg->cmsg_type == IP_TTL) { memcpy (&recv_ttl, CMSG_DATA (cmsg), @@ -489,9 +510,11 @@ static int ping_receive_one (int fd, pinghost_t *ph, struct timeval *now) cmsg->cmsg_type); } } /* }}} */ - else if (cmsg->cmsg_level == IPPROTO_IPV6) /* {{{ */ + else if (ph->addrfamily == AF_INET6) /* {{{ */ { - family = AF_INET6; + if (cmsg->cmsg_level != IPPROTO_IPV6) + continue; + if (cmsg->cmsg_type == IPV6_HOPLIMIT) { memcpy (&recv_ttl, CMSG_DATA (cmsg), @@ -512,22 +535,22 @@ static int ping_receive_one (int fd, pinghost_t *ph, struct timeval *now) } } /* }}} for (cmsg) */ - if (family == AF_INET) + if (ph->addrfamily == AF_INET) { - host = ping_receive_ipv4 (ph, payload_buffer, payload_buffer_len); + host = ping_receive_ipv4 (obj, payload_buffer, payload_buffer_len); if (host == NULL) return (-1); } - else if (family == AF_INET6) + else if (ph->addrfamily == AF_INET6) { - host = ping_receive_ipv6 (ph, payload_buffer, payload_buffer_len); + host = ping_receive_ipv6 (obj, payload_buffer, payload_buffer_len); if (host == NULL) return (-1); } else { dprintf ("ping_receive_one: Unknown address family %i.\n", - family); + ph->addrfamily); return (-1); } @@ -548,11 +571,12 @@ static int ping_receive_one (int fd, pinghost_t *ph, struct timeval *now) (int) diff.tv_sec, (int) diff.tv_usec); + if (recv_ttl >= 0) + host->recv_ttl = recv_ttl; + host->latency = ((double) diff.tv_usec) / 1000.0; host->latency += ((double) diff.tv_sec) * 1000.0; - host->recv_ttl = recv_ttl; - timerclear (host->timer); return (0); @@ -578,7 +602,10 @@ static int ping_receive_all (pingobj_t *obj) ret = 0; for (ptr = ph; ptr != NULL; ptr = ptr->next) - ptr->latency = -1.0; + { + ptr->latency = -1.0; + ptr->recv_ttl = -1; + } if (gettimeofday (&nowtime, NULL) == -1) { @@ -664,7 +691,7 @@ static int ping_receive_all (pingobj_t *obj) for (ptr = ph; ptr != NULL; ptr = ptr->next) { if (FD_ISSET (ptr->fd, &readfds)) - if (ping_receive_one (ptr->fd, ph, &nowtime) == 0) + if (ping_receive_one (obj, ptr, &nowtime) == 0) ret++; } } /* while (1) */ @@ -1041,6 +1068,13 @@ int ping_setopt (pingobj_t *obj, int option, void *value) obj->ttl = PING_DEF_TTL; ret = -1; } + else + { + pinghost_t *ph; + + for (ph = obj->head; ph != NULL; ph = ph->next) + ping_set_ttl (ph, obj->ttl); + } break; case PING_OPT_AF: @@ -1331,6 +1365,7 @@ int ping_host_add (pingobj_t *obj, const char *host) setsockopt (ph->fd, IPPROTO_IP, IP_RECVTTL, &opt, sizeof (opt)); } +#if defined(IPPROTO_IPV6) && defined(IPV6_RECVHOPLIMIT) else if (ph->addrfamily == AF_INET6) { int opt = 1; @@ -1338,6 +1373,7 @@ int ping_host_add (pingobj_t *obj, const char *host) setsockopt (ph->fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &opt, sizeof (opt)); } +#endif break; }