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