/* Operations on network stuff. Copyright (C) 2018-2023 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 . */ #include "common-defs.h" #include "netstuff.h" #include #ifdef USE_WIN32API #include #else #include #include #include #include #include #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); }