2005-02-02 Andrew Cagney <cagney@gnu.org>
[deliverable/binutils-gdb.git] / gdb / ser-tcp.c
index 86baf34910877298209ff3eb1ed4cfc67d60d5fe..632ea1cadfe05bef23f42b24b353cf9ae3d815b7 100644 (file)
@@ -1,5 +1,6 @@
 /* Serial interface for raw TCP connections on Un*x like systems
-   Copyright 1992, 1993, 1998-1999 Free Software Foundation, Inc.
+   Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2001
+   Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "ser-unix.h"
 
 #include <sys/types.h>
+
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>  /* For FIONBIO. */
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>  /* For FIONBIO. */
+#endif
+
 #include <sys/time.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>
 #include <sys/socket.h>
-#ifndef __CYGWIN32__
 #include <netinet/tcp.h>
-#endif
 
-#include "signals.h"
+#include <signal.h>
 #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);
 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 deprecated_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);
@@ -73,57 +93,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 (deprecated_ui_loop_hook)
+           {
+             if (deprecated_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;
@@ -136,11 +207,11 @@ void
 _initialize_ser_tcp (void)
 {
   struct serial_ops *ops = XMALLOC (struct serial_ops);
-  memset (ops, sizeof (struct serial_ops), 0);
+  memset (ops, 0, sizeof (struct serial_ops));
   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;
This page took 0.028123 seconds and 4 git commands to generate.