1 /* Operations on network stuff. 2 Copyright (C) 2018-2024 Free Software Foundation, Inc. 3 4 This file is part of GDB. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18 19 #include "netstuff.h" 20 #include <algorithm> 21 22 #ifdef USE_WIN32API 23 #include <ws2tcpip.h> 24 #else 25 #include <netinet/in.h> 26 #include <arpa/inet.h> 27 #include <netdb.h> 28 #include <sys/socket.h> 29 #include <netinet/tcp.h> 30 #endif 31 32 /* See gdbsupport/netstuff.h. */ 33 34 scoped_free_addrinfo::~scoped_free_addrinfo () 35 { 36 freeaddrinfo (m_res); 37 } 38 39 /* See gdbsupport/netstuff.h. */ 40 41 parsed_connection_spec 42 parse_connection_spec_without_prefix (std::string spec, struct addrinfo *hint) 43 { 44 parsed_connection_spec ret; 45 size_t last_colon_pos = 0; 46 /* We're dealing with IPv6 if: 47 48 - ai_family is AF_INET6, or 49 - ai_family is not AF_INET, and 50 - spec[0] is '[', or 51 - the number of ':' on spec is greater than 1. */ 52 bool is_ipv6 = (hint->ai_family == AF_INET6 53 || (hint->ai_family != AF_INET 54 && (spec[0] == '[' 55 || std::count (spec.begin (), 56 spec.end (), ':') > 1))); 57 58 if (is_ipv6) 59 { 60 if (spec[0] == '[') 61 { 62 /* IPv6 addresses can be written as '[ADDR]:PORT', and we 63 support this notation. */ 64 size_t close_bracket_pos = spec.find_first_of (']'); 65 66 if (close_bracket_pos == std::string::npos) 67 error (_("Missing close bracket in hostname '%s'"), 68 spec.c_str ()); 69 70 hint->ai_family = AF_INET6; 71 72 const char c = spec[close_bracket_pos + 1]; 73 74 if (c == '\0') 75 last_colon_pos = std::string::npos; 76 else if (c != ':') 77 error (_("Invalid cruft after close bracket in '%s'"), 78 spec.c_str ()); 79 80 /* Erase both '[' and ']'. */ 81 spec.erase (0, 1); 82 spec.erase (close_bracket_pos - 1, 1); 83 } 84 else if (spec.find_first_of (']') != std::string::npos) 85 error (_("Missing open bracket in hostname '%s'"), 86 spec.c_str ()); 87 } 88 89 if (last_colon_pos == 0) 90 last_colon_pos = spec.find_last_of (':'); 91 92 /* The length of the hostname part. */ 93 size_t host_len; 94 95 if (last_colon_pos != std::string::npos) 96 { 97 /* The user has provided a port. */ 98 host_len = last_colon_pos; 99 ret.port_str = spec.substr (last_colon_pos + 1); 100 } 101 else 102 host_len = spec.size (); 103 104 ret.host_str = spec.substr (0, host_len); 105 106 /* Default hostname is localhost. */ 107 if (ret.host_str.empty ()) 108 ret.host_str = "localhost"; 109 110 return ret; 111 } 112 113 /* See gdbsupport/netstuff.h. */ 114 115 parsed_connection_spec 116 parse_connection_spec (const char *spec, struct addrinfo *hint) 117 { 118 /* Struct to hold the association between valid prefixes, their 119 family and socktype. */ 120 struct host_prefix 121 { 122 /* The prefix. */ 123 const char *prefix; 124 125 /* The 'ai_family'. */ 126 int family; 127 128 /* The 'ai_socktype'. */ 129 int socktype; 130 }; 131 static const struct host_prefix prefixes[] = 132 { 133 { "udp:", AF_UNSPEC, SOCK_DGRAM }, 134 { "tcp:", AF_UNSPEC, SOCK_STREAM }, 135 { "udp4:", AF_INET, SOCK_DGRAM }, 136 { "tcp4:", AF_INET, SOCK_STREAM }, 137 { "udp6:", AF_INET6, SOCK_DGRAM }, 138 { "tcp6:", AF_INET6, SOCK_STREAM }, 139 }; 140 141 for (const host_prefix prefix : prefixes) 142 if (startswith (spec, prefix.prefix)) 143 { 144 spec += strlen (prefix.prefix); 145 hint->ai_family = prefix.family; 146 hint->ai_socktype = prefix.socktype; 147 hint->ai_protocol 148 = hint->ai_socktype == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP; 149 break; 150 } 151 152 return parse_connection_spec_without_prefix (spec, hint); 153 } 154