changeset 8330:ec940c11f749 v7.4.1457

commit https://github.com/vim/vim/commit/d42119fff228434fe57e88d501c744de0a9fb1b1 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Feb 28 20:51:49 2016 +0100 patch 7.4.1457 Problem: Opening a channel with select() is not done properly. Solution: Also used read-fds. Use getsockopt() to check for errors. (Ozaki Kiichi)
author Christian Brabandt <cb@256bit.org>
date Sun, 28 Feb 2016 21:00:04 +0100
parents 105cfd08008e
children b3ad9d4a8107
files src/channel.c src/version.c
diffstat 2 files changed, 37 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/src/channel.c
+++ b/src/channel.c
@@ -28,6 +28,8 @@
 # define ECONNREFUSED WSAECONNREFUSED
 # undef EWOULDBLOCK
 # define EWOULDBLOCK WSAEWOULDBLOCK
+# undef EINPROGRESS
+# define EINPROGRESS WSAEINPROGRESS
 # ifdef EINTR
 #  undef EINTR
 # endif
@@ -550,8 +552,6 @@ channel_open(
 #else
     int			port = port_in;
     struct timeval	start_tv;
-    int			so_error;
-    socklen_t		so_error_len = sizeof(so_error);
 #endif
     channel_T		*channel;
     int			ret;
@@ -633,7 +633,6 @@ channel_open(
 	{
 	    if (errno != EWOULDBLOCK
 		    && errno != ECONNREFUSED
-
 #ifdef EINPROGRESS
 		    && errno != EINPROGRESS
 #endif
@@ -653,14 +652,13 @@ channel_open(
 	if (waittime >= 0 && ret < 0)
 	{
 	    struct timeval	tv;
+	    fd_set		rfds;
 	    fd_set		wfds;
-#if defined(__APPLE__) && __APPLE__ == 1
-# define PASS_RFDS
-	    fd_set	    rfds;
+	    int			so_error = 0;
+	    socklen_t		so_error_len = sizeof(so_error);
 
 	    FD_ZERO(&rfds);
 	    FD_SET(sd, &rfds);
-#endif
 	    FD_ZERO(&wfds);
 	    FD_SET(sd, &wfds);
 
@@ -671,13 +669,7 @@ channel_open(
 #endif
 	    ch_logn(channel,
 		    "Waiting for connection (waittime %d msec)...", waittime);
-	    ret = select((int)sd + 1,
-#ifdef PASS_RFDS
-		    &rfds,
-#else
-		    NULL,
-#endif
-		    &wfds, NULL, &tv);
+	    ret = select((int)sd + 1, &rfds, &wfds, NULL, &tv);
 
 	    if (ret < 0)
 	    {
@@ -689,30 +681,39 @@ channel_open(
 		channel_free(channel);
 		return NULL;
 	    }
-#ifdef PASS_RFDS
-	    if (ret == 0 && FD_ISSET(sd, &rfds) && FD_ISSET(sd, &wfds))
-	    {
-		/* For OS X, this implies error. See tcp(4). */
-		ch_error(channel, "channel_open: Connect failed");
-		EMSG(_(e_cannot_connect));
-		sock_close(sd);
-		channel_free(channel);
-		return NULL;
-	    }
-#endif
-#ifdef WIN32
-	    /* On Win32 select() is expected to work and wait for up to the
-	     * waittime for the socket to be open. */
-	    if (!FD_ISSET(sd, &wfds) || ret == 0)
-#else
-	    /* See socket(7) for the behavior on Linux-like systems:
+
+	    /* On Win32: select() is expected to work and wait for up to the
+	     * waittime for the socket to be open.
+	     * On Linux-like systems: See socket(7) for the behavior
 	     * After putting the socket in non-blocking mode, connect() will
 	     * return EINPROGRESS, select() will not wait (as if writing is
 	     * possible), need to use getsockopt() to check if the socket is
-	     * actually open. */
-	    getsockopt(sd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_len);
-	    if (!FD_ISSET(sd, &wfds) || ret == 0 || so_error != 0)
+	     * actually connect.
+	     * We detect an failure to connect when both read and write fds
+	     * are set.  Use getsockopt() to find out what kind of failure. */
+	    if (FD_ISSET(sd, &rfds) && FD_ISSET(sd, &wfds))
+	    {
+		ret = getsockopt(sd,
+			    SOL_SOCKET, SO_ERROR, &so_error, &so_error_len);
+		if (ret < 0 || (so_error != 0
+			&& so_error != EWOULDBLOCK
+			&& so_error != ECONNREFUSED
+#ifdef EINPROGRESS
+			&& so_error != EINPROGRESS
 #endif
+			))
+		{
+		    ch_errorn(channel,
+			    "channel_open: Connect failed with errno %d",
+			    so_error);
+		    PERROR(_(e_cannot_connect));
+		    sock_close(sd);
+		    channel_free(channel);
+		    return NULL;
+		}
+	    }
+
+	    if (!FD_ISSET(sd, &wfds) || so_error != 0)
 	    {
 #ifndef WIN32
 		struct  timeval end_tv;
--- a/src/version.c
+++ b/src/version.c
@@ -744,6 +744,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1457,
+/**/
     1456,
 /**/
     1455,