Blame SOURCES/gdb-rhbz881849-ipv6-1of3.patch

4c2ad1
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
4c2ad1
From: Sergio Durigan Junior <sergiodj@redhat.com>
4c2ad1
Date: Fri, 18 May 2018 01:29:24 -0400
4c2ad1
Subject: gdb-rhbz881849-ipv6-1of3.patch
4c2ad1
4c2ad1
;; Implement IPv6 support for GDB/gdbserver (RH BZ 881849, Sergio Durigan Junior).
4c2ad1
4c2ad1
Implement IPv6 support for GDB/gdbserver
4c2ad1
4c2ad1
This patch implements IPv6 support for both GDB and gdbserver.  Based
4c2ad1
on my research, it is the fourth attempt to do that since 2006.  Since
4c2ad1
I used ideas from all of the previous patches, I also added their
4c2ad1
authors's names on the ChangeLogs as a way to recognize their
4c2ad1
efforts.  For reference sake, you can find the previous attempts at:
4c2ad1
4c2ad1
  https://sourceware.org/ml/gdb-patches/2006-09/msg00192.html
4c2ad1
4c2ad1
  https://sourceware.org/ml/gdb-patches/2014-02/msg00248.html
4c2ad1
4c2ad1
  https://sourceware.org/ml/gdb-patches/2016-02/msg00226.html
4c2ad1
4c2ad1
The basic idea behind the patch is to start using the new
4c2ad1
'getaddrinfo'/'getnameinfo' calls, which are responsible for
4c2ad1
translating names and addresses in a protocol-independent way.  This
4c2ad1
means that if we ever have a new version of the IP protocol, we won't
4c2ad1
need to change the code again (or, at least, won't have to change the
4c2ad1
majority of the code).
4c2ad1
4c2ad1
The function 'getaddrinfo' returns a linked list of possible addresses
4c2ad1
to connect to.  Dealing with multiple addresses proved to be a hard
4c2ad1
task with the current TCP auto-retry mechanism implemented on
4c2ad1
ser-tcp:net_open.  For example, when gdbserver listened only on an
4c2ad1
IPv4 socket:
4c2ad1
4c2ad1
  $ ./gdbserver --once 127.0.0.1:1234 ./a.out
4c2ad1
4c2ad1
and GDB was instructed to try to connect to both IPv6 and IPv4
4c2ad1
sockets:
4c2ad1
4c2ad1
  $ ./gdb -ex 'target extended-remote localhost:1234' ./a.out
4c2ad1
4c2ad1
the user would notice a somewhat big delay before GDB was able to
4c2ad1
connect to the IPv4 socket.  This happened because GDB was trying to
4c2ad1
connect to the IPv6 socket first, and had to wait until the connection
4c2ad1
timed out before it tried to connect to the IPv4 socket.
4c2ad1
4c2ad1
For that reason, I had to rewrite the main loop and implement a new
4c2ad1
method for handling multiple connections.  After some discussion,
4c2ad1
Pedro and I agreed on the following algorithm:
4c2ad1
4c2ad1
  1) For each entry returned by 'getaddrinfo', we try to open a socket
4c2ad1
  and connect to it.
4c2ad1
4c2ad1
  2.a) If we have a successful 'connect', we just use that connection.
4c2ad1
4c2ad1
  2.b) If we don't have a successfull 'connect', but if we've got a
4c2ad1
  ECONNREFUSED (meaning the the connection was refused), we keep track
4c2ad1
  of this fact by using a flag.
4c2ad1
4c2ad1
  2.c) If we don't have a successfull 'connect', but if we've got a
4c2ad1
  EINPROGRESS (meaning that the connection is in progress), we perform
4c2ad1
  a 'select' call on the socket until we have a result (either a
4c2ad1
  successful connection, or an error on the socket).
4c2ad1
4c2ad1
  3) If tcp_auto_retry is true, and we haven't gotten a successful
4c2ad1
  connection, and at least one of our attempts failed with
4c2ad1
  ECONNREFUSED, then we wait a little bit (i.e., call
4c2ad1
  'wait_for_connect'), check to see if there was a
4c2ad1
  timeout/interruption (in which case we bail out), and then go back
4c2ad1
  to (1).
4c2ad1
4c2ad1
After multiple tests, I was able to connect without delay on the
4c2ad1
scenario described above, and was also able to connect in all other
4c2ad1
types of scenarios.
4c2ad1
4c2ad1
I also implemented some hostname parsing functions (along with their
4c2ad1
corresponding unit tests) which are used to help GDB and gdbserver to
4c2ad1
parse hostname strings provided by the user.  These new functions are
4c2ad1
living inside common/netstuff.[ch].  I've had to do that since IPv6
4c2ad1
introduces a new URL scheme, which defines that square brackets can be
4c2ad1
used to enclose the host part and differentiate it from the
4c2ad1
port (e.g., "[::1]:1234" means "host ::1, port 1234").  I spent some
4c2ad1
time thinking about a reasonable way to interpret what the user wants,
4c2ad1
and I came up with the following:
4c2ad1
4c2ad1
  - If the user has provided a prefix that doesn't specify the protocol
4c2ad1
    version (i.e., "tcp:" or "udp:"), or if the user has not provided
4c2ad1
    any prefix, don't make any assumptions (i.e., assume AF_UNSPEC when
4c2ad1
    dealing with 'getaddrinfo') *unless* the host starts with "[" (in
4c2ad1
    which case, assume it's an IPv6 host).
4c2ad1
4c2ad1
  - If the user has provided a prefix that does specify the protocol
4c2ad1
    version (i.e., "tcp4:", "tcp6:", "udp4:" or "udp6:"), then respect
4c2ad1
    that.
4c2ad1
4c2ad1
This method doesn't follow strictly what RFC 2732 proposes (that
4c2ad1
literal IPv6 addresses should be provided enclosed in "[" and "]")
4c2ad1
because IPv6 addresses still can be provided without square brackets
4c2ad1
in our case, but since we have prefixes to specify protocol versions I
4c2ad1
think this is not an issue.
4c2ad1
4c2ad1
Another thing worth mentioning is the new 'GDB_TEST_SOCKETHOST'
4c2ad1
testcase parameter, which makes it possible to specify the
4c2ad1
hostname (without the port) to be used when testing GDB and
4c2ad1
gdbserver.  For example, to run IPv6 tests:
4c2ad1
4c2ad1
  $ make check-gdb RUNTESTFLAGS='GDB_TEST_SOCKETHOST=tcp6:[::1]'
4c2ad1
4c2ad1
Or, to run IPv4 tests:
4c2ad1
4c2ad1
  $ make check-gdb RUNTESTFLAGS='GDB_TEST_SOCKETHOST=tcp4:127.0.0.1'
4c2ad1
4c2ad1
This required a few changes on the gdbserver-base.exp, and also a
4c2ad1
minimal adjustment on gdb.server/run-without-local-binary.exp.
4c2ad1
4c2ad1
Finally, I've implemented a new testcase,
4c2ad1
gdb.server/server-connect.exp, which is supposed to run on the native
4c2ad1
host and perform various "smoke tests" using different connection
4c2ad1
methods.
4c2ad1
4c2ad1
This patch has been regression-tested on BuildBot and locally, and
4c2ad1
also built using a x86_64-w64-mingw32 GCC, and no problems were found.
4c2ad1
4c2ad1
gdb/ChangeLog:
4c2ad1
2018-07-11  Sergio Durigan Junior  <sergiodj@redhat.com>
4c2ad1
	    Jan Kratochvil  <jan.kratochvil@redhat.com>
4c2ad1
	    Paul Fertser  <fercerpav@gmail.com>
4c2ad1
	    Tsutomu Seki  <sekiriki@gmail.com>
4c2ad1
	    Pedro Alves  <palves@redhat.com>
4c2ad1
4c2ad1
	* Makefile.in (SUBDIR_UNITTESTS_SRCS): Add
4c2ad1
	'unittests/parse-connection-spec-selftests.c'.
4c2ad1
	(COMMON_SFILES): Add 'common/netstuff.c'.
4c2ad1
	(HFILES_NO_SRCDIR): Add 'common/netstuff.h'.
4c2ad1
	* NEWS (Changes since GDB 8.2): Mention IPv6 support.
4c2ad1
	* common/netstuff.c: New file.
4c2ad1
	* common/netstuff.h: New file.
4c2ad1
	* ser-tcp.c: Include 'netstuff.h' and 'wspiapi.h'.
4c2ad1
	(wait_for_connect): Update comment.  New parameter
4c2ad1
	'gdb::optional<int> sock' instead of 'struct serial *scb'.
4c2ad1
	Use 'sock' directly instead of 'scb->fd'.
4c2ad1
	(try_connect): New function, with code from 'net_open'.
4c2ad1
	(net_open): Rewrite main loop to deal with multiple
4c2ad1
	sockets/addresses.  Handle IPv6-style hostnames; implement
4c2ad1
	support for IPv6 connections.
4c2ad1
	* unittests/parse-connection-spec-selftests.c: New file.
4c2ad1
4c2ad1
gdb/gdbserver/ChangeLog:
4c2ad1
2018-07-11  Sergio Durigan Junior  <sergiodj@redhat.com>
4c2ad1
	    Jan Kratochvil  <jan.kratochvil@redhat.com>
4c2ad1
	    Paul Fertser  <fercerpav@gmail.com>
4c2ad1
	    Tsutomu Seki  <sekiriki@gmail.com>
4c2ad1
4c2ad1
	* Makefile.in (SFILES): Add '$(srcdir)/common/netstuff.c'.
4c2ad1
	(OBS): Add 'common/netstuff.o'.
4c2ad1
	(GDBREPLAY_OBS): Likewise.
4c2ad1
	* gdbreplay.c: Include 'wspiapi.h' and 'netstuff.h'.
4c2ad1
	(remote_open): Implement support for IPv6
4c2ad1
	connections.
4c2ad1
	* remote-utils.c: Include 'netstuff.h', 'filestuff.h'
4c2ad1
	and 'wspiapi.h'.
4c2ad1
	(handle_accept_event): Accept connections from IPv6 sources.
4c2ad1
	(remote_prepare): Handle IPv6-style hostnames; implement
4c2ad1
	support for IPv6 connections.
4c2ad1
	(remote_open): Implement support for printing connections from
4c2ad1
	IPv6 sources.
4c2ad1
4c2ad1
gdb/testsuite/ChangeLog:
4c2ad1
2018-07-11  Sergio Durigan Junior  <sergiodj@redhat.com>
4c2ad1
	    Jan Kratochvil  <jan.kratochvil@redhat.com>
4c2ad1
	    Paul Fertser  <fercerpav@gmail.com>
4c2ad1
	    Tsutomu Seki  <sekiriki@gmail.com>
4c2ad1
4c2ad1
	* README (Testsuite Parameters): Mention new 'GDB_TEST_SOCKETHOST'
4c2ad1
	parameter.
4c2ad1
	* boards/native-extended-gdbserver.exp: Do not set 'sockethost'
4c2ad1
	by default.
4c2ad1
	* boards/native-gdbserver.exp: Likewise.
4c2ad1
	* gdb.server/run-without-local-binary.exp: Improve regexp used
4c2ad1
	for detecting when a remote debugging connection succeeds.
4c2ad1
	* gdb.server/server-connect.exp: New file.
4c2ad1
	* lib/gdbserver-support.exp (gdbserver_default_get_comm_port):
4c2ad1
	Do not prefix the port number with ":".
4c2ad1
	(gdbserver_start): New global GDB_TEST_SOCKETHOST.  Implement
4c2ad1
	support for detecting and using it.  Add '$debughost_gdbserver'
4c2ad1
	to the list of arguments used to start gdbserver.  Handle case
4c2ad1
	when gdbserver cannot resolve a network name.
4c2ad1
4c2ad1
gdb/doc/ChangeLog:
4c2ad1
2018-07-11  Sergio Durigan Junior  <sergiodj@redhat.com>
4c2ad1
	    Jan Kratochvil  <jan.kratochvil@redhat.com>
4c2ad1
	    Paul Fertser  <fercerpav@gmail.com>
4c2ad1
	    Tsutomu Seki  <sekiriki@gmail.com>
4c2ad1
4c2ad1
	* gdb.texinfo (Remote Connection Commands): Add explanation
4c2ad1
	about new IPv6 support.  Add new connection prefixes.
4c2ad1
4c2ad1
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
4c2ad1
--- a/gdb/Makefile.in
4c2ad1
+++ b/gdb/Makefile.in
4c2ad1
@@ -430,6 +430,7 @@ SUBDIR_UNITTESTS_SRCS = \
4c2ad1
 	unittests/offset-type-selftests.c \
4c2ad1
 	unittests/observable-selftests.c \
4c2ad1
 	unittests/optional-selftests.c \
4c2ad1
+	unittests/parse-connection-spec-selftests.c \
4c2ad1
 	unittests/ptid-selftests.c \
4c2ad1
 	unittests/rsp-low-selftests.c \
4c2ad1
 	unittests/scoped_fd-selftests.c \
4c2ad1
@@ -967,6 +968,7 @@ COMMON_SFILES = \
4c2ad1
 	common/job-control.c \
4c2ad1
 	common/gdb_tilde_expand.c \
4c2ad1
 	common/gdb_vecs.c \
4c2ad1
+	common/netstuff.c \
4c2ad1
 	common/new-op.c \
4c2ad1
 	common/pathstuff.c \
4c2ad1
 	common/print-utils.c \
4c2ad1
@@ -1448,6 +1450,7 @@ HFILES_NO_SRCDIR = \
4c2ad1
 	common/gdb_vecs.h \
4c2ad1
 	common/gdb_wait.h \
4c2ad1
 	common/common-inferior.h \
4c2ad1
+	common/netstuff.h \
4c2ad1
 	common/host-defs.h \
4c2ad1
 	common/pathstuff.h \
4c2ad1
 	common/print-utils.h \
4c2ad1
diff --git a/gdb/NEWS b/gdb/NEWS
4c2ad1
--- a/gdb/NEWS
4c2ad1
+++ b/gdb/NEWS
4c2ad1
@@ -1,6 +1,12 @@
4c2ad1
 		What has changed in GDB?
4c2ad1
 	     (Organized release by release)
4c2ad1
 
4c2ad1
+*** Changes since GDB 8.2
4c2ad1
+
4c2ad1
+* GDB and GDBserver now support IPv6 connections.  IPv6 addresses
4c2ad1
+  can be passed using the '[ADDRESS]:PORT' notation, or the regular
4c2ad1
+  'ADDRESS:PORT' method.
4c2ad1
+
4c2ad1
 *** Changes in GDB 8.2
4c2ad1
 
4c2ad1
 * The 'set disassembler-options' command now supports specifying options
4c2ad1
diff --git a/gdb/common/netstuff.c b/gdb/common/netstuff.c
4c2ad1
new file mode 100644
4c2ad1
--- /dev/null
4c2ad1
+++ b/gdb/common/netstuff.c
4c2ad1
@@ -0,0 +1,155 @@
4c2ad1
+/* Operations on network stuff.
4c2ad1
+   Copyright (C) 2018 Free Software Foundation, Inc.
4c2ad1
+
4c2ad1
+   This file is part of GDB.
4c2ad1
+
4c2ad1
+   This program is free software; you can redistribute it and/or modify
4c2ad1
+   it under the terms of the GNU General Public License as published by
4c2ad1
+   the Free Software Foundation; either version 3 of the License, or
4c2ad1
+   (at your option) any later version.
4c2ad1
+
4c2ad1
+   This program is distributed in the hope that it will be useful,
4c2ad1
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
4c2ad1
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4c2ad1
+   GNU General Public License for more details.
4c2ad1
+
4c2ad1
+   You should have received a copy of the GNU General Public License
4c2ad1
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
4c2ad1
+
4c2ad1
+#include "common-defs.h"
4c2ad1
+#include "netstuff.h"
4c2ad1
+#include <algorithm>
4c2ad1
+
4c2ad1
+#ifdef USE_WIN32API
4c2ad1
+#include <winsock2.h>
4c2ad1
+#include <wspiapi.h>
4c2ad1
+#else
4c2ad1
+#include <netinet/in.h>
4c2ad1
+#include <arpa/inet.h>
4c2ad1
+#include <netdb.h>
4c2ad1
+#include <sys/socket.h>
4c2ad1
+#include <netinet/tcp.h>
4c2ad1
+#endif
4c2ad1
+
4c2ad1
+/* See common/netstuff.h.  */
4c2ad1
+
4c2ad1
+scoped_free_addrinfo::~scoped_free_addrinfo ()
4c2ad1
+{
4c2ad1
+  freeaddrinfo (m_res);
4c2ad1
+}
4c2ad1
+
4c2ad1
+/* See common/netstuff.h.  */
4c2ad1
+
4c2ad1
+parsed_connection_spec
4c2ad1
+parse_connection_spec_without_prefix (std::string spec, struct addrinfo *hint)
4c2ad1
+{
4c2ad1
+  parsed_connection_spec ret;
4c2ad1
+  size_t last_colon_pos = 0;
4c2ad1
+  /* We're dealing with IPv6 if:
4c2ad1
+
4c2ad1
+     - ai_family is AF_INET6, or
4c2ad1
+     - ai_family is not AF_INET, and
4c2ad1
+       - spec[0] is '[', or
4c2ad1
+       - the number of ':' on spec is greater than 1.  */
4c2ad1
+  bool is_ipv6 = (hint->ai_family == AF_INET6
4c2ad1
+		  || (hint->ai_family != AF_INET
4c2ad1
+		      && (spec[0] == '['
4c2ad1
+			  || std::count (spec.begin (),
4c2ad1
+					 spec.end (), ':') > 1)));
4c2ad1
+
4c2ad1
+  if (is_ipv6)
4c2ad1
+    {
4c2ad1
+      if (spec[0] == '[')
4c2ad1
+	{
4c2ad1
+	  /* IPv6 addresses can be written as '[ADDR]:PORT', and we
4c2ad1
+	     support this notation.  */
4c2ad1
+	  size_t close_bracket_pos = spec.find_first_of (']');
4c2ad1
+
4c2ad1
+	  if (close_bracket_pos == std::string::npos)
4c2ad1
+	    error (_("Missing close bracket in hostname '%s'"),
4c2ad1
+		   spec.c_str ());
4c2ad1
+
4c2ad1
+	  hint->ai_family = AF_INET6;
4c2ad1
+
4c2ad1
+	  const char c = spec[close_bracket_pos + 1];
4c2ad1
+
4c2ad1
+	  if (c == '\0')
4c2ad1
+	    last_colon_pos = std::string::npos;
4c2ad1
+	  else if (c != ':')
4c2ad1
+	    error (_("Invalid cruft after close bracket in '%s'"),
4c2ad1
+		   spec.c_str ());
4c2ad1
+
4c2ad1
+	  /* Erase both '[' and ']'.  */
4c2ad1
+	  spec.erase (0, 1);
4c2ad1
+	  spec.erase (close_bracket_pos - 1, 1);
4c2ad1
+	}
4c2ad1
+      else if (spec.find_first_of (']') != std::string::npos)
4c2ad1
+	error (_("Missing open bracket in hostname '%s'"),
4c2ad1
+	       spec.c_str ());
4c2ad1
+    }
4c2ad1
+
4c2ad1
+  if (last_colon_pos == 0)
4c2ad1
+    last_colon_pos = spec.find_last_of (':');
4c2ad1
+
4c2ad1
+  /* The length of the hostname part.  */
4c2ad1
+  size_t host_len;
4c2ad1
+
4c2ad1
+  if (last_colon_pos != std::string::npos)
4c2ad1
+    {
4c2ad1
+      /* The user has provided a port.  */
4c2ad1
+      host_len = last_colon_pos;
4c2ad1
+      ret.port_str = spec.substr (last_colon_pos + 1);
4c2ad1
+    }
4c2ad1
+  else
4c2ad1
+    host_len = spec.size ();
4c2ad1
+
4c2ad1
+  ret.host_str = spec.substr (0, host_len);
4c2ad1
+
4c2ad1
+  /* Default hostname is localhost.  */
4c2ad1
+  if (ret.host_str.empty ())
4c2ad1
+    ret.host_str = "localhost";
4c2ad1
+
4c2ad1
+  return ret;
4c2ad1
+}
4c2ad1
+
4c2ad1
+/* See common/netstuff.h.  */
4c2ad1
+
4c2ad1
+parsed_connection_spec
4c2ad1
+parse_connection_spec (const char *spec, struct addrinfo *hint)
4c2ad1
+{
4c2ad1
+  /* Struct to hold the association between valid prefixes, their
4c2ad1
+     family and socktype.  */
4c2ad1
+  struct host_prefix
4c2ad1
+    {
4c2ad1
+      /* The prefix.  */
4c2ad1
+      const char *prefix;
4c2ad1
+
4c2ad1
+      /* The 'ai_family'.  */
4c2ad1
+      int family;
4c2ad1
+
4c2ad1
+      /* The 'ai_socktype'.  */
4c2ad1
+      int socktype;
4c2ad1
+    };
4c2ad1
+  static const struct host_prefix prefixes[] =
4c2ad1
+    {
4c2ad1
+      { "udp:",  AF_UNSPEC, SOCK_DGRAM },
4c2ad1
+      { "tcp:",  AF_UNSPEC, SOCK_STREAM },
4c2ad1
+      { "udp4:", AF_INET,   SOCK_DGRAM },
4c2ad1
+      { "tcp4:", AF_INET,   SOCK_STREAM },
4c2ad1
+      { "udp6:", AF_INET6,  SOCK_DGRAM },
4c2ad1
+      { "tcp6:", AF_INET6,  SOCK_STREAM },
4c2ad1
+    };
4c2ad1
+
4c2ad1
+  for (const host_prefix prefix : prefixes)
4c2ad1
+    if (startswith (spec, prefix.prefix))
4c2ad1
+      {
4c2ad1
+	spec += strlen (prefix.prefix);
4c2ad1
+	hint->ai_family = prefix.family;
4c2ad1
+	hint->ai_socktype = prefix.socktype;
4c2ad1
+	hint->ai_protocol
4c2ad1
+	  = hint->ai_socktype == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
4c2ad1
+	break;
4c2ad1
+      }
4c2ad1
+
4c2ad1
+  return parse_connection_spec_without_prefix (spec, hint);
4c2ad1
+}
4c2ad1
diff --git a/gdb/common/netstuff.h b/gdb/common/netstuff.h
4c2ad1
new file mode 100644
4c2ad1
--- /dev/null
4c2ad1
+++ b/gdb/common/netstuff.h
4c2ad1
@@ -0,0 +1,76 @@
4c2ad1
+/* Operations on network stuff.
4c2ad1
+   Copyright (C) 2018 Free Software Foundation, Inc.
4c2ad1
+
4c2ad1
+   This file is part of GDB.
4c2ad1
+
4c2ad1
+   This program is free software; you can redistribute it and/or modify
4c2ad1
+   it under the terms of the GNU General Public License as published by
4c2ad1
+   the Free Software Foundation; either version 3 of the License, or
4c2ad1
+   (at your option) any later version.
4c2ad1
+
4c2ad1
+   This program is distributed in the hope that it will be useful,
4c2ad1
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
4c2ad1
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4c2ad1
+   GNU General Public License for more details.
4c2ad1
+
4c2ad1
+   You should have received a copy of the GNU General Public License
4c2ad1
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
4c2ad1
+
4c2ad1
+#ifndef NETSTUFF_H
4c2ad1
+#define NETSTUFF_H
4c2ad1
+
4c2ad1
+#include <string>
4c2ad1
+
4c2ad1
+/* Like NI_MAXHOST/NI_MAXSERV, but enough for numeric forms.  */
4c2ad1
+#define GDB_NI_MAX_ADDR 64
4c2ad1
+#define GDB_NI_MAX_PORT 16
4c2ad1
+
4c2ad1
+/* Helper class to guarantee that we always call 'freeaddrinfo'.  */
4c2ad1
+
4c2ad1
+class scoped_free_addrinfo
4c2ad1
+{
4c2ad1
+public:
4c2ad1
+  /* Default constructor.  */
4c2ad1
+  explicit scoped_free_addrinfo (struct addrinfo *ainfo)
4c2ad1
+    : m_res (ainfo)
4c2ad1
+  {
4c2ad1
+  }
4c2ad1
+
4c2ad1
+  /* Destructor responsible for free'ing M_RES by calling
4c2ad1
+     'freeaddrinfo'.  */
4c2ad1
+  ~scoped_free_addrinfo ();
4c2ad1
+
4c2ad1
+  DISABLE_COPY_AND_ASSIGN (scoped_free_addrinfo);
4c2ad1
+
4c2ad1
+private:
4c2ad1
+  /* The addrinfo resource.  */
4c2ad1
+  struct addrinfo *m_res;
4c2ad1
+};
4c2ad1
+
4c2ad1
+/* The struct we return after parsing the connection spec.  */
4c2ad1
+
4c2ad1
+struct parsed_connection_spec
4c2ad1
+{
4c2ad1
+  /* The hostname.  */
4c2ad1
+  std::string host_str;
4c2ad1
+
4c2ad1
+  /* The port, if any.  */
4c2ad1
+  std::string port_str;
4c2ad1
+};
4c2ad1
+
4c2ad1
+
4c2ad1
+/* Parse SPEC (which is a string in the form of "ADDR:PORT") and
4c2ad1
+   return a 'parsed_connection_spec' structure with the proper fields
4c2ad1
+   filled in.  Also adjust HINT accordingly.  */
4c2ad1
+extern parsed_connection_spec
4c2ad1
+  parse_connection_spec_without_prefix (std::string spec,
4c2ad1
+					struct addrinfo *hint);
4c2ad1
+
4c2ad1
+/* Parse SPEC (which is a string in the form of
4c2ad1
+   "[tcp[6]:|udp[6]:]ADDR:PORT") and return a 'parsed_connection_spec'
4c2ad1
+   structure with the proper fields filled in.  Also adjust HINT
4c2ad1
+   accordingly.  */
4c2ad1
+extern parsed_connection_spec parse_connection_spec (const char *spec,
4c2ad1
+						     struct addrinfo *hint);
4c2ad1
+
4c2ad1
+#endif /* ! NETSTUFF_H */
4c2ad1
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
4c2ad1
--- a/gdb/doc/ChangeLog
4c2ad1
+++ b/gdb/doc/ChangeLog
4c2ad1
@@ -1,3 +1,11 @@
4c2ad1
+2018-07-11  Sergio Durigan Junior  <sergiodj@redhat.com>
4c2ad1
+	    Jan Kratochvil  <jan.kratochvil@redhat.com>
4c2ad1
+	    Paul Fertser  <fercerpav@gmail.com>
4c2ad1
+	    Tsutomu Seki  <sekiriki@gmail.com>
4c2ad1
+
4c2ad1
+	* gdb.texinfo (Remote Connection Commands): Add explanation
4c2ad1
+	about new IPv6 support.  Add new connection prefixes.
4c2ad1
+
4c2ad1
 2018-08-21  Alan Hayward  <alan.hayward@arm.com>
4c2ad1
 
4c2ad1
 	* gdb.texinfo (AArch64 SVE): New subsubsection.
4c2ad1
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
4c2ad1
--- a/gdb/doc/gdb.texinfo
4c2ad1
+++ b/gdb/doc/gdb.texinfo
4c2ad1
@@ -20548,16 +20548,27 @@ If you're using a serial line, you may want to give @value{GDBN} the
4c2ad1
 @code{target} command.
4c2ad1
 
4c2ad1
 @item target remote @code{@var{host}:@var{port}}
4c2ad1
+@itemx target remote @code{@var{[host]}:@var{port}}
4c2ad1
 @itemx target remote @code{tcp:@var{host}:@var{port}}
4c2ad1
+@itemx target remote @code{tcp:@var{[host]}:@var{port}}
4c2ad1
+@itemx target remote @code{tcp4:@var{host}:@var{port}}
4c2ad1
+@itemx target remote @code{tcp6:@var{host}:@var{port}}
4c2ad1
+@itemx target remote @code{tcp6:@var{[host]}:@var{port}}
4c2ad1
 @itemx target extended-remote @code{@var{host}:@var{port}}
4c2ad1
+@itemx target extended-remote @code{@var{[host]}:@var{port}}
4c2ad1
 @itemx target extended-remote @code{tcp:@var{host}:@var{port}}
4c2ad1
+@itemx target extended-remote @code{tcp:@var{[host]}:@var{port}}
4c2ad1
+@itemx target extended-remote @code{tcp4:@var{host}:@var{port}}
4c2ad1
+@itemx target extended-remote @code{tcp6:@var{host}:@var{port}}
4c2ad1
+@itemx target extended-remote @code{tcp6:@var{[host]}:@var{port}}
4c2ad1
 @cindex @acronym{TCP} port, @code{target remote}
4c2ad1
 Debug using a @acronym{TCP} connection to @var{port} on @var{host}.
4c2ad1
-The @var{host} may be either a host name or a numeric @acronym{IP}
4c2ad1
-address; @var{port} must be a decimal number.  The @var{host} could be
4c2ad1
-the target machine itself, if it is directly connected to the net, or
4c2ad1
-it might be a terminal server which in turn has a serial line to the
4c2ad1
-target.
4c2ad1
+The @var{host} may be either a host name, a numeric @acronym{IPv4}
4c2ad1
+address, or a numeric @acronym{IPv6} address (with or without the
4c2ad1
+square brackets to separate the address from the port); @var{port}
4c2ad1
+must be a decimal number.  The @var{host} could be the target machine
4c2ad1
+itself, if it is directly connected to the net, or it might be a
4c2ad1
+terminal server which in turn has a serial line to the target.
4c2ad1
 
4c2ad1
 For example, to connect to port 2828 on a terminal server named
4c2ad1
 @code{manyfarms}:
4c2ad1
@@ -20566,6 +20577,28 @@ For example, to connect to port 2828 on a terminal server named
4c2ad1
 target remote manyfarms:2828
4c2ad1
 @end smallexample
4c2ad1
 
4c2ad1
+To connect to port 2828 on a terminal server whose address is
4c2ad1
+@code{2001:0db8:85a3:0000:0000:8a2e:0370:7334}, you can either use the
4c2ad1
+square bracket syntax:
4c2ad1
+
4c2ad1
+@smallexample
4c2ad1
+target remote [2001:0db8:85a3:0000:0000:8a2e:0370:7334]:2828
4c2ad1
+@end smallexample
4c2ad1
+
4c2ad1
+@noindent
4c2ad1
+or explicitly specify the @acronym{IPv6} protocol:
4c2ad1
+
4c2ad1
+@smallexample
4c2ad1
+target remote tcp6:2001:0db8:85a3:0000:0000:8a2e:0370:7334:2828
4c2ad1
+@end smallexample
4c2ad1
+
4c2ad1
+This last example may be confusing to the reader, because there is no
4c2ad1
+visible separation between the hostname and the port number.
4c2ad1
+Therefore, we recommend the user to provide @acronym{IPv6} addresses
4c2ad1
+using square brackets for clarity.  However, it is important to
4c2ad1
+mention that for @value{GDBN} there is no ambiguity: the number after
4c2ad1
+the last colon is considered to be the port number.
4c2ad1
+
4c2ad1
 If your remote target is actually running on the same machine as your
4c2ad1
 debugger session (e.g.@: a simulator for your target running on the
4c2ad1
 same host), you can omit the hostname.  For example, to connect to
4c2ad1
@@ -20579,7 +20612,15 @@ target remote :1234
4c2ad1
 Note that the colon is still required here.
4c2ad1
 
4c2ad1
 @item target remote @code{udp:@var{host}:@var{port}}
4c2ad1
+@itemx target remote @code{udp:@var{[host]}:@var{port}}
4c2ad1
+@itemx target remote @code{udp4:@var{host}:@var{port}}
4c2ad1
+@itemx target remote @code{udp6:@var{[host]}:@var{port}}
4c2ad1
+@itemx target extended-remote @code{udp:@var{host}:@var{port}}
4c2ad1
 @itemx target extended-remote @code{udp:@var{host}:@var{port}}
4c2ad1
+@itemx target extended-remote @code{udp:@var{[host]}:@var{port}}
4c2ad1
+@itemx target extended-remote @code{udp4:@var{host}:@var{port}}
4c2ad1
+@itemx target extended-remote @code{udp6:@var{host}:@var{port}}
4c2ad1
+@itemx target extended-remote @code{udp6:@var{[host]}:@var{port}}
4c2ad1
 @cindex @acronym{UDP} port, @code{target remote}
4c2ad1
 Debug using @acronym{UDP} packets to @var{port} on @var{host}.  For example, to
4c2ad1
 connect to @acronym{UDP} port 2828 on a terminal server named @code{manyfarms}:
4c2ad1
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
4c2ad1
--- a/gdb/gdbserver/ChangeLog
4c2ad1
+++ b/gdb/gdbserver/ChangeLog
4c2ad1
@@ -1,3 +1,22 @@
4c2ad1
+2018-07-11  Sergio Durigan Junior  <sergiodj@redhat.com>
4c2ad1
+	    Jan Kratochvil  <jan.kratochvil@redhat.com>
4c2ad1
+	    Paul Fertser  <fercerpav@gmail.com>
4c2ad1
+	    Tsutomu Seki  <sekiriki@gmail.com>
4c2ad1
+
4c2ad1
+	* Makefile.in (SFILES): Add '$(srcdir)/common/netstuff.c'.
4c2ad1
+	(OBS): Add 'common/netstuff.o'.
4c2ad1
+	(GDBREPLAY_OBS): Likewise.
4c2ad1
+	* gdbreplay.c: Include 'wspiapi.h' and 'netstuff.h'.
4c2ad1
+	(remote_open): Implement support for IPv6
4c2ad1
+	connections.
4c2ad1
+	* remote-utils.c: Include 'netstuff.h', 'filestuff.h'
4c2ad1
+	and 'wspiapi.h'.
4c2ad1
+	(handle_accept_event): Accept connections from IPv6 sources.
4c2ad1
+	(remote_prepare): Handle IPv6-style hostnames; implement
4c2ad1
+	support for IPv6 connections.
4c2ad1
+	(remote_open): Implement support for printing connections from
4c2ad1
+	IPv6 sources.
4c2ad1
+
4c2ad1
 2018-08-26  Simon Marchi  <simon.marchi@ericsson.com>
4c2ad1
 
4c2ad1
 	PR gdb/23374
4c2ad1
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
4c2ad1
--- a/gdb/gdbserver/Makefile.in
4c2ad1
+++ b/gdb/gdbserver/Makefile.in
4c2ad1
@@ -211,6 +211,7 @@ SFILES = \
4c2ad1
 	$(srcdir)/common/job-control.c \
4c2ad1
 	$(srcdir)/common/gdb_tilde_expand.c \
4c2ad1
 	$(srcdir)/common/gdb_vecs.c \
4c2ad1
+	$(srcdir)/common/netstuff.c \
4c2ad1
 	$(srcdir)/common/new-op.c \
4c2ad1
 	$(srcdir)/common/pathstuff.c \
4c2ad1
 	$(srcdir)/common/print-utils.c \
4c2ad1
@@ -254,6 +255,7 @@ OBS = \
4c2ad1
 	common/format.o \
4c2ad1
 	common/gdb_tilde_expand.o \
4c2ad1
 	common/gdb_vecs.o \
4c2ad1
+	common/netstuff.o \
4c2ad1
 	common/new-op.o \
4c2ad1
 	common/pathstuff.o \
4c2ad1
 	common/print-utils.o \
4c2ad1
@@ -290,6 +292,7 @@ GDBREPLAY_OBS = \
4c2ad1
 	common/common-exceptions.o \
4c2ad1
 	common/common-utils.o \
4c2ad1
 	common/errors.o \
4c2ad1
+	common/netstuff.o \
4c2ad1
 	common/print-utils.o \
4c2ad1
 	gdbreplay.o \
4c2ad1
 	utils.o \
4c2ad1
diff --git a/gdb/gdbserver/gdbreplay.c b/gdb/gdbserver/gdbreplay.c
4c2ad1
--- a/gdb/gdbserver/gdbreplay.c
4c2ad1
+++ b/gdb/gdbserver/gdbreplay.c
4c2ad1
@@ -46,8 +46,11 @@
4c2ad1
 
4c2ad1
 #if USE_WIN32API
4c2ad1
 #include <winsock2.h>
4c2ad1
+#include <wspiapi.h>
4c2ad1
 #endif
4c2ad1
 
4c2ad1
+#include "netstuff.h"
4c2ad1
+
4c2ad1
 #ifndef HAVE_SOCKLEN_T
4c2ad1
 typedef int socklen_t;
4c2ad1
 #endif
4c2ad1
@@ -142,56 +145,108 @@ remote_close (void)
4c2ad1
 static void
4c2ad1
 remote_open (char *name)
4c2ad1
 {
4c2ad1
-  if (!strchr (name, ':'))
4c2ad1
+  char *last_colon = strrchr (name, ':');
4c2ad1
+
4c2ad1
+  if (last_colon == NULL)
4c2ad1
     {
4c2ad1
       fprintf (stderr, "%s: Must specify tcp connection as host:addr\n", name);
4c2ad1
       fflush (stderr);
4c2ad1
       exit (1);
4c2ad1
     }
4c2ad1
-  else
4c2ad1
-    {
4c2ad1
+
4c2ad1
 #ifdef USE_WIN32API
4c2ad1
-      static int winsock_initialized;
4c2ad1
+  static int winsock_initialized;
4c2ad1
 #endif
4c2ad1
-      char *port_str;
4c2ad1
-      int port;
4c2ad1
-      struct sockaddr_in sockaddr;
4c2ad1
-      socklen_t tmp;
4c2ad1
-      int tmp_desc;
4c2ad1
+  char *port_str;
4c2ad1
+  int tmp;
4c2ad1
+  int tmp_desc;
4c2ad1
+  struct addrinfo hint;
4c2ad1
+  struct addrinfo *ainfo;
4c2ad1
 
4c2ad1
-      port_str = strchr (name, ':');
4c2ad1
+  memset (&hint, 0, sizeof (hint));
4c2ad1
+  /* Assume no prefix will be passed, therefore we should use
4c2ad1
+     AF_UNSPEC.  */
4c2ad1
+  hint.ai_family = AF_UNSPEC;
4c2ad1
+  hint.ai_socktype = SOCK_STREAM;
4c2ad1
+  hint.ai_protocol = IPPROTO_TCP;
4c2ad1
 
4c2ad1
-      port = atoi (port_str + 1);
4c2ad1
+  parsed_connection_spec parsed = parse_connection_spec (name, &hint);
4c2ad1
+
4c2ad1
+  if (parsed.port_str.empty ())
4c2ad1
+    error (_("Missing port on hostname '%s'"), name);
4c2ad1
 
4c2ad1
 #ifdef USE_WIN32API
4c2ad1
-      if (!winsock_initialized)
4c2ad1
-	{
4c2ad1
-	  WSADATA wsad;
4c2ad1
+  if (!winsock_initialized)
4c2ad1
+    {
4c2ad1
+      WSADATA wsad;
4c2ad1
 
4c2ad1
-	  WSAStartup (MAKEWORD (1, 0), &wsad);
4c2ad1
-	  winsock_initialized = 1;
4c2ad1
-	}
4c2ad1
+      WSAStartup (MAKEWORD (1, 0), &wsad);
4c2ad1
+      winsock_initialized = 1;
4c2ad1
+    }
4c2ad1
 #endif
4c2ad1
 
4c2ad1
-      tmp_desc = socket (PF_INET, SOCK_STREAM, 0);
4c2ad1
-      if (tmp_desc == -1)
4c2ad1
-	perror_with_name ("Can't open socket");
4c2ad1
+  int r = getaddrinfo (parsed.host_str.c_str (), parsed.port_str.c_str (),
4c2ad1
+		       &hint, &ainfo);
4c2ad1
 
4c2ad1
-      /* Allow rapid reuse of this port. */
4c2ad1
-      tmp = 1;
4c2ad1
-      setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
4c2ad1
-		  sizeof (tmp));
4c2ad1
+  if (r != 0)
4c2ad1
+    {
4c2ad1
+      fprintf (stderr, "%s:%s: cannot resolve name: %s\n",
4c2ad1
+	       parsed.host_str.c_str (), parsed.port_str.c_str (),
4c2ad1
+	       gai_strerror (r));
4c2ad1
+      fflush (stderr);
4c2ad1
+      exit (1);
4c2ad1
+    }
4c2ad1
+
4c2ad1
+  scoped_free_addrinfo free_ainfo (ainfo);
4c2ad1
+
4c2ad1
+  struct addrinfo *p;
4c2ad1
+
4c2ad1
+  for (p = ainfo; p != NULL; p = p->ai_next)
4c2ad1
+    {
4c2ad1
+      tmp_desc = socket (p->ai_family, p->ai_socktype, p->ai_protocol);
4c2ad1
 
4c2ad1
-      sockaddr.sin_family = PF_INET;
4c2ad1
-      sockaddr.sin_port = htons (port);
4c2ad1
-      sockaddr.sin_addr.s_addr = INADDR_ANY;
4c2ad1
+      if (tmp_desc >= 0)
4c2ad1
+	break;
4c2ad1
+    }
4c2ad1
+
4c2ad1
+  if (p == NULL)
4c2ad1
+    perror_with_name ("Cannot open socket");
4c2ad1
 
4c2ad1
-      if (bind (tmp_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
4c2ad1
-	  || listen (tmp_desc, 1))
4c2ad1
-	perror_with_name ("Can't bind address");
4c2ad1
+  /* Allow rapid reuse of this port. */
4c2ad1
+  tmp = 1;
4c2ad1
+  setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
4c2ad1
+	      sizeof (tmp));
4c2ad1
+
4c2ad1
+  switch (p->ai_family)
4c2ad1
+    {
4c2ad1
+    case AF_INET:
4c2ad1
+      ((struct sockaddr_in *) p->ai_addr)->sin_addr.s_addr = INADDR_ANY;
4c2ad1
+      break;
4c2ad1
+    case AF_INET6:
4c2ad1
+      ((struct sockaddr_in6 *) p->ai_addr)->sin6_addr = in6addr_any;
4c2ad1
+      break;
4c2ad1
+    default:
4c2ad1
+      fprintf (stderr, "Invalid 'ai_family' %d\n", p->ai_family);
4c2ad1
+      exit (1);
4c2ad1
+    }
4c2ad1
+
4c2ad1
+  if (bind (tmp_desc, p->ai_addr, p->ai_addrlen) != 0)
4c2ad1
+    perror_with_name ("Can't bind address");
4c2ad1
+
4c2ad1
+  if (p->ai_socktype == SOCK_DGRAM)
4c2ad1
+    remote_desc = tmp_desc;
4c2ad1
+  else
4c2ad1
+    {
4c2ad1
+      struct sockaddr_storage sockaddr;
4c2ad1
+      socklen_t sockaddrsize = sizeof (sockaddr);
4c2ad1
+      char orig_host[GDB_NI_MAX_ADDR], orig_port[GDB_NI_MAX_PORT];
4c2ad1
+
4c2ad1
+      if (listen (tmp_desc, 1) != 0)
4c2ad1
+	perror_with_name ("Can't listen on socket");
4c2ad1
+
4c2ad1
+      remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr,
4c2ad1
+			    &sockaddrsize);
4c2ad1
 
4c2ad1
-      tmp = sizeof (sockaddr);
4c2ad1
-      remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, &tmp);
4c2ad1
       if (remote_desc == -1)
4c2ad1
 	perror_with_name ("Accept failed");
4c2ad1
 
4c2ad1
@@ -206,6 +261,16 @@ remote_open (char *name)
4c2ad1
       setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY,
4c2ad1
 		  (char *) &tmp, sizeof (tmp));
4c2ad1
 
4c2ad1
+      if (getnameinfo ((struct sockaddr *) &sockaddr, sockaddrsize,
4c2ad1
+		       orig_host, sizeof (orig_host),
4c2ad1
+		       orig_port, sizeof (orig_port),
4c2ad1
+		       NI_NUMERICHOST | NI_NUMERICSERV) == 0)
4c2ad1
+	{
4c2ad1
+	  fprintf (stderr, "Remote debugging from host %s, port %s\n",
4c2ad1
+		   orig_host, orig_port);
4c2ad1
+	  fflush (stderr);
4c2ad1
+	}
4c2ad1
+
4c2ad1
 #ifndef USE_WIN32API
4c2ad1
       close (tmp_desc);		/* No longer need this */
4c2ad1
 
4c2ad1
diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c
4c2ad1
--- a/gdb/gdbserver/remote-utils.c
4c2ad1
+++ b/gdb/gdbserver/remote-utils.c
4c2ad1
@@ -26,6 +26,8 @@
4c2ad1
 #include "dll.h"
4c2ad1
 #include "rsp-low.h"
4c2ad1
 #include "gdbthread.h"
4c2ad1
+#include "netstuff.h"
4c2ad1
+#include "filestuff.h"
4c2ad1
 #include <ctype.h>
4c2ad1
 #if HAVE_SYS_IOCTL_H
4c2ad1
 #include <sys/ioctl.h>
4c2ad1
@@ -63,6 +65,7 @@
4c2ad1
 
4c2ad1
 #if USE_WIN32API
4c2ad1
 #include <winsock2.h>
4c2ad1
+#include <wspiapi.h>
4c2ad1
 #endif
4c2ad1
 
4c2ad1
 #if __QNX__
4c2ad1
@@ -151,19 +154,18 @@ enable_async_notification (int fd)
4c2ad1
 static int
4c2ad1
 handle_accept_event (int err, gdb_client_data client_data)
4c2ad1
 {
4c2ad1
-  struct sockaddr_in sockaddr;
4c2ad1
-  socklen_t tmp;
4c2ad1
+  struct sockaddr_storage sockaddr;
4c2ad1
+  socklen_t len = sizeof (sockaddr);
4c2ad1
 
4c2ad1
   if (debug_threads)
4c2ad1
     debug_printf ("handling possible accept event\n");
4c2ad1
 
4c2ad1
-  tmp = sizeof (sockaddr);
4c2ad1
-  remote_desc = accept (listen_desc, (struct sockaddr *) &sockaddr, &tmp);
4c2ad1
+  remote_desc = accept (listen_desc, (struct sockaddr *) &sockaddr, &len;;
4c2ad1
   if (remote_desc == -1)
4c2ad1
     perror_with_name ("Accept failed");
4c2ad1
 
4c2ad1
   /* Enable TCP keep alive process. */
4c2ad1
-  tmp = 1;
4c2ad1
+  socklen_t tmp = 1;
4c2ad1
   setsockopt (remote_desc, SOL_SOCKET, SO_KEEPALIVE,
4c2ad1
 	      (char *) &tmp, sizeof (tmp));
4c2ad1
 
4c2ad1
@@ -192,8 +194,19 @@ handle_accept_event (int err, gdb_client_data client_data)
4c2ad1
   delete_file_handler (listen_desc);
4c2ad1
 
4c2ad1
   /* Convert IP address to string.  */
4c2ad1
-  fprintf (stderr, "Remote debugging from host %s\n",
4c2ad1
-	   inet_ntoa (sockaddr.sin_addr));
4c2ad1
+  char orig_host[GDB_NI_MAX_ADDR], orig_port[GDB_NI_MAX_PORT];
4c2ad1
+
4c2ad1
+  int r = getnameinfo ((struct sockaddr *) &sockaddr, len,
4c2ad1
+		       orig_host, sizeof (orig_host),
4c2ad1
+		       orig_port, sizeof (orig_port),
4c2ad1
+		       NI_NUMERICHOST | NI_NUMERICSERV);
4c2ad1
+
4c2ad1
+  if (r != 0)
4c2ad1
+    fprintf (stderr, _("Could not obtain remote address: %s\n"),
4c2ad1
+	     gai_strerror (r));
4c2ad1
+  else
4c2ad1
+    fprintf (stderr, _("Remote debugging from host %s, port %s\n"),
4c2ad1
+	     orig_host, orig_port);
4c2ad1
 
4c2ad1
   enable_async_notification (remote_desc);
4c2ad1
 
4c2ad1
@@ -222,10 +235,7 @@ remote_prepare (const char *name)
4c2ad1
 #ifdef USE_WIN32API
4c2ad1
   static int winsock_initialized;
4c2ad1
 #endif
4c2ad1
-  int port;
4c2ad1
-  struct sockaddr_in sockaddr;
4c2ad1
   socklen_t tmp;
4c2ad1
-  char *port_end;
4c2ad1
 
4c2ad1
   remote_is_stdio = 0;
4c2ad1
   if (strcmp (name, STDIO_CONNECTION_NAME) == 0)
4c2ad1
@@ -238,17 +248,25 @@ remote_prepare (const char *name)
4c2ad1
       return;
4c2ad1
     }
4c2ad1
 
4c2ad1
-  port_str = strchr (name, ':');
4c2ad1
-  if (port_str == NULL)
4c2ad1
+  struct addrinfo hint;
4c2ad1
+  struct addrinfo *ainfo;
4c2ad1
+
4c2ad1
+  memset (&hint, 0, sizeof (hint));
4c2ad1
+  /* Assume no prefix will be passed, therefore we should use
4c2ad1
+     AF_UNSPEC.  */
4c2ad1
+  hint.ai_family = AF_UNSPEC;
4c2ad1
+  hint.ai_socktype = SOCK_STREAM;
4c2ad1
+  hint.ai_protocol = IPPROTO_TCP;
4c2ad1
+
4c2ad1
+  parsed_connection_spec parsed
4c2ad1
+    = parse_connection_spec_without_prefix (name, &hint);
4c2ad1
+
4c2ad1
+  if (parsed.port_str.empty ())
4c2ad1
     {
4c2ad1
       cs.transport_is_reliable = 0;
4c2ad1
       return;
4c2ad1
     }
4c2ad1
 
4c2ad1
-  port = strtoul (port_str + 1, &port_end, 10);
4c2ad1
-  if (port_str[1] == '\0' || *port_end != '\0')
4c2ad1
-    error ("Bad port argument: %s", name);
4c2ad1
-
4c2ad1
 #ifdef USE_WIN32API
4c2ad1
   if (!winsock_initialized)
4c2ad1
     {
4c2ad1
@@ -259,8 +277,26 @@ remote_prepare (const char *name)
4c2ad1
     }
4c2ad1
 #endif
4c2ad1
 
4c2ad1
-  listen_desc = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
4c2ad1
-  if (listen_desc == -1)
4c2ad1
+  int r = getaddrinfo (parsed.host_str.c_str (), parsed.port_str.c_str (),
4c2ad1
+		       &hint, &ainfo);
4c2ad1
+
4c2ad1
+  if (r != 0)
4c2ad1
+    error (_("%s: cannot resolve name: %s"), name, gai_strerror (r));
4c2ad1
+
4c2ad1
+  scoped_free_addrinfo freeaddrinfo (ainfo);
4c2ad1
+
4c2ad1
+  struct addrinfo *iter;
4c2ad1
+
4c2ad1
+  for (iter = ainfo; iter != NULL; iter = iter->ai_next)
4c2ad1
+    {
4c2ad1
+      listen_desc = gdb_socket_cloexec (iter->ai_family, iter->ai_socktype,
4c2ad1
+					iter->ai_protocol);
4c2ad1
+
4c2ad1
+      if (listen_desc >= 0)
4c2ad1
+	break;
4c2ad1
+    }
4c2ad1
+
4c2ad1
+  if (iter == NULL)
4c2ad1
     perror_with_name ("Can't open socket");
4c2ad1
 
4c2ad1
   /* Allow rapid reuse of this port. */
4c2ad1
@@ -268,14 +304,25 @@ remote_prepare (const char *name)
4c2ad1
   setsockopt (listen_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
4c2ad1
 	      sizeof (tmp));
4c2ad1
 
4c2ad1
-  sockaddr.sin_family = PF_INET;
4c2ad1
-  sockaddr.sin_port = htons (port);
4c2ad1
-  sockaddr.sin_addr.s_addr = INADDR_ANY;
4c2ad1
+  switch (iter->ai_family)
4c2ad1
+    {
4c2ad1
+    case AF_INET:
4c2ad1
+      ((struct sockaddr_in *) iter->ai_addr)->sin_addr.s_addr = INADDR_ANY;
4c2ad1
+      break;
4c2ad1
+    case AF_INET6:
4c2ad1
+      ((struct sockaddr_in6 *) iter->ai_addr)->sin6_addr = in6addr_any;
4c2ad1
+      break;
4c2ad1
+    default:
4c2ad1
+      internal_error (__FILE__, __LINE__,
4c2ad1
+		      _("Invalid 'ai_family' %d\n"), iter->ai_family);
4c2ad1
+    }
4c2ad1
 
4c2ad1
-  if (bind (listen_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
4c2ad1
-      || listen (listen_desc, 1))
4c2ad1
+  if (bind (listen_desc, iter->ai_addr, iter->ai_addrlen) != 0)
4c2ad1
     perror_with_name ("Can't bind address");
4c2ad1
 
4c2ad1
+  if (listen (listen_desc, 1) != 0)
4c2ad1
+    perror_with_name ("Can't listen on socket");
4c2ad1
+
4c2ad1
   cs.transport_is_reliable = 1;
4c2ad1
 }
4c2ad1
 
4c2ad1
@@ -350,18 +397,24 @@ remote_open (const char *name)
4c2ad1
 #endif /* USE_WIN32API */
4c2ad1
   else
4c2ad1
     {
4c2ad1
-      int port;
4c2ad1
-      socklen_t len;
4c2ad1
-      struct sockaddr_in sockaddr;
4c2ad1
-
4c2ad1
-      len = sizeof (sockaddr);
4c2ad1
-      if (getsockname (listen_desc,
4c2ad1
-		       (struct sockaddr *) &sockaddr, &len) < 0
4c2ad1
-	  || len < sizeof (sockaddr))
4c2ad1
+      char listen_port[GDB_NI_MAX_PORT];
4c2ad1
+      struct sockaddr_storage sockaddr;
4c2ad1
+      socklen_t len = sizeof (sockaddr);
4c2ad1
+
4c2ad1
+      if (getsockname (listen_desc, (struct sockaddr *) &sockaddr, &len) < 0)
4c2ad1
 	perror_with_name ("Can't determine port");
4c2ad1
-      port = ntohs (sockaddr.sin_port);
4c2ad1
 
4c2ad1
-      fprintf (stderr, "Listening on port %d\n", port);
4c2ad1
+      int r = getnameinfo ((struct sockaddr *) &sockaddr, len,
4c2ad1
+			   NULL, 0,
4c2ad1
+			   listen_port, sizeof (listen_port),
4c2ad1
+			   NI_NUMERICSERV);
4c2ad1
+
4c2ad1
+      if (r != 0)
4c2ad1
+	fprintf (stderr, _("Can't obtain port where we are listening: %s"),
4c2ad1
+		 gai_strerror (r));
4c2ad1
+      else
4c2ad1
+	fprintf (stderr, _("Listening on port %s\n"), listen_port);
4c2ad1
+
4c2ad1
       fflush (stderr);
4c2ad1
 
4c2ad1
       /* Register the event loop handler.  */
4c2ad1
diff --git a/gdb/ser-tcp.c b/gdb/ser-tcp.c
4c2ad1
--- a/gdb/ser-tcp.c
4c2ad1
+++ b/gdb/ser-tcp.c
4c2ad1
@@ -25,6 +25,7 @@
4c2ad1
 #include "cli/cli-decode.h"
4c2ad1
 #include "cli/cli-setshow.h"
4c2ad1
 #include "filestuff.h"
4c2ad1
+#include "netstuff.h"
4c2ad1
 
4c2ad1
 #include <sys/types.h>
4c2ad1
 
4c2ad1
@@ -39,6 +40,7 @@
4c2ad1
 
4c2ad1
 #ifdef USE_WIN32API
4c2ad1
 #include <winsock2.h>
4c2ad1
+#include <wspiapi.h>
4c2ad1
 #ifndef ETIMEDOUT
4c2ad1
 #define ETIMEDOUT WSAETIMEDOUT
4c2ad1
 #endif
4c2ad1
@@ -81,12 +83,13 @@ static unsigned int tcp_retry_limit = 15;
4c2ad1
 
4c2ad1
 #define POLL_INTERVAL 5
4c2ad1
 
4c2ad1
-/* Helper function to wait a while.  If SCB is non-null, wait on its
4c2ad1
-   file descriptor.  Otherwise just wait on a timeout, updating *POLLS.
4c2ad1
-   Returns -1 on timeout or interrupt, otherwise the value of select.  */
4c2ad1
+/* Helper function to wait a while.  If SOCK is not -1, wait on its
4c2ad1
+   file descriptor.  Otherwise just wait on a timeout, updating
4c2ad1
+   *POLLS.  Returns -1 on timeout or interrupt, otherwise the value of
4c2ad1
+   select.  */
4c2ad1
 
4c2ad1
 static int
4c2ad1
-wait_for_connect (struct serial *scb, unsigned int *polls)
4c2ad1
+wait_for_connect (int sock, unsigned int *polls)
4c2ad1
 {
4c2ad1
   struct timeval t;
4c2ad1
   int n;
4c2ad1
@@ -120,24 +123,24 @@ wait_for_connect (struct serial *scb, unsigned int *polls)
4c2ad1
       t.tv_usec = 0;
4c2ad1
     }
4c2ad1
 
4c2ad1
-  if (scb)
4c2ad1
+  if (sock >= 0)
4c2ad1
     {
4c2ad1
       fd_set rset, wset, eset;
4c2ad1
 
4c2ad1
       FD_ZERO (&rset);
4c2ad1
-      FD_SET (scb->fd, &rset);
4c2ad1
+      FD_SET (sock, &rset);
4c2ad1
       wset = rset;
4c2ad1
       eset = rset;
4c2ad1
-	  
4c2ad1
+
4c2ad1
       /* POSIX systems return connection success or failure by signalling
4c2ad1
 	 wset.  Windows systems return success in wset and failure in
4c2ad1
 	 eset.
4c2ad1
-     
4c2ad1
+
4c2ad1
 	 We must call select here, rather than gdb_select, because
4c2ad1
 	 the serial structure has not yet been initialized - the
4c2ad1
 	 MinGW select wrapper will not know that this FD refers
4c2ad1
 	 to a socket.  */
4c2ad1
-      n = select (scb->fd + 1, &rset, &wset, &eset, &t);
4c2ad1
+      n = select (sock + 1, &rset, &wset, &eset, &t);
4c2ad1
     }
4c2ad1
   else
4c2ad1
     /* Use gdb_select here, since we have no file descriptors, and on
4c2ad1
@@ -153,80 +156,28 @@ wait_for_connect (struct serial *scb, unsigned int *polls)
4c2ad1
   return n;
4c2ad1
 }
4c2ad1
 
4c2ad1
-/* Open a tcp socket.  */
4c2ad1
+/* Try to connect to the host represented by AINFO.  If the connection
4c2ad1
+   succeeds, return its socket.  Otherwise, return -1 and set ERRNO
4c2ad1
+   accordingly.  POLLS is used when 'connect' returns EINPROGRESS, and
4c2ad1
+   we need to invoke 'wait_for_connect' to obtain the status.  */
4c2ad1
 
4c2ad1
-int
4c2ad1
-net_open (struct serial *scb, const char *name)
4c2ad1
+static int
4c2ad1
+try_connect (const struct addrinfo *ainfo, unsigned int *polls)
4c2ad1
 {
4c2ad1
-  char hostname[100];
4c2ad1
-  const char *port_str;
4c2ad1
-  int n, port, tmp;
4c2ad1
-  int use_udp;
4c2ad1
-  struct hostent *hostent;
4c2ad1
-  struct sockaddr_in sockaddr;
4c2ad1
-#ifdef USE_WIN32API
4c2ad1
-  u_long ioarg;
4c2ad1
-#else
4c2ad1
-  int ioarg;
4c2ad1
-#endif
4c2ad1
-  unsigned int polls = 0;
4c2ad1
-
4c2ad1
-  use_udp = 0;
4c2ad1
-  if (startswith (name, "udp:"))
4c2ad1
-    {
4c2ad1
-      use_udp = 1;
4c2ad1
-      name = name + 4;
4c2ad1
-    }
4c2ad1
-  else if (startswith (name, "tcp:"))
4c2ad1
-    name = name + 4;
4c2ad1
-
4c2ad1
-  port_str = strchr (name, ':');
4c2ad1
-
4c2ad1
-  if (!port_str)
4c2ad1
-    error (_("net_open: No colon in host name!"));  /* Shouldn't ever
4c2ad1
-						       happen.  */
4c2ad1
-
4c2ad1
-  tmp = std::min (port_str - name, (ptrdiff_t) sizeof hostname - 1);
4c2ad1
-  strncpy (hostname, name, tmp);	/* Don't want colon.  */
4c2ad1
-  hostname[tmp] = '\000';	/* Tie off host name.  */
4c2ad1
-  port = atoi (port_str + 1);
4c2ad1
-
4c2ad1
-  /* Default hostname is localhost.  */
4c2ad1
-  if (!hostname[0])
4c2ad1
-    strcpy (hostname, "localhost");
4c2ad1
-
4c2ad1
-  hostent = gethostbyname (hostname);
4c2ad1
-  if (!hostent)
4c2ad1
-    {
4c2ad1
-      fprintf_unfiltered (gdb_stderr, "%s: unknown host\n", hostname);
4c2ad1
-      errno = ENOENT;
4c2ad1
-      return -1;
4c2ad1
-    }
4c2ad1
+  int sock = gdb_socket_cloexec (ainfo->ai_family, ainfo->ai_socktype,
4c2ad1
+				 ainfo->ai_protocol);
4c2ad1
 
4c2ad1
-  sockaddr.sin_family = PF_INET;
4c2ad1
-  sockaddr.sin_port = htons (port);
4c2ad1
-  memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr,
4c2ad1
-	  sizeof (struct in_addr));
4c2ad1
-
4c2ad1
- retry:
4c2ad1
-
4c2ad1
-  if (use_udp)
4c2ad1
-    scb->fd = gdb_socket_cloexec (PF_INET, SOCK_DGRAM, 0);
4c2ad1
-  else
4c2ad1
-    scb->fd = gdb_socket_cloexec (PF_INET, SOCK_STREAM, 0);
4c2ad1
-
4c2ad1
-  if (scb->fd == -1)
4c2ad1
+  if (sock < 0)
4c2ad1
     return -1;
4c2ad1
-  
4c2ad1
+
4c2ad1
   /* Set socket nonblocking.  */
4c2ad1
-  ioarg = 1;
4c2ad1
-  ioctl (scb->fd, FIONBIO, &ioarg);
4c2ad1
+  int ioarg = 1;
4c2ad1
+
4c2ad1
+  ioctl (sock, FIONBIO, &ioarg);
4c2ad1
 
4c2ad1
   /* Use Non-blocking connect.  connect() will return 0 if connected
4c2ad1
      already.  */
4c2ad1
-  n = connect (scb->fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr));
4c2ad1
-
4c2ad1
-  if (n < 0)
4c2ad1
+  if (connect (sock, ainfo->ai_addr, ainfo->ai_addrlen) < 0)
4c2ad1
     {
4c2ad1
 #ifdef USE_WIN32API
4c2ad1
       int err = WSAGetLastError();
4c2ad1
@@ -234,21 +185,26 @@ net_open (struct serial *scb, const char *name)
4c2ad1
       int err = errno;
4c2ad1
 #endif
4c2ad1
 
4c2ad1
-      /* Maybe we're waiting for the remote target to become ready to
4c2ad1
-	 accept connections.  */
4c2ad1
-      if (tcp_auto_retry
4c2ad1
+      /* If we've got a "connection refused" error, just return
4c2ad1
+	 -1.  The caller will know what to do.  */
4c2ad1
+      if (
4c2ad1
 #ifdef USE_WIN32API
4c2ad1
-	  && err == WSAECONNREFUSED
4c2ad1
+	  err == WSAECONNREFUSED
4c2ad1
 #else
4c2ad1
-	  && err == ECONNREFUSED
4c2ad1
+	  err == ECONNREFUSED
4c2ad1
 #endif
4c2ad1
-	  && wait_for_connect (NULL, &polls) >= 0)
4c2ad1
+	  )
4c2ad1
 	{
4c2ad1
-	  close (scb->fd);
4c2ad1
-	  goto retry;
4c2ad1
+	  close (sock);
4c2ad1
+	  errno = err;
4c2ad1
+	  return -1;
4c2ad1
 	}
4c2ad1
 
4c2ad1
       if (
4c2ad1
+	  /* Any other error (except EINPROGRESS) will be "swallowed"
4c2ad1
+	     here.  We return without specifying a return value, and
4c2ad1
+	     set errno if the caller wants to inspect what
4c2ad1
+	     happened.  */
4c2ad1
 #ifdef USE_WIN32API
4c2ad1
 	  /* Under Windows, calling "connect" with a non-blocking socket
4c2ad1
 	     results in WSAEWOULDBLOCK, not WSAEINPROGRESS.  */
4c2ad1
@@ -258,66 +214,166 @@ net_open (struct serial *scb, const char *name)
4c2ad1
 #endif
4c2ad1
 	  )
4c2ad1
 	{
4c2ad1
+	  close (sock);
4c2ad1
 	  errno = err;
4c2ad1
-	  net_close (scb);
4c2ad1
 	  return -1;
4c2ad1
 	}
4c2ad1
 
4c2ad1
       /* Looks like we need to wait for the connect.  */
4c2ad1
-      do 
4c2ad1
-	{
4c2ad1
-	  n = wait_for_connect (scb, &polls);
4c2ad1
-	} 
4c2ad1
+      int n;
4c2ad1
+
4c2ad1
+      do
4c2ad1
+	n = wait_for_connect (sock, polls);
4c2ad1
       while (n == 0);
4c2ad1
+
4c2ad1
       if (n < 0)
4c2ad1
 	{
4c2ad1
-	  net_close (scb);
4c2ad1
+	  int saved_errno = errno;
4c2ad1
+
4c2ad1
+	  /* A negative value here means that we either timed out or
4c2ad1
+	     got interrupted by the user.  Just return.  */
4c2ad1
+	  close (sock);
4c2ad1
+	  errno = saved_errno;
4c2ad1
 	  return -1;
4c2ad1
 	}
4c2ad1
     }
4c2ad1
 
4c2ad1
   /* Got something.  Is it an error?  */
4c2ad1
-  {
4c2ad1
-    int res, err;
4c2ad1
-    socklen_t len;
4c2ad1
-
4c2ad1
-    len = sizeof (err);
4c2ad1
-    /* On Windows, the fourth parameter to getsockopt is a "char *";
4c2ad1
-       on UNIX systems it is generally "void *".  The cast to "char *"
4c2ad1
-       is OK everywhere, since in C++ any data pointer type can be
4c2ad1
-       implicitly converted to "void *".  */
4c2ad1
-    res = getsockopt (scb->fd, SOL_SOCKET, SO_ERROR, (char *) &err, &len;;
4c2ad1
-    if (res < 0 || err)
4c2ad1
-      {
4c2ad1
-	/* Maybe the target still isn't ready to accept the connection.  */
4c2ad1
-	if (tcp_auto_retry
4c2ad1
+  int err;
4c2ad1
+  socklen_t len = sizeof (err);
4c2ad1
+
4c2ad1
+  /* On Windows, the fourth parameter to getsockopt is a "char *";
4c2ad1
+     on UNIX systems it is generally "void *".  The cast to "char *"
4c2ad1
+     is OK everywhere, since in C++ any data pointer type can be
4c2ad1
+     implicitly converted to "void *".  */
4c2ad1
+  int ret = getsockopt (sock, SOL_SOCKET, SO_ERROR, (char *) &err, &len;;
4c2ad1
+
4c2ad1
+  if (ret < 0)
4c2ad1
+    {
4c2ad1
+      int saved_errno = errno;
4c2ad1
+
4c2ad1
+      close (sock);
4c2ad1
+      errno = saved_errno;
4c2ad1
+      return -1;
4c2ad1
+    }
4c2ad1
+  else if (ret == 0 && err != 0)
4c2ad1
+    {
4c2ad1
+      close (sock);
4c2ad1
+      errno = err;
4c2ad1
+      return -1;
4c2ad1
+    }
4c2ad1
+
4c2ad1
+  /* The connection succeeded.  Return the socket.  */
4c2ad1
+  return sock;
4c2ad1
+}
4c2ad1
+
4c2ad1
+/* Open a tcp socket.  */
4c2ad1
+
4c2ad1
+int
4c2ad1
+net_open (struct serial *scb, const char *name)
4c2ad1
+{
4c2ad1
+  struct addrinfo hint;
4c2ad1
+  struct addrinfo *ainfo;
4c2ad1
+
4c2ad1
+  memset (&hint, 0, sizeof (hint));
4c2ad1
+  /* Assume no prefix will be passed, therefore we should use
4c2ad1
+     AF_UNSPEC.  */
4c2ad1
+  hint.ai_family = AF_UNSPEC;
4c2ad1
+  hint.ai_socktype = SOCK_STREAM;
4c2ad1
+  hint.ai_protocol = IPPROTO_TCP;
4c2ad1
+
4c2ad1
+  parsed_connection_spec parsed = parse_connection_spec (name, &hint);
4c2ad1
+
4c2ad1
+  if (parsed.port_str.empty ())
4c2ad1
+    error (_("Missing port on hostname '%s'"), name);
4c2ad1
+
4c2ad1
+  int r = getaddrinfo (parsed.host_str.c_str (),
4c2ad1
+		       parsed.port_str.c_str (),
4c2ad1
+		       &hint, &ainfo);
4c2ad1
+
4c2ad1
+  if (r != 0)
4c2ad1
+    {
4c2ad1
+      fprintf_unfiltered (gdb_stderr, _("%s: cannot resolve name: %s\n"),
4c2ad1
+			  name, gai_strerror (r));
4c2ad1
+      errno = ENOENT;
4c2ad1
+      return -1;
4c2ad1
+    }
4c2ad1
+
4c2ad1
+  scoped_free_addrinfo free_ainfo (ainfo);
4c2ad1
+
4c2ad1
+  /* Flag to indicate whether we've got a connection refused.  It will
4c2ad1
+     be true if any of the connections tried was refused.  */
4c2ad1
+  bool got_connrefused;
4c2ad1
+  /* If a connection succeeeds, SUCCESS_AINFO will point to the
4c2ad1
+     'struct addrinfo' that succeed.  */
4c2ad1
+  struct addrinfo *success_ainfo = NULL;
4c2ad1
+  unsigned int polls = 0;
4c2ad1
+
4c2ad1
+  /* Assume the worst.  */
4c2ad1
+  scb->fd = -1;
4c2ad1
+
4c2ad1
+  do
4c2ad1
+    {
4c2ad1
+      got_connrefused = false;
4c2ad1
+
4c2ad1
+      for (struct addrinfo *iter = ainfo; iter != NULL; iter = iter->ai_next)
4c2ad1
+	{
4c2ad1
+	  /* Iterate over the list of possible addresses to connect
4c2ad1
+	     to.  For each, we'll try to connect and see if it
4c2ad1
+	     succeeds.  */
4c2ad1
+	  int sock = try_connect (iter, &polls);
4c2ad1
+
4c2ad1
+	  if (sock >= 0)
4c2ad1
+	    {
4c2ad1
+	      /* We've gotten a successful connection.  Save its
4c2ad1
+		 'struct addrinfo', the socket, and break.  */
4c2ad1
+	      success_ainfo = iter;
4c2ad1
+	      scb->fd = sock;
4c2ad1
+	      break;
4c2ad1
+	    }
4c2ad1
+	  else if (
4c2ad1
 #ifdef USE_WIN32API
4c2ad1
-	    && err == WSAECONNREFUSED
4c2ad1
+	  errno == WSAECONNREFUSED
4c2ad1
 #else
4c2ad1
-	    && err == ECONNREFUSED
4c2ad1
+	  errno == ECONNREFUSED
4c2ad1
 #endif
4c2ad1
-	    && wait_for_connect (NULL, &polls) >= 0)
4c2ad1
-	  {
4c2ad1
-	    close (scb->fd);
4c2ad1
-	    goto retry;
4c2ad1
-	  }
4c2ad1
-	if (err)
4c2ad1
-	  errno = err;
4c2ad1
-	net_close (scb);
4c2ad1
-	return -1;
4c2ad1
-      }
4c2ad1
-  } 
4c2ad1
+		   )
4c2ad1
+	    got_connrefused = true;
4c2ad1
+	}
4c2ad1
+    }
4c2ad1
+  /* Just retry if:
4c2ad1
+
4c2ad1
+     - tcp_auto_retry is true, and
4c2ad1
+     - We haven't gotten a connection yet, and
4c2ad1
+     - Any of our connection attempts returned with ECONNREFUSED, and
4c2ad1
+     - wait_for_connect signals that we can keep going.  */
4c2ad1
+  while (tcp_auto_retry
4c2ad1
+	 && success_ainfo == NULL
4c2ad1
+	 && got_connrefused
4c2ad1
+	 && wait_for_connect (-1, &polls) >= 0);
4c2ad1
+
4c2ad1
+  if (success_ainfo == NULL)
4c2ad1
+    {
4c2ad1
+      net_close (scb);
4c2ad1
+      return -1;
4c2ad1
+    }
4c2ad1
 
4c2ad1
   /* Turn off nonblocking.  */
4c2ad1
-  ioarg = 0;
4c2ad1
+#ifdef USE_WIN32API
4c2ad1
+  u_long ioarg = 0;
4c2ad1
+#else
4c2ad1
+  int ioarg = 0;
4c2ad1
+#endif
4c2ad1
+
4c2ad1
   ioctl (scb->fd, FIONBIO, &ioarg);
4c2ad1
 
4c2ad1
-  if (use_udp == 0)
4c2ad1
+  if (success_ainfo->ai_socktype == IPPROTO_TCP)
4c2ad1
     {
4c2ad1
       /* Disable Nagle algorithm.  Needed in some cases.  */
4c2ad1
-      tmp = 1;
4c2ad1
+      int tmp = 1;
4c2ad1
+
4c2ad1
       setsockopt (scb->fd, IPPROTO_TCP, TCP_NODELAY,
4c2ad1
-		  (char *)&tmp, sizeof (tmp));
4c2ad1
+		  (char *) &tmp, sizeof (tmp));
4c2ad1
     }
4c2ad1
 
4c2ad1
 #ifdef SIGPIPE
4c2ad1
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
4c2ad1
--- a/gdb/testsuite/ChangeLog
4c2ad1
+++ b/gdb/testsuite/ChangeLog
4c2ad1
@@ -1,3 +1,23 @@
4c2ad1
+2018-07-11  Sergio Durigan Junior  <sergiodj@redhat.com>
4c2ad1
+	    Jan Kratochvil  <jan.kratochvil@redhat.com>
4c2ad1
+	    Paul Fertser  <fercerpav@gmail.com>
4c2ad1
+	    Tsutomu Seki  <sekiriki@gmail.com>
4c2ad1
+
4c2ad1
+	* README (Testsuite Parameters): Mention new 'GDB_TEST_SOCKETHOST'
4c2ad1
+	parameter.
4c2ad1
+	* boards/native-extended-gdbserver.exp: Do not set 'sockethost'
4c2ad1
+	by default.
4c2ad1
+	* boards/native-gdbserver.exp: Likewise.
4c2ad1
+	* gdb.server/run-without-local-binary.exp: Improve regexp used
4c2ad1
+	for detecting when a remote debugging connection succeeds.
4c2ad1
+	* gdb.server/server-connect.exp: New file.
4c2ad1
+	* lib/gdbserver-support.exp (gdbserver_default_get_comm_port):
4c2ad1
+	Do not prefix the port number with ":".
4c2ad1
+	(gdbserver_start): New global GDB_TEST_SOCKETHOST.  Implement
4c2ad1
+	support for detecting and using it.  Add '$debughost_gdbserver'
4c2ad1
+	to the list of arguments used to start gdbserver.  Handle case
4c2ad1
+	when gdbserver cannot resolve a network name.
4c2ad1
+
4c2ad1
 2018-08-31  Tom Tromey  <tom@tromey.com>
4c2ad1
 
4c2ad1
 	* gdb.rust/simple.rs: Rename second variable "v".
4c2ad1
diff --git a/gdb/testsuite/README b/gdb/testsuite/README
4c2ad1
--- a/gdb/testsuite/README
4c2ad1
+++ b/gdb/testsuite/README
4c2ad1
@@ -259,6 +259,20 @@ This make (not runtest) variable is used to specify whether the
4c2ad1
 testsuite preloads the read1.so library into expect.  Any non-empty
4c2ad1
 value means true.  See "Race detection" below.
4c2ad1
 
4c2ad1
+GDB_TEST_SOCKETHOST
4c2ad1
+
4c2ad1
+This variable can provide the hostname/address that should be used
4c2ad1
+when performing GDBserver-related tests.  This is useful in some
4c2ad1
+situations, e.g., when you want to test the IPv6 connectivity of GDB
4c2ad1
+and GDBserver, or when using a different hostname/address is needed.
4c2ad1
+For example, to make GDB and GDBserver use IPv6-only connections, you
4c2ad1
+can do:
4c2ad1
+
4c2ad1
+	make check TESTS="gdb.server/*.exp" RUNTESTFLAGS='GDB_TEST_SOCKETHOST=tcp6:[::1]'
4c2ad1
+
4c2ad1
+Note that only a hostname/address can be provided, without a port
4c2ad1
+number.
4c2ad1
+
4c2ad1
 Race detection
4c2ad1
 **************
4c2ad1
 
4c2ad1
diff --git a/gdb/testsuite/boards/native-extended-gdbserver.exp b/gdb/testsuite/boards/native-extended-gdbserver.exp
4c2ad1
--- a/gdb/testsuite/boards/native-extended-gdbserver.exp
4c2ad1
+++ b/gdb/testsuite/boards/native-extended-gdbserver.exp
4c2ad1
@@ -24,8 +24,6 @@ load_generic_config "extended-gdbserver"
4c2ad1
 load_board_description "gdbserver-base"
4c2ad1
 load_board_description "local-board"
4c2ad1
 
4c2ad1
-set_board_info sockethost "localhost:"
4c2ad1
-
4c2ad1
 # We will be using the extended GDB remote protocol.
4c2ad1
 set_board_info gdb_protocol "extended-remote"
4c2ad1
 
4c2ad1
diff --git a/gdb/testsuite/boards/native-gdbserver.exp b/gdb/testsuite/boards/native-gdbserver.exp
4c2ad1
--- a/gdb/testsuite/boards/native-gdbserver.exp
4c2ad1
+++ b/gdb/testsuite/boards/native-gdbserver.exp
4c2ad1
@@ -30,7 +30,6 @@ set_board_info gdb,do_reload_on_run 1
4c2ad1
 # There's no support for argument-passing (yet).
4c2ad1
 set_board_info noargs 1
4c2ad1
 
4c2ad1
-set_board_info sockethost "localhost:"
4c2ad1
 set_board_info use_gdb_stub 1
4c2ad1
 set_board_info exit_is_reliable 1
4c2ad1
 
4c2ad1
diff --git a/gdb/testsuite/gdb.server/run-without-local-binary.exp b/gdb/testsuite/gdb.server/run-without-local-binary.exp
4c2ad1
--- a/gdb/testsuite/gdb.server/run-without-local-binary.exp
4c2ad1
+++ b/gdb/testsuite/gdb.server/run-without-local-binary.exp
4c2ad1
@@ -53,7 +53,7 @@ save_vars { GDBFLAGS } {
4c2ad1
     set use_gdb_stub 0
4c2ad1
 
4c2ad1
     gdb_test "target ${gdbserver_protocol} ${gdbserver_gdbport}" \
4c2ad1
-	"Remote debugging using $gdbserver_gdbport" \
4c2ad1
+	"Remote debugging using [string_to_regexp $gdbserver_gdbport]" \
4c2ad1
 	"connect to gdbserver"
4c2ad1
 
4c2ad1
     gdb_test "run" \
4c2ad1
diff --git a/gdb/testsuite/gdb.server/server-connect.exp b/gdb/testsuite/gdb.server/server-connect.exp
4c2ad1
new file mode 100644
4c2ad1
--- /dev/null
4c2ad1
+++ b/gdb/testsuite/gdb.server/server-connect.exp
4c2ad1
@@ -0,0 +1,111 @@
4c2ad1
+# This testcase is part of GDB, the GNU debugger.
4c2ad1
+#
4c2ad1
+# Copyright 2018 Free Software Foundation, Inc.
4c2ad1
+#
4c2ad1
+# This program is free software; you can redistribute it and/or modify
4c2ad1
+# it under the terms of the GNU General Public License as published by
4c2ad1
+# the Free Software Foundation; either version 3 of the License, or
4c2ad1
+# (at your option) any later version.
4c2ad1
+#
4c2ad1
+# This program is distributed in the hope that it will be useful,
4c2ad1
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
4c2ad1
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4c2ad1
+# GNU General Public License for more details.
4c2ad1
+#
4c2ad1
+# You should have received a copy of the GNU General Public License
4c2ad1
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
4c2ad1
+
4c2ad1
+# Test multiple types of connection (IPv4, IPv6, TCP, UDP) and make
4c2ad1
+# sure both gdbserver and GDB work.
4c2ad1
+
4c2ad1
+load_lib gdbserver-support.exp
4c2ad1
+
4c2ad1
+standard_testfile normal.c
4c2ad1
+
4c2ad1
+if {[skip_gdbserver_tests]} {
4c2ad1
+    return 0
4c2ad1
+}
4c2ad1
+
4c2ad1
+# We want to have control over where we start gdbserver.
4c2ad1
+if { [is_remote target] } {
4c2ad1
+    return 0
4c2ad1
+}
4c2ad1
+
4c2ad1
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
4c2ad1
+    return -1
4c2ad1
+}
4c2ad1
+
4c2ad1
+# Make sure we're disconnected, in case we're testing with an
4c2ad1
+# extended-remote board, therefore already connected.
4c2ad1
+gdb_test "disconnect" ".*"
4c2ad1
+
4c2ad1
+set target_exec [gdbserver_download_current_prog]
4c2ad1
+
4c2ad1
+# An array containing the test instructions for each scenario.  The
4c2ad1
+# description of each field is as follows:
4c2ad1
+#
4c2ad1
+# - The connection specification to be used when starting
4c2ad1
+#   gdbserver/GDB.  This string will be used to set the
4c2ad1
+#   GDB_TEST_SOCKETHOST when calling gdbserver_start.
4c2ad1
+#
4c2ad1
+# - A flag indicating whether gdbserver should fail when we attempt to
4c2ad1
+#   start it.  Useful when testing erroneous connection specs such as
4c2ad1
+#   "tcp8:".
4c2ad1
+#
4c2ad1
+# - The prefix that should be prepended to the test messages.
4c2ad1
+set test_params \
4c2ad1
+    { \
4c2ad1
+	  { "tcp4:127.0.0.1" 0 "tcp4" } \
4c2ad1
+	  { "tcp6:::1"       0 "tcp6" } \
4c2ad1
+	  { "tcp6:[::1]"     0 "tcp6-with-brackets" } \
4c2ad1
+	  { "tcp:localhost"  0 "tcp" } \
4c2ad1
+	  { "udp4:127.0.0.1" 0 "udp4" } \
4c2ad1
+	  { "udp6:::1"       0 "udp6" } \
4c2ad1
+	  { "udp6:[::1]"     0 "udp6-with-brackets" } \
4c2ad1
+	  { "tcp8:123"       1 "tcp8" } \
4c2ad1
+	  { "udp123:::"      1 "udp123" } \
4c2ad1
+	  { "garbage:1234"   1 "garbage:1234" } \
4c2ad1
+    }
4c2ad1
+
4c2ad1
+# The best way to test different types of connections is to set the
4c2ad1
+# GDB_TEST_SOCKETHOST variable accordingly.
4c2ad1
+save_vars { GDB_TEST_SOCKETHOST } {
4c2ad1
+    foreach line $test_params {
4c2ad1
+	set sockhost [lindex $line 0]
4c2ad1
+	set gdbserver_should_fail [lindex $line 1]
4c2ad1
+	set prefix [lindex $line 2]
4c2ad1
+
4c2ad1
+	with_test_prefix $prefix {
4c2ad1
+	    set GDB_TEST_SOCKETHOST $sockhost
4c2ad1
+	    set test "start gdbserver"
4c2ad1
+
4c2ad1
+	    # Try to start gdbserver.
4c2ad1
+	    set catchres [catch {set res [gdbserver_start "" $target_exec]} errmsg]
4c2ad1
+
4c2ad1
+	    if { $catchres != 0 } {
4c2ad1
+		if { $gdbserver_should_fail } {
4c2ad1
+		    pass "$test: gdbserver failed as expected"
4c2ad1
+		} else {
4c2ad1
+		    fail "$test: $errmsg"
4c2ad1
+		}
4c2ad1
+		continue
4c2ad1
+	    } else {
4c2ad1
+		if { $gdbserver_should_fail } {
4c2ad1
+		    fail "$test: gdbserver should fail but did not"
4c2ad1
+		} else {
4c2ad1
+		    pass "$test"
4c2ad1
+		}
4c2ad1
+	    }
4c2ad1
+
4c2ad1
+	    set gdbserver_protocol [lindex $res 0]
4c2ad1
+	    set gdbserver_gdbport [lindex $res 1]
4c2ad1
+	    set test "connect to gdbserver using $sockhost"
4c2ad1
+
4c2ad1
+	    if { [gdb_target_cmd $gdbserver_protocol $gdbserver_gdbport] == 0 } {
4c2ad1
+		pass $test
4c2ad1
+	    } else {
4c2ad1
+		fail $test
4c2ad1
+	    }
4c2ad1
+	}
4c2ad1
+    }
4c2ad1
+}
4c2ad1
diff --git a/gdb/testsuite/lib/gdbserver-support.exp b/gdb/testsuite/lib/gdbserver-support.exp
4c2ad1
--- a/gdb/testsuite/lib/gdbserver-support.exp
4c2ad1
+++ b/gdb/testsuite/lib/gdbserver-support.exp
4c2ad1
@@ -211,7 +211,7 @@ proc gdbserver_default_get_remote_address { host port } {
4c2ad1
 # Default routine to compute the "comm" argument for gdbserver.
4c2ad1
 
4c2ad1
 proc gdbserver_default_get_comm_port { port } {
4c2ad1
-    return ":$port"
4c2ad1
+    return "$port"
4c2ad1
 }
4c2ad1
 
4c2ad1
 # Start a gdbserver process with initial OPTIONS and trailing ARGUMENTS.
4c2ad1
@@ -221,6 +221,7 @@ proc gdbserver_default_get_comm_port { port } {
4c2ad1
 
4c2ad1
 proc gdbserver_start { options arguments } {
4c2ad1
     global portnum
4c2ad1
+    global GDB_TEST_SOCKETHOST
4c2ad1
 
4c2ad1
     # Port id -- either specified in baseboard file, or managed here.
4c2ad1
     if [target_info exists gdb,socketport] {
4c2ad1
@@ -231,10 +232,22 @@ proc gdbserver_start { options arguments } {
4c2ad1
     }
4c2ad1
 
4c2ad1
     # Extract the local and remote host ids from the target board struct.
4c2ad1
-    if [target_info exists sockethost] {
4c2ad1
+    if { [info exists GDB_TEST_SOCKETHOST] } {
4c2ad1
+	# The user is not supposed to provide a port number, just a
4c2ad1
+	# hostname/address, therefore we add the trailing ":" here.
4c2ad1
+	set debughost "${GDB_TEST_SOCKETHOST}:"
4c2ad1
+	# Escape open and close square brackets.
4c2ad1
+	set debughost_tmp [string map { [ \\[ ] \\] } $debughost]
4c2ad1
+	# We need a "gdbserver" version of the debughost, which will
4c2ad1
+	# have the possible connection prefix stripped.  This is
4c2ad1
+	# because gdbserver currently doesn't recognize the prefixes.
4c2ad1
+	regsub -all "^\(tcp:|udp:|tcp4:|udp4:|tcp6:|udp6:\)" $debughost_tmp "" debughost_gdbserver
4c2ad1
+    } elseif [target_info exists sockethost] {
4c2ad1
 	set debughost [target_info sockethost]
4c2ad1
+	set debughost_gdbserver $debughost
4c2ad1
     } else {
4c2ad1
 	set debughost "localhost:"
4c2ad1
+	set debughost_gdbserver $debughost
4c2ad1
     }
4c2ad1
 
4c2ad1
     # Some boards use a different value for the port that is passed to
4c2ad1
@@ -277,8 +290,14 @@ proc gdbserver_start { options arguments } {
4c2ad1
 	if { $options != "" } {
4c2ad1
 	    append gdbserver_command " $options"
4c2ad1
 	}
4c2ad1
+	if { $debughost_gdbserver != "" } {
4c2ad1
+	    append gdbserver_command " $debughost_gdbserver"
4c2ad1
+	}
4c2ad1
 	if { $portnum != "" } {
4c2ad1
-	    append gdbserver_command " [$get_comm_port $portnum]"
4c2ad1
+	    if { $debughost_gdbserver == "" } {
4c2ad1
+		append gdbserver_command " "
4c2ad1
+	    }
4c2ad1
+	    append gdbserver_command "[$get_comm_port $portnum]"
4c2ad1
 	}
4c2ad1
 	if { $arguments != "" } {
4c2ad1
 	    append gdbserver_command " $arguments"
4c2ad1
@@ -307,6 +326,9 @@ proc gdbserver_start { options arguments } {
4c2ad1
 		    continue
4c2ad1
 		}
4c2ad1
 	    }
4c2ad1
+	    -re ".*: cannot resolve name: Name or service not known\r\n" {
4c2ad1
+		error "gdbserver cannot resolve name."
4c2ad1
+	    }
4c2ad1
 	    timeout {
4c2ad1
 		error "Timeout waiting for gdbserver response."
4c2ad1
 	    }
4c2ad1
diff --git a/gdb/unittests/parse-connection-spec-selftests.c b/gdb/unittests/parse-connection-spec-selftests.c
4c2ad1
new file mode 100644
4c2ad1
--- /dev/null
4c2ad1
+++ b/gdb/unittests/parse-connection-spec-selftests.c
4c2ad1
@@ -0,0 +1,249 @@
4c2ad1
+/* Self tests for parsing connection specs for GDB, the GNU debugger.
4c2ad1
+
4c2ad1
+   Copyright (C) 2018 Free Software Foundation, Inc.
4c2ad1
+
4c2ad1
+   This file is part of GDB.
4c2ad1
+
4c2ad1
+   This program is free software; you can redistribute it and/or modify
4c2ad1
+   it under the terms of the GNU General Public License as published by
4c2ad1
+   the Free Software Foundation; either version 3 of the License, or
4c2ad1
+   (at your option) any later version.
4c2ad1
+
4c2ad1
+   This program is distributed in the hope that it will be useful,
4c2ad1
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
4c2ad1
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4c2ad1
+   GNU General Public License for more details.
4c2ad1
+
4c2ad1
+   You should have received a copy of the GNU General Public License
4c2ad1
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
4c2ad1
+
4c2ad1
+#include "defs.h"
4c2ad1
+#include "selftest.h"
4c2ad1
+#include "common/netstuff.h"
4c2ad1
+#include "diagnostics.h"
4c2ad1
+#ifdef USE_WIN32API
4c2ad1
+#include <winsock2.h>
4c2ad1
+#include <wspiapi.h>
4c2ad1
+#else
4c2ad1
+#include <netinet/in.h>
4c2ad1
+#include <arpa/inet.h>
4c2ad1
+#include <netdb.h>
4c2ad1
+#include <sys/socket.h>
4c2ad1
+#include <netinet/tcp.h>
4c2ad1
+#endif
4c2ad1
+
4c2ad1
+namespace selftests {
4c2ad1
+namespace parse_connection_spec_tests {
4c2ad1
+
4c2ad1
+/* Auxiliary struct that holds info about a specific test for a
4c2ad1
+   connection spec.  */
4c2ad1
+
4c2ad1
+struct parse_conn_test
4c2ad1
+{
4c2ad1
+  /* The connection spec.  */
4c2ad1
+  const char *connspec;
4c2ad1
+
4c2ad1
+  /* Expected result from 'parse_connection_spec'.  */
4c2ad1
+  parsed_connection_spec expected_result;
4c2ad1
+
4c2ad1
+  /* True if this test should fail, false otherwise.  If true, only
4c2ad1
+     the CONNSPEC field should be considered as valid.  */
4c2ad1
+  bool should_fail;
4c2ad1
+
4c2ad1
+  /* The expected AI_FAMILY to be found on the 'struct addrinfo'
4c2ad1
+     HINT.  */
4c2ad1
+  int exp_ai_family;
4c2ad1
+
4c2ad1
+  /* The expected AI_SOCKTYPE to be found on the 'struct addrinfo'
4c2ad1
+     HINT.  */
4c2ad1
+  int exp_ai_socktype;
4c2ad1
+
4c2ad1
+  /* The expected AI_PROTOCOL to be found on the 'struct addrinfo'
4c2ad1
+     HINT.  */
4c2ad1
+  int exp_ai_protocol;
4c2ad1
+};
4c2ad1
+
4c2ad1
+/* Some defines to help us fill a 'struct parse_conn_test'.  */
4c2ad1
+
4c2ad1
+/* Initialize a full entry.  */
4c2ad1
+#define INIT_ENTRY(ADDR, EXP_HOST, EXP_PORT, SHOULD_FAIL, EXP_AI_FAMILY, \
4c2ad1
+		   EXP_AI_SOCKTYPE, EXP_AI_PROTOCOL)			\
4c2ad1
+  { ADDR, { EXP_HOST, EXP_PORT }, SHOULD_FAIL, EXP_AI_FAMILY, \
4c2ad1
+    EXP_AI_SOCKTYPE, EXP_AI_PROTOCOL }
4c2ad1
+
4c2ad1
+/* Initialize an unprefixed entry.  In this case, we don't expect
4c2ad1
+   anything on the 'struct addrinfo' HINT.  */
4c2ad1
+#define INIT_UNPREFIXED_ENTRY(ADDR, EXP_HOST, EXP_PORT) \
4c2ad1
+  INIT_ENTRY (ADDR, EXP_HOST, EXP_PORT, false, 0, 0, 0)
4c2ad1
+
4c2ad1
+/* Initialized an unprefixed IPv6 entry.  In this case, we don't
4c2ad1
+   expect anything on the 'struct addrinfo' HINT.  */
4c2ad1
+#define INIT_UNPREFIXED_IPV6_ENTRY(ADDR, EXP_HOST, EXP_PORT) \
4c2ad1
+  INIT_ENTRY (ADDR, EXP_HOST, EXP_PORT, false, AF_INET6, 0, 0)
4c2ad1
+
4c2ad1
+/* Initialize a prefixed entry.  */
4c2ad1
+#define INIT_PREFIXED_ENTRY(ADDR, EXP_HOST, EXP_PORT, EXP_AI_FAMILY, \
4c2ad1
+			    EXP_AI_SOCKTYPE, EXP_AI_PROTOCOL) \
4c2ad1
+  INIT_ENTRY (ADDR, EXP_HOST, EXP_PORT, false, EXP_AI_FAMILY, \
4c2ad1
+	      EXP_AI_SOCKTYPE, EXP_AI_PROTOCOL)
4c2ad1
+
4c2ad1
+/* Initialize an entry prefixed with "tcp4:".  */
4c2ad1
+#define INIT_PREFIXED_IPV4_TCP(ADDR, EXP_HOST, EXP_PORT) \
4c2ad1
+  INIT_PREFIXED_ENTRY (ADDR, EXP_HOST, EXP_PORT, AF_INET, SOCK_STREAM, \
4c2ad1
+		       IPPROTO_TCP)
4c2ad1
+
4c2ad1
+/* Initialize an entry prefixed with "tcp6:".  */
4c2ad1
+#define INIT_PREFIXED_IPV6_TCP(ADDR, EXP_HOST, EXP_PORT) \
4c2ad1
+  INIT_PREFIXED_ENTRY (ADDR, EXP_HOST, EXP_PORT, AF_INET6, SOCK_STREAM, \
4c2ad1
+		       IPPROTO_TCP)
4c2ad1
+
4c2ad1
+/* Initialize an entry prefixed with "udp4:".  */
4c2ad1
+#define INIT_PREFIXED_IPV4_UDP(ADDR, EXP_HOST, EXP_PORT) \
4c2ad1
+  INIT_PREFIXED_ENTRY (ADDR, EXP_HOST, EXP_PORT, AF_INET, SOCK_DGRAM, \
4c2ad1
+		       IPPROTO_UDP)
4c2ad1
+
4c2ad1
+/* Initialize an entry prefixed with "udp6:".  */
4c2ad1
+#define INIT_PREFIXED_IPV6_UDP(ADDR, EXP_HOST, EXP_PORT) \
4c2ad1
+  INIT_PREFIXED_ENTRY (ADDR, EXP_HOST, EXP_PORT, AF_INET6, SOCK_DGRAM, \
4c2ad1
+		       IPPROTO_UDP)
4c2ad1
+
4c2ad1
+/* Initialize a bogus entry, i.e., a connection spec that should
4c2ad1
+   fail.  */
4c2ad1
+#define INIT_BOGUS_ENTRY(ADDR) \
4c2ad1
+  INIT_ENTRY (ADDR, "", "", true, 0, 0, 0)
4c2ad1
+
4c2ad1
+/* The variable which holds all of our tests.  */
4c2ad1
+
4c2ad1
+static const parse_conn_test conn_test[] =
4c2ad1
+  {
4c2ad1
+    /* Unprefixed addresses.  */
4c2ad1
+
4c2ad1
+    /* IPv4, host and port present.  */
4c2ad1
+    INIT_UNPREFIXED_ENTRY ("127.0.0.1:1234", "127.0.0.1", "1234"),
4c2ad1
+    /* IPv4, only host.  */
4c2ad1
+    INIT_UNPREFIXED_ENTRY ("127.0.0.1", "127.0.0.1", ""),
4c2ad1
+    /* IPv4, missing port.  */
4c2ad1
+    INIT_UNPREFIXED_ENTRY ("127.0.0.1:", "127.0.0.1", ""),
4c2ad1
+
4c2ad1
+    /* IPv6, host and port present, no brackets.  */
4c2ad1
+    INIT_UNPREFIXED_ENTRY ("::1:1234", "::1", "1234"),
4c2ad1
+    /* IPv6, missing port, no brackets.  */
4c2ad1
+    INIT_UNPREFIXED_ENTRY ("::1:", "::1", ""),
4c2ad1
+    /* IPv6, host and port present, with brackets.  */
4c2ad1
+    INIT_UNPREFIXED_IPV6_ENTRY ("[::1]:1234", "::1", "1234"),
4c2ad1
+    /* IPv6, only host, with brackets.  */
4c2ad1
+    INIT_UNPREFIXED_IPV6_ENTRY ("[::1]", "::1", ""),
4c2ad1
+    /* IPv6, missing port, with brackets.  */
4c2ad1
+    INIT_UNPREFIXED_IPV6_ENTRY ("[::1]:", "::1", ""),
4c2ad1
+
4c2ad1
+    /* Unspecified, only port.  */
4c2ad1
+    INIT_UNPREFIXED_ENTRY (":1234", "localhost", "1234"),
4c2ad1
+
4c2ad1
+    /* Prefixed addresses.  */
4c2ad1
+
4c2ad1
+    /* Prefixed "tcp4:" IPv4, host and port presents.  */
4c2ad1
+    INIT_PREFIXED_IPV4_TCP ("tcp4:127.0.0.1:1234", "127.0.0.1", "1234"),
4c2ad1
+    /* Prefixed "tcp4:" IPv4, only port.  */
4c2ad1
+    INIT_PREFIXED_IPV4_TCP ("tcp4::1234", "localhost", "1234"),
4c2ad1
+    /* Prefixed "tcp4:" IPv4, only host.  */
4c2ad1
+    INIT_PREFIXED_IPV4_TCP ("tcp4:127.0.0.1", "127.0.0.1", ""),
4c2ad1
+    /* Prefixed "tcp4:" IPv4, missing port.  */
4c2ad1
+    INIT_PREFIXED_IPV4_TCP ("tcp4:127.0.0.1:", "127.0.0.1", ""),
4c2ad1
+
4c2ad1
+    /* Prefixed "udp4:" IPv4, host and port present.  */
4c2ad1
+    INIT_PREFIXED_IPV4_UDP ("udp4:127.0.0.1:1234", "127.0.0.1", "1234"),
4c2ad1
+    /* Prefixed "udp4:" IPv4, only port.  */
4c2ad1
+    INIT_PREFIXED_IPV4_UDP ("udp4::1234", "localhost", "1234"),
4c2ad1
+    /* Prefixed "udp4:" IPv4, only host.  */
4c2ad1
+    INIT_PREFIXED_IPV4_UDP ("udp4:127.0.0.1", "127.0.0.1", ""),
4c2ad1
+    /* Prefixed "udp4:" IPv4, missing port.  */
4c2ad1
+    INIT_PREFIXED_IPV4_UDP ("udp4:127.0.0.1:", "127.0.0.1", ""),
4c2ad1
+
4c2ad1
+
4c2ad1
+    /* Prefixed "tcp6:" IPv6, host and port present.  */
4c2ad1
+    INIT_PREFIXED_IPV6_TCP ("tcp6:::1:1234", "::1", "1234"),
4c2ad1
+    /* Prefixed "tcp6:" IPv6, only port.  */
4c2ad1
+    INIT_PREFIXED_IPV6_TCP ("tcp6::1234", "localhost", "1234"),
4c2ad1
+    /* Prefixed "tcp6:" IPv6, only host.  */
4c2ad1
+    //INIT_PREFIXED_IPV6_TCP ("tcp6:::1", "::1", ""),
4c2ad1
+    /* Prefixed "tcp6:" IPv6, missing port.  */
4c2ad1
+    INIT_PREFIXED_IPV6_TCP ("tcp6:::1:", "::1", ""),
4c2ad1
+
4c2ad1
+    /* Prefixed "udp6:" IPv6, host and port present.  */
4c2ad1
+    INIT_PREFIXED_IPV6_UDP ("udp6:::1:1234", "::1", "1234"),
4c2ad1
+    /* Prefixed "udp6:" IPv6, only port.  */
4c2ad1
+    INIT_PREFIXED_IPV6_UDP ("udp6::1234", "localhost", "1234"),
4c2ad1
+    /* Prefixed "udp6:" IPv6, only host.  */
4c2ad1
+    //INIT_PREFIXED_IPV6_UDP ("udp6:::1", "::1", ""),
4c2ad1
+    /* Prefixed "udp6:" IPv6, missing port.  */
4c2ad1
+    INIT_PREFIXED_IPV6_UDP ("udp6:::1:", "::1", ""),
4c2ad1
+
4c2ad1
+    /* Prefixed "tcp6:" IPv6 with brackets, host and port present.  */
4c2ad1
+    INIT_PREFIXED_IPV6_TCP ("tcp6:[::1]:1234", "::1", "1234"),
4c2ad1
+    /* Prefixed "tcp6:" IPv6 with brackets, only host.  */
4c2ad1
+    INIT_PREFIXED_IPV6_TCP ("tcp6:[::1]", "::1", ""),
4c2ad1
+    /* Prefixed "tcp6:" IPv6 with brackets, missing port.  */
4c2ad1
+    INIT_PREFIXED_IPV6_TCP ("tcp6:[::1]:", "::1", ""),
4c2ad1
+
4c2ad1
+    /* Prefixed "udp6:" IPv6 with brackets, host and port present.  */
4c2ad1
+    INIT_PREFIXED_IPV6_UDP ("udp6:[::1]:1234", "::1", "1234"),
4c2ad1
+    /* Prefixed "udp6:" IPv6 with brackets, only host.  */
4c2ad1
+    INIT_PREFIXED_IPV6_UDP ("udp6:[::1]", "::1", ""),
4c2ad1
+    /* Prefixed "udp6:" IPv6 with brackets, missing port.  */
4c2ad1
+    INIT_PREFIXED_IPV6_UDP ("udp6:[::1]:", "::1", ""),
4c2ad1
+
4c2ad1
+
4c2ad1
+    /* Bogus addresses.  */
4c2ad1
+    INIT_BOGUS_ENTRY ("tcp6:[::1]123:44"),
4c2ad1
+    INIT_BOGUS_ENTRY ("[::1"),
4c2ad1
+    INIT_BOGUS_ENTRY ("tcp6:::1]:"),
4c2ad1
+  };
4c2ad1
+
4c2ad1
+/* Test a connection spec C.  */
4c2ad1
+
4c2ad1
+static void
4c2ad1
+test_conn (const parse_conn_test &c)
4c2ad1
+{
4c2ad1
+  struct addrinfo hint;
4c2ad1
+  parsed_connection_spec ret;
4c2ad1
+
4c2ad1
+  memset (&hint, 0, sizeof (hint));
4c2ad1
+
4c2ad1
+  TRY
4c2ad1
+    {
4c2ad1
+      ret = parse_connection_spec (c.connspec, &hint);
4c2ad1
+    }
4c2ad1
+  CATCH (ex, RETURN_MASK_ERROR)
4c2ad1
+    {
4c2ad1
+      /* If we caught an error, we should check if this connection
4c2ad1
+	 spec was supposed to fail.  */
4c2ad1
+      SELF_CHECK (c.should_fail);
4c2ad1
+      return;
4c2ad1
+    }
4c2ad1
+  END_CATCH
4c2ad1
+
4c2ad1
+  SELF_CHECK (!c.should_fail);
4c2ad1
+  SELF_CHECK (ret.host_str == c.expected_result.host_str);
4c2ad1
+  SELF_CHECK (ret.port_str == c.expected_result.port_str);
4c2ad1
+  SELF_CHECK (hint.ai_family == c.exp_ai_family);
4c2ad1
+  SELF_CHECK (hint.ai_socktype == c.exp_ai_socktype);
4c2ad1
+  SELF_CHECK (hint.ai_protocol == c.exp_ai_protocol);
4c2ad1
+}
4c2ad1
+
4c2ad1
+/* Run the tests associated with parsing connection specs.  */
4c2ad1
+
4c2ad1
+static void
4c2ad1
+run_tests ()
4c2ad1
+{
4c2ad1
+  for (const parse_conn_test &c : conn_test)
4c2ad1
+    test_conn (c);
4c2ad1
+}
4c2ad1
+} /* namespace parse_connection_spec_tests */
4c2ad1
+} /* namespace selftests */
4c2ad1
+
4c2ad1
+void
4c2ad1
+_initialize_parse_connection_spec_selftests ()
4c2ad1
+{
4c2ad1
+  selftests::register_test ("parse_connection_spec",
4c2ad1
+			    selftests::parse_connection_spec_tests::run_tests);
4c2ad1
+}