The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#)
https://grpc.io/
189 lines
6.6 KiB
189 lines
6.6 KiB
/* |
|
* |
|
* Copyright 2015, Google Inc. |
|
* All rights reserved. |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions are |
|
* met: |
|
* |
|
* * Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* * Redistributions in binary form must reproduce the above |
|
* copyright notice, this list of conditions and the following disclaimer |
|
* in the documentation and/or other materials provided with the |
|
* distribution. |
|
* * Neither the name of Google Inc. nor the names of its |
|
* contributors may be used to endorse or promote products derived from |
|
* this software without specific prior written permission. |
|
* |
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
* |
|
*/ |
|
|
|
#include "src/core/iomgr/sockaddr_utils.h" |
|
|
|
#include <errno.h> |
|
#include <string.h> |
|
|
|
#include "src/core/support/string.h" |
|
#include <grpc/support/host_port.h> |
|
#include <grpc/support/log.h> |
|
#include <grpc/support/port_platform.h> |
|
|
|
static const gpr_uint8 kV4MappedPrefix[] = {0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0xff, 0xff}; |
|
|
|
int grpc_sockaddr_is_v4mapped(const struct sockaddr *addr, |
|
struct sockaddr_in *addr4_out) { |
|
GPR_ASSERT(addr != (struct sockaddr *)addr4_out); |
|
if (addr->sa_family == AF_INET6) { |
|
const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; |
|
if (memcmp(addr6->sin6_addr.s6_addr, kV4MappedPrefix, |
|
sizeof(kV4MappedPrefix)) == 0) { |
|
if (addr4_out != NULL) { |
|
/* Normalize ::ffff:0.0.0.0/96 to IPv4. */ |
|
memset(addr4_out, 0, sizeof(*addr4_out)); |
|
addr4_out->sin_family = AF_INET; |
|
/* s6_addr32 would be nice, but it's non-standard. */ |
|
memcpy(&addr4_out->sin_addr, &addr6->sin6_addr.s6_addr[12], 4); |
|
addr4_out->sin_port = addr6->sin6_port; |
|
} |
|
return 1; |
|
} |
|
} |
|
return 0; |
|
} |
|
|
|
int grpc_sockaddr_to_v4mapped(const struct sockaddr *addr, |
|
struct sockaddr_in6 *addr6_out) { |
|
GPR_ASSERT(addr != (struct sockaddr *)addr6_out); |
|
if (addr->sa_family == AF_INET) { |
|
const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr; |
|
memset(addr6_out, 0, sizeof(*addr6_out)); |
|
addr6_out->sin6_family = AF_INET6; |
|
memcpy(&addr6_out->sin6_addr.s6_addr[0], kV4MappedPrefix, 12); |
|
memcpy(&addr6_out->sin6_addr.s6_addr[12], &addr4->sin_addr, 4); |
|
addr6_out->sin6_port = addr4->sin_port; |
|
return 1; |
|
} |
|
return 0; |
|
} |
|
|
|
int grpc_sockaddr_is_wildcard(const struct sockaddr *addr, int *port_out) { |
|
struct sockaddr_in addr4_normalized; |
|
if (grpc_sockaddr_is_v4mapped(addr, &addr4_normalized)) { |
|
addr = (struct sockaddr *)&addr4_normalized; |
|
} |
|
if (addr->sa_family == AF_INET) { |
|
/* Check for 0.0.0.0 */ |
|
const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr; |
|
if (addr4->sin_addr.s_addr != 0) { |
|
return 0; |
|
} |
|
*port_out = ntohs(addr4->sin_port); |
|
return 1; |
|
} else if (addr->sa_family == AF_INET6) { |
|
/* Check for :: */ |
|
const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; |
|
int i; |
|
for (i = 0; i < 16; i++) { |
|
if (addr6->sin6_addr.s6_addr[i] != 0) { |
|
return 0; |
|
} |
|
} |
|
*port_out = ntohs(addr6->sin6_port); |
|
return 1; |
|
} else { |
|
return 0; |
|
} |
|
} |
|
|
|
void grpc_sockaddr_make_wildcards(int port, struct sockaddr_in *wild4_out, |
|
struct sockaddr_in6 *wild6_out) { |
|
grpc_sockaddr_make_wildcard4(port, wild4_out); |
|
grpc_sockaddr_make_wildcard6(port, wild6_out); |
|
} |
|
|
|
void grpc_sockaddr_make_wildcard4(int port, struct sockaddr_in *wild_out) { |
|
memset(wild_out, 0, sizeof(*wild_out)); |
|
wild_out->sin_family = AF_INET; |
|
wild_out->sin_port = htons(port); |
|
} |
|
|
|
void grpc_sockaddr_make_wildcard6(int port, struct sockaddr_in6 *wild_out) { |
|
memset(wild_out, 0, sizeof(*wild_out)); |
|
wild_out->sin6_family = AF_INET6; |
|
wild_out->sin6_port = htons(port); |
|
} |
|
|
|
int grpc_sockaddr_to_string(char **out, const struct sockaddr *addr, |
|
int normalize) { |
|
const int save_errno = errno; |
|
struct sockaddr_in addr_normalized; |
|
char ntop_buf[INET6_ADDRSTRLEN]; |
|
const void *ip = NULL; |
|
int port; |
|
int ret; |
|
|
|
*out = NULL; |
|
if (normalize && grpc_sockaddr_is_v4mapped(addr, &addr_normalized)) { |
|
addr = (const struct sockaddr *)&addr_normalized; |
|
} |
|
if (addr->sa_family == AF_INET) { |
|
const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr; |
|
ip = &addr4->sin_addr; |
|
port = ntohs(addr4->sin_port); |
|
} else if (addr->sa_family == AF_INET6) { |
|
const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; |
|
ip = &addr6->sin6_addr; |
|
port = ntohs(addr6->sin6_port); |
|
} |
|
if (ip != NULL && |
|
inet_ntop(addr->sa_family, ip, ntop_buf, sizeof(ntop_buf)) != NULL) { |
|
ret = gpr_join_host_port(out, ntop_buf, port); |
|
} else { |
|
ret = gpr_asprintf(out, "(sockaddr family=%d)", addr->sa_family); |
|
} |
|
/* This is probably redundant, but we wouldn't want to log the wrong error. */ |
|
errno = save_errno; |
|
return ret; |
|
} |
|
|
|
int grpc_sockaddr_get_port(const struct sockaddr *addr) { |
|
switch (addr->sa_family) { |
|
case AF_INET: |
|
return ntohs(((struct sockaddr_in *)addr)->sin_port); |
|
case AF_INET6: |
|
return ntohs(((struct sockaddr_in6 *)addr)->sin6_port); |
|
case AF_UNIX: |
|
return 1; |
|
default: |
|
gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_get_port", addr->sa_family); |
|
return 0; |
|
} |
|
} |
|
|
|
int grpc_sockaddr_set_port(const struct sockaddr *addr, int port) { |
|
switch (addr->sa_family) { |
|
case AF_INET: |
|
((struct sockaddr_in *)addr)->sin_port = htons(port); |
|
return 1; |
|
case AF_INET6: |
|
((struct sockaddr_in6 *)addr)->sin6_port = htons(port); |
|
return 1; |
|
default: |
|
gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_set_port", addr->sa_family); |
|
return 0; |
|
} |
|
}
|
|
|