Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc-cloned / deps / grpc / src / core / ext / filters / client_channel / parse_address.cc
1 /*
2  *
3  * Copyright 2016 gRPC authors.
4  *
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
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  *
17  */
18
19 #include <grpc/support/port_platform.h>
20
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"
25
26 #include <stdio.h>
27 #include <string.h>
28 #ifdef GRPC_HAVE_UNIX_SOCKET
29 #include <sys/un.h>
30 #endif
31
32 #include <grpc/support/alloc.h>
33 #include <grpc/support/log.h>
34 #include <grpc/support/string_util.h>
35
36 #include "src/core/lib/gpr/string.h"
37 #include "src/core/lib/gprpp/host_port.h"
38
39 #ifdef GRPC_POSIX_SOCKET
40 #include <errno.h>
41 #include <net/if.h>
42 #endif
43
44 #ifdef GRPC_HAVE_UNIX_SOCKET
45
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);
50     return false;
51   }
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));
60   return true;
61 }
62
63 #else /* GRPC_HAVE_UNIX_SOCKET */
64
65 bool grpc_parse_unix(const grpc_uri* uri,
66                      grpc_resolved_address* resolved_addr) {
67   abort();
68 }
69
70 #endif /* GRPC_HAVE_UNIX_SOCKET */
71
72 bool grpc_parse_ipv4_hostport(const char* hostport, grpc_resolved_address* addr,
73                               bool log_errors) {
74   bool success = false;
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)) {
79     if (log_errors) {
80       gpr_log(GPR_ERROR, "Failed gpr_split_host_port(%s, ...)", hostport);
81     }
82     return false;
83   }
84   // Parse IP address.
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) {
90     if (log_errors) {
91       gpr_log(GPR_ERROR, "invalid ipv4 address: '%s'", host.get());
92     }
93     goto done;
94   }
95   // Parse port.
96   if (port == nullptr) {
97     if (log_errors) gpr_log(GPR_ERROR, "no port given for ipv4 scheme");
98     goto done;
99   }
100   int port_num;
101   if (sscanf(port.get(), "%d", &port_num) != 1 || port_num < 0 ||
102       port_num > 65535) {
103     if (log_errors) gpr_log(GPR_ERROR, "invalid ipv4 port: '%s'", port.get());
104     goto done;
105   }
106   in->sin_port = grpc_htons(static_cast<uint16_t>(port_num));
107   success = true;
108 done:
109   return success;
110 }
111
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);
116     return false;
117   }
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 */);
122 }
123
124 bool grpc_parse_ipv6_hostport(const char* hostport, grpc_resolved_address* addr,
125                               bool log_errors) {
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)) {
131     if (log_errors) {
132       gpr_log(GPR_ERROR, "Failed gpr_split_host_port(%s, ...)", hostport);
133     }
134     return false;
135   }
136   // Parse IP address.
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.
142   char* host_end =
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) {
150       if (log_errors) {
151         gpr_log(
152             GPR_ERROR,
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);
156       }
157       goto done;
158     }
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) ==
162         0) {
163       if (log_errors) {
164         gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host_without_scope);
165       }
166       goto done;
167     }
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) {
172         gpr_log(GPR_ERROR,
173                 "Invalid interface name: '%s'. "
174                 "Non-numeric and failed if_nametoindex.",
175                 host_end + 1);
176         goto done;
177       }
178     }
179     // Handle "sin6_scope_id" being type "u_long". See grpc issue #10027.
180     in6->sin6_scope_id = sin6_scope_id;
181   } else {
182     if (grpc_inet_pton(GRPC_AF_INET6, host.get(), &in6->sin6_addr) == 0) {
183       if (log_errors) {
184         gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host.get());
185       }
186       goto done;
187     }
188   }
189   // Parse port.
190   if (port == nullptr) {
191     if (log_errors) gpr_log(GPR_ERROR, "no port given for ipv6 scheme");
192     goto done;
193   }
194   int port_num;
195   if (sscanf(port.get(), "%d", &port_num) != 1 || port_num < 0 ||
196       port_num > 65535) {
197     if (log_errors) gpr_log(GPR_ERROR, "invalid ipv6 port: '%s'", port.get());
198     goto done;
199   }
200   in6->sin6_port = grpc_htons(static_cast<uint16_t>(port_num));
201   success = true;
202 done:
203   return success;
204 }
205
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);
210     return false;
211   }
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 */);
216 }
217
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);
225   }
226   gpr_log(GPR_ERROR, "Can't parse scheme '%s'", uri->scheme);
227   return false;
228 }
229
230 uint16_t grpc_strhtons(const char* port) {
231   if (strcmp(port, "http") == 0) {
232     return htons(80);
233   } else if (strcmp(port, "https") == 0) {
234     return htons(443);
235   }
236   return htons(static_cast<unsigned short>(atoi(port)));
237 }