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