summaryrefslogtreecommitdiff
path: root/gdbsupport/netstuff.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdbsupport/netstuff.c')
-rw-r--r--gdbsupport/netstuff.c154
1 files changed, 154 insertions, 0 deletions
diff --git a/gdbsupport/netstuff.c b/gdbsupport/netstuff.c
new file mode 100644
index 00000000000..1bf8f4b886f
--- /dev/null
+++ b/gdbsupport/netstuff.c
@@ -0,0 +1,154 @@
+/* Operations on network stuff.
+ Copyright (C) 2018-2020 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "common-defs.h"
+#include "netstuff.h"
+#include <algorithm>
+
+#ifdef USE_WIN32API
+#include <ws2tcpip.h>
+#else
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/tcp.h>
+#endif
+
+/* See gdbsupport/netstuff.h. */
+
+scoped_free_addrinfo::~scoped_free_addrinfo ()
+{
+ freeaddrinfo (m_res);
+}
+
+/* See gdbsupport/netstuff.h. */
+
+parsed_connection_spec
+parse_connection_spec_without_prefix (std::string spec, struct addrinfo *hint)
+{
+ parsed_connection_spec ret;
+ size_t last_colon_pos = 0;
+ /* We're dealing with IPv6 if:
+
+ - ai_family is AF_INET6, or
+ - ai_family is not AF_INET, and
+ - spec[0] is '[', or
+ - the number of ':' on spec is greater than 1. */
+ bool is_ipv6 = (hint->ai_family == AF_INET6
+ || (hint->ai_family != AF_INET
+ && (spec[0] == '['
+ || std::count (spec.begin (),
+ spec.end (), ':') > 1)));
+
+ if (is_ipv6)
+ {
+ if (spec[0] == '[')
+ {
+ /* IPv6 addresses can be written as '[ADDR]:PORT', and we
+ support this notation. */
+ size_t close_bracket_pos = spec.find_first_of (']');
+
+ if (close_bracket_pos == std::string::npos)
+ error (_("Missing close bracket in hostname '%s'"),
+ spec.c_str ());
+
+ hint->ai_family = AF_INET6;
+
+ const char c = spec[close_bracket_pos + 1];
+
+ if (c == '\0')
+ last_colon_pos = std::string::npos;
+ else if (c != ':')
+ error (_("Invalid cruft after close bracket in '%s'"),
+ spec.c_str ());
+
+ /* Erase both '[' and ']'. */
+ spec.erase (0, 1);
+ spec.erase (close_bracket_pos - 1, 1);
+ }
+ else if (spec.find_first_of (']') != std::string::npos)
+ error (_("Missing open bracket in hostname '%s'"),
+ spec.c_str ());
+ }
+
+ if (last_colon_pos == 0)
+ last_colon_pos = spec.find_last_of (':');
+
+ /* The length of the hostname part. */
+ size_t host_len;
+
+ if (last_colon_pos != std::string::npos)
+ {
+ /* The user has provided a port. */
+ host_len = last_colon_pos;
+ ret.port_str = spec.substr (last_colon_pos + 1);
+ }
+ else
+ host_len = spec.size ();
+
+ ret.host_str = spec.substr (0, host_len);
+
+ /* Default hostname is localhost. */
+ if (ret.host_str.empty ())
+ ret.host_str = "localhost";
+
+ return ret;
+}
+
+/* See gdbsupport/netstuff.h. */
+
+parsed_connection_spec
+parse_connection_spec (const char *spec, struct addrinfo *hint)
+{
+ /* Struct to hold the association between valid prefixes, their
+ family and socktype. */
+ struct host_prefix
+ {
+ /* The prefix. */
+ const char *prefix;
+
+ /* The 'ai_family'. */
+ int family;
+
+ /* The 'ai_socktype'. */
+ int socktype;
+ };
+ static const struct host_prefix prefixes[] =
+ {
+ { "udp:", AF_UNSPEC, SOCK_DGRAM },
+ { "tcp:", AF_UNSPEC, SOCK_STREAM },
+ { "udp4:", AF_INET, SOCK_DGRAM },
+ { "tcp4:", AF_INET, SOCK_STREAM },
+ { "udp6:", AF_INET6, SOCK_DGRAM },
+ { "tcp6:", AF_INET6, SOCK_STREAM },
+ };
+
+ for (const host_prefix prefix : prefixes)
+ if (startswith (spec, prefix.prefix))
+ {
+ spec += strlen (prefix.prefix);
+ hint->ai_family = prefix.family;
+ hint->ai_socktype = prefix.socktype;
+ hint->ai_protocol
+ = hint->ai_socktype == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
+ break;
+ }
+
+ return parse_connection_spec_without_prefix (spec, hint);
+}