Code

Relicense: Use the LGPL v2.1 (or later) for liboping.
[liboping.git] / src / liboping.c
index 36a3a3ef623d00c68f68d6fe1bdc241c89d5890e..3c1c92a4a5a1ab7a86dac708f18eb83a2fe36267 100644 (file)
@@ -1,20 +1,20 @@
 /**
  * Object oriented C module to send ICMP and ICMPv6 `echo's.
- * Copyright (C) 2006-2009  Florian octo Forster <octo at verplant.org>
+ * Copyright (C) 2006-2010  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; 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
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #if HAVE_CONFIG_H
@@ -134,6 +134,8 @@ struct pingobj
        struct sockaddr         *srcaddr;
        socklen_t                srcaddrlen;
 
+       char                    *device;
+
        char                     errmsg[PING_ERRMSG_LEN];
 
        pinghost_t              *head;
@@ -588,9 +590,10 @@ static int ping_receive_one (pingobj_t *obj, const pinghost_t *ph,
 
 static int ping_receive_all (pingobj_t *obj)
 {
-       fd_set readfds;
-       int num_readfds;
-       int max_readfds;
+       fd_set read_fds;
+       fd_set err_fds;
+       int num_fds;
+       int max_fd;
 
        pinghost_t *ph;
        pinghost_t *ptr;
@@ -629,23 +632,25 @@ static int ping_receive_all (pingobj_t *obj)
 
        while (1)
        {
-               FD_ZERO (&readfds);
-               num_readfds =  0;
-               max_readfds = -1;
+               FD_ZERO (&read_fds);
+               FD_ZERO (&err_fds);
+               num_fds =  0;
+               max_fd = -1;
 
                for (ptr = ph; ptr != NULL; ptr = ptr->next)
                {
                        if (!timerisset (ptr->timer))
                                continue;
 
-                       FD_SET (ptr->fd, &readfds);
-                       num_readfds++;
+                       FD_SET (ptr->fd, &read_fds);
+                       FD_SET (ptr->fd, &err_fds);
+                       num_fds++;
 
-                       if (max_readfds < ptr->fd)
-                               max_readfds = ptr->fd;
+                       if (max_fd < ptr->fd)
+                               max_fd = ptr->fd;
                }
 
-               if (num_readfds == 0)
+               if (num_fds == 0)
                        break;
 
                if (gettimeofday (&nowtime, NULL) == -1)
@@ -657,11 +662,11 @@ static int ping_receive_all (pingobj_t *obj)
                if (ping_timeval_sub (&endtime, &nowtime, &timeout) == -1)
                        break;
 
-               dprintf ("Waiting on %i sockets for %i.%06i seconds\n", num_readfds,
+               dprintf ("Waiting on %i sockets for %i.%06i seconds\n", num_fds,
                                (int) timeout.tv_sec,
                                (int) timeout.tv_usec);
 
-               status = select (max_readfds + 1, &readfds, NULL, NULL, &timeout);
+               status = select (max_fd + 1, &read_fds, NULL, &err_fds, &timeout);
 
                if (gettimeofday (&nowtime, NULL) == -1)
                {
@@ -694,9 +699,18 @@ static int ping_receive_all (pingobj_t *obj)
 
                for (ptr = ph; ptr != NULL; ptr = ptr->next)
                {
-                       if (FD_ISSET (ptr->fd, &readfds))
+                       if (FD_ISSET (ptr->fd, &read_fds))
+                       {
                                if (ping_receive_one (obj, ptr, &nowtime) == 0)
                                        ret++;
+                       }
+                       else if (FD_ISSET (ptr->fd, &err_fds))
+                       {
+                               /* clear the timer in this case so that we
+                                * don't run into an endless loop. */
+                               /* TODO: Set an error flag in this case. */
+                               timerclear (ptr->timer);
+                       }
                }
        } /* while (1) */
        
@@ -1005,6 +1019,8 @@ static void ping_free (pinghost_t *ph)
  */
 const char *ping_get_error (pingobj_t *obj)
 {
+       if (obj == NULL)
+               return (NULL);
        return (obj->errmsg);
 }
 
@@ -1029,6 +1045,9 @@ void ping_destroy (pingobj_t *obj)
        pinghost_t *current;
        pinghost_t *next;
 
+       if (obj == NULL)
+               return;
+
        current = obj->head;
        next = NULL;
 
@@ -1045,6 +1064,9 @@ void ping_destroy (pingobj_t *obj)
        if (obj->srcaddr != NULL)
                free (obj->srcaddr);
 
+       if (obj->device != NULL)
+               free (obj->device);
+
        free (obj);
 
        return;
@@ -1054,7 +1076,7 @@ int ping_setopt (pingobj_t *obj, int option, void *value)
 {
        int ret = 0;
 
-       if (value == NULL)
+       if ((obj == NULL) || (value == NULL))
                return (-1);
 
        switch (option)
@@ -1170,6 +1192,28 @@ int ping_setopt (pingobj_t *obj, int option, void *value)
                } /* case PING_OPT_SOURCE */
                break;
 
+               case PING_OPT_DEVICE:
+               {
+#ifdef SO_BINDTODEVICE
+                       char *device = strdup ((char *) value);
+
+                       if (device == NULL)
+                       {
+                               ping_set_errno (obj, errno);
+                               ret = -1;
+                               break;
+                       }
+
+                       if (obj->device != NULL)
+                               free (obj->device);
+                       obj->device = device;
+#else /* ! SO_BINDTODEVICE */
+                       ping_set_errno (obj, ENOTSUP);
+                       ret = -1;
+#endif /* ! SO_BINDTODEVICE */
+               } /* case PING_OPT_DEVICE */
+               break;
+
                default:
                        ret = -2;
        } /* switch (option) */
@@ -1182,6 +1226,9 @@ int ping_send (pingobj_t *obj)
 {
        int ret;
 
+       if (obj == NULL)
+               return (-1);
+
        if (ping_send_all (obj) < 0)
                return (-1);
 
@@ -1212,6 +1259,9 @@ int ping_host_add (pingobj_t *obj, const char *host)
        struct addrinfo *ai_list, *ai_ptr;
        int              ai_return;
 
+       if ((obj == NULL) || (host == NULL))
+               return (-1);
+
        dprintf ("host = %s\n", host);
 
        if (ping_host_search (obj->head, host) != NULL)
@@ -1337,6 +1387,25 @@ int ping_host_add (pingobj_t *obj, const char *host)
                        }
                }
 
+#ifdef SO_BINDTODEVICE
+               if (obj->device != NULL)
+               {
+                       if (setsockopt (ph->fd, SOL_SOCKET, SO_BINDTODEVICE,
+                                       obj->device, strlen (obj->device) + 1) != 0)
+                       {
+#if WITH_DEBUG
+                               char errbuf[PING_ERRMSG_LEN];
+                               dprintf ("setsockopt: %s\n",
+                                               sstrerror (errno, errbuf, sizeof (errbuf)));
+#endif
+                               ping_set_errno (obj, errno);
+                               close (ph->fd);
+                               ph->fd = -1;
+                               continue;
+                       }
+               }
+#endif /* SO_BINDTODEVICE */
+
                assert (sizeof (struct sockaddr_storage) >= ai_ptr->ai_addrlen);
                memset (ph->addr, '\0', sizeof (struct sockaddr_storage));
                memcpy (ph->addr, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
@@ -1423,6 +1492,9 @@ int ping_host_remove (pingobj_t *obj, const char *host)
 {
        pinghost_t *pre, *cur;
 
+       if ((obj == NULL) || (host == NULL))
+               return (-1);
+
        pre = NULL;
        cur = obj->head;
 
@@ -1453,11 +1525,15 @@ int ping_host_remove (pingobj_t *obj, const char *host)
 
 pingobj_iter_t *ping_iterator_get (pingobj_t *obj)
 {
+       if (obj == NULL)
+               return (NULL);
        return ((pingobj_iter_t *) obj->head);
 }
 
 pingobj_iter_t *ping_iterator_next (pingobj_iter_t *iter)
 {
+       if (iter == NULL)
+               return (NULL);
        return ((pingobj_iter_t *) iter->next);
 }
 
@@ -1468,6 +1544,12 @@ int ping_iterator_get_info (pingobj_iter_t *iter, int info,
 
        size_t orig_buffer_len = *buffer_len;
 
+       if ((iter == NULL) || (buffer_len == NULL))
+               return (-1);
+
+       if ((buffer == NULL) && (*buffer_len != 0 ))
+               return (-1);
+
        switch (info)
        {
                case PING_INFO_USERNAME:
@@ -1587,10 +1669,14 @@ int ping_iterator_get_info (pingobj_iter_t *iter, int info,
 
 void *ping_iterator_get_context (pingobj_iter_t *iter)
 {
+       if (iter == NULL)
+               return (NULL);
        return (iter->context);
 }
 
 void ping_iterator_set_context (pingobj_iter_t *iter, void *context)
 {
+       if (iter == NULL)
+               return;
        iter->context = context;
 }