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

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