Make UNIX socket non-blocking for ctrl_iface
authorBen Greear <greearb@candelatech.com>
Sat, 4 Aug 2012 17:34:27 +0000 (20:34 +0300)
committerJouni Malinen <j@w1.fi>
Sat, 4 Aug 2012 17:34:27 +0000 (20:34 +0300)
This keeps wpa_cli from hanging forever if the other end of the socket
dies.

Signed-hostap: Ben Greear <greearb@candelatech.com>

src/common/wpa_ctrl.c
wpa_supplicant/ctrl_iface_unix.c

index b2b0683..2eac803 100644 (file)
@@ -12,6 +12,8 @@
 
 #ifdef CONFIG_CTRL_IFACE_UNIX
 #include <sys/un.h>
+#include <unistd.h>
+#include <fcntl.h>
 #endif /* CONFIG_CTRL_IFACE_UNIX */
 
 #ifdef ANDROID
@@ -73,6 +75,7 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
        int ret;
        size_t res;
        int tries = 0;
+       int flags;
 
        ctrl = os_malloc(sizeof(*ctrl));
        if (ctrl == NULL)
@@ -156,6 +159,19 @@ try_again:
                return NULL;
        }
 
+       /*
+        * Make socket non-blocking so that we don't hang forever if
+        * target dies unexpectedly.
+        */
+       flags = fcntl(ctrl->s, F_GETFL);
+       if (flags >= 0) {
+               flags |= O_NONBLOCK;
+               if (fcntl(ctrl->s, F_SETFL, flags) < 0) {
+                       perror("fcntl(ctrl->s, O_NONBLOCK)");
+                       /* Not fatal, continue on.*/
+               }
+       }
+
        return ctrl;
 }
 
@@ -289,6 +305,7 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
                     void (*msg_cb)(char *msg, size_t len))
 {
        struct timeval tv;
+       struct os_time started_at;
        int res;
        fd_set rfds;
        const char *_cmd;
@@ -315,7 +332,30 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
                _cmd_len = cmd_len;
        }
 
+       errno = 0;
+       started_at.sec = 0;
+       started_at.usec = 0;
+retry_send:
        if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
+               if (errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK)
+               {
+                       /*
+                        * Must be a non-blocking socket... Try for a bit
+                        * longer before giving up.
+                        */
+                       if (started_at.sec == 0)
+                               os_get_time(&started_at);
+                       else {
+                               struct os_time n;
+                               os_get_time(&n);
+                               /* Try for a few seconds. */
+                               if (n.sec > started_at.sec + 5)
+                                       goto send_err;
+                       }
+                       os_sleep(1, 0);
+                       goto retry_send;
+               }
+       send_err:
                os_free(cmd_buf);
                return -1;
        }
index 7bebcb8..c106350 100644 (file)
@@ -11,6 +11,8 @@
 #include <sys/stat.h>
 #include <grp.h>
 #include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
 #ifdef ANDROID
 #include <cutils/sockets.h>
 #endif /* ANDROID */
@@ -259,6 +261,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
        char *buf, *dir = NULL, *gid_str = NULL;
        struct group *grp;
        char *endp;
+       int flags;
 
        priv = os_zalloc(sizeof(*priv));
        if (priv == NULL)
@@ -405,6 +408,20 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
 #ifdef ANDROID
 havesock:
 #endif /* ANDROID */
+
+       /*
+        * Make socket non-blocking so that we don't hang forever if
+        * target dies unexpectedly.
+        */
+       flags = fcntl(priv->sock, F_GETFL);
+       if (flags >= 0) {
+               flags |= O_NONBLOCK;
+               if (fcntl(priv->sock, F_SETFL, flags) < 0) {
+                       perror("fcntl(ctrl, O_NONBLOCK)");
+                       /* Not fatal, continue on.*/
+               }
+       }
+
        eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
                                 wpa_s, priv);
        wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);