X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fser-tcp.c;h=c6ae19dab02c741564a9b2406a626f3139963def;hb=3bcbaac54041e1226ae28cf918d4f5daf1a899af;hp=7f6b65a5411c43ab94e08fa7409a9d5c74f07b97;hpb=b6ba6518e9254bc25f88088228e93ac966ebccd1;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/ser-tcp.c b/gdb/ser-tcp.c index 7f6b65a541..c6ae19dab0 100644 --- a/gdb/ser-tcp.c +++ b/gdb/ser-tcp.c @@ -24,49 +24,69 @@ #include "ser-unix.h" #include + +#ifdef HAVE_SYS_FILIO_H +#include /* For FIONBIO. */ +#endif +#ifdef HAVE_SYS_IOCTL_H +#include /* For FIONBIO. */ +#endif + #include #include #include #include #include -#ifndef __CYGWIN32__ #include -#endif #include #include "gdb_string.h" -static int tcp_open (serial_t scb, const char *name); -static void tcp_close (serial_t scb); - +static int net_open (struct serial *scb, const char *name); +static void net_close (struct serial *scb); +extern int (*ui_loop_hook) (int); void _initialize_ser_tcp (void); -/* Open up a raw tcp socket */ +/* seconds to wait for connect */ +#define TIMEOUT 15 +/* how many times per second to poll ui_loop_hook */ +#define POLL_INTERVAL 2 + +/* Open a tcp socket */ static int -tcp_open (serial_t scb, const char *name) +net_open (struct serial *scb, const char *name) { - char *port_str; - int port; + char *port_str, hostname[100]; + int n, port, tmp; + int use_udp; struct hostent *hostent; struct sockaddr_in sockaddr; - int tmp; - char hostname[100]; - struct protoent *protoent; - int i; + + use_udp = 0; + if (strncmp (name, "udp:", 4) == 0) + { + use_udp = 1; + name = name + 4; + } + else if (strncmp (name, "tcp:", 4) == 0) + name = name + 4; port_str = strchr (name, ':'); if (!port_str) - error ("tcp_open: No colon in host name!"); /* Shouldn't ever happen */ + error ("net_open: No colon in 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); - hostent = gethostbyname (hostname); + /* default hostname is localhost */ + if (!hostname[0]) + strcpy (hostname, "localhost"); + hostent = gethostbyname (hostname); if (!hostent) { fprintf_unfiltered (gdb_stderr, "%s: unknown host\n", hostname); @@ -74,57 +94,108 @@ tcp_open (serial_t scb, const char *name) return -1; } - for (i = 1; i <= 15; i++) - { - scb->fd = socket (PF_INET, SOCK_STREAM, 0); - if (scb->fd < 0) - return -1; - - /* Allow rapid reuse of this port. */ - tmp = 1; - setsockopt (scb->fd, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, sizeof (tmp)); + if (use_udp) + scb->fd = socket (PF_INET, SOCK_DGRAM, 0); + else + scb->fd = socket (PF_INET, SOCK_STREAM, 0); - /* Enable TCP keep alive process. */ - tmp = 1; - setsockopt (scb->fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &tmp, sizeof (tmp)); + if (scb->fd < 0) + return -1; + + sockaddr.sin_family = PF_INET; + sockaddr.sin_port = htons (port); + memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr, + sizeof (struct in_addr)); - sockaddr.sin_family = PF_INET; - sockaddr.sin_port = htons (port); - memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr, - sizeof (struct in_addr)); + /* set socket nonblocking */ + tmp = 1; + ioctl (scb->fd, FIONBIO, &tmp); - if (!connect (scb->fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr))) - break; + /* Use Non-blocking connect. connect() will return 0 if connected already. */ + n = connect (scb->fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr)); - close (scb->fd); - scb->fd = -1; + if (n < 0 && errno != EINPROGRESS) + { + net_close (scb); + return -1; + } -/* We retry for ECONNREFUSED because that is often a temporary condition, which - happens when the server is being restarted. */ + if (n) + { + /* looks like we need to wait for the connect */ + struct timeval t; + fd_set rset, wset; + int polls = 0; + FD_ZERO (&rset); + + do + { + /* While we wait for the connect to complete + poll the UI so it can update or the user can + interrupt. */ + if (ui_loop_hook) + { + if (ui_loop_hook (0)) + { + errno = EINTR; + net_close (scb); + return -1; + } + } + + FD_SET (scb->fd, &rset); + wset = rset; + t.tv_sec = 0; + t.tv_usec = 1000000 / POLL_INTERVAL; + + n = select (scb->fd + 1, &rset, &wset, NULL, &t); + polls++; + } + while (n == 0 && polls <= TIMEOUT * POLL_INTERVAL); + if (n < 0 || polls > TIMEOUT * POLL_INTERVAL) + { + if (polls > TIMEOUT * POLL_INTERVAL) + errno = ETIMEDOUT; + net_close (scb); + return -1; + } + } - if (errno != ECONNREFUSED) + /* Got something. Is it an error? */ + { + int res, err, len; + len = sizeof(err); + res = getsockopt (scb->fd, SOL_SOCKET, SO_ERROR, &err, &len); + if (res < 0 || err) + { + if (err) + errno = err; + net_close (scb); return -1; + } + } - sleep (1); - } - - protoent = getprotobyname ("tcp"); - if (!protoent) - return -1; + /* turn off nonblocking */ + tmp = 0; + ioctl (scb->fd, FIONBIO, &tmp); - tmp = 1; - if (setsockopt (scb->fd, protoent->p_proto, TCP_NODELAY, - (char *) &tmp, sizeof (tmp))) - return -1; + if (use_udp == 0) + { + /* Disable Nagle algorithm. Needed in some cases. */ + tmp = 1; + setsockopt (scb->fd, IPPROTO_TCP, TCP_NODELAY, + (char *)&tmp, sizeof (tmp)); + } - signal (SIGPIPE, SIG_IGN); /* If we don't do this, then GDB simply exits - when the remote side dies. */ + /* If we don't do this, then GDB simply exits + when the remote side dies. */ + signal (SIGPIPE, SIG_IGN); return 0; } static void -tcp_close (serial_t scb) +net_close (struct serial *scb) { if (scb->fd < 0) return; @@ -140,8 +211,8 @@ _initialize_ser_tcp (void) memset (ops, sizeof (struct serial_ops), 0); ops->name = "tcp"; ops->next = 0; - ops->open = tcp_open; - ops->close = tcp_close; + ops->open = net_open; + ops->close = net_close; ops->readchar = ser_unix_readchar; ops->write = ser_unix_write; ops->flush_output = ser_unix_nop_flush_output;