]> code.delx.au - gnu-emacs/blobdiff - src/process.c
Merge from origin/emacs-25
[gnu-emacs] / src / process.c
index d78b04f977012422c1bcb10ad1abaf8b2a32e194..4359f681b452c305b38495a4c5478edc2edbac73 100644 (file)
@@ -75,11 +75,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 # include <sys/stropts.h>
 #endif
 
-#ifdef HAVE_RES_INIT
-#include <arpa/nameser.h>
-#include <resolv.h>
-#endif
-
 #ifdef HAVE_UTIL_H
 #include <util.h>
 #endif
@@ -125,6 +120,11 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #endif
 #endif
 
+#if defined HAVE_GETADDRINFO_A || defined HAVE_GNUTLS
+/* This is 0.1s in nanoseconds. */
+#define ASYNC_RETRY_NSEC 100000000
+#endif
+
 #ifdef WINDOWSNT
 extern int sys_select (int, fd_set *, fd_set *, fd_set *,
                       struct timespec *, void *);
@@ -281,7 +281,7 @@ static int max_input_desc;
 
 /* Indexed by descriptor, gives the process (if any) for that descriptor.  */
 static Lisp_Object chan_process[FD_SETSIZE];
-static void wait_for_socket_fds (Lisp_Object process, char *name);
+static void wait_for_socket_fds (Lisp_Object, char const *);
 
 /* Alist of elements (NAME . PROCESS).  */
 static Lisp_Object Vprocess_alist;
@@ -302,7 +302,7 @@ static struct coding_system *proc_encode_coding_system[FD_SETSIZE];
 /* Table of `partner address' for datagram sockets.  */
 static struct sockaddr_and_len {
   struct sockaddr *sa;
-  int len;
+  ptrdiff_t len;
 } datagram_address[FD_SETSIZE];
 #define DATAGRAM_CHAN_P(chan)  (datagram_address[chan].sa != 0)
 #define DATAGRAM_CONN_P(proc)                                           \
@@ -745,14 +745,10 @@ free_dns_request (Lisp_Object proc)
 {
   struct Lisp_Process *p = XPROCESS (proc);
 
-  if (p->dns_requests[0]->ar_result)
-    freeaddrinfo (p->dns_requests[0]->ar_result);
-  xfree ((void *)p->dns_requests[0]->ar_request);
-  xfree ((void *)p->dns_requests[0]->ar_name);
-  xfree ((void *)p->dns_requests[0]->ar_service);
-  xfree (p->dns_requests[0]);
-  xfree (p->dns_requests);
-  p->dns_requests = NULL;
+  if (p->dns_request->ar_result)
+    freeaddrinfo (p->dns_request->ar_result);
+  xfree (p->dns_request);
+  p->dns_request = NULL;
 }
 #endif
 
@@ -847,10 +843,25 @@ nil, indicating the current buffer's process.  */)
   p = XPROCESS (process);
 
 #ifdef HAVE_GETADDRINFO_A
-  if (p->dns_requests)
+  if (p->dns_request)
     {
-      gai_cancel (p->dns_requests[0]);
-      free_dns_request (process);
+      int ret;
+
+      gai_cancel (p->dns_request);
+      ret = gai_error (p->dns_request);
+      if (ret == EAI_CANCELED || ret == 0)
+       free_dns_request (process);
+      else
+       {
+         /* If we're called during shutdown, we don't really about
+            freeing all the resources.  Otherwise wait until
+            completion, and then free the request. */
+         if (! inhibit_sentinels)
+           {
+             gai_suspend ((struct gaicb const **) &p->dns_request, 1, NULL);
+             free_dns_request (process);
+           }
+       }
     }
 #endif
 
@@ -1063,13 +1074,10 @@ The string argument is normally a multibyte string, except:
 - if `default-enable-multibyte-characters' is nil, it is a unibyte
   string (the result of converting the decoded input multibyte
   string to unibyte with `string-make-unibyte').  */)
-  (register Lisp_Object process, Lisp_Object filter)
+  (Lisp_Object process, Lisp_Object filter)
 {
-  struct Lisp_Process *p;
-
   CHECK_PROCESS (process);
-
-  p = XPROCESS (process);
+  struct Lisp_Process *p = XPROCESS (process);
 
   /* Don't signal an error if the process's input file descriptor
      is closed.  This could make debugging Lisp more difficult,
@@ -1214,8 +1222,10 @@ SERVICE) for a network connection or (PORT SPEED) for a serial
 connection.  If KEY is t, the complete contact information for the
 connection is returned, else the specific value for the keyword KEY is
 returned.  See `make-network-process' or `make-serial-process' for a
-list of keywords.  */)
-  (register Lisp_Object process, Lisp_Object key)
+list of keywords.
+If PROCESS is a non-blocking network process that hasn't been fully
+set up yet, this function will block until socket setup has completed.  */)
+  (Lisp_Object process, Lisp_Object key)
 {
   Lisp_Object contact;
 
@@ -1261,8 +1271,8 @@ DEFUN ("process-plist", Fprocess_plist, Sprocess_plist,
 
 DEFUN ("set-process-plist", Fset_process_plist, Sset_process_plist,
        2, 2, 0,
-       doc: /* Replace the plist of PROCESS with PLIST.  Returns PLIST.  */)
-  (register Lisp_Object process, Lisp_Object plist)
+       doc: /* Replace the plist of PROCESS with PLIST.  Return PLIST.  */)
+  (Lisp_Object process, Lisp_Object plist)
 {
   CHECK_PROCESS (process);
   CHECK_LIST (plist);
@@ -1302,7 +1312,7 @@ A 4 or 5 element vector represents an IPv4 address (with port number).
 An 8 or 9 element vector represents an IPv6 address (with port number).
 If optional second argument OMIT-PORT is non-nil, don't include a port
 number in the string, even when present in ADDRESS.
-Returns nil if format of ADDRESS is invalid.  */)
+Return nil if format of ADDRESS is invalid.  */)
   (Lisp_Object address, Lisp_Object omit_port)
 {
   if (NILP (address))
@@ -2250,12 +2260,12 @@ usage:  (make-pipe-process &rest ARGS)  */)
    The address family of sa is not included in the result.  */
 
 Lisp_Object
-conv_sockaddr_to_lisp (struct sockaddr *sa, int len)
+conv_sockaddr_to_lisp (struct sockaddr *sa, ptrdiff_t len)
 {
   Lisp_Object address;
-  int i;
+  ptrdiff_t i;
   unsigned char *cp;
-  register struct Lisp_Vector *p;
+  struct Lisp_Vector *p;
 
   /* Workaround for a bug in getsockname on BSD: Names bound to
      sockets in the UNIX domain are inaccessible; getsockname returns
@@ -2330,10 +2340,10 @@ conv_sockaddr_to_lisp (struct sockaddr *sa, int len)
 
 /* Get family and required size for sockaddr structure to hold ADDRESS.  */
 
-static int
+static ptrdiff_t
 get_lisp_to_sockaddr_size (Lisp_Object address, int *familyp)
 {
-  register struct Lisp_Vector *p;
+  struct Lisp_Vector *p;
 
   if (VECTORP (address))
     {
@@ -2449,7 +2459,9 @@ conv_lisp_to_sockaddr (int family, Lisp_Object address, struct sockaddr *sa, int
 #ifdef DATAGRAM_SOCKETS
 DEFUN ("process-datagram-address", Fprocess_datagram_address, Sprocess_datagram_address,
        1, 1, 0,
-       doc: /* Get the current datagram address associated with PROCESS.  */)
+       doc: /* Get the current datagram address associated with PROCESS.
+If PROCESS is a non-blocking network process that hasn't been fully
+set up yet, this function will block until socket setup has completed.  */)
   (Lisp_Object process)
 {
   int channel;
@@ -2470,11 +2482,15 @@ DEFUN ("process-datagram-address", Fprocess_datagram_address, Sprocess_datagram_
 DEFUN ("set-process-datagram-address", Fset_process_datagram_address, Sset_process_datagram_address,
        2, 2, 0,
        doc: /* Set the datagram address for PROCESS to ADDRESS.
-Returns nil upon error setting address, ADDRESS otherwise.  */)
+Return nil upon error setting address, ADDRESS otherwise.
+
+If PROCESS is a non-blocking network process that hasn't been fully
+set up yet, this function will block until socket setup has completed.  */)
   (Lisp_Object process, Lisp_Object address)
 {
   int channel;
-  int family, len;
+  int family;
+  ptrdiff_t len;
 
   CHECK_PROCESS (process);
 
@@ -2536,7 +2552,7 @@ static const struct socket_options {
 
 /* Set option OPT to value VAL on socket S.
 
-   Returns (1<<socket_options[OPT].optbit) if option is known, 0 otherwise.
+   Return (1<<socket_options[OPT].optbit) if option is known, 0 otherwise.
    Signals an error if setting a known option fails.
 */
 
@@ -2638,7 +2654,10 @@ DEFUN ("set-network-process-option",
        doc: /* For network process PROCESS set option OPTION to value VALUE.
 See `make-network-process' for a list of options and values.
 If optional fourth arg NO-ERROR is non-nil, don't signal an error if
-OPTION is not a supported option, return nil instead; otherwise return t.  */)
+OPTION is not a supported option, return nil instead; otherwise return t.
+
+If PROCESS is a non-blocking network process that hasn't been fully
+set up yet, this function will block until socket setup has completed. */)
   (Lisp_Object process, Lisp_Object option, Lisp_Object value, Lisp_Object no_error)
 {
   int s;
@@ -2945,19 +2964,16 @@ usage:  (make-serial-process &rest ARGS)  */)
   return proc;
 }
 
-void set_network_socket_coding_system (Lisp_Object proc)
+static void
+set_network_socket_coding_system (Lisp_Object proc, Lisp_Object host,
+                                 Lisp_Object service, Lisp_Object name)
 {
   Lisp_Object tem;
   struct Lisp_Process *p = XPROCESS (proc);
   Lisp_Object contact = p->childp;
-  Lisp_Object service, host, name;
   Lisp_Object coding_systems = Qt;
   Lisp_Object val;
 
-  service = Fplist_get (contact, QCservice);
-  host = Fplist_get (contact, QChost);
-  name = Fplist_get (contact, QCname);
-
   tem = Fplist_member (contact, QCcoding);
   if (!NILP (tem) && (!CONSP (tem) || !CONSP (XCDR (tem))))
     tem = Qnil;  /* No error message (too late!).  */
@@ -2973,9 +2989,10 @@ void set_network_socket_coding_system (Lisp_Object proc)
     }
   else if (!NILP (Vcoding_system_for_read))
     val = Vcoding_system_for_read;
-  else if ((!NILP (p->buffer) &&
-           NILP (BVAR (XBUFFER (p->buffer), enable_multibyte_characters)))
-          || (NILP (p->buffer) && NILP (BVAR (&buffer_defaults, enable_multibyte_characters))))
+  else if ((!NILP (p->buffer)
+           && NILP (BVAR (XBUFFER (p->buffer), enable_multibyte_characters)))
+          || (NILP (p->buffer)
+              && NILP (BVAR (&buffer_defaults, enable_multibyte_characters))))
     /* We dare not decode end-of-line format by setting VAL to
        Qraw_text, because the existing Emacs Lisp libraries
        assume that they receive bare code including a sequence of
@@ -3037,7 +3054,7 @@ void set_network_socket_coding_system (Lisp_Object proc)
 }
 
 #ifdef HAVE_GNUTLS
-void
+static void
 finish_after_tls_connection (Lisp_Object proc)
 {
   struct Lisp_Process *p = XPROCESS (proc);
@@ -3073,7 +3090,7 @@ finish_after_tls_connection (Lisp_Object proc)
 }
 #endif
 
-void
+static void
 connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses)
 {
   ptrdiff_t count = SPECPDL_INDEX ();
@@ -3084,7 +3101,7 @@ connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses)
   int family;
   struct sockaddr *sa = NULL;
   int ret;
-  int addrlen;
+  ptrdiff_t addrlen;
   struct Lisp_Process *p = XPROCESS (proc);
   Lisp_Object contact = p->childp;
   int optbits = 0;
@@ -3182,8 +3199,8 @@ connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses)
                  Lisp_Object service;
                  service = make_number (ntohs (sa1.sin_port));
                  contact = Fplist_put (contact, QCservice, service);
-                 // Save the port number so that we can stash it in
-                 // the process object later.
+                 /* Save the port number so that we can stash it in
+                    the process object later.  */
                  ((struct sockaddr_in *)sa)->sin_port = sa1.sin_port;
                }
            }
@@ -3282,8 +3299,8 @@ connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses)
              memset (datagram_address[s].sa, 0, addrlen);
              if (remote = Fplist_get (contact, QCremote), !NILP (remote))
                {
-                 int rfamily, rlen;
-                 rlen = get_lisp_to_sockaddr_size (remote, &rfamily);
+                 int rfamily;
+                 ptrdiff_t rlen = get_lisp_to_sockaddr_size (remote, &rfamily);
                  if (rlen != 0 && rfamily == family
                      && rlen == addrlen)
                    conv_lisp_to_sockaddr (rfamily, remote,
@@ -3414,15 +3431,14 @@ connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses)
 
 #ifndef HAVE_GETADDRINFO
 static Lisp_Object
-conv_numerical_to_lisp (unsigned char *number, unsigned int length, int port)
+conv_numerical_to_lisp (unsigned char *number, int length, int port)
 {
   Lisp_Object address = Fmake_vector (make_number (length + 1), Qnil);
-  register struct Lisp_Vector *p = XVECTOR (address);
-  int i;
+  struct Lisp_Vector *p = XVECTOR (address);
 
   p->contents[length] = make_number (port);
-  for (i = 0; i < length; i++)
-    p->contents[i] = make_number (*(number + i));
+  for (int i = 0; i < length; i++)
+    p->contents[i] = make_number (number[i]);
 
   return address;
 }
@@ -3598,15 +3614,15 @@ usage: (make-network-process &rest ARGS)  */)
   Lisp_Object proc;
   Lisp_Object contact;
   struct Lisp_Process *p;
-#if defined(HAVE_GETADDRINFO) || defined(HAVE_GETADDRINFO_A)
-  struct addrinfo *hints;
+#if defined HAVE_GETADDRINFO || defined HAVE_GETADDRINFO_A
   const char *portstring;
-  char portbuf[128];
+  ptrdiff_t portstringlen ATTRIBUTE_UNUSED;
+  char portbuf[INT_BUFSIZE_BOUND (EMACS_INT)];
 #endif
 #ifdef HAVE_LOCAL_SOCKETS
   struct sockaddr_un address_un;
 #endif
-  int port = 0;
+  EMACS_INT port = 0;
   Lisp_Object tem;
   Lisp_Object name, buffer, host, service, address;
   Lisp_Object filter, sentinel;
@@ -3615,7 +3631,7 @@ usage: (make-network-process &rest ARGS)  */)
   int family = -1;
   int ai_protocol = 0;
 #ifdef HAVE_GETADDRINFO_A
-  struct gaicb **dns_requests = NULL;
+  struct gaicb *dns_request = NULL;
 #endif
   ptrdiff_t count = SPECPDL_INDEX ();
 
@@ -3665,7 +3681,7 @@ usage: (make-network-process &rest ARGS)  */)
       if (!get_lisp_to_sockaddr_size (address, &family))
        error ("Malformed :address");
 
-      ip_addresses = Fcons (address, Qnil);
+      ip_addresses = list1 (address);
       goto open_socket;
     }
 
@@ -3729,7 +3745,7 @@ usage: (make-network-process &rest ARGS)  */)
       CHECK_STRING (service);
       if (sizeof address_un.sun_path <= SBYTES (service))
        error ("Service name too long");
-      ip_addresses = Fcons (service, Qnil);
+      ip_addresses = list1 (service);
       goto open_socket;
     }
 #endif
@@ -3745,54 +3761,58 @@ usage: (make-network-process &rest ARGS)  */)
     }
 #endif
 
-#if defined (HAVE_GETADDRINFO) || defined (HAVE_GETADDRINFO_A)
+#if defined HAVE_GETADDRINFO || defined HAVE_GETADDRINFO_A
   if (!NILP (host))
     {
-
       /* SERVICE can either be a string or int.
         Convert to a C string for later use by getaddrinfo.  */
       if (EQ (service, Qt))
-       portstring = "0";
+       {
+         portstring = "0";
+         portstringlen = 1;
+       }
       else if (INTEGERP (service))
        {
-         sprintf (portbuf, "%"pI"d", XINT (service));
          portstring = portbuf;
+         portstringlen = sprintf (portbuf, "%"pI"d", XINT (service));
        }
       else
        {
          CHECK_STRING (service);
          portstring = SSDATA (service);
+         portstringlen = SBYTES (service);
        }
-
-      hints = xzalloc (sizeof (struct addrinfo));
-      hints->ai_flags = 0;
-      hints->ai_family = family;
-      hints->ai_socktype = socktype;
-      hints->ai_protocol = 0;
     }
-
 #endif
 
 #ifdef HAVE_GETADDRINFO_A
-  if (!NILP (Fplist_get (contact, QCnowait)) &&
-      !NILP (host))
+  if (!NILP (host) && !NILP (Fplist_get (contact, QCnowait)))
     {
-      int ret;
-
-      printf("Async DNS for '%s'\n", SSDATA (host));
-      dns_requests = xmalloc (sizeof (struct gaicb*));
-      dns_requests[0] = xmalloc (sizeof (struct gaicb));
-      dns_requests[0]->ar_name = strdup (SSDATA (host));
-      dns_requests[0]->ar_service = strdup (portstring);
-      dns_requests[0]->ar_request = hints;
-      dns_requests[0]->ar_result = NULL;
-
-      ret = getaddrinfo_a (GAI_NOWAIT, dns_requests, 1, NULL);
+      ptrdiff_t hostlen = SBYTES (host);
+      struct req
+      {
+       struct gaicb gaicb;
+       struct addrinfo hints;
+       char str[FLEXIBLE_ARRAY_MEMBER];
+      } *req = xmalloc (offsetof (struct req, str)
+                       + hostlen + 1 + portstringlen + 1);
+      dns_request = &req->gaicb;
+      dns_request->ar_name = req->str;
+      dns_request->ar_service = req->str + hostlen + 1;
+      dns_request->ar_request = &req->hints;
+      dns_request->ar_result = NULL;
+      memset (&req->hints, 0, sizeof req->hints);
+      req->hints.ai_family = family;
+      req->hints.ai_socktype = socktype;
+      strcpy (req->str, SSDATA (host));
+      strcpy (req->str + hostlen + 1, portstring);
+
+      int ret = getaddrinfo_a (GAI_NOWAIT, &dns_request, 1, NULL);
       if (ret)
        error ("%s/%s getaddrinfo_a error %d", SSDATA (host), portstring, ret);
 
       goto open_socket;
- }
   }
 #endif /* HAVE_GETADDRINFO_A */
 
 #ifdef HAVE_GETADDRINFO
@@ -3807,11 +3827,12 @@ usage: (make-network-process &rest ARGS)  */)
       immediate_quit = 1;
       QUIT;
 
-#ifdef HAVE_RES_INIT
-      res_init ();
-#endif
+      struct addrinfo hints;
+      memset (&hints, 0, sizeof hints);
+      hints.ai_family = family;
+      hints.ai_socktype = socktype;
 
-      ret = getaddrinfo (SSDATA (host), portstring, hints, &res);
+      ret = getaddrinfo (SSDATA (host), portstring, &hints, &res);
       if (ret)
 #ifdef HAVE_GAI_STRERROR
        error ("%s/%s %s", SSDATA (host), portstring, gai_strerror (ret));
@@ -3831,7 +3852,6 @@ usage: (make-network-process &rest ARGS)  */)
       ip_addresses = Fnreverse (ip_addresses);
 
       freeaddrinfo (res);
-      xfree (hints);
 
       goto open_socket;
     }
@@ -3843,42 +3863,56 @@ usage: (make-network-process &rest ARGS)  */)
   if (EQ (service, Qt))
     port = 0;
   else if (INTEGERP (service))
-    port = (unsigned short) XINT (service);
+    port = XINT (service);
   else
     {
-      struct servent *svc_info;
       CHECK_STRING (service);
-      svc_info = getservbyname (SSDATA (service),
-                               (socktype == SOCK_DGRAM ? "udp" : "tcp"));
-      if (svc_info == 0)
-       error ("Unknown service: %s", SDATA (service));
-      port = ntohs (svc_info->s_port);
+
+      port = -1;
+      if (SBYTES (service) != 0)
+       {
+         /* Allow the service to be a string containing the port number,
+            because that's allowed if you have getaddrbyname.  */
+         char *service_end;
+         long int lport = strtol (SSDATA (service), &service_end, 10);
+         if (service_end == SSDATA (service) + SBYTES (service))
+           port = lport;
+         else
+           {
+             struct servent *svc_info
+               = getservbyname (SSDATA (service),
+                                socktype == SOCK_DGRAM ? "udp" : "tcp");
+             if (svc_info)
+               port = ntohs (svc_info->s_port);
+           }
+       }
+    }
+
+  if (! (0 <= port && port < 1 << 16))
+    {
+      AUTO_STRING (unknown_service, "Unknown service: %s");
+      xsignal1 (Qerror, CALLN (Fformat, unknown_service, service));
     }
 
 #ifndef HAVE_GETADDRINFO
   if (!NILP (host))
     {
       struct hostent *host_info_ptr;
+      unsigned char *addr;
+      int addrlen;
 
       /* gethostbyname may fail with TRY_AGAIN, but we don't honor that,
         as it may `hang' Emacs for a very long time.  */
       immediate_quit = 1;
       QUIT;
 
-#ifdef HAVE_RES_INIT
-      res_init ();
-#endif
-
       host_info_ptr = gethostbyname ((const char *) SDATA (host));
       immediate_quit = 0;
 
       if (host_info_ptr)
        {
-         ip_addresses = Fcons (conv_numerical_to_lisp
-                               ((unsigned char *) host_info_ptr->h_addr,
-                                host_info_ptr->h_length,
-                                port),
-                               Qnil);
+         addr = (unsigned char *) host_info_ptr->h_addr;
+         addrlen = host_info_ptr->h_length;
        }
       else
        /* Attempt to interpret host as numeric inet address.  This
@@ -3889,11 +3923,11 @@ usage: (make-network-process &rest ARGS)  */)
          if (numeric_addr == -1)
            error ("Unknown host \"%s\"", SDATA (host));
 
-         ip_addresses = Fcons (conv_numerical_to_lisp
-                               ((unsigned char *) &numeric_addr, 4, port),
-                               Qnil);
+         addr = (unsigned char *) &numeric_addr;
+         addrlen = 4;
        }
 
+      ip_addresses = list1 (conv_numerical_to_lisp (addr, addrlen, port));
     }
 #endif /* not HAVE_GETADDRINFO */
 
@@ -3923,7 +3957,7 @@ usage: (make-network-process &rest ARGS)  */)
   p->socktype = socktype;
   p->ai_protocol = ai_protocol;
 #ifdef HAVE_GETADDRINFO_A
-  p->dns_requests = NULL;
+  p->dns_request = NULL;
 #endif
 #ifdef HAVE_GNUTLS
   tem = Fplist_get (contact, QCtls_parameters);
@@ -3931,7 +3965,7 @@ usage: (make-network-process &rest ARGS)  */)
   p->gnutls_boot_parameters = tem;
 #endif
 
-  set_network_socket_coding_system (proc);
+  set_network_socket_coding_system (proc, service, host, name);
 
   unbind_to (count, Qnil);
 
@@ -3962,7 +3996,7 @@ usage: (make-network-process &rest ARGS)  */)
      here will be nil, so we postpone connecting to the server. */
   if (!p->is_server && NILP (ip_addresses))
     {
-      p->dns_requests = dns_requests;
+      p->dns_request = dns_request;
       p->status = Qconnect;
     }
   else
@@ -4686,10 +4720,10 @@ check_for_dns (Lisp_Object proc)
   int ret = 0;
 
   /* Sanity check. */
-  if (! p->dns_requests)
+  if (! p->dns_request)
     return Qnil;
 
-  ret = gai_error (p->dns_requests[0]);
+  ret = gai_error (p->dns_request);
   if (ret == EAI_INPROGRESS)
     return Qt;
 
@@ -4698,7 +4732,7 @@ check_for_dns (Lisp_Object proc)
     {
       struct addrinfo *res;
 
-      for (res = p->dns_requests[0]->ar_result; res; res = res->ai_next)
+      for (res = p->dns_request->ar_result; res; res = res->ai_next)
        {
          ip_addresses = Fcons (conv_sockaddr_to_lisp
                                (res->ai_addr, res->ai_addrlen),
@@ -4708,13 +4742,13 @@ check_for_dns (Lisp_Object proc)
       ip_addresses = Fnreverse (ip_addresses);
     }
   /* The DNS lookup failed. */
-  else if (!EQ (p->status, Qconnect))
+  else if (EQ (p->status, Qconnect))
     {
       deactivate_process (proc);
       pset_status (p, (list2
                       (Qfailed,
                        concat3 (build_string ("Name lookup of "),
-                                build_string (p->dns_requests[0]->ar_name),
+                                build_string (p->dns_request->ar_name),
                                 build_string (" failed")))));
     }
 
@@ -4730,12 +4764,12 @@ check_for_dns (Lisp_Object proc)
 #endif /* HAVE_GETADDRINFO_A */
 
 static void
-wait_for_socket_fds (Lisp_Object process, char *name)
+wait_for_socket_fds (Lisp_Object process, char const *name)
 {
-  while (XPROCESS (process)->infd < 0 &&
-        EQ (XPROCESS (process)->status, Qconnect))
+  while (XPROCESS (process)->infd < 0
+        && EQ (XPROCESS (process)->status, Qconnect))
     {
-      printf("Waiting for socket from %s...\n", name);
+      add_to_log ("Waiting for socket from %s...", build_string (name));
       wait_reading_process_output (0, 20 * 1000 * 1000, 0, 0, Qnil, NULL, 0);
     }
 }
@@ -4745,7 +4779,7 @@ wait_while_connecting (Lisp_Object process)
 {
   while (EQ (XPROCESS (process)->status, Qconnect))
     {
-      printf("Waiting for connection...\n");
+      add_to_log ("Waiting for connection...");
       wait_reading_process_output (0, 20 * 1000 * 1000, 0, 0, Qnil, NULL, 0);
     }
 }
@@ -4754,10 +4788,10 @@ static void
 wait_for_tls_negotiation (Lisp_Object process)
 {
 #ifdef HAVE_GNUTLS
-  while (XPROCESS (process)->gnutls_p &&
-        XPROCESS (process)->gnutls_initstage != GNUTLS_STAGE_READY)
+  while (XPROCESS (process)->gnutls_p
+        && XPROCESS (process)->gnutls_initstage != GNUTLS_STAGE_READY)
     {
-      printf("Waiting for TLS...\n");
+      add_to_log ("Waiting for TLS...");
       wait_reading_process_output (0, 20 * 1000 * 1000, 0, 0, Qnil, NULL, 0);
     }
 #endif
@@ -4841,6 +4875,9 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
   struct timespec got_output_end_time = invalid_timespec ();
   enum { MINIMUM = -1, TIMEOUT, INFINITY } wait;
   int got_some_output = -1;
+#if defined HAVE_GETADDRINFO_A || defined HAVE_GNUTLS
+  bool retry_for_async;
+#endif
   ptrdiff_t count = SPECPDL_INDEX ();
 
   /* Close to the current time if known, an invalid timespec otherwise.  */
@@ -4888,12 +4925,12 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
       if (! NILP (wait_for_cell) && ! NILP (XCAR (wait_for_cell)))
        break;
 
-#if defined (HAVE_GETADDRINFO_A) || defined (HAVE_GNUTLS)
+#if defined HAVE_GETADDRINFO_A || defined HAVE_GNUTLS
       {
-       Lisp_Object ip_addresses;
        Lisp_Object process_list_head, aproc;
        struct Lisp_Process *p;
 
+       retry_for_async = false;
        FOR_EACH_PROCESS(process_list_head, aproc)
          {
            p = XPROCESS (aproc);
@@ -4902,30 +4939,38 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
              {
 #ifdef HAVE_GETADDRINFO_A
                /* Check for pending DNS requests. */
-               if (p->dns_requests)
+               if (p->dns_request)
                  {
-                   ip_addresses = check_for_dns (aproc);
-                   if (!NILP (ip_addresses) &&
-                       !EQ (ip_addresses, Qt))
+                   Lisp_Object ip_addresses = check_for_dns (aproc);
+                   if (!NILP (ip_addresses) && !EQ (ip_addresses, Qt))
                      connect_network_socket (aproc, ip_addresses);
+                   else
+                     retry_for_async = true;
                  }
 #endif
 #ifdef HAVE_GNUTLS
                /* Continue TLS negotiation. */
-               if (p->gnutls_initstage == GNUTLS_STAGE_HANDSHAKE_TRIED &&
-                   p->is_non_blocking_client)
+               if (p->gnutls_initstage == GNUTLS_STAGE_HANDSHAKE_TRIED
+                   && p->is_non_blocking_client)
                  {
                    gnutls_try_handshake (p);
                    p->gnutls_handshakes_tried++;
 
                    if (p->gnutls_initstage == GNUTLS_STAGE_READY)
-                     finish_after_tls_connection (aproc);
-                   else if (p->gnutls_handshakes_tried >
-                            GNUTLS_EMACS_HANDSHAKES_LIMIT)
                      {
-                       deactivate_process (aproc);
-                       pset_status (p, list2 (Qfailed,
-                                              build_string ("TLS negotiation failed")));
+                       gnutls_verify_boot (aproc, Qnil);
+                       finish_after_tls_connection (aproc);
+                     }
+                   else
+                     {
+                       retry_for_async = true;
+                       if (p->gnutls_handshakes_tried
+                           > GNUTLS_EMACS_HANDSHAKES_LIMIT)
+                         {
+                           deactivate_process (aproc);
+                           pset_status (p, list2 (Qfailed,
+                                                  build_string ("TLS negotiation failed")));
+                         }
                      }
                  }
 #endif
@@ -5192,6 +5237,15 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
          if (timeout.tv_sec > 0 || timeout.tv_nsec > 0)
            now = invalid_timespec ();
 
+#if defined HAVE_GETADDRINFO_A || defined HAVE_GNUTLS
+         if (retry_for_async
+             && (timeout.tv_sec > 0 || timeout.tv_nsec > ASYNC_RETRY_NSEC))
+           {
+             timeout.tv_sec = 0;
+             timeout.tv_nsec = ASYNC_RETRY_NSEC;
+           }
+#endif
+
 #if defined (HAVE_NS)
           nfds = ns_select
 #elif defined (HAVE_GLIB)
@@ -5557,8 +5611,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                  /* If we have an incompletely set up TLS connection,
                     then defer the sentinel signalling until
                     later. */
-                 if (NILP (p->gnutls_boot_parameters) &&
-                     !p->gnutls_p)
+                 if (NILP (p->gnutls_boot_parameters)
+                     && !p->gnutls_p)
 #endif
                    {
                      pset_status (p, Qrun);
@@ -6024,10 +6078,11 @@ send_process (Lisp_Object proc, const char *buf, ptrdiff_t len,
   ssize_t rv;
   struct coding_system *coding;
 
-  if (NETCONN_P (proc)) {
-    wait_while_connecting (proc);
-    wait_for_tls_negotiation (proc);
-  }
+  if (NETCONN_P (proc))
+    {
+      wait_while_connecting (proc);
+      wait_for_tls_negotiation (proc);
+    }
 
   if (p->raw_status_new)
     update_status (p);
@@ -6246,7 +6301,10 @@ nil, indicating the current buffer's process.
 Called from program, takes three arguments, PROCESS, START and END.
 If the region is more than 500 characters long,
 it is sent in several bunches.  This may happen even for shorter regions.
-Output from processes can arrive in between bunches.  */)
+Output from processes can arrive in between bunches.
+
+If PROCESS is a non-blocking network process that hasn't been fully
+set up yet, this function will block until socket setup has completed.  */)
   (Lisp_Object process, Lisp_Object start, Lisp_Object end)
 {
   Lisp_Object proc = get_process (process);
@@ -6276,13 +6334,14 @@ PROCESS may be a process, a buffer, the name of a process or buffer, or
 nil, indicating the current buffer's process.
 If STRING is more than 500 characters long,
 it is sent in several bunches.  This may happen even for shorter strings.
-Output from processes can arrive in between bunches.  */)
+Output from processes can arrive in between bunches.
+
+If PROCESS is a non-blocking network process that hasn't been fully
+set up yet, this function will block until socket setup has completed.  */)
   (Lisp_Object process, Lisp_Object string)
 {
-  Lisp_Object proc;
   CHECK_STRING (string);
-  proc = get_process (process);
-
+  Lisp_Object proc = get_process (process);
   send_process (proc, SSDATA (string),
                SBYTES (string), string);
   return Qnil;
@@ -6324,12 +6383,8 @@ process group.  */)
 {
   /* Initialize in case ioctl doesn't exist or gives an error,
      in a way that will cause returning t.  */
-  pid_t gid;
-  Lisp_Object proc;
-  struct Lisp_Process *p;
-
-  proc = get_process (process);
-  p = XPROCESS (proc);
+  Lisp_Object proc = get_process (process);
+  struct Lisp_Process *p = XPROCESS (proc);
 
   if (!EQ (p->type, Qreal))
     error ("Process %s is not a subprocess",
@@ -6338,7 +6393,7 @@ process group.  */)
     error ("Process %s is not active",
           SDATA (p->name));
 
-  gid = emacs_get_tty_pgrp (p);
+  pid_t gid = emacs_get_tty_pgrp (p);
 
   if (gid == p->pid)
     return Qnil;
@@ -7150,27 +7205,24 @@ DEFUN ("set-process-coding-system", Fset_process_coding_system,
        Sset_process_coding_system, 1, 3, 0,
        doc: /* Set coding systems of PROCESS to DECODING and ENCODING.
 DECODING will be used to decode subprocess output and ENCODING to
-encode subprocess input.  */)
-  (register Lisp_Object process, Lisp_Object decoding, Lisp_Object encoding)
+encode subprocess input. */)
+  (Lisp_Object process, Lisp_Object decoding, Lisp_Object encoding)
 {
-  register struct Lisp_Process *p;
-
   CHECK_PROCESS (process);
 
-  if (NETCONN_P (process))
-    wait_for_socket_fds (process, "set-process-coding-system");
-
-  p = XPROCESS (process);
+  struct Lisp_Process *p = XPROCESS (process);
 
-  if (p->infd < 0)
-    error ("Input file descriptor of %s closed", SDATA (p->name));
-  if (p->outfd < 0)
-    error ("Output file descriptor of %s closed", SDATA (p->name));
   Fcheck_coding_system (decoding);
   Fcheck_coding_system (encoding);
   encoding = coding_inherit_eol_type (encoding, Qnil);
   pset_decode_coding_system (p, decoding);
   pset_encode_coding_system (p, encoding);
+
+  /* If the sockets haven't been set up yet, the final setup part of
+     this will be called asynchronously. */
+  if (p->infd < 0 || p->outfd < 0)
+    return Qnil;
+
   setup_process_coding_systems (process);
 
   return Qnil;
@@ -7195,17 +7247,18 @@ all character code conversion except for end-of-line conversion is
 suppressed.  */)
   (Lisp_Object process, Lisp_Object flag)
 {
-  register struct Lisp_Process *p;
-
   CHECK_PROCESS (process);
 
-  if (NETCONN_P (process))
-    wait_for_socket_fds (process, "set-process-filter-multibyte");
-
-  p = XPROCESS (process);
+  struct Lisp_Process *p = XPROCESS (process);
   if (NILP (flag))
     pset_decode_coding_system
       (p, raw_text_coding_system (p->decode_coding_system));
+
+  /* If the sockets haven't been set up yet, the final setup part of
+     this will be called asynchronously. */
+  if (p->infd < 0 || p->outfd < 0)
+    return Qnil;
+
   setup_process_coding_systems (process);
 
   return Qnil;
@@ -7216,14 +7269,11 @@ DEFUN ("process-filter-multibyte-p", Fprocess_filter_multibyte_p,
        doc: /* Return t if a multibyte string is given to PROCESS's filter.*/)
   (Lisp_Object process)
 {
-  register struct Lisp_Process *p;
-  struct coding_system *coding;
-
   CHECK_PROCESS (process);
-  p = XPROCESS (process);
+  struct Lisp_Process *p = XPROCESS (process);
   if (p->infd < 0)
     return Qnil;
-  coding = proc_decode_coding_system[p->infd];
+  struct coding_system *coding = proc_decode_coding_system[p->infd];
   return (CODING_FOR_UNIBYTE (coding) ? Qnil : Qt);
 }