|
|
|
@ -38,7 +38,7 @@ |
|
|
|
|
|
|
|
|
|
#include "src/core/lib/iomgr/port.h" |
|
|
|
|
|
|
|
|
|
#ifdef GPR_POSIX_SOCKET |
|
|
|
|
#ifdef GRPC_POSIX_SOCKET |
|
|
|
|
|
|
|
|
|
#include "src/core/lib/iomgr/udp_server.h" |
|
|
|
|
|
|
|
|
@ -62,6 +62,7 @@ |
|
|
|
|
#include "src/core/lib/iomgr/error.h" |
|
|
|
|
#include "src/core/lib/iomgr/ev_posix.h" |
|
|
|
|
#include "src/core/lib/iomgr/resolve_address.h" |
|
|
|
|
#include "src/core/lib/iomgr/sockaddr.h" |
|
|
|
|
#include "src/core/lib/iomgr/sockaddr_utils.h" |
|
|
|
|
#include "src/core/lib/iomgr/socket_utils_posix.h" |
|
|
|
|
#include "src/core/lib/support/string.h" |
|
|
|
@ -73,11 +74,7 @@ typedef struct { |
|
|
|
|
int fd; |
|
|
|
|
grpc_fd *emfd; |
|
|
|
|
grpc_udp_server *server; |
|
|
|
|
union { |
|
|
|
|
uint8_t untyped[GRPC_MAX_SOCKADDR_SIZE]; |
|
|
|
|
struct sockaddr sockaddr; |
|
|
|
|
} addr; |
|
|
|
|
size_t addr_len; |
|
|
|
|
grpc_resolved_address addr; |
|
|
|
|
grpc_closure read_closure; |
|
|
|
|
grpc_closure destroyed_closure; |
|
|
|
|
grpc_udp_server_read_cb read_cb; |
|
|
|
@ -214,10 +211,9 @@ void grpc_udp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_udp_server *s, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Prepare a recently-created socket for listening. */ |
|
|
|
|
static int prepare_socket(int fd, const struct sockaddr *addr, |
|
|
|
|
size_t addr_len) { |
|
|
|
|
struct sockaddr_storage sockname_temp; |
|
|
|
|
socklen_t sockname_len; |
|
|
|
|
static int prepare_socket(int fd, const grpc_resolved_address *addr) { |
|
|
|
|
grpc_resolved_address sockname_temp; |
|
|
|
|
struct sockaddr *addr_ptr = (struct sockaddr *)addr->addr; |
|
|
|
|
/* Set send/receive socket buffers to 1 MB */ |
|
|
|
|
int buffer_size_bytes = 1024 * 1024; |
|
|
|
|
|
|
|
|
@ -237,15 +233,15 @@ static int prepare_socket(int fd, const struct sockaddr *addr, |
|
|
|
|
if (grpc_set_socket_ip_pktinfo_if_possible(fd) != GRPC_ERROR_NONE) { |
|
|
|
|
gpr_log(GPR_ERROR, "Unable to set ip_pktinfo."); |
|
|
|
|
goto error; |
|
|
|
|
} else if (addr->sa_family == AF_INET6) { |
|
|
|
|
} else if (addr_ptr->sa_family == AF_INET6) { |
|
|
|
|
if (grpc_set_socket_ipv6_recvpktinfo_if_possible(fd) != GRPC_ERROR_NONE) { |
|
|
|
|
gpr_log(GPR_ERROR, "Unable to set ipv6_recvpktinfo."); |
|
|
|
|
goto error; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
GPR_ASSERT(addr_len < ~(socklen_t)0); |
|
|
|
|
if (bind(fd, addr, (socklen_t)addr_len) < 0) { |
|
|
|
|
GPR_ASSERT(addr->len < ~(socklen_t)0); |
|
|
|
|
if (bind(fd, (struct sockaddr *)addr, (socklen_t)addr->len) < 0) { |
|
|
|
|
char *addr_str; |
|
|
|
|
grpc_sockaddr_to_string(&addr_str, addr, 0); |
|
|
|
|
gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, strerror(errno)); |
|
|
|
@ -253,8 +249,10 @@ static int prepare_socket(int fd, const struct sockaddr *addr, |
|
|
|
|
goto error; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sockname_len = sizeof(sockname_temp); |
|
|
|
|
if (getsockname(fd, (struct sockaddr *)&sockname_temp, &sockname_len) < 0) { |
|
|
|
|
sockname_temp.len = sizeof(struct sockaddr_storage); |
|
|
|
|
|
|
|
|
|
if (getsockname(fd, (struct sockaddr *)sockname_temp.addr, |
|
|
|
|
(socklen_t *)&sockname_temp.len) < 0) { |
|
|
|
|
goto error; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -270,7 +268,7 @@ static int prepare_socket(int fd, const struct sockaddr *addr, |
|
|
|
|
goto error; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); |
|
|
|
|
return grpc_sockaddr_get_port(&sockname_temp); |
|
|
|
|
|
|
|
|
|
error: |
|
|
|
|
if (fd >= 0) { |
|
|
|
@ -303,7 +301,7 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int add_socket_to_server(grpc_udp_server *s, int fd, |
|
|
|
|
const struct sockaddr *addr, size_t addr_len, |
|
|
|
|
const grpc_resolved_address *addr, |
|
|
|
|
grpc_udp_server_read_cb read_cb, |
|
|
|
|
grpc_udp_server_orphan_cb orphan_cb) { |
|
|
|
|
server_port *sp; |
|
|
|
@ -311,9 +309,9 @@ static int add_socket_to_server(grpc_udp_server *s, int fd, |
|
|
|
|
char *addr_str; |
|
|
|
|
char *name; |
|
|
|
|
|
|
|
|
|
port = prepare_socket(fd, addr, addr_len); |
|
|
|
|
port = prepare_socket(fd, addr); |
|
|
|
|
if (port >= 0) { |
|
|
|
|
grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1); |
|
|
|
|
grpc_sockaddr_to_string(&addr_str, addr, 1); |
|
|
|
|
gpr_asprintf(&name, "udp-server-listener:%s", addr_str); |
|
|
|
|
gpr_free(addr_str); |
|
|
|
|
gpr_mu_lock(&s->mu); |
|
|
|
@ -326,8 +324,7 @@ static int add_socket_to_server(grpc_udp_server *s, int fd, |
|
|
|
|
sp->server = s; |
|
|
|
|
sp->fd = fd; |
|
|
|
|
sp->emfd = grpc_fd_create(fd, name); |
|
|
|
|
memcpy(sp->addr.untyped, addr, addr_len); |
|
|
|
|
sp->addr_len = addr_len; |
|
|
|
|
memcpy(&sp->addr, addr, sizeof(grpc_resolved_address)); |
|
|
|
|
sp->read_cb = read_cb; |
|
|
|
|
sp->orphan_cb = orphan_cb; |
|
|
|
|
GPR_ASSERT(sp->emfd); |
|
|
|
@ -338,34 +335,34 @@ static int add_socket_to_server(grpc_udp_server *s, int fd, |
|
|
|
|
return port; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr, |
|
|
|
|
size_t addr_len, grpc_udp_server_read_cb read_cb, |
|
|
|
|
int grpc_udp_server_add_port(grpc_udp_server *s, |
|
|
|
|
const grpc_resolved_address *addr, |
|
|
|
|
grpc_udp_server_read_cb read_cb, |
|
|
|
|
grpc_udp_server_orphan_cb orphan_cb) { |
|
|
|
|
int allocated_port1 = -1; |
|
|
|
|
int allocated_port2 = -1; |
|
|
|
|
unsigned i; |
|
|
|
|
int fd; |
|
|
|
|
grpc_dualstack_mode dsmode; |
|
|
|
|
struct sockaddr_in6 addr6_v4mapped; |
|
|
|
|
struct sockaddr_in wild4; |
|
|
|
|
struct sockaddr_in6 wild6; |
|
|
|
|
struct sockaddr_in addr4_copy; |
|
|
|
|
struct sockaddr *allocated_addr = NULL; |
|
|
|
|
struct sockaddr_storage sockname_temp; |
|
|
|
|
socklen_t sockname_len; |
|
|
|
|
grpc_resolved_address addr6_v4mapped; |
|
|
|
|
grpc_resolved_address wild4; |
|
|
|
|
grpc_resolved_address wild6; |
|
|
|
|
grpc_resolved_address addr4_copy; |
|
|
|
|
grpc_resolved_address *allocated_addr = NULL; |
|
|
|
|
grpc_resolved_address sockname_temp; |
|
|
|
|
int port; |
|
|
|
|
|
|
|
|
|
/* Check if this is a wildcard port, and if so, try to keep the port the same
|
|
|
|
|
as some previously created listener. */ |
|
|
|
|
if (grpc_sockaddr_get_port(addr) == 0) { |
|
|
|
|
for (i = 0; i < s->nports; i++) { |
|
|
|
|
sockname_len = sizeof(sockname_temp); |
|
|
|
|
if (0 == getsockname(s->ports[i].fd, (struct sockaddr *)&sockname_temp, |
|
|
|
|
&sockname_len)) { |
|
|
|
|
port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); |
|
|
|
|
sockname_temp.len = sizeof(struct sockaddr_storage); |
|
|
|
|
if (0 == getsockname(s->ports[i].fd, (struct sockaddr *)sockname_temp.addr, |
|
|
|
|
(socklen_t *)&sockname_temp.len)) { |
|
|
|
|
port = grpc_sockaddr_get_port(&sockname_temp); |
|
|
|
|
if (port > 0) { |
|
|
|
|
allocated_addr = gpr_malloc(addr_len); |
|
|
|
|
memcpy(allocated_addr, addr, addr_len); |
|
|
|
|
allocated_addr = gpr_malloc(sizeof(grpc_resolved_address)); |
|
|
|
|
memcpy(allocated_addr, addr, sizeof(grpc_resolved_address)); |
|
|
|
|
grpc_sockaddr_set_port(allocated_addr, port); |
|
|
|
|
addr = allocated_addr; |
|
|
|
|
break; |
|
|
|
@ -375,8 +372,7 @@ int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { |
|
|
|
|
addr = (const struct sockaddr *)&addr6_v4mapped; |
|
|
|
|
addr_len = sizeof(addr6_v4mapped); |
|
|
|
|
addr = &addr6_v4mapped; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ |
|
|
|
@ -384,22 +380,20 @@ int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr, |
|
|
|
|
grpc_sockaddr_make_wildcards(port, &wild4, &wild6); |
|
|
|
|
|
|
|
|
|
/* Try listening on IPv6 first. */ |
|
|
|
|
addr = (struct sockaddr *)&wild6; |
|
|
|
|
addr_len = sizeof(wild6); |
|
|
|
|
addr = &wild6; |
|
|
|
|
// TODO(rjshade): Test and propagate the returned grpc_error*:
|
|
|
|
|
grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd); |
|
|
|
|
allocated_port1 = |
|
|
|
|
add_socket_to_server(s, fd, addr, addr_len, read_cb, orphan_cb); |
|
|
|
|
add_socket_to_server(s, fd, addr, read_cb, orphan_cb); |
|
|
|
|
if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) { |
|
|
|
|
goto done; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* If we didn't get a dualstack socket, also listen on 0.0.0.0. */ |
|
|
|
|
if (port == 0 && allocated_port1 > 0) { |
|
|
|
|
grpc_sockaddr_set_port((struct sockaddr *)&wild4, allocated_port1); |
|
|
|
|
grpc_sockaddr_set_port(&wild4, allocated_port1); |
|
|
|
|
} |
|
|
|
|
addr = (struct sockaddr *)&wild4; |
|
|
|
|
addr_len = sizeof(wild4); |
|
|
|
|
addr = &wild4; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TODO(rjshade): Test and propagate the returned grpc_error*:
|
|
|
|
@ -409,11 +403,9 @@ int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr, |
|
|
|
|
} |
|
|
|
|
if (dsmode == GRPC_DSMODE_IPV4 && |
|
|
|
|
grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) { |
|
|
|
|
addr = (struct sockaddr *)&addr4_copy; |
|
|
|
|
addr_len = sizeof(addr4_copy); |
|
|
|
|
addr = &addr4_copy; |
|
|
|
|
} |
|
|
|
|
allocated_port2 = |
|
|
|
|
add_socket_to_server(s, fd, addr, addr_len, read_cb, orphan_cb); |
|
|
|
|
allocated_port2 = add_socket_to_server(s, fd, addr, read_cb, orphan_cb); |
|
|
|
|
|
|
|
|
|
done: |
|
|
|
|
gpr_free(allocated_addr); |
|
|
|
|