+ {
+#if defined(HAVE_GETADDRINFO) && defined(HAVE_GETNAMEINFO)
+ struct addrinfo hints, *res;
+ struct addrinfo * volatile lres;
+ char *portstring;
+ volatile int xerrno = 0;
+ volatile int failed_connect = 0;
+ char *ext_host;
+ char portbuf[sizeof(long)*3 + 2];
+ /*
+ * Caution: service can either be a string or int.
+ * Convert to a C string for later use by getaddrinfo.
+ */
+ if (INTP (service))
+ {
+ snprintf (portbuf, sizeof (portbuf), "%ld", (long) XINT (service));
+ portstring = portbuf;
+ port = htons ((unsigned short) XINT (service));
+ }
+ else
+ {
+ CHECK_STRING (service);
+ LISP_STRING_TO_EXTERNAL (service, portstring, Qnative);
+ port = 0;
+ }
+
+ xzero (hints);
+ hints.ai_flags = 0;
+ hints.ai_family = AF_UNSPEC;
+ if (EQ (protocol, Qtcp))
+ hints.ai_socktype = SOCK_STREAM;
+ else /* EQ (protocol, Qudp) */
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = 0;
+ LISP_STRING_TO_EXTERNAL (host, ext_host, Qnative);
+ retval = getaddrinfo (ext_host, portstring, &hints, &res);
+ if (retval != 0)
+ {
+ char *gai_error;
+
+ EXTERNAL_TO_C_STRING (gai_strerror (retval), gai_error, Qnative);
+ error ("%s/%s %s", XSTRING_DATA (host), portstring, gai_error);
+ }
+
+ /* address loop */
+ for (lres = res; lres ; lres = lres->ai_next)
+ {
+ if (EQ (protocol, Qtcp))
+ s = socket (lres->ai_family, SOCK_STREAM, 0);
+ else /* EQ (protocol, Qudp) */
+ s = socket (lres->ai_family, SOCK_DGRAM, 0);
+
+ if (s < 0)
+ continue;
+
+ /* Turn off interrupts here -- see comments below. There used to
+ be code which called bind_polling_period() to slow the polling
+ period down rather than turn it off, but that seems rather
+ bogus to me. Best thing here is to use a non-blocking connect
+ or something, to check for QUIT. */
+
+ /* Comments that are not quite valid: */
+
+ /* Kernel bugs (on Ultrix at least) cause lossage (not just EINTR)
+ when connect is interrupted. So let's not let it get interrupted.
+ Note we do not turn off polling, because polling is only used
+ when not interrupt_input, and thus not normally used on the systems
+ which have this bug. On systems which use polling, there's no way
+ to quit if polling is turned off. */
+
+ /* Slow down polling. Some kernels have a bug which causes retrying
+ connect to fail after a connect. */
+
+ slow_down_interrupts ();
+
+ loop:
+
+ /* A system call interrupted with a SIGALRM or SIGIO comes back
+ here, with can_break_system_calls reset to 0. */
+ SETJMP (break_system_call_jump);
+ if (QUITP)
+ {
+ speed_up_interrupts ();
+ REALLY_QUIT;
+ /* In case something really weird happens ... */
+ slow_down_interrupts ();
+ }
+
+ /* Break out of connect with a signal (it isn't otherwise possible).
+ Thus you don't get screwed with a hung network. */
+ can_break_system_calls = 1;
+ retval = connect (s, lres->ai_addr, lres->ai_addrlen);
+ can_break_system_calls = 0;
+ if (retval == -1)
+ {
+ xerrno = errno;
+ if (errno != EISCONN)
+ {
+ if (errno == EINTR)
+ goto loop;
+ if (errno == 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.
+ `sleep-for' allowed for quitting this loop with interrupts
+ slowed down so it can't be used here. Async timers should
+ already be disabled at this point so we can use `sleep'. */
+ sleep (1);
+ retry++;
+ goto loop;
+ }
+ }