From: Florian Forster Date: Fri, 5 May 2017 06:43:52 +0000 (+0200) Subject: Merge remote-tracking branch 'github/master' into lh/performance X-Git-Url: https://git.tokkee.org/?p=liboping.git;a=commitdiff_plain;h=40f1574f0b5f713e44c73115553977900c9f933f Merge remote-tracking branch 'github/master' into lh/performance --- 40f1574f0b5f713e44c73115553977900c9f933f diff --cc src/liboping.c index 776f24f,fc9ed65..31b8813 --- a/src/liboping.c +++ b/src/liboping.c @@@ -145,7 -148,6 +152,7 @@@ struct pingob char errmsg[PING_ERRMSG_LEN]; pinghost_t *head; - pinghost_t *table[PING_TABLE_LEN]; ++ pinghost_t *table[PING_TABLE_LEN]; }; /* @@@ -947,130 -1110,6 +969,158 @@@ static void ping_free (pinghost_t *ph free (ph); } +static int ping_open_socket(pingobj_t *obj, int addrfam) +{ + int fd; + if (addrfam == AF_INET6) + { + fd = socket(addrfam, SOCK_RAW, IPPROTO_ICMPV6); + } + else if (addrfam == AF_INET) + { + fd = socket(addrfam, SOCK_RAW, IPPROTO_ICMP); + } + else /* this should not happen */ + { + dprintf ("Unknown address family: %i\n", addrfam); + return (-1); + } + + if (fd == -1) + { +#if WITH_DEBUG + char errbuf[PING_ERRMSG_LEN]; + dprintf ("socket: %s\n", + sstrerror (errno, errbuf, sizeof (errbuf))); +#endif + ping_set_errno (obj, errno); + return -1; + } ++ else if (fd >= FD_SETSIZE) ++ { ++ dprintf ("socket(2) returned file descriptor %d, which is above the file " ++ "descriptor limit for select(2) (FD_SETSIZE = %d)\n", ++ fd, FD_SETSIZE); ++ close (fd); ++ ping_set_errno (obj, EMFILE); ++ return -1; ++ } + + if (obj->srcaddr != NULL) + { + assert (obj->srcaddrlen > 0); + assert (obj->srcaddrlen <= sizeof (struct sockaddr_storage)); + + if (bind (fd, obj->srcaddr, obj->srcaddrlen) == -1) + { +#if WITH_DEBUG + char errbuf[PING_ERRMSG_LEN]; + dprintf ("bind: %s\n", + sstrerror (errno, errbuf, sizeof (errbuf))); +#endif + ping_set_errno (obj, errno); + close (fd); + return -1; + } + } + +#ifdef SO_BINDTODEVICE + if (obj->device != NULL) + { + if (setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, + obj->device, strlen (obj->device) + 1) != 0) + { +#if WITH_DEBUG + char errbuf[PING_ERRMSG_LEN]; + dprintf ("setsockopt (SO_BINDTODEVICE): %s\n", + sstrerror (errno, errbuf, sizeof (errbuf))); +#endif + ping_set_errno (obj, errno); + close (fd); + return -1; + } + } +#endif /* SO_BINDTODEVICE */ ++#ifdef SO_MARK ++ if (obj->set_mark) ++ { ++ if (setsockopt(fd, SOL_SOCKET, SO_MARK, ++ &obj->mark, sizeof(obj->mark)) != 0) ++ { ++ ping_set_errno (obj, errno); ++#if WITH_DEBUG ++ char errbuf[PING_ERRMSG_LEN]; ++ dprintf ("setsockopt (SO_MARK): %s\n", ++ sstrerror (errno, errbuf, sizeof (errbuf))); ++#endif ++ close (fd); ++ return -1; ++ } ++ } ++#endif +#ifdef SO_TIMESTAMP + if (1) /* {{{ */ + { + int status; + int opt = 1; + + status = setsockopt (fd, + SOL_SOCKET, SO_TIMESTAMP, + &opt, sizeof (opt)); + if (status != 0) + { +#if WITH_DEBUG + char errbuf[PING_ERRMSG_LEN]; + dprintf ("setsockopt (SO_TIMESTAMP): %s\n", + sstrerror (errno, errbuf, sizeof (errbuf))); +#endif + ping_set_errno (obj, errno); + close (fd); + return -1; + } + } /* }}} if (1) */ +#endif /* SO_TIMESTAMP */ + + if (addrfam == AF_INET) + { + int opt; + ++#ifdef IP_RECVTOS + /* Enable receiving the TOS field */ + opt = 1; + setsockopt (fd, IPPROTO_IP, IP_RECVTOS, + &opt, sizeof (opt)); ++#endif /* IP_RECVTOS */ + + /* Enable receiving the TTL field */ + opt = 1; + setsockopt (fd, IPPROTO_IP, IP_RECVTTL, + &opt, sizeof (opt)); + } +#if defined(IPV6_RECVHOPLIMIT) || defined(IPV6_RECVTCLASS) + else if (addrfam == AF_INET6) + { + int opt; + +# if defined(IPV6_RECVHOPLIMIT) + /* For details see RFC 3542, section 6.3. */ + opt = 1; + setsockopt (fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, + &opt, sizeof (opt)); +# endif /* IPV6_RECVHOPLIMIT */ + +# if defined(IPV6_RECVTCLASS) + /* For details see RFC 3542, section 6.5. */ + opt = 1; + setsockopt (fd, IPPROTO_IPV6, IPV6_RECVTCLASS, + &opt, sizeof (opt)); +# endif /* IPV6_RECVTCLASS */ + } +#endif /* IPV6_RECVHOPLIMIT || IPV6_RECVTCLASS */ + + return fd; +} + /* * public methods */ @@@ -1285,6 -1321,19 +1335,19 @@@ int ping_setopt (pingobj_t *obj, int op } /* case PING_OPT_DEVICE */ break; + case PING_OPT_MARK: + { + #ifdef SO_MARK + obj->mark = *(int*)(value); + obj->set_mark = 1; + #else /* SO_MARK */ + ping_set_errno (obj, ENOTSUP); + ret = -1; + #endif /* !SO_MARK */ - ++ + } /* case PING_OPT_MARK */ + break; + default: ret = -2; } /* switch (option) */ @@@ -1292,200 -1341,17 +1355,202 @@@ return (ret); } /* int ping_setopt */ - int ping_send (pingobj_t *obj) { - if (obj == NULL) + fd_set read_fds; + fd_set write_fds; + fd_set err_fds; + + int num_fds; + int max_fd; + + pinghost_t *ph; + pinghost_t *ptr; + + struct timeval endtime; + struct timeval nowtime; + struct timeval timeout; + int status; + + int pings = 0; + int ret = 0; + + ph = obj->head; + + int fd4 = obj->fd4; + int fd6 = obj->fd6; + + for (ptr = ph; ptr != NULL; ptr = ptr->next) + { + if (fd6 == -1 && ptr->addrfamily == AF_INET6) + { + obj->fd6 = fd6 = ping_open_socket(obj, AF_INET6); + ping_set_ttl (obj, obj->ttl); + ping_set_qos (obj, obj->qos); + } + else if (fd4 == -1 && ptr->addrfamily == AF_INET) + { + obj->fd4 = fd4 = ping_open_socket(obj, AF_INET); + ping_set_ttl (obj, obj->ttl); + ping_set_qos (obj, obj->qos); + } + + if ((fd6 == -1 && ptr->addrfamily == AF_INET6) + || (fd4 == -1 && ptr->addrfamily == AF_INET)) + { +#if WITH_DEBUG + char errbuf[PING_ERRMSG_LEN]; + dprintf ("socket: %s\n", + sstrerror (errno, errbuf, sizeof (errbuf))); +#endif + ping_set_errno (obj, errno); + return (-1); + } + + ptr->latency = -1.0; + ptr->recv_ttl = -1; + } + + if (fd4 == -1 && fd6 == -1) + { + dprintf("No sockets to use\n"); return (-1); + } - if (ping_send_all (obj) < 0) + if (gettimeofday (&nowtime, NULL) == -1) + { + ping_set_errno (obj, errno); return (-1); + } - return (ping_receive_all (obj)); -} + /* Set up timeout */ + timeout.tv_sec = (time_t) obj->timeout; + timeout.tv_usec = (suseconds_t) (1000000 * (obj->timeout - ((double) timeout.tv_sec))); + + dprintf ("Set timeout to %i.%06i seconds\n", + (int) timeout.tv_sec, + (int) timeout.tv_usec); + + ping_timeval_add (&nowtime, &timeout, &endtime); + + ptr = ph; + num_fds = 0; + if (fd4 != -1) num_fds++; + if (fd6 != -1) num_fds++; + max_fd = fd4 > fd6 ? fd4 : fd6; ++ assert (max_fd < FD_SETSIZE); + + while (pings > 0 || ptr != NULL) + { + FD_ZERO (&read_fds); + FD_ZERO (&write_fds); + FD_ZERO (&err_fds); + + if (fd4 != -1) FD_SET(fd4, &read_fds); + if (fd6 != -1) FD_SET(fd6, &read_fds); + + if (fd4 != -1 && ptr != NULL && ptr->addrfamily == AF_INET) + FD_SET(fd4, &write_fds); + if (fd6 != -1 && ptr != NULL && ptr->addrfamily == AF_INET6) + FD_SET(fd6, &write_fds); + if (fd4 != -1) FD_SET(fd4, &err_fds); + if (fd6 != -1) FD_SET(fd6, &err_fds); + + if (gettimeofday (&nowtime, NULL) == -1) + { + ping_set_errno (obj, errno); + return (-1); + } + + if (ping_timeval_sub (&endtime, &nowtime, &timeout) == -1) + break; + + dprintf ("Waiting on %i sockets for %i.%06i seconds\n", num_fds, + (int) timeout.tv_sec, + (int) timeout.tv_usec); + + status = select (max_fd + 1, &read_fds, &write_fds, &err_fds, &timeout); + + if (gettimeofday (&nowtime, NULL) == -1) + { + ping_set_errno (obj, errno); + return (-1); + } + + if ((status == -1) && (errno == EINTR)) + { + dprintf ("select was interrupted by signal..\n"); - continue; ++ ping_set_errno (obj, EINTR); ++ return (-1); + } + else if (status < 0) + { +#if WITH_DEBUG + char errbuf[PING_ERRMSG_LEN]; + dprintf ("select: %s\n", + sstrerror (errno, errbuf, sizeof (errbuf))); +#endif + break; + } + else if (status == 0) + { + dprintf ("select timed out\n"); + for (ptr = ph; ptr != NULL; ptr = ptr->next) + if (ptr->latency < 0.0) + ptr->dropped++; + + break; + } + + if (fd4 != -1) + { + if (FD_ISSET (fd4, &read_fds)) + { + if (!ping_receive_one(obj, &nowtime, AF_INET)) + --pings; + } - else if (ptr != NULL && ptr->addrfamily == AF_INET && ++ else if (ptr != NULL && ptr->addrfamily == AF_INET && + FD_ISSET (fd4, &write_fds)) + { + if (!ping_send_one(obj, ptr, fd4)) + { + ptr = ptr->next; + ++pings; + } + else + { + --ret; + } + } + + } + + if (fd6 != -1) + { + if (FD_ISSET (fd6, &read_fds)) + { + if (!ping_receive_one(obj, &nowtime, AF_INET6)) + --pings; + } + else if (ptr != NULL && ptr->addrfamily == AF_INET6 && + FD_ISSET (fd6, &write_fds)) + { + if (!ping_send_one(obj, ptr, fd6)) + { + ++pings; + ptr = ptr->next; + } + else + { + --ret; + } + } + } + + } /* while (1) */ + + return (ret); +} /* int ping_send */ static pinghost_t *ping_host_search (pinghost_t *ph, const char *host) {