src/liboping.c: Fix an incorrect assertion in `ping_timeval_add'.
[liboping.git] / src / liboping.c
index 21855e1..02125e2 100644 (file)
@@ -1,11 +1,11 @@
 /**
  * Object oriented C module to send ICMP and ICMPv6 `echo's.
- * Copyright (C) 2006  Florian octo Forster <octo at verplant.org>
+ * Copyright (C) 2006-2008  Florian octo Forster <octo at verplant.org>
  *
  * 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 Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation; only version 2 of the License is
+ * applicable.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -25,6 +25,8 @@
 # include <stdlib.h>
 # include <stdio.h>
 # include <string.h>
+# include <stdint.h>
+# include <inttypes.h>
 # include <errno.h>
 # include <assert.h>
 #else
@@ -97,6 +99,9 @@
 
 struct pinghost
 {
+       /* username: name passed in by the user */
+       char                    *username;
+       /* hostname: name returned by the reverse lookup */
        char                    *hostname;
        struct sockaddr_storage *addr;
        socklen_t                addrlen;
@@ -106,6 +111,7 @@ struct pinghost
        int                      sequence;
        struct timeval          *timer;
        double                   latency;
+       uint32_t                 dropped;
        char                    *data;
 
        void                    *context;
@@ -156,7 +162,6 @@ static int ping_timeval_add (struct timeval *tv1, struct timeval *tv2,
 static int ping_timeval_sub (struct timeval *tv1, struct timeval *tv2,
                struct timeval *res)
 {
-
        if ((tv1->tv_sec < tv2->tv_sec)
                        || ((tv1->tv_sec == tv2->tv_sec)
                                && (tv1->tv_usec < tv2->tv_usec)))
@@ -165,7 +170,7 @@ static int ping_timeval_sub (struct timeval *tv1, struct timeval *tv2,
        res->tv_sec  = tv1->tv_sec  - tv2->tv_sec;
        res->tv_usec = tv1->tv_usec - tv2->tv_usec;
 
-       assert ((res->tv_sec > 0) || ((res->tv_sec == 0) && (res->tv_usec > 0)));
+       assert ((res->tv_sec > 0) || ((res->tv_sec == 0) && (res->tv_usec >= 0)));
 
        while (res->tv_usec < 0)
        {
@@ -288,6 +293,22 @@ static pinghost_t *ping_receive_ipv4 (pinghost_t *ph, char *buffer, size_t buffe
        return (ptr);
 }
 
+#ifndef ICMP6_ECHO_REQUEST
+# ifdef ICMP6_ECHO /* AIX netinet/ip6_icmp.h */
+#  define ICMP6_ECHO_REQUEST ICMP6_ECHO
+# else
+#  define ICMP6_ECHO_REQUEST 128
+# endif
+#endif
+
+#ifndef ICMP6_ECHO_REPLY
+# ifdef ICMP6_ECHOREPLY /* AIX netinet/ip6_icmp.h */
+#  define ICMP6_ECHO_REPLY ICMP6_ECHOREPLY
+# else
+#  define ICMP6_ECHO_REPLY 129
+# endif
+#endif
+
 static pinghost_t *ping_receive_ipv6 (pinghost_t *ph, char *buffer, size_t buffer_len)
 {
        struct icmp6_hdr *icmp_hdr;
@@ -504,6 +525,9 @@ static int ping_receive_all (pingobj_t *obj)
                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;
                }
 
@@ -540,7 +564,17 @@ static ssize_t ping_sendto (pingobj_t *obj, pinghost_t *ph,
                        (struct sockaddr *) ph->addr, ph->addrlen);
 
        if (ret < 0)
+       {
+#if defined(EHOSTUNREACH)
+               if (errno == EHOSTUNREACH)
+                       return (0);
+#endif
+#if defined(ENETUNREACH)
+               if (errno == ENETUNREACH)
+                       return (0);
+#endif
                ping_set_error (obj, "sendto", strerror (errno));
+       }
 
        return (ret);
 }
@@ -768,7 +802,9 @@ static pinghost_t *ping_alloc (void)
        ph->addr    = (struct sockaddr_storage *) (ph->timer + 1);
 
        ph->addrlen = sizeof (struct sockaddr_storage);
+       ph->fd      = -1;
        ph->latency = -1.0;
+       ph->dropped = 0;
        ph->ident   = ping_get_ident () & 0xFFFF;
 
        return (ph);
@@ -776,6 +812,12 @@ static pinghost_t *ping_alloc (void)
 
 static void ping_free (pinghost_t *ph)
 {
+       if (ph->fd >= 0)
+               close (ph->fd);
+       
+       if (ph->username != NULL)
+               free (ph->username);
+
        if (ph->hostname != NULL)
                free (ph->hostname);
 
@@ -905,9 +947,11 @@ int ping_setopt (pingobj_t *obj, int option, void *value)
                        if (status != 0)
                        {
                                ping_set_error (obj, "getaddrinfo",
-                                               status == EAI_SYSTEM
-                                               ? strerror (errno)
-                                               : gai_strerror (status));
+#if defined(EAI_SYSTEM)
+                                               (status == EAI_SYSTEM)
+                                               ? strerror (errno) :
+#endif
+                                               gai_strerror (status));
                                ret = -1;
                                break;
                        }
@@ -966,7 +1010,7 @@ static pinghost_t *ping_host_search (pinghost_t *ph, const char *host)
 {
        while (ph != NULL)
        {
-               if (strcasecmp (ph->hostname, host) == 0)
+               if (strcasecmp (ph->username, host) == 0)
                        break;
 
                ph = ph->next;
@@ -1008,6 +1052,14 @@ int ping_host_add (pingobj_t *obj, const char *host)
                return (-1);
        }
 
+       if ((ph->username = strdup (host)) == NULL)
+       {
+               dprintf ("Out of memory!\n");
+               ping_set_error (obj, "strdup", strerror (errno));
+               ping_free (ph);
+               return (-1);
+       }
+
        if ((ph->hostname = strdup (host)) == NULL)
        {
                dprintf ("Out of memory!\n");
@@ -1029,9 +1081,11 @@ int ping_host_add (pingobj_t *obj, const char *host)
        {
                dprintf ("getaddrinfo failed\n");
                ping_set_error (obj, "getaddrinfo",
-                               (ai_return == EAI_SYSTEM)
-                               ? strerror (errno)
-                               : gai_strerror (ai_return));
+#if defined(EAI_SYSTEM)
+                                               (ai_return == EAI_SYSTEM)
+                                               ? strerror (errno) :
+#endif
+                               gai_strerror (ai_return));
                ping_free (ph);
                return (-1);
        }
@@ -1142,8 +1196,7 @@ int ping_host_add (pingobj_t *obj, const char *host)
 
        if (ph->fd < 0)
        {
-               free (ph->hostname);
-               free (ph);
+               ping_free (ph);
                return (-1);
        }
 
@@ -1182,7 +1235,7 @@ int ping_host_remove (pingobj_t *obj, const char *host)
 
        while (cur != NULL)
        {
-               if (strcasecmp (host, cur->hostname))
+               if (strcasecmp (host, cur->username) == 0)
                        break;
 
                pre = cur;
@@ -1200,9 +1253,6 @@ int ping_host_remove (pingobj_t *obj, const char *host)
        else
                pre->next = cur->next;
        
-       if (cur->fd >= 0)
-               close (cur->fd);
-
        ping_free (cur);
 
        return (0);
@@ -1227,9 +1277,21 @@ int ping_iterator_get_info (pingobj_iter_t *iter, int info,
 
        switch (info)
        {
+               case PING_INFO_USERNAME:
+                       ret = ENOMEM;
+                       *buffer_len = strlen (iter->username) + 1;
+                       if (orig_buffer_len <= *buffer_len)
+                               break;
+                       /* Since (orig_buffer_len > *buffer_len) `strncpy'
+                        * will copy `*buffer_len' and pad the rest of
+                        * `buffer' with null-bytes */
+                       strncpy (buffer, iter->username, orig_buffer_len);
+                       ret = 0;
+                       break;
+
                case PING_INFO_HOSTNAME:
                        ret = ENOMEM;
-                       *buffer_len = strlen (iter->hostname);
+                       *buffer_len = strlen (iter->hostname) + 1;
                        if (orig_buffer_len <= *buffer_len)
                                break;
                        /* Since (orig_buffer_len > *buffer_len) `strncpy'
@@ -1254,9 +1316,10 @@ int ping_iterator_get_info (pingobj_iter_t *iter, int info,
 #endif
                                   )
                                        ret = ENOMEM;
+#if defined(EAI_SYSTEM)
                                else if (ret == EAI_SYSTEM)
-                                       /* XXX: Not thread-safe! */
                                        ret = errno;
+#endif
                                else
                                        ret = EINVAL;
                        }
@@ -1280,6 +1343,15 @@ int ping_iterator_get_info (pingobj_iter_t *iter, int info,
                        ret = 0;
                        break;
 
+               case PING_INFO_DROPPED:
+                       ret = ENOMEM;
+                       *buffer_len = sizeof (uint32_t);
+                       if (orig_buffer_len < sizeof (uint32_t))
+                               break;
+                       *((uint32_t *) buffer) = iter->dropped;
+                       ret = 0;
+                       break;
+
                case PING_INFO_SEQUENCE:
                        ret = ENOMEM;
                        *buffer_len = sizeof (unsigned int);
@@ -1309,7 +1381,7 @@ int ping_iterator_get_info (pingobj_iter_t *iter, int info,
        }
 
        return (ret);
-}
+} /* ping_iterator_get_info */
 
 void *ping_iterator_get_context (pingobj_iter_t *iter)
 {