diff -Nru a/gdb-7.5.1/gdb/gdbserver/gdbreplay.c b/gdb-7.5.1/gdb/gdbserver/gdbreplay.c --- a/gdb-7.5.1/gdb/gdbserver/gdbreplay.c 2012-08-22 13:05:02 -0700 +++ b/gdb-7.5.1/gdb/gdbserver/gdbreplay.c 2013-04-15 03:20:40 -0700 @@ -190,14 +190,41 @@ static void remote_open (char *name) { - if (!strchr (name, ':')) + char *port_str; + char *host_start, *host_end; + + host_start = name; + if (host_start[0] == '[') { - fprintf (stderr, "%s: Must specify tcp connection as host:addr\n", name); - fflush (stderr); - exit (1); + ++host_start; + host_end = strchr (host_start, ']'); + if (host_end == NULL) + { + fprintf (stderr, "Mismatched `[' in hostname."); + fflush (stderr); + exit (1); + } + port_str = host_end + 1; + if (*port_str != ':') + { + fprintf (stderr, "Missing port after hostname, specify tcp connection as host:port or [host]:port."); + fflush (stderr); + exit (1); + } } else { + port_str = strchr (name, ':'); + host_end = port_str; + if (port_str == NULL) + { + fprintf (stderr, "Missing port after hostname, specify tcp connection as host:port or [host]:port."); + fflush (stderr); + exit(1); + } + } + + { #ifdef USE_WIN32API static int winsock_initialized; #endif diff -Nru a/gdb-7.5.1/gdb/gdbserver/remote-utils.c b/gdb-7.5.1/gdb/gdbserver/remote-utils.c --- a/gdb-7.5.1/gdb/gdbserver/remote-utils.c 2012-04-28 23:28:30 -0700 +++ b/gdb-7.5.1/gdb/gdbserver/remote-utils.c 2013-04-16 06:25:07 -0700 @@ -16,6 +16,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#define _WIN32_WINNT 0x501 + #include "server.h" #include "terminal.h" #include "target.h" @@ -63,6 +65,13 @@ #if USE_WIN32API #include +#include +#else +#include /* sockaddr_in{} and other Internet defns */ +#endif + +#ifndef SOL_IPV6 +#define SOL_IPV6 IPPROTO_IPV6 #endif #if __QNX__ @@ -109,7 +118,7 @@ static int remote_is_stdio = 0; static gdb_fildes_t remote_desc = INVALID_DESCRIPTOR; -static gdb_fildes_t listen_desc = INVALID_DESCRIPTOR; +gdb_fildes_t *listening_sockets = NULL; /* FIXME headerize? */ extern int using_threads; @@ -156,15 +165,17 @@ static int handle_accept_event (int err, gdb_client_data client_data) { - struct sockaddr_in sockaddr; + struct sockaddr_storage address; socklen_t tmp; + char back_host[64], back_port[16]; + gdb_fildes_t listen_desc = *(gdb_fildes_t *)client_data; if (debug_threads) fprintf (stderr, "handling possible accept event\n"); - tmp = sizeof (sockaddr); - remote_desc = accept (listen_desc, (struct sockaddr *) &sockaddr, &tmp); - if (remote_desc == -1) + tmp = (socklen_t) sizeof (address); + remote_desc = accept (listen_desc, (struct sockaddr *) &address, &tmp); + if (remote_desc == INVALID_DESCRIPTOR) perror_with_name ("Accept failed"); /* Enable TCP keep alive process. */ @@ -178,27 +189,55 @@ setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY, (char *) &tmp, sizeof (tmp)); + if (listening_sockets) + { + /* We assume that all sockets have been registered, and none triggers + while doing this. This is true in the current single threaded + implementation. */ + gdb_fildes_t *l_sock = listening_sockets; + for (++l_sock; *l_sock != INVALID_DESCRIPTOR; ++l_sock) + { #ifndef USE_WIN32API - signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbserver simply - exits when the remote side dies. */ + signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbserver simply + exits when the remote side dies. */ #endif - if (run_once) - { + if (run_once) + { #ifndef USE_WIN32API - close (listen_desc); /* No longer need this */ + close (*l_sock); /* No longer need this */ #else - closesocket (listen_desc); /* No longer need this */ + closesocket (*l_sock); /* No longer need this */ #endif - } + } - /* Even if !RUN_ONCE no longer notice new connections. Still keep the + /* Even if !RUN_ONCE no longer notice new connections. Still keep the descriptor open for add_file_handler to wait for a new connection. */ - delete_file_handler (listen_desc); + delete_file_handler (*l_sock); + } + if (run_once) + { + free(listening_sockets); + listening_sockets = NULL; + } + } /* Convert IP address to string. */ - fprintf (stderr, "Remote debugging from host %s\n", - inet_ntoa (sockaddr.sin_addr)); + if (getnameinfo ((struct sockaddr *) &address, + (socklen_t) sizeof (address), + back_host, (socklen_t) sizeof (back_host), + back_port, (socklen_t) sizeof (back_port), + NI_NUMERICHOST | NI_NUMERICSERV)) + { + fprintf (stderr, "Error detecting originating address, trying anyway\n"); + } + else + { + back_host[sizeof (back_host) - 1] = 0; + back_port[sizeof (back_port) - 1] = 0; + fprintf (stderr, "Remote debugging from host %s port %s\n", + back_host, back_port); + } enable_async_notification (remote_desc); @@ -224,12 +263,15 @@ { char *port_str; #ifdef USE_WIN32API - static int winsock_initialized; + static int winsock_initialized = 0; #endif - int port; - struct sockaddr_in sockaddr; - socklen_t tmp; - char *port_end; + char *host_start, *host_end; + struct addrinfo hints, *ainfo, *ainfo0; + gdb_fildes_t *socktable = NULL; + gdb_fildes_t s = INVALID_DESCRIPTOR; + int nsock = 0, socktable_size = 0, err, port = 0; + char *host_str = NULL; + char back_host[128], back_port[32]; remote_is_stdio = 0; if (strcmp (name, STDIO_CONNECTION_NAME) == 0) @@ -249,8 +291,24 @@ return; } - port = strtoul (port_str + 1, &port_end, 10); - if (port_str[1] == '\0' || *port_end != '\0') + host_start = name; + if (host_start[0] == '[') + { + ++host_start; + host_end = strchr (host_start, ']'); + if (host_end == NULL) + fatal ("Mismatched `[' in hostname."); + port_str = host_end + 1; + if (*port_str != ':') + fatal ("Missing port after hostname."); + } + else + { + port_str = strchr (name, ':'); + host_end = port_str; + } + + if (port_str[1] == '\0') fatal ("Bad port argument: %s", name); #ifdef USE_WIN32API @@ -263,24 +321,181 @@ } #endif - listen_desc = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); - if (listen_desc == -1) - perror_with_name ("Can't open socket"); + if (host_start < host_end) + { + host_str = strdup(host_start); + host_str[host_end - host_start] = 0; + } + ++port_str; - /* Allow rapid reuse of this port. */ - tmp = 1; - setsockopt (listen_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, - sizeof (tmp)); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + + err = getaddrinfo(host_str, port_str, &hints, &ainfo0); + if (err) + fatal ("%s for %s", gai_strerror(err), name); + + for (ainfo = ainfo0; ainfo; ainfo = ainfo->ai_next) + { + int current_port, tmp; + + if (getnameinfo ((struct sockaddr *) ainfo->ai_addr, + (socklen_t) ainfo->ai_addrlen, + back_host, (socklen_t) sizeof (back_host), + back_port, (socklen_t) sizeof (back_port), + NI_NUMERICHOST | NI_NUMERICSERV)) + { + back_host[0] = 0; + back_port[0] = 0; + } + else + { + back_host[sizeof (back_host) - 1] = 0; + back_port[sizeof (back_port) - 1] = 0; + } + + switch (ainfo->ai_addr->sa_family) + { + case AF_INET: + current_port = ntohs (((struct sockaddr_in *) ainfo->ai_addr) + ->sin_port); + break; + case AF_INET6: + current_port = ntohs (((struct sockaddr_in6 *) ainfo->ai_addr) + ->sin6_port); + break; + default: + fatal ("Unexpected address family: %d for %s %s", + ainfo->ai_addr->sa_family,back_host,back_port); + } + + if (port != 0 && current_port == 0) + { + /* Use the same port for all protocol/interfaces. */ + switch (ainfo->ai_addr->sa_family) + { + case AF_INET: + ((struct sockaddr_in *) ainfo->ai_addr)->sin_port = + htons(port); + break; + case AF_INET6: + ((struct sockaddr_in6 *) ainfo->ai_addr)->sin6_port = + htons(port); + break; + } + } + s = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol); + if (s < 0) + continue; + + /* Allow rapid reuse of this port. */ + tmp = 1; + if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, + (socklen_t) sizeof (tmp)) != 0) + { + fprintf (stderr, "Trying to bind %s port %s.\n", + back_host, back_port); + perror("setsockopt(s, SOL_SOCKET, SO_REUSEADDR,[1],4)"); + } +#ifdef IPV6_V6ONLY + if (ainfo->ai_addr->sa_family == AF_INET6 + && setsockopt (s, SOL_IPV6, IPV6_V6ONLY, (char *) &tmp, + (socklen_t) sizeof (tmp)) != 0) + { + fprintf (stderr, "Trying to bind %s port %s.\n", + back_host, back_port); + perror("setsockopt(s, SOL_IPV6, IPV6_V6ONLY,[1],4)"); + } +#endif + + if (bind (s, ainfo->ai_addr, ainfo->ai_addrlen) != 0) + { + fprintf (stderr, "Trying to bind %s port %s.\n", + back_host, back_port); + perror ("bind failed"); + close (s); + s = -1; + continue; + } + + if (listen (s, 1) != 0) + { + fprintf (stderr, "Trying to bind %s port %s.\n", + back_host, back_port); + perror ("Can't listen to a bound socket"); + close (s); + s = -1; + continue; + } + + { + struct sockaddr_storage address; + socklen_t alen = (socklen_t) sizeof (address); + + if (getsockname (s, (struct sockaddr *) &address, &alen)) + fatal ("Failed to get socket address %s, on soket bound to %s port %s.", + strerror (errno), back_host, back_port); + + if (port == 0) + /* Try to recover the port set by the kernel. */ + switch (address.ss_family) + { + case AF_INET: + port = ntohs (((struct sockaddr_in *) &address)->sin_port); + break; + case AF_INET6: + port = ntohs (((struct sockaddr_in6 *) &address)->sin6_port); + break; + default: + fatal ("Unexpected address family: %d", address.ss_family); + } + + if (getnameinfo ((struct sockaddr *) &address, + (socklen_t) sizeof (address), + back_host, (socklen_t) sizeof (back_host), + back_port, (socklen_t) sizeof (back_port), + NI_NUMERICHOST | NI_NUMERICSERV)) + { + fprintf (stderr, "Error detecting bound address.\n"); + } + else + { + back_host[sizeof (back_host) - 1] = 0; + back_port[sizeof (back_port) - 1] = 0; + fprintf (stderr, "Sucessfully bound %s port %s\n", + back_host, back_port); + } + } - sockaddr.sin_family = PF_INET; - sockaddr.sin_port = htons (port); - sockaddr.sin_addr.s_addr = INADDR_ANY; - - if (bind (listen_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) - || listen (listen_desc, 1)) - perror_with_name ("Can't bind address"); + if (socktable_size < nsock + 3) + { + socktable = xrealloc (socktable, + (nsock + 10) * sizeof (gdb_fildes_t)); + socktable[0] = INVALID_DESCRIPTOR; + } + socktable[++nsock] = s; + } + + freeaddrinfo (ainfo0); + free (host_str); + + if (nsock == 0) + fatal("Failed to bind any socket."); + + /* Bound socktable from both ends, so an inner pointer can still + find the whole array. */ + socktable[++nsock] = INVALID_DESCRIPTOR; transport_is_reliable = 1; + fprintf (stderr, "Listening on port %d\n", port); + fflush (stderr); + transport_is_reliable = 1; + if (listening_sockets) + fatal ("Multiple concurrent remote_open not supported."); + + listening_sockets = socktable; } /* Open a connection to a remote debugger. @@ -290,8 +505,24 @@ remote_open (char *name) { char *port_str; + char *host_start, *host_end; - port_str = strchr (name, ':'); + host_start = name; + if (host_start[0] == '[') + { + ++host_start; + host_end = strchr (host_start, ']'); + if (host_end == NULL) + fatal ("Mismatched `[' in hostname."); + port_str = host_end + 1; + if (*port_str != ':') + fatal ("Missing port after hostname."); + } + else + { + port_str = strchr (name, ':'); + host_end = port_str; + } #ifdef USE_WIN32API if (port_str == NULL) error ("Only : is supported on this platform."); @@ -381,22 +612,17 @@ #endif /* USE_WIN32API */ else { - int port; - socklen_t len; - struct sockaddr_in sockaddr; - - len = sizeof (sockaddr); - if (getsockname (listen_desc, - (struct sockaddr *) &sockaddr, &len) < 0 - || len < sizeof (sockaddr)) - perror_with_name ("Can't determine port"); - port = ntohs (sockaddr.sin_port); + int isock; - fprintf (stderr, "Listening on port %d\n", port); - fflush (stderr); - - /* Register the event loop handler. */ - add_file_handler (listen_desc, handle_accept_event, NULL); + if (! listening_sockets) + fatal ("Listening_sockets not initialized (missing call to remote_prepare)."); + for (isock = 1; listening_sockets[isock] != INVALID_DESCRIPTOR; ++isock) + { + /* This assumes the loop ends before any of the handlers is called. + This is true in the current non threaded implementation. */ + add_file_handler (listening_sockets[isock], handle_accept_event, + listening_sockets + isock); + } } } diff -Nru a/gdb-7.5.1/gdb/ser-tcp.c b/gdb-7.5.1/gdb/ser-tcp.c --- a/gdb-7.5.1/gdb/ser-tcp.c 2012-01-04 00:17:10 -0800 +++ b/gdb-7.5.1/gdb/ser-tcp.c 2013-04-15 03:20:40 -0700 @@ -38,7 +38,9 @@ #include #ifdef USE_WIN32API +#define _WIN32_WINNT 0x0501 #include +#include #ifndef ETIMEDOUT #define ETIMEDOUT WSAETIMEDOUT #endif @@ -50,6 +52,7 @@ #include #include #include +#include #endif #include @@ -79,76 +82,49 @@ #define POLL_INTERVAL 5 -/* Helper function to wait a while. If SCB is non-null, wait on its - file descriptor. Otherwise just wait on a timeout, updating *POLLS. - Returns -1 on timeout or interrupt, otherwise the value of select. */ +enum { + ADDR_DROP, + ADDR_RECONNECT, + ADDR_WAIT, + ADDR_SUCCESS +}; +/* Tries to connect to a socket */ static int -wait_for_connect (struct serial *scb, int *polls) +check_sock_err (int fd) { - struct timeval t; - int n; - - /* While we wait for the connect to complete, - poll the UI so it can update or the user can - interrupt. */ - if (deprecated_ui_loop_hook && deprecated_ui_loop_hook (0)) - { - errno = EINTR; - return -1; - } - - /* Check for timeout. */ - if (*polls > tcp_retry_limit * POLL_INTERVAL) - { - errno = ETIMEDOUT; - return -1; - } - - /* Back off to polling once per second after the first POLL_INTERVAL - polls. */ - if (*polls < POLL_INTERVAL) - { - t.tv_sec = 0; - t.tv_usec = 1000000 / POLL_INTERVAL; - } - else - { - t.tv_sec = 1; - t.tv_usec = 0; - } + int res, err; + socklen_t len; - if (scb) + len = sizeof (err); + /* On Windows, the fourth parameter to getsockopt is a "char *"; + on UNIX systems it is generally "void *". The cast to "void *" + is OK everywhere, since in C "void *" can be implicitly + converted to any pointer type. */ + res = getsockopt (fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len); + if (res < 0 || err) { - fd_set rset, wset, eset; - - FD_ZERO (&rset); - FD_SET (scb->fd, &rset); - wset = rset; - eset = rset; - - /* POSIX systems return connection success or failure by signalling - wset. Windows systems return success in wset and failure in - eset. - - We must call select here, rather than gdb_select, because - the serial structure has not yet been initialized - the - MinGW select wrapper will not know that this FD refers - to a socket. */ - n = select (scb->fd + 1, &rset, &wset, &eset, &t); + /* Maybe the target still isn't ready to accept the connection. */ + if (tcp_auto_retry + #ifdef USE_WIN32API + && err == WSAECONNREFUSED + #else + && err == ECONNREFUSED + #endif + ) + { + close (fd); + return ADDR_RECONNECT; + } + else + { + if (err) + errno = err; + close (fd); + return ADDR_DROP; + } } - else - /* Use gdb_select here, since we have no file descriptors, and on - Windows, plain select doesn't work in that case. */ - n = gdb_select (0, NULL, NULL, NULL, &t); - - /* If we didn't time out, only count it as one poll. */ - if (n > 0 || *polls < POLL_INTERVAL) - (*polls)++; - else - (*polls) += POLL_INTERVAL; - - return n; + return ADDR_SUCCESS; } /* Open a tcp socket. */ @@ -156,18 +132,24 @@ int net_open (struct serial *scb, const char *name) { - char *port_str, hostname[100]; - int n, port, tmp; + char *port_str, hostname[100], *name_end; + int n = 0, tmp; int use_udp; struct hostent *hostent; - struct sockaddr_in sockaddr; + struct addrinfo hints, *ainfo, *ainfo0, *ainfo_reconnect, *ainfo_old, + *ainfo_tmp; + struct sockaddr_storage address; + int max_w_socks = 0, n_w_socks = 0; + int *waiting_socks = NULL; #ifdef USE_WIN32API u_long ioarg; #else int ioarg; #endif int polls = 0; + int err, fd = -1; + scb->fd = -1; use_udp = 0; if (strncmp (name, "udp:", 4) == 0) { @@ -177,134 +159,286 @@ else if (strncmp (name, "tcp:", 4) == 0) name = name + 4; - port_str = strchr (name, ':'); - - if (!port_str) - error (_("net_open: No colon in host name!")); /* Shouldn't ever + if (name[0]=='[') + { + ++name; + name_end = strchr(name, ']'); + if (name_end == NULL) + error (_("net_open: Mismatched '['")); + port_str = name_end+1; + } else { + port_str = strchr (name, ':'); + name_end = port_str; + } + if (!port_str || port_str[0] !=':') + error (_("net_open: No colon after host name!")); /* Shouldn't ever happen. */ - tmp = min (port_str - name, (int) sizeof hostname - 1); - strncpy (hostname, name, tmp); /* Don't want colon. */ - hostname[tmp] = '\000'; /* Tie off host name. */ - port = atoi (port_str + 1); - - /* Default hostname is localhost. */ - if (!hostname[0]) - strcpy (hostname, "localhost"); - - hostent = gethostbyname (hostname); - if (!hostent) + tmp = min (name_end - name, (int) sizeof hostname - 1); + /* Default hostname is localhost. Keeping this but NULL should also work. */ + if (!name[0]) { - fprintf_unfiltered (gdb_stderr, "%s: unknown host\n", hostname); - errno = ENOENT; - return -1; + strcpy (hostname, "localhost"); } - - sockaddr.sin_family = PF_INET; - sockaddr.sin_port = htons (port); - memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr, - sizeof (struct in_addr)); - - retry: - - if (use_udp) - scb->fd = socket (PF_INET, SOCK_DGRAM, 0); else - scb->fd = socket (PF_INET, SOCK_STREAM, 0); - - if (scb->fd == -1) - return -1; + { + strncpy (hostname, name, tmp); /* Don't want colon. */ + hostname[tmp] = '\000'; /* Tie off host name. */ + } + ++port_str; - /* Set socket nonblocking. */ - ioarg = 1; - ioctl (scb->fd, FIONBIO, &ioarg); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + if (use_udp) + hints.ai_socktype = SOCK_DGRAM; + else + hints.ai_socktype = SOCK_STREAM; - /* Use Non-blocking connect. connect() will return 0 if connected - already. */ - n = connect (scb->fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr)); + err = getaddrinfo(hostname, port_str, &hints, &ainfo0); + if (err) + { + fprintf_unfiltered (gdb_stderr, "%s: connecting to %s on port %s\n", + gai_strerror(err), hostname, port_str); + errno = ENOENT; + return -1; + } - if (n < 0) + do { -#ifdef USE_WIN32API - int err = WSAGetLastError(); -#else - int err = errno; -#endif + ainfo = ainfo0; + ainfo_old = NULL; + while (ainfo) + { + int op_to_do, connect_ret; + + ainfo_old = ainfo; + fd = socket (ainfo->ai_family, ainfo->ai_socktype, + ainfo->ai_protocol); + + if (fd == -1) + { + ainfo = ainfo->ai_next; + continue; + } + + /* Set socket nonblocking. */ + ioarg = 1; + ioctl (fd, FIONBIO, &ioarg); + + /* Use Non-blocking connect. connect() will return 0 if connected + already. */ + connect_ret = connect (fd, ainfo->ai_addr, ainfo->ai_addrlen); - /* Maybe we're waiting for the remote target to become ready to - accept connections. */ - if (tcp_auto_retry + if (connect_ret < 0) + { #ifdef USE_WIN32API - && err == WSAECONNREFUSED + int err = WSAGetLastError(); #else - && err == ECONNREFUSED + int err = errno; #endif - && wait_for_connect (NULL, &polls) >= 0) - { - close (scb->fd); - goto retry; - } - if ( -#ifdef USE_WIN32API - /* Under Windows, calling "connect" with a non-blocking socket - results in WSAEWOULDBLOCK, not WSAEINPROGRESS. */ - err != WSAEWOULDBLOCK -#else - err != EINPROGRESS -#endif - ) - { - errno = err; - net_close (scb); - return -1; - } - - /* Looks like we need to wait for the connect. */ - do - { - n = wait_for_connect (scb, &polls); - } - while (n == 0); - if (n < 0) - { - net_close (scb); - return -1; - } + /* Maybe we're waiting for the remote target to become ready to + accept connections. */ + if (tcp_auto_retry + #ifdef USE_WIN32API + && err == WSAECONNREFUSED + #else + && err == ECONNREFUSED + #endif + ) + { + close (fd); + op_to_do = ADDR_RECONNECT; + } + else if ( + #ifdef USE_WIN32API + /* Under Windows, calling "connect" with a non-blocking socket + results in WSAEWOULDBLOCK, not WSAEINPROGRESS. */ + err != WSAEWOULDBLOCK + #else + err != EINPROGRESS + #endif + ) + { + close (fd); + op_to_do = ADDR_DROP; + } + else + { + op_to_do = ADDR_WAIT; + } + } + else + { + op_to_do = check_sock_err(fd); + } + switch (op_to_do) + { + case ADDR_DROP: + break; + case ADDR_RECONNECT: + ainfo_tmp = ainfo->ai_next; + ainfo->ai_next = ainfo_reconnect; + ainfo_reconnect->ai_next = ainfo; + ainfo = ainfo_tmp; + ainfo_old = NULL; + break; + case ADDR_WAIT: + /* Looks like we need to wait for the connect. */ + if (n_w_socks >= max_w_socks) + { + max_w_socks += 10; + waiting_socks= xrealloc (waiting_socks, max_w_socks + * sizeof(*waiting_socks)); + } + waiting_socks[n_w_socks++] = fd; + break; + case ADDR_SUCCESS: + break; + default: + fatal (_("Unexpected value for try_connect in net_open.")); + } + if (ainfo_old) + { + ainfo = ainfo_old->ai_next; + ainfo_old->ai_next = NULL; + freeaddrinfo (ainfo_old); + } + if (op_to_do == ADDR_SUCCESS) + break; + fd = -1; + } + ainfo0 = ainfo_reconnect; + ainfo_reconnect = NULL; + + if (fd != -1 || !(ainfo0 != NULL || n_w_socks != 0)) + break; + + do + { + struct timeval t; + int max_fd; + fd_set rset; + + /* While we wait for the connect to complete, + poll the UI so it can update or the user can + interrupt. */ + if (deprecated_ui_loop_hook && deprecated_ui_loop_hook (0)) + { + errno = EINTR; + return -1; + } + + /* Check for timeout. */ + if (polls > tcp_retry_limit * POLL_INTERVAL) + { + errno = ETIMEDOUT; + return -1; + } + + /* Back off to polling once per second after the first POLL_INTERVAL + polls. */ + if (polls < POLL_INTERVAL) + { + t.tv_sec = 0; + t.tv_usec = 1000000 / POLL_INTERVAL; + } + else + { + t.tv_sec = 1; + t.tv_usec = 0; + } + + max_fd=-1; + if (n_w_socks) + { + int ifd; + + FD_ZERO (&rset); + for (ifd = 0; ifd < n_w_socks; ++ifd) + { + if (waiting_socks[ifd] != -1) + { + FD_SET (waiting_socks[ifd], &rset); + if (max_fd < waiting_socks[ifd]) + max_fd = waiting_socks[ifd]; + } + } + } + if (max_fd != -1) + { + int ifd; + fd_set wset, eset; + wset = rset; + eset = rset; + + /* POSIX systems return connection success or failure by signalling + wset. Windows systems return success in wset and failure in + eset. + + We must call select here, rather than gdb_select, because + the serial structure has not yet been initialized - the + MinGW select wrapper will not know that this FD refers + to a socket. */ + n = select (max_fd + 1, &rset, &wset, &eset, &t); + if (n > 0) + for (ifd = 0; ifd < n_w_socks && fd == -1; ++ifd) + if (FD_ISSET(waiting_socks[ifd], &rset) + || FD_ISSET(waiting_socks[ifd], &wset) + || FD_ISSET(waiting_socks[ifd], &eset)) + { + int op_to_do; + + op_to_do = check_sock_err(waiting_socks[ifd]); + switch (op_to_do) + { + case ADDR_RECONNECT: + //waiting_socks[ifd] = -1; + break; + case ADDR_DROP: + //waiting_socks[ifd] = -1; + break; + case ADDR_WAIT: + break; + case ADDR_SUCCESS: + fd = waiting_socks[ifd]; + break; + default: + fatal (_("Unexpected value for try_connect in net_open.")); + } + } + } + else + /* Use gdb_select here, since we have no file descriptors, and on + Windows, plain select doesn't work in that case. */ + n = gdb_select (0, NULL, NULL, NULL, &t); + + /* If we didn't time out, only count it as one poll. */ + if (n > 0 || polls < POLL_INTERVAL) + polls++; + else + polls += POLL_INTERVAL; + } + while (fd == -1 && n == 0 && ainfo0 == NULL); } + while (fd == -1 && n >= 0); - /* Got something. Is it an error? */ - { - int res, err; - socklen_t len; - - len = sizeof (err); - /* On Windows, the fourth parameter to getsockopt is a "char *"; - on UNIX systems it is generally "void *". The cast to "void *" - is OK everywhere, since in C "void *" can be implicitly - converted to any pointer type. */ - res = getsockopt (scb->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len); - if (res < 0 || err) - { - /* Maybe the target still isn't ready to accept the connection. */ - if (tcp_auto_retry -#ifdef USE_WIN32API - && err == WSAECONNREFUSED -#else - && err == ECONNREFUSED -#endif - && wait_for_connect (NULL, &polls) >= 0) - { - close (scb->fd); - goto retry; - } - if (err) - errno = err; - net_close (scb); - return -1; - } - } + freeaddrinfo (ainfo0); + if (waiting_socks) + { + int ifd; + + for (ifd = 0; ifd < n_w_socks && fd == -1; ++ifd) + if (waiting_socks[ifd] != fd && waiting_socks[ifd] != -1) + close (waiting_socks[ifd]); + } + free (waiting_socks); + + if (fd == -1) + return -1; + scb->fd = fd; /* Turn off nonblocking. */ ioarg = 0; ioctl (scb->fd, FIONBIO, &ioarg);