src/liboping.c: Let ping_setopt() return -1 if 'value' is NULL.
[liboping.git] / src / liboping.c
index 579aba3..36a3a3e 100644 (file)
@@ -145,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;
 
@@ -259,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;
@@ -306,7 +307,8 @@ static pinghost_t *ping_receive_ipv4 (pinghost_t *ph, char *buffer, size_t buffe
 
        if (recv_checksum != calc_checksum)
        {
-               dprintf ("Checksum missmatch: Got 0x%04x, calculated 0x%04x\n",
+               dprintf ("Checksum missmatch: Got 0x%04"PRIx16", "
+                               "calculated 0x%04"PRIx16"\n",
                                recv_checksum, calc_checksum);
                return (NULL);
        }
@@ -314,7 +316,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));
@@ -331,7 +335,8 @@ static pinghost_t *ping_receive_ipv4 (pinghost_t *ph, char *buffer, size_t buffe
                if (((ptr->sequence - 1) & 0xFFFF) != seq)
                        continue;
 
-               dprintf ("Match found: hostname = %s, ident = 0x%04x, seq = %i\n",
+               dprintf ("Match found: hostname = %s, ident = 0x%04"PRIx16", "
+                               "seq = %"PRIu16"\n",
                                ptr->hostname, ident, seq);
 
                break;
@@ -339,11 +344,12 @@ static pinghost_t *ping_receive_ipv4 (pinghost_t *ph, char *buffer, size_t buffe
 
        if (ptr == NULL)
        {
-               dprintf ("No match found for ident = 0x%04x, seq = %i\n",
+               dprintf ("No match found for ident = 0x%04"PRIx16", seq = %"PRIu16"\n",
                                ident, seq);
        }
-       
-       ptr->recv_ttl = ip_hdr->ip_ttl;
+
+       if (ptr != NULL)
+               ptr->recv_ttl = ip_hdr->ip_ttl;
 
        return (ptr);
 }
@@ -364,7 +370,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;
 
@@ -395,7 +402,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));
@@ -412,7 +421,8 @@ static pinghost_t *ping_receive_ipv6 (pinghost_t *ph, char *buffer, size_t buffe
                if (((ptr->sequence - 1) & 0xFFFF) != seq)
                        continue;
 
-               dprintf ("Match found: hostname = %s, ident = 0x%04x, seq = %i\n",
+               dprintf ("Match found: hostname = %s, ident = 0x%04"PRIx16", "
+                               "seq = %"PRIu16"\n",
                                ptr->hostname, ident, seq);
 
                break;
@@ -420,15 +430,21 @@ static pinghost_t *ping_receive_ipv6 (pinghost_t *ph, char *buffer, size_t buffe
 
        if (ptr == NULL)
        {
-               dprintf ("No match found for ident = 0x%04x, seq = %i\n",
+               dprintf ("No match found for ident = 0x%04"PRIx16", "
+                               "seq = %"PRIu16"\n",
                                ident, seq);
        }
 
        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 recv_ttl;
@@ -463,7 +479,7 @@ static int ping_receive_one (int fd, pinghost_t *ph, struct timeval *now)
        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
@@ -473,11 +489,10 @@ 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 */
        recv_ttl = -1;
-       ph->recv_ttl = -1;
        for (cmsg = CMSG_FIRSTHDR (&msghdr); /* {{{ */
                        cmsg != NULL;
                        cmsg = CMSG_NXTHDR (&msghdr, cmsg))
@@ -526,13 +541,13 @@ static int ping_receive_one (int fd, pinghost_t *ph, struct timeval *now)
 
        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 (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);
        }
@@ -591,7 +606,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)
        {
@@ -677,7 +695,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) */
@@ -1036,6 +1054,9 @@ int ping_setopt (pingobj_t *obj, int option, void *value)
 {
        int ret = 0;
 
+       if (value == NULL)
+               return (-1);
+
        switch (option)
        {
                case PING_OPT_TIMEOUT:
@@ -1351,6 +1372,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;
@@ -1358,6 +1380,7 @@ int ping_host_add (pingobj_t *obj, const char *host)
                        setsockopt (ph->fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
                                        &opt, sizeof (opt));
                }
+#endif
 
                break;
        }