]> code.delx.au - gnu-emacs/commitdiff
Fix asynchronous TLS connections on MS-Windows
authorAlain Schneble <a.s@realize.ch>
Thu, 10 Mar 2016 14:43:09 +0000 (16:43 +0200)
committerEli Zaretskii <eliz@gnu.org>
Thu, 10 Mar 2016 14:43:09 +0000 (16:43 +0200)
* src/w32.c (sys_write): Don't switch the socket to blocking mode
if the connection attempt is in progress.  Instead, return either
EWOULDBLOCK immediately if the connection is in progress, or the
error code produced by '_sys_wait_connect' if the connection
failed.  Switching the socket to blocking mode was found to
interfere with GnuTLS handshake.  (Bug#22789)

src/w32.c

index ccf7cc335cea9f99514ae93b472fad13c8147682..c55315275c7602f3280137163b55e7f2a7f9ceef 100644 (file)
--- a/src/w32.c
+++ b/src/w32.c
@@ -8772,6 +8772,30 @@ sys_write (int fd, const void * buffer, unsigned int count)
       unsigned long nblock = 0;
       if (winsock_lib == NULL) emacs_abort ();
 
+      child_process *cp = fd_info[fd].cp;
+
+      /* If this is a non-blocking socket whose connection is in
+        progress or terminated with an error already, return the
+        proper error code to the caller. */
+      if (cp != NULL && (fd_info[fd].flags & FILE_CONNECT) != 0)
+       {
+         /* In case connection is in progress, ENOTCONN that would
+            result from calling pfn_send is not what callers expect. */
+         if (cp->status != STATUS_CONNECT_FAILED)
+           {
+             errno = EWOULDBLOCK;
+             return -1;
+           }
+         /* In case connection failed, use the actual error code
+            stashed by '_sys_wait_connect' in cp->errcode. */
+         else if (cp->errcode != 0)
+           {
+             pfn_WSASetLastError (cp->errcode);
+             set_errno ();
+             return -1;
+           }
+       }
+
       /* TODO: implement select() properly so non-blocking I/O works. */
       /* For now, make sure the write blocks.  */
       if (fd_info[fd].flags & FILE_NDELAY)
@@ -8782,14 +8806,8 @@ sys_write (int fd, const void * buffer, unsigned int count)
       if (nchars == SOCKET_ERROR)
         {
          set_errno ();
-         /* If this is a non-blocking socket whose connection is in
-            progress, return the proper error code to the caller;
-            ENOTCONN is not what they expect . */
-         if (errno == ENOTCONN && (fd_info[fd].flags & FILE_CONNECT) != 0)
-           errno = EWOULDBLOCK;
-         else
-           DebPrint (("sys_write.send failed with error %d on socket %ld\n",
-                      pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
+         DebPrint (("sys_write.send failed with error %d on socket %ld\n",
+                    pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
        }
 
       /* Set the socket back to non-blocking if it was before,