Home | History | Annotate | Download | only in client_channel
      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/sockaddr.h"
     23 #include "src/core/lib/iomgr/socket_utils.h"
     24 
     25 #include <stdio.h>
     26 #include <string.h>
     27 #ifdef GRPC_HAVE_UNIX_SOCKET
     28 #include <sys/un.h>
     29 #endif
     30 
     31 #include <grpc/support/alloc.h>
     32 #include <grpc/support/log.h>
     33 #include <grpc/support/string_util.h>
     34 
     35 #include "src/core/lib/gpr/host_port.h"
     36 #include "src/core/lib/gpr/string.h"
     37 
     38 #ifdef GRPC_HAVE_UNIX_SOCKET
     39 
     40 bool grpc_parse_unix(const grpc_uri* uri,
     41                      grpc_resolved_address* resolved_addr) {
     42   if (strcmp("unix", uri->scheme) != 0) {
     43     gpr_log(GPR_ERROR, "Expected 'unix' scheme, got '%s'", uri->scheme);
     44     return false;
     45   }
     46   struct sockaddr_un* un =
     47       reinterpret_cast<struct sockaddr_un*>(resolved_addr->addr);
     48   const size_t maxlen = sizeof(un->sun_path);
     49   const size_t path_len = strnlen(uri->path, maxlen);
     50   if (path_len == maxlen) return false;
     51   un->sun_family = AF_UNIX;
     52   strcpy(un->sun_path, uri->path);
     53   resolved_addr->len = static_cast<socklen_t>(sizeof(*un));
     54   return true;
     55 }
     56 
     57 #else /* GRPC_HAVE_UNIX_SOCKET */
     58 
     59 bool grpc_parse_unix(const grpc_uri* uri,
     60                      grpc_resolved_address* resolved_addr) {
     61   abort();
     62 }
     63 
     64 #endif /* GRPC_HAVE_UNIX_SOCKET */
     65 
     66 bool grpc_parse_ipv4_hostport(const char* hostport, grpc_resolved_address* addr,
     67                               bool log_errors) {
     68   bool success = false;
     69   // Split host and port.
     70   char* host;
     71   char* port;
     72   if (!gpr_split_host_port(hostport, &host, &port)) return false;
     73   // Parse IP address.
     74   memset(addr, 0, sizeof(*addr));
     75   addr->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in));
     76   grpc_sockaddr_in* in = reinterpret_cast<grpc_sockaddr_in*>(addr->addr);
     77   in->sin_family = GRPC_AF_INET;
     78   if (grpc_inet_pton(GRPC_AF_INET, host, &in->sin_addr) == 0) {
     79     if (log_errors) gpr_log(GPR_ERROR, "invalid ipv4 address: '%s'", host);
     80     goto done;
     81   }
     82   // Parse port.
     83   if (port == nullptr) {
     84     if (log_errors) gpr_log(GPR_ERROR, "no port given for ipv4 scheme");
     85     goto done;
     86   }
     87   int port_num;
     88   if (sscanf(port, "%d", &port_num) != 1 || port_num < 0 || port_num > 65535) {
     89     if (log_errors) gpr_log(GPR_ERROR, "invalid ipv4 port: '%s'", port);
     90     goto done;
     91   }
     92   in->sin_port = grpc_htons(static_cast<uint16_t>(port_num));
     93   success = true;
     94 done:
     95   gpr_free(host);
     96   gpr_free(port);
     97   return success;
     98 }
     99 
    100 bool grpc_parse_ipv4(const grpc_uri* uri,
    101                      grpc_resolved_address* resolved_addr) {
    102   if (strcmp("ipv4", uri->scheme) != 0) {
    103     gpr_log(GPR_ERROR, "Expected 'ipv4' scheme, got '%s'", uri->scheme);
    104     return false;
    105   }
    106   const char* host_port = uri->path;
    107   if (*host_port == '/') ++host_port;
    108   return grpc_parse_ipv4_hostport(host_port, resolved_addr,
    109                                   true /* log_errors */);
    110 }
    111 
    112 bool grpc_parse_ipv6_hostport(const char* hostport, grpc_resolved_address* addr,
    113                               bool log_errors) {
    114   bool success = false;
    115   // Split host and port.
    116   char* host;
    117   char* port;
    118   if (!gpr_split_host_port(hostport, &host, &port)) return false;
    119   // Parse IP address.
    120   memset(addr, 0, sizeof(*addr));
    121   addr->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in6));
    122   grpc_sockaddr_in6* in6 = reinterpret_cast<grpc_sockaddr_in6*>(addr->addr);
    123   in6->sin6_family = GRPC_AF_INET6;
    124   // Handle the RFC6874 syntax for IPv6 zone identifiers.
    125   char* host_end = static_cast<char*>(gpr_memrchr(host, '%', strlen(host)));
    126   if (host_end != nullptr) {
    127     GPR_ASSERT(host_end >= host);
    128     char host_without_scope[GRPC_INET6_ADDRSTRLEN + 1];
    129     size_t host_without_scope_len = static_cast<size_t>(host_end - host);
    130     uint32_t sin6_scope_id = 0;
    131     if (host_without_scope_len > GRPC_INET6_ADDRSTRLEN) {
    132       if (log_errors) {
    133         gpr_log(
    134             GPR_ERROR,
    135             "invalid ipv6 address length %zu. Length cannot be greater than "
    136             "GRPC_INET6_ADDRSTRLEN i.e %d)",
    137             host_without_scope_len, GRPC_INET6_ADDRSTRLEN);
    138       }
    139       goto done;
    140     }
    141     strncpy(host_without_scope, host, host_without_scope_len);
    142     host_without_scope[host_without_scope_len] = '\0';
    143     if (grpc_inet_pton(GRPC_AF_INET6, host_without_scope, &in6->sin6_addr) ==
    144         0) {
    145       if (log_errors) {
    146         gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host_without_scope);
    147       }
    148       goto done;
    149     }
    150     if (gpr_parse_bytes_to_uint32(host_end + 1,
    151                                   strlen(host) - host_without_scope_len - 1,
    152                                   &sin6_scope_id) == 0) {
    153       if (log_errors) {
    154         gpr_log(GPR_ERROR, "invalid ipv6 scope id: '%s'", host_end + 1);
    155       }
    156       goto done;
    157     }
    158     // Handle "sin6_scope_id" being type "u_long". See grpc issue #10027.
    159     in6->sin6_scope_id = sin6_scope_id;
    160   } else {
    161     if (grpc_inet_pton(GRPC_AF_INET6, host, &in6->sin6_addr) == 0) {
    162       if (log_errors) gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host);
    163       goto done;
    164     }
    165   }
    166   // Parse port.
    167   if (port == nullptr) {
    168     if (log_errors) gpr_log(GPR_ERROR, "no port given for ipv6 scheme");
    169     goto done;
    170   }
    171   int port_num;
    172   if (sscanf(port, "%d", &port_num) != 1 || port_num < 0 || port_num > 65535) {
    173     if (log_errors) gpr_log(GPR_ERROR, "invalid ipv6 port: '%s'", port);
    174     goto done;
    175   }
    176   in6->sin6_port = grpc_htons(static_cast<uint16_t>(port_num));
    177   success = true;
    178 done:
    179   gpr_free(host);
    180   gpr_free(port);
    181   return success;
    182 }
    183 
    184 bool grpc_parse_ipv6(const grpc_uri* uri,
    185                      grpc_resolved_address* resolved_addr) {
    186   if (strcmp("ipv6", uri->scheme) != 0) {
    187     gpr_log(GPR_ERROR, "Expected 'ipv6' scheme, got '%s'", uri->scheme);
    188     return false;
    189   }
    190   const char* host_port = uri->path;
    191   if (*host_port == '/') ++host_port;
    192   return grpc_parse_ipv6_hostport(host_port, resolved_addr,
    193                                   true /* log_errors */);
    194 }
    195 
    196 bool grpc_parse_uri(const grpc_uri* uri, grpc_resolved_address* resolved_addr) {
    197   if (strcmp("unix", uri->scheme) == 0) {
    198     return grpc_parse_unix(uri, resolved_addr);
    199   } else if (strcmp("ipv4", uri->scheme) == 0) {
    200     return grpc_parse_ipv4(uri, resolved_addr);
    201   } else if (strcmp("ipv6", uri->scheme) == 0) {
    202     return grpc_parse_ipv6(uri, resolved_addr);
    203   }
    204   gpr_log(GPR_ERROR, "Can't parse scheme '%s'", uri->scheme);
    205   return false;
    206 }
    207 
    208 uint16_t grpc_strhtons(const char* port) {
    209   if (strcmp(port, "http") == 0) {
    210     return htons(80);
    211   } else if (strcmp(port, "https") == 0) {
    212     return htons(443);
    213   }
    214   return htons(static_cast<unsigned short>(atoi(port)));
    215 }
    216