3 * Copyright 2016 gRPC authors.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 #include <grpc/support/port_platform.h>
21 #include "src/core/ext/filters/client_channel/parse_address.h"
22 #include "src/core/lib/iomgr/grpc_if_nametoindex.h"
23 #include "src/core/lib/iomgr/sockaddr.h"
24 #include "src/core/lib/iomgr/socket_utils.h"
28 #ifdef GRPC_HAVE_UNIX_SOCKET
32 #include <grpc/support/alloc.h>
33 #include <grpc/support/log.h>
34 #include <grpc/support/string_util.h>
36 #include "src/core/lib/gpr/string.h"
37 #include "src/core/lib/gprpp/host_port.h"
39 #ifdef GRPC_POSIX_SOCKET
44 #ifdef GRPC_HAVE_UNIX_SOCKET
46 bool grpc_parse_unix(const grpc_uri* uri,
47 grpc_resolved_address* resolved_addr) {
48 if (strcmp("unix", uri->scheme) != 0) {
49 gpr_log(GPR_ERROR, "Expected 'unix' scheme, got '%s'", uri->scheme);
52 struct sockaddr_un* un =
53 reinterpret_cast<struct sockaddr_un*>(resolved_addr->addr);
54 const size_t maxlen = sizeof(un->sun_path);
55 const size_t path_len = strnlen(uri->path, maxlen);
56 if (path_len == maxlen) return false;
57 un->sun_family = AF_UNIX;
58 strcpy(un->sun_path, uri->path);
59 resolved_addr->len = static_cast<socklen_t>(sizeof(*un));
63 #else /* GRPC_HAVE_UNIX_SOCKET */
65 bool grpc_parse_unix(const grpc_uri* uri,
66 grpc_resolved_address* resolved_addr) {
70 #endif /* GRPC_HAVE_UNIX_SOCKET */
72 bool grpc_parse_ipv4_hostport(const char* hostport, grpc_resolved_address* addr,
75 // Split host and port.
76 grpc_core::UniquePtr<char> host;
77 grpc_core::UniquePtr<char> port;
78 if (!grpc_core::SplitHostPort(hostport, &host, &port)) {
80 gpr_log(GPR_ERROR, "Failed gpr_split_host_port(%s, ...)", hostport);
85 memset(addr, 0, sizeof(*addr));
86 addr->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in));
87 grpc_sockaddr_in* in = reinterpret_cast<grpc_sockaddr_in*>(addr->addr);
88 in->sin_family = GRPC_AF_INET;
89 if (grpc_inet_pton(GRPC_AF_INET, host.get(), &in->sin_addr) == 0) {
91 gpr_log(GPR_ERROR, "invalid ipv4 address: '%s'", host.get());
96 if (port == nullptr) {
97 if (log_errors) gpr_log(GPR_ERROR, "no port given for ipv4 scheme");
101 if (sscanf(port.get(), "%d", &port_num) != 1 || port_num < 0 ||
103 if (log_errors) gpr_log(GPR_ERROR, "invalid ipv4 port: '%s'", port.get());
106 in->sin_port = grpc_htons(static_cast<uint16_t>(port_num));
112 bool grpc_parse_ipv4(const grpc_uri* uri,
113 grpc_resolved_address* resolved_addr) {
114 if (strcmp("ipv4", uri->scheme) != 0) {
115 gpr_log(GPR_ERROR, "Expected 'ipv4' scheme, got '%s'", uri->scheme);
118 const char* host_port = uri->path;
119 if (*host_port == '/') ++host_port;
120 return grpc_parse_ipv4_hostport(host_port, resolved_addr,
121 true /* log_errors */);
124 bool grpc_parse_ipv6_hostport(const char* hostport, grpc_resolved_address* addr,
126 bool success = false;
127 // Split host and port.
128 grpc_core::UniquePtr<char> host;
129 grpc_core::UniquePtr<char> port;
130 if (!grpc_core::SplitHostPort(hostport, &host, &port)) {
132 gpr_log(GPR_ERROR, "Failed gpr_split_host_port(%s, ...)", hostport);
137 memset(addr, 0, sizeof(*addr));
138 addr->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in6));
139 grpc_sockaddr_in6* in6 = reinterpret_cast<grpc_sockaddr_in6*>(addr->addr);
140 in6->sin6_family = GRPC_AF_INET6;
141 // Handle the RFC6874 syntax for IPv6 zone identifiers.
143 static_cast<char*>(gpr_memrchr(host.get(), '%', strlen(host.get())));
144 if (host_end != nullptr) {
145 GPR_ASSERT(host_end >= host.get());
146 char host_without_scope[GRPC_INET6_ADDRSTRLEN + 1];
147 size_t host_without_scope_len = static_cast<size_t>(host_end - host.get());
148 uint32_t sin6_scope_id = 0;
149 if (host_without_scope_len > GRPC_INET6_ADDRSTRLEN) {
153 "invalid ipv6 address length %zu. Length cannot be greater than "
154 "GRPC_INET6_ADDRSTRLEN i.e %d)",
155 host_without_scope_len, GRPC_INET6_ADDRSTRLEN);
159 strncpy(host_without_scope, host.get(), host_without_scope_len);
160 host_without_scope[host_without_scope_len] = '\0';
161 if (grpc_inet_pton(GRPC_AF_INET6, host_without_scope, &in6->sin6_addr) ==
164 gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host_without_scope);
168 if (gpr_parse_bytes_to_uint32(
169 host_end + 1, strlen(host.get()) - host_without_scope_len - 1,
170 &sin6_scope_id) == 0) {
171 if ((sin6_scope_id = grpc_if_nametoindex(host_end + 1)) == 0) {
173 "Invalid interface name: '%s'. "
174 "Non-numeric and failed if_nametoindex.",
179 // Handle "sin6_scope_id" being type "u_long". See grpc issue #10027.
180 in6->sin6_scope_id = sin6_scope_id;
182 if (grpc_inet_pton(GRPC_AF_INET6, host.get(), &in6->sin6_addr) == 0) {
184 gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host.get());
190 if (port == nullptr) {
191 if (log_errors) gpr_log(GPR_ERROR, "no port given for ipv6 scheme");
195 if (sscanf(port.get(), "%d", &port_num) != 1 || port_num < 0 ||
197 if (log_errors) gpr_log(GPR_ERROR, "invalid ipv6 port: '%s'", port.get());
200 in6->sin6_port = grpc_htons(static_cast<uint16_t>(port_num));
206 bool grpc_parse_ipv6(const grpc_uri* uri,
207 grpc_resolved_address* resolved_addr) {
208 if (strcmp("ipv6", uri->scheme) != 0) {
209 gpr_log(GPR_ERROR, "Expected 'ipv6' scheme, got '%s'", uri->scheme);
212 const char* host_port = uri->path;
213 if (*host_port == '/') ++host_port;
214 return grpc_parse_ipv6_hostport(host_port, resolved_addr,
215 true /* log_errors */);
218 bool grpc_parse_uri(const grpc_uri* uri, grpc_resolved_address* resolved_addr) {
219 if (strcmp("unix", uri->scheme) == 0) {
220 return grpc_parse_unix(uri, resolved_addr);
221 } else if (strcmp("ipv4", uri->scheme) == 0) {
222 return grpc_parse_ipv4(uri, resolved_addr);
223 } else if (strcmp("ipv6", uri->scheme) == 0) {
224 return grpc_parse_ipv6(uri, resolved_addr);
226 gpr_log(GPR_ERROR, "Can't parse scheme '%s'", uri->scheme);
230 uint16_t grpc_strhtons(const char* port) {
231 if (strcmp(port, "http") == 0) {
233 } else if (strcmp(port, "https") == 0) {
236 return htons(static_cast<unsigned short>(atoi(port)));