]> code.delx.au - gnu-emacs/blobdiff - src/process.c
Merge from origin/emacs-25
[gnu-emacs] / src / process.c
index 5172518ac6bec3450d28ba6fe6d64c63fbabaa0f..9f2d379c330f8395b5628d28e8ee9934f32a9497 100644 (file)
@@ -7,8 +7,8 @@ This file is part of GNU Emacs.
 
 GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -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 *);
@@ -193,16 +193,6 @@ static EMACS_INT process_tick;
 /* Number of events for which the user or sentinel has been notified.  */
 static EMACS_INT update_tick;
 
-/* Define NON_BLOCKING_CONNECT if we can support non-blocking connects.
-   The code can be simplified by assuming NON_BLOCKING_CONNECT once
-   Emacs starts assuming POSIX 1003.1-2001 or later.  */
-
-#if (defined HAVE_SELECT                               \
-     && (defined GNU_LINUX || defined HAVE_GETPEERNAME)        \
-     && (defined EWOULDBLOCK || defined EINPROGRESS))
-# define NON_BLOCKING_CONNECT
-#endif
-
 /* Define DATAGRAM_SOCKETS if datagrams can be used safely on
    this system.  We need to read full packets, so we need a
    "non-destructive" select.  So we require either native select,
@@ -262,7 +252,6 @@ static fd_set non_process_wait_mask;
 
 static fd_set write_mask;
 
-#ifdef NON_BLOCKING_CONNECT
 /* Mask of bits indicating the descriptors that we wait for connect to
    complete on.  Once they complete, they are removed from this mask
    and added to the input_wait_mask and non_keyboard_wait_mask.  */
@@ -271,7 +260,6 @@ static fd_set connect_wait_mask;
 
 /* Number of bits set in connect_wait_mask.  */
 static int num_pending_connects;
-#endif /* NON_BLOCKING_CONNECT */
 
 /* The largest descriptor currently in use for a process object; -1 if none.  */
 static int max_process_desc;
@@ -279,9 +267,15 @@ static int max_process_desc;
 /* The largest descriptor currently in use for input; -1 if none.  */
 static int max_input_desc;
 
+/* Set the external socket descriptor for Emacs to use when
+   `make-network-process' is called with a non-nil
+   `:use-external-socket' option.  The value should be either -1, or
+   the file descriptor of a socket that is already bound.  */
+static int external_sock_fd;
+
 /* 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 +296,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)                                           \
@@ -687,12 +681,7 @@ allocate_process (void)
 static Lisp_Object
 make_process (Lisp_Object name)
 {
-  register Lisp_Object val, tem, name1;
-  register struct Lisp_Process *p;
-  char suffix[sizeof "<>" + INT_STRLEN_BOUND (printmax_t)];
-  printmax_t i;
-
-  p = allocate_process ();
+  struct Lisp_Process *p = allocate_process ();
   /* Initialize Lisp data.  Note that allocate_process initializes all
      Lisp data to nil, so do it only for slots which should not be nil.  */
   pset_status (p, Qrun);
@@ -702,7 +691,7 @@ make_process (Lisp_Object name)
      non-Lisp data, so do it only for slots which should not be zero.  */
   p->infd = -1;
   p->outfd = -1;
-  for (i = 0; i < PROCESS_OPEN_FDS; i++)
+  for (int i = 0; i < PROCESS_OPEN_FDS; i++)
     p->open_fd[i] = -1;
 
 #ifdef HAVE_GNUTLS
@@ -712,17 +701,22 @@ make_process (Lisp_Object name)
 
   /* If name is already in use, modify it until it is unused.  */
 
-  name1 = name;
-  for (i = 1; ; i++)
+  Lisp_Object name1 = name;
+  for (printmax_t i = 1; ; i++)
     {
-      tem = Fget_process (name1);
-      if (NILP (tem)) break;
-      name1 = concat2 (name, make_formatted_string (suffix, "<%"pMd">", i));
+      Lisp_Object tem = Fget_process (name1);
+      if (NILP (tem))
+       break;
+      char const suffix_fmt[] = "<%"pMd">";
+      char suffix[sizeof suffix_fmt + INT_STRLEN_BOUND (printmax_t)];
+      AUTO_STRING_WITH_LEN (lsuffix, suffix, sprintf (suffix, suffix_fmt, i));
+      name1 = concat2 (name, lsuffix);
     }
   name = name1;
   pset_name (p, name);
   pset_sentinel (p, Qinternal_default_process_sentinel);
   pset_filter (p, Qinternal_default_process_filter);
+  Lisp_Object val;
   XSETPROCESS (val, p);
   Vprocess_alist = Fcons (Fcons (name, val), Vprocess_alist);
   return val;
@@ -745,14 +739,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 +837,21 @@ 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);
+      /* Cancel the request.  Unless shutting down, wait until
+        completion.  Free the request if completely canceled. */
+
+      bool canceled = gai_cancel (p->dns_request) != EAI_NOTCANCELED;
+      if (!canceled && !inhibit_sentinels)
+       {
+         struct gaicb const *req = p->dns_request;
+         while (gai_suspend (&req, 1, NULL) != 0)
+           continue;
+         canceled = true;
+       }
+      if (canceled)
+       free_dns_request (process);
     }
 #endif
 
@@ -975,7 +976,7 @@ DEFUN ("process-command", Fprocess_command, Sprocess_command, 1, 1, 0,
 This is a list of strings, the first string being the program executed
 and the rest of the strings being the arguments given to it.
 For a network or serial process, this is nil (process is running) or t
-(process is stopped).  */)
+\(process is stopped).  */)
   (register Lisp_Object process)
 {
   CHECK_PROCESS (process);
@@ -1063,13 +1064,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,
@@ -1217,7 +1215,7 @@ returned.  See `make-network-process' or `make-serial-process' for a
 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.  */)
-  (register Lisp_Object process, Lisp_Object key)
+  (Lisp_Object process, Lisp_Object key)
 {
   Lisp_Object contact;
 
@@ -1263,8 +1261,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);
@@ -1304,7 +1302,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))
@@ -2252,12 +2250,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
@@ -2332,10 +2330,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))
     {
@@ -2474,14 +2472,15 @@ set up yet, this function will block until socket setup has completed.  */)
 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);
 
@@ -2543,7 +2542,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.
 */
 
@@ -2721,7 +2720,7 @@ is not given or nil, 1 stopbit is used.
 :flowcontrol FLOWCONTROL -- FLOWCONTROL determines the type of
 flowcontrol to be used, which is either nil (don't use flowcontrol),
 the symbol `hw' (use RTS/CTS hardware flowcontrol), or the symbol `sw'
-(use XON/XOFF software flowcontrol).  If FLOWCONTROL is not given, no
+\(use XON/XOFF software flowcontrol).  If FLOWCONTROL is not given, no
 flowcontrol is used.
 
 `serial-process-configure' is called by `make-serial-process' for the
@@ -2729,12 +2728,12 @@ initial configuration of the serial port.
 
 Examples:
 
-(serial-process-configure :process "/dev/ttyS0" :speed 1200)
+\(serial-process-configure :process "/dev/ttyS0" :speed 1200)
 
-(serial-process-configure
+\(serial-process-configure
     :buffer "COM1" :stopbits 1 :parity \\='odd :flowcontrol \\='hw)
 
-(serial-process-configure :port "\\\\.\\COM13" :bytesize 7)
+\(serial-process-configure :port "\\\\.\\COM13" :bytesize 7)
 
 usage: (serial-process-configure &rest ARGS)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
@@ -2828,13 +2827,13 @@ is available via the function `process-contact'.
 
 Examples:
 
-(make-serial-process :port "/dev/ttyS0" :speed 9600)
+\(make-serial-process :port "/dev/ttyS0" :speed 9600)
 
-(make-serial-process :port "COM1" :speed 115200 :stopbits 2)
+\(make-serial-process :port "COM1" :speed 115200 :stopbits 2)
 
-(make-serial-process :port "\\\\.\\COM13" :speed 1200 :bytesize 7 :parity \\='odd)
+\(make-serial-process :port "\\\\.\\COM13" :speed 1200 :bytesize 7 :parity \\='odd)
 
-(make-serial-process :port "/dev/tty.BlueConsole-SPP-1" :speed nil)
+\(make-serial-process :port "/dev/tty.BlueConsole-SPP-1" :speed nil)
 
 usage:  (make-serial-process &rest ARGS)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
@@ -2955,10 +2954,9 @@ usage:  (make-serial-process &rest ARGS)  */)
   return proc;
 }
 
-void set_network_socket_coding_system (Lisp_Object proc,
-                                      Lisp_Object host,
-                                      Lisp_Object service,
-                                      Lisp_Object name)
+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);
@@ -2981,9 +2979,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
@@ -3045,7 +3044,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);
@@ -3081,8 +3080,9 @@ finish_after_tls_connection (Lisp_Object proc)
 }
 #endif
 
-void
-connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses)
+static void
+connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses,
+                        Lisp_Object use_external_socket_p)
 {
   ptrdiff_t count = SPECPDL_INDEX ();
   ptrdiff_t count1;
@@ -3092,10 +3092,19 @@ 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;
+  int socket_to_use = -1;
+
+  if (!NILP (use_external_socket_p))
+    {
+      socket_to_use = external_sock_fd;
+
+      /* Ensure we don't consume the external socket twice.  */
+      external_sock_fd = -1;
+    }
 
   /* Do this in case we never enter the while-loop below.  */
   count1 = SPECPDL_INDEX ();
@@ -3116,11 +3125,15 @@ connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses)
       sa = xmalloc (addrlen);
       conv_lisp_to_sockaddr (family, ip_address, sa, addrlen);
 
-      s = socket (family, p->socktype | SOCK_CLOEXEC, p->ai_protocol);
+      s = socket_to_use;
       if (s < 0)
        {
-         xerrno = errno;
-         continue;
+         s = socket (family, p->socktype | SOCK_CLOEXEC, p->ai_protocol);
+         if (s < 0)
+           {
+             xerrno = errno;
+             continue;
+           }
        }
 
 #ifdef DATAGRAM_SOCKETS
@@ -3128,7 +3141,6 @@ connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses)
        break;
 #endif /* DATAGRAM_SOCKETS */
 
-#ifdef NON_BLOCKING_CONNECT
       if (p->is_non_blocking_client)
        {
          ret = fcntl (s, F_SETFL, O_NONBLOCK);
@@ -3140,7 +3152,6 @@ connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses)
              continue;
            }
        }
-#endif
 
       /* Make us close S if quit.  */
       record_unwind_protect_int (close_file_unwind, s);
@@ -3177,7 +3188,8 @@ connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses)
                  report_file_error ("Cannot set reuse option on server socket", Qnil);
              }
 
-         if (bind (s, sa, addrlen))
+          /* If passed a socket descriptor, it should be already bound. */
+         if (socket_to_use < 0 && bind (s, sa, addrlen) != 0)
            report_file_error ("Cannot bind server socket", Qnil);
 
 #ifdef HAVE_GETSOCKNAME
@@ -3190,8 +3202,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;
                }
            }
@@ -3216,17 +3228,8 @@ connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses)
          break;
        }
 
-#ifdef NON_BLOCKING_CONNECT
-#ifdef EINPROGRESS
       if (p->is_non_blocking_client && xerrno == EINPROGRESS)
        break;
-#else
-#ifdef EWOULDBLOCK
-      if (p->is_non_blocking_client && xerrno == EWOULDBLOCK)
-       break;
-#endif
-#endif
-#endif
 
 #ifndef WINDOWSNT
       if (xerrno == EINTR)
@@ -3290,8 +3293,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,
@@ -3361,7 +3364,6 @@ connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses)
                     BUF_ZV (XBUFFER (p->buffer)),
                     BUF_ZV_BYTE (XBUFFER (p->buffer)));
 
-#ifdef NON_BLOCKING_CONNECT
   if (p->is_non_blocking_client)
     {
       /* We may get here if connect did succeed immediately.  However,
@@ -3376,7 +3378,6 @@ connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses)
        }
     }
   else
-#endif
     /* A server may have a client filter setting of Qt, but it must
        still listen for incoming connects unless it is stopped.  */
     if ((!EQ (p->filter, Qt) && !EQ (p->command, Qt))
@@ -3420,22 +3421,6 @@ 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)
-{
-  Lisp_Object address = Fmake_vector (make_number (length + 1), Qnil);
-  register struct Lisp_Vector *p = XVECTOR (address);
-  int i;
-
-  p->contents[length] = make_number (port);
-  for (i = 0; i < length; i++)
-    p->contents[i] = make_number (*(number + i));
-
-  return address;
-}
-#endif
-
 /* Create a network stream/datagram client/server process.  Treated
    exactly like a normal process when reading and writing.  Primary
    differences are in status display and process deletion.  A network
@@ -3471,9 +3456,8 @@ host, and only clients connecting to that address will be accepted.
 
 :service SERVICE -- SERVICE is name of the service desired, or an
 integer specifying a port number to connect to.  If SERVICE is t,
-a random port number is selected for the server.  (If Emacs was
-compiled with getaddrinfo, a port number can also be specified as a
-string, e.g. "80", as well as an integer.  This is not portable.)
+a random port number is selected for the server.  A port number can
+be specified as an integer string, e.g., "80", as well as an integer.
 
 :type TYPE -- TYPE is the type of connection.  The default (nil) is a
 stream type connection, `datagram' creates a datagram type connection,
@@ -3571,6 +3555,11 @@ The following network options can be specified for this connection:
                       (this is allowed by default for a server process).
 :bindtodevice NAME -- bind to interface NAME.  Using this may require
                       special privileges on some systems.
+:use-external-socket BOOL -- Use any pre-allocated sockets that have
+                             been passed to Emacs.  If Emacs wasn't
+                             passed a socket, this option is silently
+                             ignored.
+
 
 Consult the relevant system programmer's manual pages for more
 information on using these options.
@@ -3606,24 +3595,22 @@ 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;
   const char *portstring;
-  char portbuf[128];
-#endif
+  ptrdiff_t portstringlen ATTRIBUTE_UNUSED;
+  char portbuf[INT_BUFSIZE_BOUND (EMACS_INT)];
 #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;
+  Lisp_Object filter, sentinel, use_external_socket_p;
   Lisp_Object ip_addresses = Qnil;
   int socktype;
   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 ();
 
@@ -3657,6 +3644,7 @@ usage: (make-network-process &rest ARGS)  */)
   buffer = Fplist_get (contact, QCbuffer);
   filter = Fplist_get (contact, QCfilter);
   sentinel = Fplist_get (contact, QCsentinel);
+  use_external_socket_p = Fplist_get (contact, QCuse_external_socket);
 
   CHECK_STRING (name);
 
@@ -3673,7 +3661,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;
     }
 
@@ -3681,7 +3669,7 @@ usage: (make-network-process &rest ARGS)  */)
   tem = Fplist_get (contact, QCfamily);
   if (NILP (tem))
     {
-#if defined (HAVE_GETADDRINFO) && defined (AF_INET6)
+#ifdef AF_INET6
       family = AF_UNSPEC;
 #else
       family = AF_INET;
@@ -3737,7 +3725,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
@@ -3753,56 +3741,58 @@ usage: (make-network-process &rest ARGS)  */)
     }
 #endif
 
-#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;
-
-      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
   /* If we have a host, use getaddrinfo to resolve both host and service.
      Otherwise, use getservbyname to lookup the service.  */
 
@@ -3814,14 +3804,22 @@ 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));
+       {
+         synchronize_system_messages_locale ();
+         char const *str = gai_strerror (ret);
+         if (! NILP (Vlocale_coding_system))
+           str = SSDATA (code_convert_string_norecord
+                         (build_string (str), Vlocale_coding_system, 0));
+         error ("%s/%s %s", SSDATA (host), portstring, str);
+       }
 #else
        error ("%s/%s getaddrinfo error %d", SSDATA (host), portstring, ret);
 #endif
@@ -3838,71 +3836,45 @@ usage: (make-network-process &rest ARGS)  */)
       ip_addresses = Fnreverse (ip_addresses);
 
       freeaddrinfo (res);
-      xfree (hints);
 
       goto open_socket;
     }
-#endif /* HAVE_GETADDRINFO */
 
-  /* We end up here if getaddrinfo is not defined, or in case no hostname
-     has been specified (e.g. for a local server process).  */
+  /* No hostname has been specified (e.g., a local server process).  */
 
   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);
-    }
 
-#ifndef HAVE_GETADDRINFO
-  if (!NILP (host))
-    {
-      struct hostent *host_info_ptr;
-
-      /* 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);
-       }
-      else
-       /* Attempt to interpret host as numeric inet address.  This
-          only works for IPv4 addresses. */
+      port = -1;
+      if (SBYTES (service) != 0)
        {
-         unsigned long numeric_addr = inet_addr (SSDATA (host));
-
-         if (numeric_addr == -1)
-           error ("Unknown host \"%s\"", SDATA (host));
-
-         ip_addresses = Fcons (conv_numerical_to_lisp
-                               ((unsigned char *) &numeric_addr, 4, port),
-                               Qnil);
+         /* 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));
     }
-#endif /* not HAVE_GETADDRINFO */
 
  open_socket:
 
@@ -3924,13 +3896,13 @@ usage: (make-network-process &rest ARGS)  */)
     pset_command (p, Qt);
   p->pid = 0;
   p->backlog = 5;
-  p->is_non_blocking_client = 0;
-  p->is_server = 0;
+  p->is_non_blocking_client = false;
+  p->is_server = false;
   p->port = port;
   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);
@@ -3948,38 +3920,28 @@ usage: (make-network-process &rest ARGS)  */)
     {
       /* Don't support network sockets when non-blocking mode is
         not available, since a blocked Emacs is not useful.  */
-      p->is_server = 1;
+      p->is_server = true;
       if (TYPE_RANGED_INTEGERP (int, tem))
        p->backlog = XINT (tem);
     }
 
   /* :nowait BOOL */
   if (!p->is_server && socktype != SOCK_DGRAM
-      && (tem = Fplist_get (contact, QCnowait), !NILP (tem)))
-    {
-#ifndef NON_BLOCKING_CONNECT
-      error ("Non-blocking connect not supported");
-#else
-      p->is_non_blocking_client = 1;
-#endif
-    }
+      && !NILP (Fplist_get (contact, QCnowait)))
+    p->is_non_blocking_client = true;
 
 #ifdef HAVE_GETADDRINFO_A
-  /* If we're doing async address resolution, the list of addresses
-     here will be nil, so we postpone connecting to the server. */
+  /* With async address resolution, the list of addresses is empty, so
+     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;
+      return proc;
     }
-  else
-    {
-      connect_network_socket (proc, ip_addresses);
-    }
-#else /* HAVE_GETADDRINFO_A */
-  connect_network_socket (proc, ip_addresses);
 #endif
 
+  connect_network_socket (proc, ip_addresses, use_external_socket_p);
   return proc;
 }
 
@@ -4316,19 +4278,6 @@ Data that is unavailable is returned as nil.  */)
 #endif
 }
 
-/* If program file NAME starts with /: for quoting a magic
-   name, remove that, preserving the multibyteness of NAME.  */
-
-Lisp_Object
-remove_slash_colon (Lisp_Object name)
-{
-  return
-    ((SBYTES (name) > 2 && SREF (name, 0) == '/' && SREF (name, 1) == ':')
-     ? make_specified_string (SSDATA (name) + 2, SCHARS (name) - 2,
-                             SBYTES (name) - 2, STRING_MULTIBYTE (name))
-     : name);
-}
-
 /* Turn off input and output for process PROC.  */
 
 static void
@@ -4372,7 +4321,6 @@ deactivate_process (Lisp_Object proc)
       chan_process[inchannel] = Qnil;
       FD_CLR (inchannel, &input_wait_mask);
       FD_CLR (inchannel, &non_keyboard_wait_mask);
-#ifdef NON_BLOCKING_CONNECT
       if (FD_ISSET (inchannel, &connect_wait_mask))
        {
          FD_CLR (inchannel, &connect_wait_mask);
@@ -4380,7 +4328,6 @@ deactivate_process (Lisp_Object proc)
          if (--num_pending_connects < 0)
            emacs_abort ();
        }
-#endif
       if (inchannel == max_process_desc)
        {
          /* We just closed the highest-numbered process input descriptor,
@@ -4690,13 +4637,12 @@ check_for_dns (Lisp_Object proc)
 {
   struct Lisp_Process *p = XPROCESS (proc);
   Lisp_Object ip_addresses = Qnil;
-  int ret = 0;
 
   /* Sanity check. */
-  if (! p->dns_requests)
+  if (! p->dns_request)
     return Qnil;
 
-  ret = gai_error (p->dns_requests[0]);
+  int ret = gai_error (p->dns_request);
   if (ret == EAI_INPROGRESS)
     return Qt;
 
@@ -4705,7 +4651,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),
@@ -4721,7 +4667,7 @@ check_for_dns (Lisp_Object 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")))));
     }
 
@@ -4737,10 +4683,10 @@ 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))
     {
       add_to_log ("Waiting for socket from %s...", build_string (name));
       wait_reading_process_output (0, 20 * 1000 * 1000, 0, 0, Qnil, NULL, 0);
@@ -4761,8 +4707,8 @@ 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)
     {
       add_to_log ("Waiting for TLS...");
       wait_reading_process_output (0, 20 * 1000 * 1000, 0, 0, Qnil, NULL, 0);
@@ -4848,6 +4794,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.  */
@@ -4895,12 +4844,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);
@@ -4909,18 +4858,19 @@ 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))
-                     connect_network_socket (aproc, ip_addresses);
+                   Lisp_Object ip_addresses = check_for_dns (aproc);
+                   if (!NILP (ip_addresses) && !EQ (ip_addresses, Qt))
+                     connect_network_socket (aproc, ip_addresses, Qnil);
+                   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++;
@@ -4930,12 +4880,16 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                        gnutls_verify_boot (aproc, Qnil);
                        finish_after_tls_connection (aproc);
                      }
-                   else if (p->gnutls_handshakes_tried >
-                            GNUTLS_EMACS_HANDSHAKES_LIMIT)
+                   else
                      {
-                       deactivate_process (aproc);
-                       pset_status (p, list2 (Qfailed,
-                                              build_string ("TLS negotiation failed")));
+                       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
@@ -5026,11 +4980,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
          timeout = make_timespec (0, 0);
          if ((pselect (max (max_process_desc, max_input_desc) + 1,
                        &Atemp,
-#ifdef NON_BLOCKING_CONNECT
                        (num_pending_connects > 0 ? &Ctemp : NULL),
-#else
-                       NULL,
-#endif
                        NULL, &timeout, NULL)
               <= 0))
            {
@@ -5202,6 +5152,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)
@@ -5513,7 +5472,6 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                                 list2 (Qexit, make_number (256)));
                }
            }
-#ifdef NON_BLOCKING_CONNECT
          if (FD_ISSET (channel, &Writeok)
              && FD_ISSET (channel, &connect_wait_mask))
            {
@@ -5565,10 +5523,10 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                {
 #ifdef HAVE_GNUTLS
                  /* If we have an incompletely set up TLS connection,
-                    then defer the sentinel signalling until
+                    then defer the sentinel signaling 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);
@@ -5586,7 +5544,6 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                    }
                }
            }
-#endif /* NON_BLOCKING_CONNECT */
        }                       /* End for each file descriptor.  */
     }                          /* End while exit conditions not met.  */
 
@@ -6034,10 +5991,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);
@@ -6295,10 +6253,8 @@ 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;
@@ -6340,12 +6296,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",
@@ -6354,7 +6306,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;
@@ -6425,7 +6377,7 @@ process_send_signal (Lisp_Object process, int signo, Lisp_Object current_group,
          break;
 
        case SIGTSTP:
-#if defined (VSWTCH) && !defined (PREFER_VSUSP)
+#ifdef VSWTCH
          sig_char = &t.c_cc[VSWTCH];
 #else
          sig_char = &t.c_cc[VSUSP];
@@ -7166,30 +7118,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.
-
-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. */)
-  (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;
@@ -7214,17 +7160,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;
@@ -7235,14 +7182,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);
 }
 
@@ -7526,6 +7470,19 @@ add_timer_wait_descriptor (int fd)
 
 #endif /* HAVE_TIMERFD */
 
+/* If program file NAME starts with /: for quoting a magic
+   name, remove that, preserving the multibyteness of NAME.  */
+
+Lisp_Object
+remove_slash_colon (Lisp_Object name)
+{
+  return
+    ((SBYTES (name) > 2 && SREF (name, 0) == '/' && SREF (name, 1) == ':')
+     ? make_specified_string (SSDATA (name) + 2, SCHARS (name) - 2,
+                             SBYTES (name) - 2, STRING_MULTIBYTE (name))
+     : name);
+}
+
 /* Add DESC to the set of keyboard input descriptors.  */
 
 void
@@ -7783,10 +7740,10 @@ catch_child_signal (void)
 /* This is not called "init_process" because that is the name of a
    Mach system call, so it would cause problems on Darwin systems.  */
 void
-init_process_emacs (void)
+init_process_emacs (int sockfd)
 {
 #ifdef subprocesses
-  register int i;
+  int i;
 
   inhibit_sentinels = 0;
 
@@ -7809,12 +7766,11 @@ init_process_emacs (void)
   FD_ZERO (&non_process_wait_mask);
   FD_ZERO (&write_mask);
   max_process_desc = max_input_desc = -1;
+  external_sock_fd = sockfd;
   memset (fd_callback_info, 0, sizeof (fd_callback_info));
 
-#ifdef NON_BLOCKING_CONNECT
   FD_ZERO (&connect_wait_mask);
   num_pending_connects = 0;
-#endif
 
   process_output_delay_count = 0;
   process_output_skip = 0;
@@ -7909,6 +7865,7 @@ syms_of_process (void)
   DEFSYM (QCserver, ":server");
   DEFSYM (QCnowait, ":nowait");
   DEFSYM (QCsentinel, ":sentinel");
+  DEFSYM (QCuse_external_socket, ":use-external-socket");
   DEFSYM (QCtls_parameters, ":tls-parameters");
   DEFSYM (Qnsm_verify_connection, "nsm-verify-connection");
   DEFSYM (QClog, ":log");
@@ -8053,13 +8010,6 @@ The variable takes effect when `start-process' is called.  */);
   defsubr (&Sset_process_filter_multibyte);
   defsubr (&Sprocess_filter_multibyte_p);
 
-#endif /* subprocesses */
-
-  defsubr (&Sget_buffer_process);
-  defsubr (&Sprocess_inherit_coding_system_flag);
-  defsubr (&Slist_system_processes);
-  defsubr (&Sprocess_attributes);
-
  {
    Lisp_Object subfeatures = Qnil;
    const struct socket_options *sopt;
@@ -8067,9 +8017,7 @@ The variable takes effect when `start-process' is called.  */);
 #define ADD_SUBFEATURE(key, val) \
   subfeatures = pure_cons (pure_cons (key, pure_cons (val, Qnil)), subfeatures)
 
-#ifdef NON_BLOCKING_CONNECT
    ADD_SUBFEATURE (QCnowait, Qt);
-#endif
 #ifdef DATAGRAM_SOCKETS
    ADD_SUBFEATURE (QCtype, Qdatagram);
 #endif
@@ -8094,4 +8042,10 @@ The variable takes effect when `start-process' is called.  */);
    Fprovide (intern_c_string ("make-network-process"), subfeatures);
  }
 
+#endif /* subprocesses */
+
+  defsubr (&Sget_buffer_process);
+  defsubr (&Sprocess_inherit_coding_system_flag);
+  defsubr (&Slist_system_processes);
+  defsubr (&Sprocess_attributes);
 }