[patch] IPv6 support for gdbserver

Jan Kratochvil jan.kratochvil@redhat.com
Wed Sep 27 16:33:00 GMT 2006


Hi,

while it may not make too much sense here is IPv6 support ("tcp6:"/"udp6:"
address prefixes, autodetected if possible) for
target-remote/gdbserver/gdbreplay.


Regards,
Jan
-------------- next part --------------
2006-09-27  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* ser-tcp.c (net_open): Support IPv6, "tcp6:"&co. notation.

2006-09-27  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* gdbreplay.c (remote_open): Support IPv6, "tcp6:"&co. notation.
	* remote-utils.c (remote_open): Likewise.

2006-09-27  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* gdb.texinfo (Connecting to a remote target): Support IPv6,
	"tcp6:"&co. notation.
	(Using the gdbserver program): Likewise.


Index: gdb/ser-tcp.c
===================================================================
RCS file: /cvs/src/src/gdb/ser-tcp.c,v
retrieving revision 1.26
diff -u -p -r1.26 ser-tcp.c
--- gdb/ser-tcp.c	10 Feb 2006 22:01:43 -0000	1.26
+++ gdb/ser-tcp.c	27 Sep 2006 13:11:01 -0000
@@ -68,67 +68,129 @@ void _initialize_ser_tcp (void);
 int
 net_open (struct serial *scb, const char *name)
 {
-  char *port_str, hostname[100];
-  int n, port, tmp;
-  int use_udp;
-  struct hostent *hostent;
-  struct sockaddr_in sockaddr;
+  char *name_base;
+  char *port_str;
+  int n, tmp;
 #ifdef USE_WIN32API
   u_long ioarg;
 #else
   int ioarg;
 #endif
-
-  use_udp = 0;
-  if (strncmp (name, "udp:", 4) == 0)
+  struct prefix
+    {
+      const char *string;
+      int family;
+      int socktype;
+    };
+  const struct prefix prefixes[] =
+    {
+      { "udp:",  AF_UNSPEC, SOCK_DGRAM  },
+      { "tcp:",  AF_UNSPEC, SOCK_STREAM },
+      { "udp4:", AF_INET,   SOCK_DGRAM  },
+      { "tcp4:", AF_INET,   SOCK_STREAM },
+      { "udp6:", AF_INET6,  SOCK_DGRAM  },
+      { "tcp6:", AF_INET6,  SOCK_STREAM },
+    };
+  const struct prefix *prefix;
+  struct addrinfo hints, *hints_p = NULL;
+  struct addrinfo *addrinfo_base, *addrinfo = NULL;
+  struct address
+    {
+      const char *string;
+      int family;
+    };
+  const struct address addresses[] =
+    {
+      { "::1",       AF_INET6  },
+      { "127.0.0.1", AF_INET   },
+      { "localhost", AF_UNSPEC },
+    };
+  const struct address *address;
+  int fake_localhost = 0;
+
+  name_base = xstrdup (name);
+  name = name_base;
+  for (prefix = prefixes; prefix < prefixes + ARRAY_SIZE (prefixes); prefix++)
+    if (strncmp (name, prefix->string, strlen (prefix->string)) == 0)
+      {
+	name += strlen (prefix->string);
+        memset (&hints, 0, sizeof (hints));
+	hints.ai_family   = prefix->family;
+	hints.ai_socktype = prefix->socktype;
+	hints_p = &hints;
+	break;
+      }
+  if (!(hints_p != NULL && hints_p->ai_family == AF_INET)
+      && name[0] == '[' && (port_str = strchr (name, ']')))
     {
-      use_udp = 1;
-      name = name + 4;
+      name++;
+      *port_str++ = 0;
     }
-  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 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);
+  else
+    port_str = strchr (name, ':');
+  /* It may happen with IPv6 for like "[::1]".  */
+  if (port_str == NULL || *port_str != ':')
+    error (_("net_open: No colon in host name!"));
+  *port_str++ = 0;
 
   /* default hostname is localhost */
-  if (!hostname[0])
-    strcpy (hostname, "localhost");
+  if (name[0] == 0)
+    fake_localhost = 1;
 
-  hostent = gethostbyname (hostname);
-  if (!hostent)
+  for (address = addresses;
+       address < addresses + sizeof (addresses) / sizeof (*addresses);
+       address++)
     {
-      fprintf_unfiltered (gdb_stderr, "%s: unknown host\n", hostname);
-      errno = ENOENT;
-      return -1;
-    }
+      int fatal;
 
-  if (use_udp)
-    scb->fd = socket (PF_INET, SOCK_DGRAM, 0);
-  else
-    scb->fd = socket (PF_INET, SOCK_STREAM, 0);
+      if (fake_localhost)
+	{
+	  if (address->family != AF_UNSPEC
+	      && hints_p != NULL && hints_p->ai_family != address->family)
+	    continue;
+	  name = (char *) address->string;
+	  fatal = (address + 1
+		   >= addresses + sizeof (addresses) / sizeof (*addresses));
+	}
+      else
+	fatal = 1;
 
-  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));
+      n = getaddrinfo (name, port_str, hints_p, &addrinfo_base);
+      if (n != 0)
+	{
+	  if (!fatal)
+	    continue;
+	  fprintf_unfiltered (gdb_stderr, "%s:%s: cannot resolve name: %s\n",
+			      name, port_str, gai_strerror (n));
+	  errno = ENOENT;
+	  free (name_base);
+	  return -1;
+	}
+      free (name_base);
+
+      for (addrinfo = addrinfo_base; addrinfo != NULL; addrinfo = addrinfo->ai_next)
+	{
+	  scb->fd = socket (addrinfo->ai_family, addrinfo->ai_socktype,
+			    addrinfo->ai_protocol);
+	  if (scb->fd >= 0)
+	    break;
+	}
+      if (addrinfo == NULL)
+	{
+	  if (!fatal)
+	    continue;
+	  freeaddrinfo (addrinfo_base);
+	  return -1;
+	}
+      break;
+    }
 
   /* set socket nonblocking */
   ioarg = 1;
   ioctl (scb->fd, FIONBIO, &ioarg);
 
   /* Use Non-blocking connect.  connect() will return 0 if connected already. */
-  n = connect (scb->fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr));
+  n = connect (scb->fd, addrinfo->ai_addr, addrinfo->ai_addrlen);
 
   if (n < 0
 #ifdef USE_WIN32API
@@ -144,6 +206,7 @@ net_open (struct serial *scb, const char
       errno = WSAGetLastError();
 #endif
       net_close (scb);
+      freeaddrinfo (addrinfo_base);
       return -1;
     }
 
@@ -166,6 +229,7 @@ net_open (struct serial *scb, const char
 		{
 		  errno = EINTR;
 		  net_close (scb);
+		  freeaddrinfo (addrinfo_base);
 		  return -1;
 		}
 	    }
@@ -193,6 +257,7 @@ net_open (struct serial *scb, const char
 	  if (polls > TIMEOUT * POLL_INTERVAL)
 	    errno = ETIMEDOUT;
 	  net_close (scb);
+	  freeaddrinfo (addrinfo_base);
 	  return -1;
 	}
     }
@@ -212,6 +277,7 @@ net_open (struct serial *scb, const char
 	if (err)
 	  errno = err;
 	net_close (scb);
+	freeaddrinfo (addrinfo_base);
 	return -1;
       }
   } 
@@ -220,7 +286,7 @@ net_open (struct serial *scb, const char
   ioarg = 0;
   ioctl (scb->fd, FIONBIO, &ioarg);
 
-  if (use_udp == 0)
+  if (addrinfo->ai_protocol == SOCK_STREAM)
     {
       /* Disable Nagle algorithm. Needed in some cases. */
       tmp = 1;
@@ -234,6 +300,7 @@ net_open (struct serial *scb, const char
   signal (SIGPIPE, SIG_IGN);
 #endif
 
+  freeaddrinfo (addrinfo_base);
   return 0;
 }
 
Index: gdb/gdbserver/gdbreplay.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/gdbreplay.c,v
retrieving revision 1.12
diff -u -p -r1.12 gdbreplay.c
--- gdb/gdbserver/gdbreplay.c	23 Jul 2006 03:52:15 -0000	1.12
+++ gdb/gdbserver/gdbreplay.c	27 Sep 2006 13:11:10 -0000
@@ -115,6 +115,8 @@ remote_close (void)
 static void
 remote_open (char *name)
 {
+  char *name_orig = name;
+
   if (!strchr (name, ':'))
     {
       fprintf (stderr, "%s: Must specify tcp connection as host:addr\n", name);
@@ -127,14 +129,145 @@ remote_open (char *name)
       static int winsock_initialized;
 #endif
       char *port_str;
-      int port;
-      struct sockaddr_in sockaddr;
       socklen_t tmp;
-      int tmp_desc;
+      int tmp_desc = -1;
+      struct prefix
+	{
+	  const char *string;
+	  int family;
+	  int socktype;
+	};
+      const struct prefix prefixes[] =
+	{
+	  { "udp:",  AF_UNSPEC, SOCK_DGRAM  },
+	  { "tcp:",  AF_UNSPEC, SOCK_STREAM },
+	  { "udp4:", AF_INET,   SOCK_DGRAM  },
+	  { "tcp4:", AF_INET,   SOCK_STREAM },
+	  { "udp6:", AF_INET6,  SOCK_DGRAM  },
+	  { "tcp6:", AF_INET6,  SOCK_STREAM },
+	};
+      const struct prefix *prefix;
+      struct addrinfo hints, *hints_p = NULL;
+      struct addrinfo *addrinfo_base, *addrinfo = NULL;
+      char back_host[64], back_port[16];
+      int fake_any = 0, err;
+      char *name_base;
+      struct address
+	{
+	  const char *string;
+	  int family;
+	};
+      const struct address addresses[] =
+        {
+	  { "::",        AF_INET6  },
+	  { "127.0.0.1", AF_INET   },
+	  { "localhost", AF_UNSPEC },
+	};
+      const struct address *address;
+
+      name_base = strdup (name);
+      name = name_base;
+      for (prefix = prefixes;
+           prefix < prefixes + sizeof (prefixes) / sizeof (*prefixes);
+	   prefix++)
+	if (strncmp (name, prefix->string, strlen (prefix->string)) == 0)
+	  {
+	    name += strlen (prefix->string);
+	    memset (&hints, 0, sizeof (hints));
+	    hints.ai_family   = prefix->family;
+	    hints.ai_socktype = prefix->socktype;
+	    hints_p = &hints;
+	    break;
+	  }
+      if (!(hints_p != NULL && hints_p->ai_family == AF_INET)
+	  && name[0] == '[' && (port_str = strchr (name, ']')))
+	{
+	  name++;
+	  *port_str++ = 0;
+	}
+      else
+	port_str = strchr (name, ':');
+      /* It may happen with IPv6 for like "[::1]".  */
+      if (port_str == NULL || *port_str != ':')
+        {
+	  fprintf (stderr, "net_open: No colon in host name!\n");
+	  fflush (stderr);
+	  exit (1);
+	}
+      *port_str++ = 0;
 
-      port_str = strchr (name, ':');
+      /* We need to provide some fake name for resolving.
+         but I am not aware of any universal host string for both
+	 `INADDR_ANY' and `in6addr_any'.
+	 So we try those from `addresses' in the specified order.  */
+      if (name[0] == 0)
+	fake_any = 1;
+
+      for (address = addresses;
+           address < addresses + sizeof (addresses) / sizeof (*addresses);
+	   address++)
+        {
+	  int fatal;
+
+	  if (fake_any)
+	    {
+	      if (address->family != AF_UNSPEC
+		  && hints_p != NULL && hints_p->ai_family != address->family)
+		continue;
+	      name = (char *) address->string;
+	      fatal = (address + 1
+	               >= addresses + sizeof (addresses) / sizeof (*addresses));
+	    }
+	  else
+	    fatal = 1;
+
+	  err = getaddrinfo (name, port_str, hints_p, &addrinfo_base);
+	  if (err != 0)
+	    {
+	      if (!fatal)
+		continue;
+	      /* `name_base' is used here for `port_str'.  */
+	      fprintf (stderr, "%s:%s: cannot resolve name: %s\n",
+		       name, port_str, gai_strerror (err));
+	      fflush (stderr);
+	      exit (1);
+	    }
+	  free (name_base);
+
+	  for (addrinfo = addrinfo_base;
+	       addrinfo != NULL;
+	       addrinfo = addrinfo->ai_next)
+	    {
+	      tmp_desc = socket (addrinfo->ai_family, addrinfo->ai_socktype,
+				addrinfo->ai_protocol);
+	      if (tmp_desc >= 0)
+		break;
+	    }
+	  if (addrinfo == NULL)
+	    {
+	      if (!fatal)
+		continue;
+	      freeaddrinfo (addrinfo_base);
+	      perror_with_name ("Can't open socket");
+	    }
+	  break;
+        }
 
-      port = atoi (port_str + 1);
+      if (fake_any)
+	switch (addrinfo->ai_family)
+	{
+	case AF_INET:
+	  ((struct sockaddr_in *)addrinfo->ai_addr)->sin_addr.s_addr
+	    = INADDR_ANY;
+	  break;
+	case AF_INET6:
+	  memcpy (&((struct sockaddr_in6 *)addrinfo->ai_addr)->sin6_addr,
+	          &in6addr_any, sizeof (in6addr_any));
+	  break;
+	default:
+	  fprintf (stderr, "Error setting 'any' listening for ai_family %d",
+		   addrinfo->ai_family);
+	}
 
 #ifdef USE_WIN32API
       if (!winsock_initialized)
@@ -146,55 +279,83 @@ remote_open (char *name)
 	}
 #endif
 
-      tmp_desc = socket (PF_INET, SOCK_STREAM, 0);
-      if (tmp_desc < 0)
-	perror_with_name ("Can't open socket");
-
       /* Allow rapid reuse of this port. */
       tmp = 1;
       setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
 		  sizeof (tmp));
 
-      sockaddr.sin_family = PF_INET;
-      sockaddr.sin_port = htons (port);
-      sockaddr.sin_addr.s_addr = INADDR_ANY;
-
-      if (bind (tmp_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
-	  || listen (tmp_desc, 1))
-	perror_with_name ("Can't bind address");
-
-      tmp = sizeof (sockaddr);
-      remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, &tmp);
-      if (remote_desc == -1)
-	perror_with_name ("Accept failed");
-
-      /* Enable TCP keep alive process. */
-      tmp = 1;
-      setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *) &tmp, sizeof (tmp));
-
-      /* Tell TCP not to delay small packets.  This greatly speeds up
-         interactive response. */
-      tmp = 1;
-      setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY,
-		  (char *) &tmp, sizeof (tmp));
+      if (bind (tmp_desc, addrinfo->ai_addr, addrinfo->ai_addrlen)
+	  || (addrinfo->ai_socktype != SOCK_DGRAM && listen (tmp_desc, 1)))
+        {
+	  freeaddrinfo (addrinfo_base);
+	  perror_with_name ("Can't bind address");
+        }
+
+      if (0 != getnameinfo (addrinfo->ai_addr, addrinfo->ai_addrlen,
+			    back_host, sizeof (back_host),
+			    back_port, sizeof (back_port),
+			    NI_NUMERICHOST | NI_NUMERICSERV))
+	fprintf (stderr, "Error detecting listening address, trying anyway\n");
+      else
+	fprintf (stderr, "Listening on port %s (on host %s)\n",
+		 back_port, back_host);
+      fflush (stderr);
 
-      close (tmp_desc);		/* No longer need this */
+      if (addrinfo->ai_socktype == SOCK_DGRAM)
+        remote_desc = tmp_desc;
+      else
+        {
+	  struct sockaddr_in6 sockaddr6;
+	  socklen_t sockaddr6_len;
+	  sockaddr6_len = sizeof (sockaddr6);
+	  remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr6, &sockaddr6_len);
+	  if (remote_desc == -1)
+	    {
+	      freeaddrinfo (addrinfo_base);
+	      perror_with_name ("Accept failed");
+	    }
+
+	  /* Enable TCP keep alive process. */
+	  tmp = 1;
+	  setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *) &tmp, sizeof (tmp));
+
+	  /* Tell TCP not to delay small packets.  This greatly speeds up
+	     interactive response. */
+	  if (addrinfo->ai_socktype == SOCK_STREAM)
+	    {
+	      tmp = 1;
+	      setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY,
+			  (char *) &tmp, sizeof (tmp));
+	    }
+	  freeaddrinfo (addrinfo_base);
 
 #ifndef USE_WIN32API
-      close (tmp_desc);		/* No longer need this */
+	  close (tmp_desc);		/* No longer need this */
 
-      signal (SIGPIPE, SIG_IGN);	/* If we don't do this, then gdbreplay 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.  */
 #else
-      closesocket (tmp_desc);	/* No longer need this */
+	  closesocket (tmp_desc);	/* No longer need this */
 #endif
+
+	  /* Convert IP address to string.  */
+	  if (0 != getnameinfo ((struct sockaddr *) &sockaddr6, sockaddr6_len,
+				back_host, sizeof (back_host),
+				back_port, sizeof (back_port),
+				NI_NUMERICHOST | NI_NUMERICSERV))
+	    fprintf (stderr, "Error detecting originating address, trying anyway\n");
+	  else
+	    fprintf (stderr, "Remote debugging from host %s port %s\n",
+		     back_host, back_port);
+	}
+      fflush (stderr);
     }
 
 #if defined(F_SETFL) && defined (FASYNC)
   fcntl (remote_desc, F_SETFL, FASYNC);
 #endif
 
-  fprintf (stderr, "Replay logfile using %s\n", name);
+  fprintf (stderr, "Replay logfile using %s\n", name_orig);
   fflush (stderr);
 }
 
Index: gdb/gdbserver/remote-utils.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/remote-utils.c,v
retrieving revision 1.32
diff -u -p -r1.32 remote-utils.c
--- gdb/gdbserver/remote-utils.c	21 Sep 2006 16:09:54 -0000	1.32
+++ gdb/gdbserver/remote-utils.c	27 Sep 2006 13:11:10 -0000
@@ -157,14 +157,139 @@ remote_open (char *name)
       static int winsock_initialized;
 #endif
       char *port_str;
-      int port;
-      struct sockaddr_in sockaddr;
       socklen_t tmp;
-      int tmp_desc;
+      int tmp_desc = -1;
+      struct prefix
+	{
+	  const char *string;
+	  int family;
+	  int socktype;
+	};
+      const struct prefix prefixes[] =
+	{
+	  { "udp:",  AF_UNSPEC, SOCK_DGRAM  },
+	  { "tcp:",  AF_UNSPEC, SOCK_STREAM },
+	  { "udp4:", AF_INET,   SOCK_DGRAM  },
+	  { "tcp4:", AF_INET,   SOCK_STREAM },
+	  { "udp6:", AF_INET6,  SOCK_DGRAM  },
+	  { "tcp6:", AF_INET6,  SOCK_STREAM },
+	};
+      const struct prefix *prefix;
+      struct addrinfo hints, *hints_p = NULL;
+      struct addrinfo *addrinfo_base, *addrinfo = NULL;
+      char back_host[64], back_port[16];
+      int fake_any = 0, err;
+      char *name_base;
+      struct address
+	{
+	  const char *string;
+	  int family;
+	};
+      const struct address addresses[] =
+        {
+	  { "::",        AF_INET6  },
+	  { "127.0.0.1", AF_INET   },
+	  { "localhost", AF_UNSPEC },
+	};
+      const struct address *address;
+
+      name_base = strdup (name);
+      name = name_base;
+      for (prefix = prefixes;
+           prefix < prefixes + sizeof (prefixes) / sizeof (*prefixes);
+	   prefix++)
+	if (strncmp (name, prefix->string, strlen (prefix->string)) == 0)
+	  {
+	    name += strlen (prefix->string);
+	    memset (&hints, 0, sizeof (hints));
+	    hints.ai_family   = prefix->family;
+	    hints.ai_socktype = prefix->socktype;
+	    hints_p = &hints;
+	    break;
+	  }
+      if (!(hints_p != NULL && hints_p->ai_family == AF_INET)
+	  && name[0] == '[' && (port_str = strchr (name, ']')))
+	{
+	  name++;
+	  *port_str++ = 0;
+	}
+      else
+	port_str = strchr (name, ':');
+      /* It may happen with IPv6 for like "[::1]".  */
+      if (port_str == NULL || *port_str != ':')
+	error ("net_open: No colon in host name!");
+      *port_str++ = 0;
+
+      /* We need to provide some fake name for resolving.
+         but I am not aware of any universal host string for both
+	 `INADDR_ANY' and `in6addr_any'.
+	 So we try those from `addresses' in the specified order.  */
+      if (name[0] == 0)
+	fake_any = 1;
+
+      for (address = addresses;
+           address < addresses + sizeof (addresses) / sizeof (*addresses);
+	   address++)
+        {
+	  int fatal;
+
+	  if (fake_any)
+	    {
+	      if (address->family != AF_UNSPEC
+		  && hints_p != NULL && hints_p->ai_family != address->family)
+		continue;
+	      name = (char *) address->string;
+	      fatal = (address + 1
+	               >= addresses + sizeof (addresses) / sizeof (*addresses));
+	    }
+	  else
+	    fatal = 1;
+
+	  err = getaddrinfo (name, port_str, hints_p, &addrinfo_base);
+	  if (err != 0)
+	    {
+	      if (!fatal)
+		continue;
+	      /* `name_base' is used here for `port_str'.  */
+	      error ("%s:%s: cannot resolve name: %s\n",
+		       name, port_str, gai_strerror (err));
+	    }
+	  free (name_base);
 
-      port_str = strchr (name, ':');
+	  for (addrinfo = addrinfo_base;
+	       addrinfo != NULL;
+	       addrinfo = addrinfo->ai_next)
+	    {
+	      tmp_desc = socket (addrinfo->ai_family, addrinfo->ai_socktype,
+				addrinfo->ai_protocol);
+	      if (tmp_desc >= 0)
+		break;
+	    }
+	  if (addrinfo == NULL)
+	    {
+	      if (!fatal)
+		continue;
+	      freeaddrinfo (addrinfo_base);
+	      perror_with_name ("Can't open socket");
+	    }
+	  break;
+        }
 
-      port = atoi (port_str + 1);
+      if (fake_any)
+	switch (addrinfo->ai_family)
+	{
+	case AF_INET:
+	  ((struct sockaddr_in *)addrinfo->ai_addr)->sin_addr.s_addr
+	    = INADDR_ANY;
+	  break;
+	case AF_INET6:
+	  memcpy (&((struct sockaddr_in6 *)addrinfo->ai_addr)->sin6_addr,
+	          &in6addr_any, sizeof (in6addr_any));
+	  break;
+	default:
+	  fprintf (stderr, "Error setting 'any' listening for ai_family %d",
+		   addrinfo->ai_family);
+	}
 
 #ifdef USE_WIN32API
       if (!winsock_initialized)
@@ -176,54 +301,76 @@ remote_open (char *name)
 	}
 #endif
 
-      tmp_desc = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
-      if (tmp_desc < 0)
-	perror_with_name ("Can't open socket");
-
       /* Allow rapid reuse of this port. */
       tmp = 1;
       setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
 		  sizeof (tmp));
 
-      sockaddr.sin_family = PF_INET;
-      sockaddr.sin_port = htons (port);
-      sockaddr.sin_addr.s_addr = INADDR_ANY;
-
-      if (bind (tmp_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
-	  || listen (tmp_desc, 1))
-	perror_with_name ("Can't bind address");
+      if (bind (tmp_desc, addrinfo->ai_addr, addrinfo->ai_addrlen)
+	  || (addrinfo->ai_socktype != SOCK_DGRAM && listen (tmp_desc, 1)))
+        {
+	  freeaddrinfo (addrinfo_base);
+	  perror_with_name ("Can't bind address");
+        }
 
-      fprintf (stderr, "Listening on port %d\n", port);
+      if (0 != getnameinfo (addrinfo->ai_addr, addrinfo->ai_addrlen,
+			    back_host, sizeof (back_host),
+			    back_port, sizeof (back_port),
+			    NI_NUMERICHOST | NI_NUMERICSERV))
+	fprintf (stderr, "Error detecting listening address, trying anyway\n");
+      else
+	fprintf (stderr, "Listening on port %s (on host %s)\n",
+		 back_port, back_host);
       fflush (stderr);
 
-      tmp = sizeof (sockaddr);
-      remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, &tmp);
-      if (remote_desc == -1)
-	perror_with_name ("Accept failed");
-
-      /* Enable TCP keep alive process. */
-      tmp = 1;
-      setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *) &tmp, sizeof (tmp));
-
-      /* Tell TCP not to delay small packets.  This greatly speeds up
-         interactive response. */
-      tmp = 1;
-      setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY,
-		  (char *) &tmp, sizeof (tmp));
+      if (addrinfo->ai_socktype == SOCK_DGRAM)
+        remote_desc = tmp_desc;
+      else
+        {
+	  struct sockaddr_in6 sockaddr6;
+	  socklen_t sockaddr6_len;
+	  sockaddr6_len = sizeof (sockaddr6);
+	  remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr6, &sockaddr6_len);
+	  if (remote_desc == -1)
+	    {
+	      freeaddrinfo (addrinfo_base);
+	      perror_with_name ("Accept failed");
+	    }
 
+	  /* Enable TCP keep alive process. */
+	  tmp = 1;
+	  setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *) &tmp, sizeof (tmp));
+
+	  /* Tell TCP not to delay small packets.  This greatly speeds up
+	     interactive response. */
+	  if (addrinfo->ai_socktype == SOCK_STREAM)
+	    {
+	      tmp = 1;
+	      setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY,
+			  (char *) &tmp, sizeof (tmp));
+	    }
+	  freeaddrinfo (addrinfo_base);
 
 #ifndef USE_WIN32API
-      close (tmp_desc);		/* No longer need this */
+	  close (tmp_desc);		/* No longer need this */
 
-      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.  */
 #else
-      closesocket (tmp_desc);	/* No longer need this */
+	  closesocket (tmp_desc);	/* No longer need this */
 #endif
 
-      /* Convert IP address to string.  */
-      fprintf (stderr, "Remote debugging from host %s\n", 
-         inet_ntoa (sockaddr.sin_addr));
+	  /* Convert IP address to string.  */
+	  if (0 != getnameinfo ((struct sockaddr *) &sockaddr6, sockaddr6_len,
+				back_host, sizeof (back_host),
+				back_port, sizeof (back_port),
+				NI_NUMERICHOST | NI_NUMERICSERV))
+	    fprintf (stderr, "Error detecting originating address, trying anyway\n");
+	  else
+	    fprintf (stderr, "Remote debugging from host %s port %s\n",
+		     back_host, back_port);
+	}
+      fflush (stderr);
     }
 
 #if defined(F_SETFL) && defined (FASYNC)
Index: gdb/doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.355
diff -u -p -r1.355 gdb.texinfo
--- gdb/doc/gdb.texinfo	21 Sep 2006 14:01:12 -0000	1.355
+++ gdb/doc/gdb.texinfo	27 Sep 2006 13:11:10 -0000
@@ -12404,8 +12404,10 @@ If you're using a serial line, you may w
 (@pxref{Remote configuration, set remotebaud}) before the
 @code{target} command.
 
-@item target remote @code{@var{host}:@var{port}}
+@item  target remote @code{@var{host}:@var{port}}
 @itemx target remote @code{tcp:@var{host}:@var{port}}
+@itemx target remote @code{tcp4:@var{host}:@var{port}}
+@itemx target remote @code{tcp6:@var{host}:@var{port}}
 @cindex @acronym{TCP} port, @code{target remote}
 Debug using a @acronym{TCP} connection to @var{port} on @var{host}.
 The @var{host} may be either a host name or a numeric @acronym{IP}
@@ -12414,6 +12416,9 @@ the target machine itself, if it is dire
 it might be a terminal server which in turn has a serial line to the
 target.
 
+@code{tcp6:} prefix forces IPv6 network connection while @code{tcp4:} forces
+IPv4, both on the reliable stream TCP connection.
+
 For example, to connect to port 2828 on a terminal server named
 @code{manyfarms}:
 
@@ -12434,10 +12439,15 @@ target remote :1234
 Note that the colon is still required here.
 
 @item target remote @code{udp:@var{host}:@var{port}}
+@itemx target remote @code{udp6:@var{host}:@var{port}}
+@itemx target remote @code{udp4:@var{host}:@var{port}}
 @cindex @acronym{UDP} port, @code{target remote}
 Debug using @acronym{UDP} packets to @var{port} on @var{host}.  For example, to
 connect to @acronym{UDP} port 2828 on a terminal server named @code{manyfarms}:
 
+@code{udp6:} prefix forces IPv6 network connection while @code{udp4:} forces
+IPv4, both on the unreliable datagram UDP connection.
+
 @smallexample
 target remote udp:manyfarms:2828
 @end smallexample
@@ -12578,14 +12588,30 @@ The only difference from the previous ex
 specifying that you are communicating with the host @value{GDBN} via
 TCP.  The @samp{host:2345} argument means that @code{gdbserver} is to
 expect a TCP connection from machine @samp{host} to local TCP port 2345.
-(Currently, the @samp{host} part is ignored.)  You can choose any number
-you want for the port number as long as it does not conflict with any
-TCP ports already in use on the target system (for example, @code{23} is
-reserved for @code{telnet}).@footnote{If you choose a port number that
-conflicts with another service, @code{gdbserver} prints an error message
+(The @samp{host} part is usually omitted as it defaults to listen from any
+host. You may use a local address as expected by the @code{bind} syscall.)
+You can choose any number you want for the port number as long as it does not
+conflict with any TCP ports already in use on the target system (for example,
+@code{23} is reserved for @code{telnet}).@footnote{If you choose a port number
+that conflicts with another service, @code{gdbserver} prints an error message
 and exits.}  You must use the same port number with the host @value{GDBN}
 @code{target remote} command.
 
+@item  gdbserver @code{tcp:@var{host}:@var{port}} emacs foo.txt
+@itemx gdbserver @code{tcp6:@var{host}:@var{port}} emacs foo.txt
+@itemx gdbserver @code{tcp4:@var{host}:@var{port}} emacs foo.txt
+@itemx gdbserver @code{udp:@var{host}:@var{port}} emacs foo.txt
+@itemx gdbserver @code{udp6:@var{host}:@var{port}} emacs foo.txt
+@itemx gdbserver @code{udp4:@var{host}:@var{port}} emacs foo.txt
+
+The @code{::} part can be also replaced by the optional @var{host} part as
+in the sample case of @code{tcp:@var{host}:@var{port}}.
+These all alternative syntaxes force either the reliable stream TCP protocol or
+the unreliable datagram UDP protocol appropriately.  You may also force the use
+of IPv6 or IPv4 network connections; @code{tcp:} and @code{udp:} select the
+network version type according to the provided @var{host}.
+The connection type defaults to the @code{tcp:} prefix behavior.
+
 On some targets, @code{gdbserver} can also attach to running programs.
 This is accomplished via the @code{--attach} argument.  The syntax is:
 


More information about the Gdb-patches mailing list