Patchwork [1/7] supplicant: Make unix socket non-blocking.

login
register
mail settings
Submitter Ben Greear
Date July 6, 2012, 4:52 p.m.
Message ID <1341593561-14090-1-git-send-email-greearb@candelatech.com>
Download mbox | patch
Permalink /patch/169501/
State Accepted
Commit 4fdc8def8855ce9b90ffbbdc47152ce46ccdcb1e
Headers show

Comments

Ben Greear - July 6, 2012, 4:52 p.m.
From: Ben Greear <greearb@candelatech.com>

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            |   37 ++++++++++++++++++++++++++++++++++++-
 wpa_supplicant/ctrl_iface_unix.c |   15 ++++++++++++++-
 2 files changed, 50 insertions(+), 2 deletions(-)
Jouni Malinen - Aug. 4, 2012, 5:36 p.m.
On Fri, Jul 06, 2012 at 09:52:35AM -0700, greearb@candelatech.com wrote:
> This keeps wpa_cli from hanging forever if the other end of the
> socket dies.

Thanks, applied with some cleanup.

>  	if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
> +		if ((errno == EAGAIN) || (errno = EBUSY)
> +		    || (errno == EWOULDBLOCK)) {

Especially that 'errno = EBUSY' part required something.. ;-)
Ben Greear - Aug. 4, 2012, 7:48 p.m.
On 08/04/2012 10:36 AM, Jouni Malinen wrote:
> On Fri, Jul 06, 2012 at 09:52:35AM -0700, greearb@candelatech.com wrote:
>> This keeps wpa_cli from hanging forever if the other end of the
>> socket dies.
>
> Thanks, applied with some cleanup.
>
>>   	if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
>> +		if ((errno == EAGAIN) || (errno = EBUSY)
>> +		    || (errno == EWOULDBLOCK)) {
>
> Especially that 'errno = EBUSY' part required something.. ;-)

Eww..thanks for catching that!

Ben

Patch

diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c
index b2b0683..e671f79 100644
--- a/src/common/wpa_ctrl.c
+++ b/src/common/wpa_ctrl.c
@@ -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
@@ -23,7 +25,6 @@ 
 #include "wpa_ctrl.h"
 #include "common.h"
 
-
 #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
 #define CTRL_IFACE_SOCKET
 #endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */
@@ -73,6 +74,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 +158,16 @@  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);
+	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 +301,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 +328,29 @@  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 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;
 	}
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 7bebcb8..e4fc6bb 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -14,7 +14,8 @@ 
 #ifdef ANDROID
 #include <cutils/sockets.h>
 #endif /* ANDROID */
-
+#include <unistd.h>
+#include <fcntl.h>
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "utils/list.h"
@@ -259,6 +260,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 +407,17 @@  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);
+	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);