X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fliboping.c;h=b6c80f2f479e875a63d26a7d47ca6f685e854a93;hb=214995c1a066ae00a1a4f369abb09f475221f5ff;hp=4579ab04e84558adc31697d485d955feb384508f;hpb=450f754967e543d3b19a9bc7ae796e26b5565ecc;p=liboping.git diff --git a/src/liboping.c b/src/liboping.c index 4579ab0..b6c80f2 100644 --- a/src/liboping.c +++ b/src/liboping.c @@ -1361,66 +1361,49 @@ int ping_setopt (pingobj_t *obj, int option, void *value) int ping_send (pingobj_t *obj) { - 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; + _Bool need_ipv4_socket = 0; + _Bool need_ipv6_socket = 0; - for (ptr = ph; ptr != NULL; ptr = ptr->next) + for (ptr = obj->head; 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 (ptr->addrfamily == AF_INET) + need_ipv4_socket = 1; + else if (ptr->addrfamily == AF_INET6) + need_ipv6_socket = 1; } - if (fd4 == -1 && fd6 == -1) + if (!need_ipv4_socket && !need_ipv6_socket) { - dprintf("No sockets to use\n"); + ping_set_error (obj, "ping_send", "No hosts to ping"); return (-1); } + if (need_ipv4_socket && obj->fd4 == -1) + { + obj->fd4 = ping_open_socket(obj, AF_INET); + if (obj->fd4 == -1) + return (-1); + ping_set_ttl (obj, obj->ttl); + ping_set_qos (obj, obj->qos); + } + if (need_ipv6_socket && obj->fd6 == -1) + { + obj->fd6 = ping_open_socket(obj, AF_INET6); + if (obj->fd6 == -1) + return (-1); + ping_set_ttl (obj, obj->ttl); + ping_set_qos (obj, obj->qos); + } + if (gettimeofday (&nowtime, NULL) == -1) { ping_set_errno (obj, errno); @@ -1437,37 +1420,59 @@ int ping_send (pingobj_t *obj) 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); + /* host_to_ping points to the host to which to send the next ping. The + * pointer is advanced to the next host in the linked list after the + * ping has been sent. If host_to_ping is NULL, no more pings need to be + * send out. */ + pinghost_t *host_to_ping = obj->head; - while (pings > 0 || ptr != NULL) + /* pings_in_flight is the number of hosts we sent a "ping" to but didn't + * receive a "pong" yet. */ + int pings_in_flight = 0; + + /* pongs_received is the number of echo replies received. Unless there + * is an error, this is used as the return value of ping_send(). */ + int pongs_received = 0; + + int error_count = 0; + + while (pings_in_flight > 0 || host_to_ping != NULL) { + fd_set read_fds; + fd_set write_fds; + + int write_fd = -1; + int max_fd = -1; + FD_ZERO (&read_fds); FD_ZERO (&write_fds); - FD_ZERO (&err_fds); - if (fd4 != -1) + if (obj->fd4 != -1) { - FD_SET(fd4, &read_fds); - if (ptr != NULL && ptr->addrfamily == AF_INET) - FD_SET(fd4, &write_fds); - FD_SET(fd4, &err_fds); + FD_SET(obj->fd4, &read_fds); + if (host_to_ping != NULL && host_to_ping->addrfamily == AF_INET) + write_fd = obj->fd4; + + if (max_fd < obj->fd4) + max_fd = obj->fd4; } - if (fd6 != -1) + if (obj->fd6 != -1) { - FD_SET(fd6, &read_fds); - if (ptr != NULL && ptr->addrfamily == AF_INET6) - FD_SET(fd6, &write_fds); - FD_SET(fd6, &err_fds); + FD_SET(obj->fd6, &read_fds); + if (host_to_ping != NULL && host_to_ping->addrfamily == AF_INET6) + write_fd = obj->fd6; + + if (max_fd < obj->fd6) + max_fd = obj->fd6; } + if (write_fd != -1) + FD_SET(write_fd, &write_fds); + + assert (max_fd != -1); + assert (max_fd < FD_SETSIZE); + if (gettimeofday (&nowtime, NULL) == -1) { ping_set_errno (obj, errno); @@ -1477,11 +1482,12 @@ int ping_send (pingobj_t *obj) 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); + dprintf ("Waiting on %i sockets for %u.%06u seconds\n", + ((obj->fd4 != -1) ? 1 : 0) + ((obj->fd6 != -1) ? 1 : 0), + (unsigned) timeout.tv_sec, + (unsigned) timeout.tv_usec); - status = select (max_fd + 1, &read_fds, &write_fds, &err_fds, &timeout); + int status = select (max_fd + 1, &read_fds, &write_fds, NULL, &timeout); if (gettimeofday (&nowtime, NULL) == -1) { @@ -1489,79 +1495,63 @@ int ping_send (pingobj_t *obj) return (-1); } - if ((status == -1) && (errno == EINTR)) + if (status == -1) { - dprintf ("select was interrupted by signal..\n"); - ping_set_errno (obj, EINTR); + ping_set_errno (obj, errno); + dprintf ("select: %s\n", obj->errmsg); 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++; + pinghost_t *ph; + for (ph = obj->head; ph != NULL; ph = ph->next) + if (ph->latency < 0.0) + ph->dropped++; break; } - if (fd4 != -1) + /* first, check if we can receive a reply ... */ + if (obj->fd6 != -1 && FD_ISSET (obj->fd6, &read_fds)) { - if (FD_ISSET (fd4, &read_fds)) + if (ping_receive_one (obj, &nowtime, AF_INET6) == 0) { - if (!ping_receive_one(obj, &nowtime, AF_INET)) - --pings; + pings_in_flight--; + pongs_received++; } - 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; - } - } - + continue; } - - if (fd6 != -1) + if (obj->fd4 != -1 && FD_ISSET (obj->fd4, &read_fds)) { - 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_receive_one (obj, &nowtime, AF_INET) == 0) { - if (!ping_send_one(obj, ptr, fd6)) - { - ++pings; - ptr = ptr->next; - } - else - { - --ret; - } + pings_in_flight--; + pongs_received++; } + continue; } + /* ... and if no reply is available to read, continue sending + * out pings. */ + + /* this condition should always be true. We keep it for + * consistency with the read blocks above and just to be on the + * safe side. */ + if (write_fd != -1 && FD_ISSET (write_fd, &write_fds)) + { + if (ping_send_one (obj, host_to_ping, write_fd) == 0) + pings_in_flight++; + else + error_count++; + host_to_ping = host_to_ping->next; + continue; + } } /* while (1) */ - return (ret); + if (error_count) + return (-1 * error_count); + return (pongs_received); } /* int ping_send */ static pinghost_t *ping_host_search (pinghost_t *ph, const char *host) @@ -1811,6 +1801,20 @@ pingobj_iter_t *ping_iterator_next (pingobj_iter_t *iter) return ((pingobj_iter_t *) iter->next); } +int ping_iterator_count (pingobj_t *obj) +{ + if (obj == NULL) + return 0; + + int count = 0; + pingobj_iter_t *iter = obj->head; + while (iter) { + count++; + iter = iter->next; + } + return count; +} + int ping_iterator_get_info (pingobj_iter_t *iter, int info, void *buffer, size_t *buffer_len) {