]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Replace select with poll and nanosleep.
authorRoy Marples <roy@marples.name>
Sun, 10 Feb 2008 23:01:44 +0000 (23:01 +0000)
committerRoy Marples <roy@marples.name>
Sun, 10 Feb 2008 23:01:44 +0000 (23:01 +0000)
arp.c
client.c
interface.c
interface.h
signal.c
signal.h
socket.c

diff --git a/arp.c b/arp.c
index 6d4f5bc8b42b236bdf3f993f9e655b8a115e7a3f..794850c7f2ed4e7658b1f1f0ae1e1a9b1ca221c8 100644 (file)
--- a/arp.c
+++ b/arp.c
@@ -28,7 +28,6 @@
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/ioctl.h>
-#include <sys/select.h>
 #include <sys/socket.h>
 #include <netinet/in_systm.h>
 #ifdef __linux__
@@ -39,6 +38,7 @@
 #include <net/if_arp.h>
 #include <arpa/inet.h>
 #include <errno.h>
+#include <poll.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -53,9 +53,9 @@
 
 /* These are really for IPV4LL */
 #define NPROBES                 3
-#define PROBE_INTERVAL          200000
+#define PROBE_INTERVAL          200
 #define NCLAIMS                 2
-#define CLAIM_INTERVAL          200000
+#define CLAIM_INTERVAL          200
 
 /* Linux does not seem to define these handy macros */
 #ifndef ar_sha
@@ -116,6 +116,10 @@ int arp_claim (interface_t *iface, struct in_addr address)
        int nprobes = 0;
        int nclaims = 0;
        struct in_addr null_address;
+       struct pollfd fds[] = {
+               { -1, POLLIN, 0 },
+               { -1, POLLIN, 0 }
+       };
 
        if (! iface)
                return (-1);
@@ -134,29 +138,25 @@ int arp_claim (interface_t *iface, struct in_addr address)
        if (! open_socket (iface, ETHERTYPE_ARP))
                return (-1);
 
+       fds[0].fd = signal_fd ();
+       fds[1].fd = iface->fd;
+
        memset (&null_address, 0, sizeof (null_address));
 
        buffer = xmalloc (iface->buffer_length);
        reply = xmalloc (iface->buffer_length);
 
        for (;;) {
-               struct timeval tv;
                size_t bufpos = 0;
                size_t buflen = iface->buffer_length;
-               fd_set rset;
                int bytes;
                int s = 0;
-               int maxfd;
                struct timeval stopat;
                struct timeval now;
 
-               /* Only select if we have a timeout */
+               /* Only poll if we have a timeout */
                if (timeout > 0) {
-                       tv.tv_sec = 0; 
-                       tv.tv_usec = timeout;
-
-                       maxfd = signal_fd_set (&rset, iface->fd);
-                       s = select (maxfd + 1, &rset, NULL, NULL, &tv);
+                       s = poll (fds, 2, timeout);
                        if (s == -1) {
                                if (errno == EINTR) {
                                        if (signal_exists (NULL) == -1) {
@@ -166,7 +166,7 @@ int arp_claim (interface_t *iface, struct in_addr address)
                                                break;
                                }
 
-                               logger (LOG_ERR, "select: `%s'",
+                               logger (LOG_ERR, "poll: `%s'",
                                        strerror (errno));
                                break;
                        }
@@ -220,7 +220,7 @@ int arp_claim (interface_t *iface, struct in_addr address)
                        continue;
                }
 
-               if (! FD_ISSET (iface->fd, &rset))
+               if (! fds[1].revents & POLLIN)
                        continue;
 
                memset (buffer, 0, buflen);
index 2975ac8582bafebdf100a18b89421e87246e6d38..8630186db5705206d384d8d3f6902b8b74808407 100644 (file)
--- a/client.c
+++ b/client.c
 
 #include <sys/time.h>
 #include <sys/types.h>
-#include <sys/select.h>
 #include <arpa/inet.h>
 #ifdef __linux__
 # include <netinet/ether.h>
 #endif
 #include <ctype.h>
 #include <errno.h>
+#include <poll.h>
 #include <signal.h>
 #include <stdbool.h>
 #include <stdlib.h>
 # endif
 #endif
 
-/* We need this for our maximum timeout as FreeBSD's select cannot handle
- * any higher than this. Is there a better way of working this out? */
-#define SELECT_MAX              100000000
+/* Some platforms don't define INFTIM */
+#ifndef INFTIM
+# define INFTIM                 -1
+#endif
 
 /* This is out mini timeout.
  * Basically we resend the last request every TIMEOUT_MINI seconds. */
 #define SOCKET_CLOSED           0
 #define SOCKET_OPEN             1
 
+/* Indexes for pollfds */
+#define POLLFD_SIGNAL           0
+#define POLLFD_IFACE            1 
+
 typedef struct _state {
        int *pidfd;
        bool forked;
@@ -460,47 +465,41 @@ static void drop_config (state_t *state, const options_t *options)
        memset (state->dhcp, 0, sizeof (*state->dhcp));
 }
 
-static int wait_for_packet (fd_set *rset, state_t *state,
+static int wait_for_packet (struct pollfd *fds, state_t *state,
                            const options_t *options)
 {
        dhcp_t *dhcp = state->dhcp;
        interface_t *iface = state->interface;
+       int timeout = 0;
        int retval = 0;
-       struct timeval tv;
-       int maxfd;
 
        if (! (state->timeout > 0 ||
               (options->timeout == 0 &&
                (state->state != STATE_INIT || state->xid)))) {
-               /* We need to zero our rset, otherwise we will block trying
-                * to read a signal. */
-               FD_ZERO (rset);
+               /* We need to zero our signal fd, otherwise we will block
+                * trying to read a signal. */
+               fds[POLLFD_SIGNAL].revents = 0;
                return (0);
        }
 
+       fds[POLLFD_IFACE].fd = iface->fd;
+
        if ((options->timeout == 0 && state->xid) ||
            (dhcp->leasetime == (unsigned) -1 &&
             state->state == STATE_BOUND))
        {
-               int retry = 0;
-
-               logger (LOG_DEBUG, "waiting on select for infinity");
+               logger (LOG_DEBUG, "waiting for infinity");
                while (retval == 0)     {
-                       maxfd = signal_fd_set (rset, iface->fd);
                        if (iface->fd == -1)
-                               retval = select (maxfd + 1, rset,
-                                                NULL, NULL, NULL);
+                               retval = poll (fds, 1, INFTIM);
                        else {
                                /* Slow down our requests */
-                               if (retry < TIMEOUT_MINI_INF)
-                                       retry += TIMEOUT_MINI;
-                               else if (retry > TIMEOUT_MINI_INF)
-                                       retry = TIMEOUT_MINI_INF;
-
-                               tv.tv_sec = retry;
-                               tv.tv_usec = 0;
-                               retval = select (maxfd + 1, rset,
-                                                NULL, NULL, &tv);
+                               if (timeout < TIMEOUT_MINI_INF)
+                                       timeout += TIMEOUT_MINI;
+                               else if (timeout > TIMEOUT_MINI_INF)
+                                       timeout = TIMEOUT_MINI_INF;
+
+                               retval = poll (fds, 2, timeout * 1000);
                                if (retval == 0)
                                        _send_message (state, state->last_type,
                                                       options);
@@ -516,22 +515,20 @@ static int wait_for_packet (fd_set *rset, state_t *state,
        if (iface->fd > -1 && uptime () - state->last_sent >= TIMEOUT_MINI)
                _send_message (state, state->last_type, options);
 
-       logger (LOG_DEBUG, "waiting on select for %ld seconds",
+       logger (LOG_DEBUG, "waiting for %ld seconds",
                (unsigned long) state->timeout);
        /* If we're waiting for a reply, then we re-send the last
         * DHCP request periodically in-case of a bad line */
        retval = 0;
        while (state->timeout > 0 && retval == 0) {
                if (iface->fd == -1)
-                       tv.tv_sec = SELECT_MAX;
+                       timeout = INFTIM;
                else
-                       tv.tv_sec = TIMEOUT_MINI;
-               if (state->timeout < tv.tv_sec)
-                       tv.tv_sec = (time_t) state->timeout;
-               tv.tv_usec = 0;
+                       timeout = TIMEOUT_MINI;
+               if (state->timeout < timeout)
+                       timeout = (int) state->timeout;
                state->start = uptime ();
-               maxfd = signal_fd_set (rset, iface->fd);
-               retval = select (maxfd + 1, rset, NULL, NULL, &tv);
+               retval = poll (fds, iface->fd == -1 ? 1 : 2, timeout * 1000);
                state->timeout -= uptime () - state->start;
                if (retval == 0 && iface->fd != -1 && state->timeout > 0)
                        _send_message (state, state->last_type, options);
@@ -765,7 +762,7 @@ static int handle_timeout (state_t *state, const options_t *options)
 
 static int handle_dhcp (state_t *state, int type, const options_t *options)
 {
-       struct timeval tv;
+       struct timespec ts;
        interface_t *iface = state->interface;
        dhcp_t *dhcp = state->dhcp;
 
@@ -782,12 +779,12 @@ static int handle_dhcp (state_t *state, int type, const options_t *options)
                if (state->nakoff > 0) {
                        logger (LOG_DEBUG, "sleeping for %ld seconds",
                                (long) state->nakoff);
-                       tv.tv_sec = state->nakoff;
-                       tv.tv_usec = 0;
+                       ts.tv_sec = state->nakoff;
+                       ts.tv_nsec = 0;
                        state->nakoff *= 2;
                        if (state->nakoff > NAKOFF_MAX)
                                state->nakoff = NAKOFF_MAX;
-                       select (0, NULL, NULL, NULL, &tv);
+                       nanosleep (&ts, NULL);
                }
 
                return (0);
@@ -864,9 +861,9 @@ static int handle_dhcp (state_t *state, int type, const options_t *options)
                        /* RFC 2131 says that we should wait for 10 seconds
                         * before doing anything else */
                        logger (LOG_INFO, "sleeping for 10 seconds");
-                       tv.tv_sec = 10;
-                       tv.tv_usec = 0;
-                       select (0, NULL, NULL, NULL, &tv);
+                       ts.tv_sec = 10;
+                       ts.tv_nsec = 0;
+                       nanosleep (&ts, NULL);
                        return (0);
                } else if (errno == EINTR)
                        return (0);     
@@ -892,7 +889,7 @@ static int handle_dhcp (state_t *state, int type, const options_t *options)
                state->state = STATE_INIT;
        } else if (dhcp->leasetime == (unsigned) -1) {
                dhcp->renewaltime = dhcp->rebindtime = dhcp->leasetime;
-               state->timeout = 1; /* So we select on infinity */
+               state->timeout = 1; /* So we wait for infinity */
                logger (LOG_INFO, "leased %s for infinity",
                        inet_ntoa (dhcp->address));
                state->state = STATE_BOUND;
@@ -1039,7 +1036,10 @@ int dhcp_run (const options_t *options, int *pidfd)
 {
        interface_t *iface;
        state_t *state = NULL;
-       fd_set rset;
+       struct pollfd fds[] = {
+               { -1, POLLIN, 0 },
+               { -1, POLLIN, 0 }
+       };
        int retval = -1;
        int sig;
 
@@ -1063,11 +1063,13 @@ int dhcp_run (const options_t *options, int *pidfd)
        if (signal_setup () == -1)
                goto eexit;
 
+       fds[POLLFD_SIGNAL].fd = signal_fd ();
+
        for (;;) {
-               retval = wait_for_packet (&rset, state, options);
+               retval = wait_for_packet (fds, state, options);
 
                /* We should always handle our signals first */
-               if ((sig = (signal_read (&rset))) != -1) {
+               if ((sig = (signal_read (&fds[POLLFD_SIGNAL]))) != -1) {
                        if (handle_signal (sig, state, options))
                                retval = 0;
                        else
@@ -1076,14 +1078,13 @@ int dhcp_run (const options_t *options, int *pidfd)
                        retval = handle_timeout (state, options);
                else if (retval > 0 &&
                         state->socket != SOCKET_CLOSED &&
-                        FD_ISSET (iface->fd, &rset))
+                        fds[POLLFD_IFACE].revents & POLLIN)
                        retval = handle_packet (state, options);
                else if (retval == -1 && errno == EINTR) {
                        /* The interupt will be handled above */
                        retval = 0;
                } else {
-                       logger (LOG_ERR, "error on select: %s",
-                               strerror (errno));
+                       logger (LOG_ERR, "poll: %s", strerror (errno));
                        retval = -1;
                }
 
index 6f546487a5a34c954b4cc051b5c5b3152f9d15f7..0b608a97039a4e757942da3ccfae1324828a8091 100644 (file)
@@ -684,7 +684,7 @@ static int do_route (const char *ifname,
  * send_netlink handles the actual transmission so we can work out
  * if there was an error or not. */
 #define BUFFERLEN 256
-static int send_netlink(struct nlmsghdr *hdr)
+int send_netlink (struct nlmsghdr *hdr, netlink_callback callback, void *arg)
 {
        int s;
        pid_t mypid = getpid ();
@@ -795,9 +795,15 @@ static int send_netlink(struct nlmsghdr *hdr)
                        }
 
                        if (err->error == 0) {
+                               int retval = 0;
+
                                close (s);
+                               if (callback) {
+                                       if ((retval = callback (hdr, arg)) == -1)
+                                               logger (LOG_ERR, "netlink: callback failed");
+                               }
                                free (buffer);
-                               return 0;
+                               return (retval);
                        }
 
                        errno = -err->error;
@@ -910,7 +916,7 @@ static int do_address(const char *ifname,
                add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_BROADCAST,
                            &broadcast.s_addr, sizeof (broadcast.s_addr));
 
-       retval = send_netlink (&nlm->hdr);
+       retval = send_netlink (&nlm->hdr, NULL, NULL);
        free (nlm);
        return retval;
 }
@@ -971,7 +977,7 @@ static int do_route (const char *ifname,
        add_attr_32 (&nlm->hdr, sizeof (*nlm), RTA_OIF, ifindex);
        add_attr_32 (&nlm->hdr, sizeof (*nlm), RTA_PRIORITY, metric);
 
-       retval = send_netlink (&nlm->hdr);
+       retval = send_netlink (&nlm->hdr, NULL, NULL);
        free (nlm);
        return retval;
 }
index 6a05a6b8d2f26c48118400d6d68a9c1b2fca2732..61bf1e90424509960203416a204f233699f3ca5f 100644 (file)
@@ -150,4 +150,8 @@ int del_route (const char *ifname, struct in_addr destination,
 int inet_ntocidr (struct in_addr address);
 int inet_cidrtoaddr (int cidr, struct in_addr *addr);
 
+#ifdef __linux__
+typedef int (*netlink_callback) (struct nlmsghdr *hdr, void *arg);
+int send_netlink (struct nlmsghdr *hdr, netlink_callback callback, void *arg);
+#endif
 #endif
index c9430e1c9f9e585272ab614cc54b08728b53a396..37b59e8f8beaacce78b14db4317cf2b4c0afc0a5 100644 (file)
--- a/signal.c
+++ b/signal.c
@@ -27,8 +27,8 @@
 
 #include <sys/types.h>
 #include <sys/socket.h>
-#include <sys/select.h>
 #include <errno.h>
+#include <poll.h>
 #include <signal.h>
 #include <string.h>
 #include <unistd.h>
@@ -67,20 +67,15 @@ static void signal_handler (int sig)
        errno = serrno;
 }
 
-/* Add the signal pipe to an fd set */
-int signal_fd_set (fd_set *rset, int fd)
+int signal_fd (void)
 {
-       FD_ZERO (rset);
-       FD_SET (signal_pipe[0], rset);
-       if (fd >= 0)
-               FD_SET (fd, rset);
-       return (signal_pipe[0] > fd ? signal_pipe[0] : fd);
+       return (signal_pipe[0]);
 }
 
 /* Check if we have a signal or not */
-int signal_exists (const fd_set *rset)
+int signal_exists (const struct pollfd *fd)
 {
-       if (signals[0] || (rset && FD_ISSET (signal_pipe[0], rset)))
+       if (signals[0] || (fd && fd->revents & POLLIN))
                return (0);
        return (-1);
 }
@@ -88,7 +83,7 @@ int signal_exists (const fd_set *rset)
 /* Read a signal from the signal pipe. Returns 0 if there is
  * no signal, -1 on error (and sets errno appropriately), and
  * your signal on success */
-int signal_read (fd_set *rset)
+int signal_read (struct pollfd *fd)
 {
        int sig = -1;
 
@@ -104,7 +99,7 @@ int signal_read (fd_set *rset)
                }
        }
 
-       if (rset && FD_ISSET (signal_pipe[0], rset)) {
+       if (fd && fd->revents & POLLIN) {
                char buf[16];
                size_t bytes;
 
@@ -117,7 +112,7 @@ int signal_read (fd_set *rset)
                /* We need to clear us from rset if nothing left in the buffer
                 * in case we are called many times */
                if (bytes == sizeof (sig))
-                       FD_CLR (signal_pipe[0], rset);
+                       fd->revents = 0;
        }
 
        return (sig);
index e72b99640a216939e8fe2cfa0c50f6a2384d4fad..63a59060e749170c3d26ada59e2a50a64ded7199 100644 (file)
--- a/signal.h
+++ b/signal.h
 #ifndef SIGNAL_H
 #define SIGNAL_H
 
+#include <poll.h>
+
 int signal_init (void);
 int signal_setup (void);
 int signal_reset (void);
-int signal_fd_set (fd_set *rset, int fd);
-int signal_exists (const fd_set *rset);
-int signal_read (fd_set *rset);
+int signal_fd (void);
+int signal_exists (const struct pollfd *fd);
+int signal_read (struct pollfd *fd);
 
 #endif
index 814d051ba7dd772320dda30066755133add03204..8292705feea8ba89cccd4eddaf01944b8aa09cf9 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -31,7 +31,6 @@
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/param.h>
-#include <sys/select.h>
 #include <sys/socket.h>
 #include <sys/uio.h>
 #include <net/if.h>
@@ -43,6 +42,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <time.h>
 #include <unistd.h>
 
 #ifdef BSD
@@ -375,12 +375,12 @@ ssize_t get_packet (const interface_t *iface, unsigned char *data,
                *buffer_len = read (iface->fd, bpf.buffer, iface->buffer_length);
                *buffer_pos = 0;
                if (*buffer_len < 1) {
-                       struct timeval tv;
+                       struct timespec tv;
                        logger (LOG_ERR, "read: %s", strerror (errno));
-                       tv.tv_sec = 3;
-                       tv.tv_usec = 0;
-                       select (0, NULL, NULL, NULL, &tv);
-                       return -1;
+                       ts.tv_sec = 3;
+                       ts.tv_nsec = 0;
+                       nanosleep (&ts, NULL);
+                       return (-1);
                }
        } else
                bpf.buffer += *buffer_pos;
@@ -566,11 +566,11 @@ ssize_t get_packet (const interface_t *iface, unsigned char *data,
        bytes = read (iface->fd, buffer, iface->buffer_length);
 
        if (bytes == -1) {
-               struct timeval tv;
+               struct timespec ts;
                logger (LOG_ERR, "read: %s", strerror (errno));
-               tv.tv_sec = 3;
-               tv.tv_usec = 0;
-               select (0, NULL, NULL, NULL, &tv);
+               ts.tv_sec = 3;
+               ts.tv_nsec = 0;
+               nanosleep (&ts, NULL);
                return (-1);
        }