changeset 32032:633b826a56f3

(Fopen_network_stream) [HAVE_GETADDRINFO]: Use gai_strerror. Make sure xerrno is set if connect fails. Improve error recovery.
author Gerd Moellmann <gerd@gnu.org>
date Sat, 30 Sep 2000 13:51:15 +0000
parents 5f0a1848cc60
children 2f02ea6f7303
files src/process.c
diffstat 1 files changed, 66 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/src/process.c	Sat Sep 30 12:15:19 2000 +0000
+++ b/src/process.c	Sat Sep 30 13:51:15 2000 +0000
@@ -1748,18 +1748,18 @@
       Lisp_Object name, buffer, host, service;
 {
   Lisp_Object proc;
-#ifndef HAVE_GETADDRINFO
+#ifdef HAVE_GETADDRINFO
+  struct addrinfo hints, *res, *lres;
+  int ret = 0;
+  int xerrno = 0;
+  char *portstring, portbuf[128];
+#else /* HAVE_GETADDRINFO */
   struct sockaddr_in address;
   struct servent *svc_info;
   struct hostent *host_info_ptr, host_info;
   char *(addr_list[2]);
   IN_ADDR numeric_addr;
   int port;
-#else /* HAVE_GETADDRINFO */
-  struct addrinfo hints, *res, *lres;
-  int ret = 0;
-  int xerrno = 0;
-  char *portstring, portbuf[128];
 #endif /* HAVE_GETADDRINFO */
   int s = -1, outch, inch;
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
@@ -1777,13 +1777,11 @@
   CHECK_STRING (host, 0);
 
 #ifdef HAVE_GETADDRINFO
-  /*
-   * SERVICE can either be a string or int.
-   * Convert to a C string for later use by getaddrinfo.
-   */
+  /* SERVICE can either be a string or int.
+     Convert to a C string for later use by getaddrinfo.  */
   if (INTEGERP (service))
     {
-      sprintf (portbuf, "%d", XINT (service));
+      sprintf (portbuf, "%ld", (long) XINT (service));
       portstring = portbuf;
     }
   else
@@ -1791,7 +1789,7 @@
       CHECK_STRING (service, 0);
       portstring = XSTRING (service)->data;
     }
-#else /* ! HAVE_GETADDRINFO */
+#else /* HAVE_GETADDRINFO */
   if (INTEGERP (service))
     port = htons ((unsigned short) XINT (service));
   else
@@ -1802,7 +1800,7 @@
 	error ("Unknown service \"%s\"", XSTRING (service)->data);
       port = svc_info->s_port;
     }
-#endif /* ! HAVE_GETADDRINFO */
+#endif /* HAVE_GETADDRINFO */
 
 
   /* Slow down polling to every ten seconds.
@@ -1815,32 +1813,30 @@
 
 #ifndef TERM
 #ifdef HAVE_GETADDRINFO
-  {
-    immediate_quit = 1;
-    QUIT;
-    memset (&hints, 0, sizeof (hints));
-    hints.ai_flags = 0;
-    hints.ai_family = AF_UNSPEC;
-    hints.ai_socktype = SOCK_STREAM;
-    hints.ai_protocol = 0;
-    ret = getaddrinfo (XSTRING (host)->data, portstring, &hints, &res);
-    if (ret)
-      {
-	error ("%s/%s %s", XSTRING (host)->data, portstring,
-	       strerror (ret));
-      }
-    immediate_quit = 0;
-  }
-
+  immediate_quit = 1;
+  QUIT;
+  memset (&hints, 0, sizeof (hints));
+  hints.ai_flags = 0;
+  hints.ai_family = AF_UNSPEC;
+  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_protocol = 0;
+  ret = getaddrinfo (XSTRING (host)->data, portstring, &hints, &res);
+  if (ret)
+    error ("%s/%s %s", XSTRING (host)->data, portstring, gai_strerror(ret));
+  immediate_quit = 0;
+
+  /* Do this in case we never enter the for-loop below.  */
+  count1 = specpdl_ptr - specpdl;
   s = -1;
-  count1 = specpdl_ptr - specpdl;
-  record_unwind_protect (close_file_unwind, make_number (s));
 
   for (lres = res; lres; lres = lres->ai_next)
     {
       s = socket (lres->ai_family, lres->ai_socktype, lres->ai_protocol);
-      if (s < 0) 
-	continue;
+      if (s < 0)
+	{
+	  xerrno = errno;
+	  continue;
+	}
 
       /* Kernel bugs (on Ultrix at least) cause lossage (not just EINTR)
 	 when connect is interrupted.  So let's not let it get interrupted.
@@ -1851,6 +1847,12 @@
       if (interrupt_input)
 	unrequest_sigio ();
 
+      /* Make us close S if quit.  */
+      count1 = specpdl_ptr - specpdl;
+      record_unwind_protect (close_file_unwind, make_number (s));
+
+    loop:
+
       immediate_quit = 1;
       QUIT;
 
@@ -1863,11 +1865,33 @@
 	 though.  Would non-blocking connect calls be portable?  */
       turn_on_atimers (0);
       ret = connect (s, lres->ai_addr, lres->ai_addrlen);
+      xerrno = errno;
       turn_on_atimers (1);
-      if (ret == 0)
+
+      if (ret == 0 || xerrno == EISCONN)
+	/* The unwind-protect will be discarded afterwards.
+	   Likewise for immediate_quit.  */
 	break;
+
+      immediate_quit = 0;
+
+      if (xerrno == EINTR)
+	goto loop;
+      if (xerrno == EADDRINUSE && retry < 20)
+	{
+	  /* A delay here is needed on some FreeBSD systems,
+	     and it is harmless, since this retrying takes time anyway
+	     and should be infrequent.  */
+	  Fsleep_for (make_number (1), Qnil);
+	  retry++;
+	  goto loop;
+	}
+
+      /* Discard the unwind protect closing S.  */
+      specpdl_ptr = specpdl + count1;
+      count1 = specpdl_ptr - specpdl;
+      
       emacs_close (s);
-      s = -1;
     }
 
   freeaddrinfo (res);
@@ -1880,7 +1904,8 @@
       report_file_error ("connection failed",
 			 Fcons (host, Fcons (name, Qnil)));
     }
-#else /* ! HAVE_GETADDRINFO */
+  
+#else /* not HAVE_GETADDRINFO */
 
   while (1)
     {
@@ -1901,6 +1926,7 @@
 	break;
       Fsleep_for (make_number (1), Qnil);
     }
+  
   if (host_info_ptr == 0)
     /* Attempt to interpret host as numeric inet address */
     {
@@ -1982,11 +2008,12 @@
       report_file_error ("connection failed",
 			 Fcons (host, Fcons (name, Qnil)));
     }
-#endif /* ! HAVE_GETADDRINFO */
+  
+#endif /* not HAVE_GETADDRINFO */
 
   immediate_quit = 0;
 
-  /* Discard the unwind protect.  */
+  /* Discard the unwind protect, if any.  */
   specpdl_ptr = specpdl + count1;
 
 #ifdef POLL_FOR_INPUT