netstuff.cc revision 1.1.1.4 1 /* Operations on network stuff.
2 Copyright (C) 2018-2025 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