1/* Operations on network stuff. 2 Copyright (C) 2018-2020 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 "common-defs.h" 20#include "netstuff.h" 21#include <algorithm> 22 23#ifdef USE_WIN32API 24#include <ws2tcpip.h> 25#else 26#include <netinet/in.h> 27#include <arpa/inet.h> 28#include <netdb.h> 29#include <sys/socket.h> 30#include <netinet/tcp.h> 31#endif 32 33/* See gdbsupport/netstuff.h. */ 34 35scoped_free_addrinfo::~scoped_free_addrinfo () 36{ 37 freeaddrinfo (m_res); 38} 39 40/* See gdbsupport/netstuff.h. */ 41 42parsed_connection_spec 43parse_connection_spec_without_prefix (std::string spec, struct addrinfo *hint) 44{ 45 parsed_connection_spec ret; 46 size_t last_colon_pos = 0; 47 /* We're dealing with IPv6 if: 48 49 - ai_family is AF_INET6, or 50 - ai_family is not AF_INET, and 51 - spec[0] is '[', or 52 - the number of ':' on spec is greater than 1. */ 53 bool is_ipv6 = (hint->ai_family == AF_INET6 54 || (hint->ai_family != AF_INET 55 && (spec[0] == '[' 56 || std::count (spec.begin (), 57 spec.end (), ':') > 1))); 58 59 if (is_ipv6) 60 { 61 if (spec[0] == '[') 62 { 63 /* IPv6 addresses can be written as '[ADDR]:PORT', and we 64 support this notation. */ 65 size_t close_bracket_pos = spec.find_first_of (']'); 66 67 if (close_bracket_pos == std::string::npos) 68 error (_("Missing close bracket in hostname '%s'"), 69 spec.c_str ()); 70 71 hint->ai_family = AF_INET6; 72 73 const char c = spec[close_bracket_pos + 1]; 74 75 if (c == '\0') 76 last_colon_pos = std::string::npos; 77 else if (c != ':') 78 error (_("Invalid cruft after close bracket in '%s'"), 79 spec.c_str ()); 80 81 /* Erase both '[' and ']'. */ 82 spec.erase (0, 1); 83 spec.erase (close_bracket_pos - 1, 1); 84 } 85 else if (spec.find_first_of (']') != std::string::npos) 86 error (_("Missing open bracket in hostname '%s'"), 87 spec.c_str ()); 88 } 89 90 if (last_colon_pos == 0) 91 last_colon_pos = spec.find_last_of (':'); 92 93 /* The length of the hostname part. */ 94 size_t host_len; 95 96 if (last_colon_pos != std::string::npos) 97 { 98 /* The user has provided a port. */ 99 host_len = last_colon_pos; 100 ret.port_str = spec.substr (last_colon_pos + 1); 101 } 102 else 103 host_len = spec.size (); 104 105 ret.host_str = spec.substr (0, host_len); 106 107 /* Default hostname is localhost. */ 108 if (ret.host_str.empty ()) 109 ret.host_str = "localhost"; 110 111 return ret; 112} 113 114/* See gdbsupport/netstuff.h. */ 115 116parsed_connection_spec 117parse_connection_spec (const char *spec, struct addrinfo *hint) 118{ 119 /* Struct to hold the association between valid prefixes, their 120 family and socktype. */ 121 struct host_prefix 122 { 123 /* The prefix. */ 124 const char *prefix; 125 126 /* The 'ai_family'. */ 127 int family; 128 129 /* The 'ai_socktype'. */ 130 int socktype; 131 }; 132 static const struct host_prefix prefixes[] = 133 { 134 { "udp:", AF_UNSPEC, SOCK_DGRAM }, 135 { "tcp:", AF_UNSPEC, SOCK_STREAM }, 136 { "udp4:", AF_INET, SOCK_DGRAM }, 137 { "tcp4:", AF_INET, SOCK_STREAM }, 138 { "udp6:", AF_INET6, SOCK_DGRAM }, 139 { "tcp6:", AF_INET6, SOCK_STREAM }, 140 }; 141 142 for (const host_prefix prefix : prefixes) 143 if (startswith (spec, prefix.prefix)) 144 { 145 spec += strlen (prefix.prefix); 146 hint->ai_family = prefix.family; 147 hint->ai_socktype = prefix.socktype; 148 hint->ai_protocol 149 = hint->ai_socktype == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP; 150 break; 151 } 152 153 return parse_connection_spec_without_prefix (spec, hint); 154} 155