static void test_sockaddr_to_v4mapped(void) { struct sockaddr_in input4; struct sockaddr_in6 input6; struct sockaddr_in6 output6; struct sockaddr_in6 expect6; gpr_log(GPR_INFO, "%s", "test_sockaddr_to_v4mapped"); /* IPv4 input should succeed. */ input4 = make_addr4(kIPv4, sizeof(kIPv4)); GPR_ASSERT( grpc_sockaddr_to_v4mapped((const struct sockaddr *)&input4, &output6)); expect6 = make_addr6(kMapped, sizeof(kMapped)); GPR_ASSERT(memcmp(&expect6, &output6, sizeof(output6)) == 0); /* IPv6 input should fail. */ input6 = make_addr6(kIPv6, sizeof(kIPv6)); GPR_ASSERT( !grpc_sockaddr_to_v4mapped((const struct sockaddr *)&input6, &output6)); /* Output is unchanged. */ GPR_ASSERT(memcmp(&expect6, &output6, sizeof(output6)) == 0); /* Already-v4mapped input should also fail. */ input6 = make_addr6(kMapped, sizeof(kMapped)); GPR_ASSERT( !grpc_sockaddr_to_v4mapped((const struct sockaddr *)&input6, &output6)); }
int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, int addr_len) { int allocated_port = -1; unsigned i; SOCKET sock; struct sockaddr_in6 addr6_v4mapped; struct sockaddr_in6 wildcard; struct sockaddr *allocated_addr = NULL; struct sockaddr_storage sockname_temp; socklen_t sockname_len; 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].socket->socket, (struct sockaddr *) &sockname_temp, &sockname_len)) { port = grpc_sockaddr_get_port((struct sockaddr *) &sockname_temp); if (port > 0) { allocated_addr = malloc(addr_len); memcpy(allocated_addr, addr, addr_len); grpc_sockaddr_set_port(allocated_addr, port); addr = allocated_addr; break; } } } } if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { addr = (const struct sockaddr *)&addr6_v4mapped; addr_len = sizeof(addr6_v4mapped); } /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ if (grpc_sockaddr_is_wildcard(addr, &port)) { grpc_sockaddr_make_wildcard6(port, &wildcard); addr = (struct sockaddr *) &wildcard; addr_len = sizeof(wildcard); } sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); if (sock == INVALID_SOCKET) { char *utf8_message = gpr_format_message(WSAGetLastError()); gpr_log(GPR_ERROR, "unable to create socket: %s", utf8_message); gpr_free(utf8_message); } allocated_port = add_socket_to_server(s, sock, addr, addr_len); gpr_free(allocated_addr); return allocated_port; }
static void test_sockaddr_is_wildcard(void) { struct sockaddr_in wild4; struct sockaddr_in6 wild6; struct sockaddr_in6 wild_mapped; struct sockaddr dummy; int port; gpr_log(GPR_INFO, "%s", "test_sockaddr_is_wildcard"); /* Generate wildcards. */ grpc_sockaddr_make_wildcards(555, &wild4, &wild6); GPR_ASSERT( grpc_sockaddr_to_v4mapped((const struct sockaddr *)&wild4, &wild_mapped)); /* Test 0.0.0.0:555 */ port = -1; GPR_ASSERT(grpc_sockaddr_is_wildcard((const struct sockaddr *)&wild4, &port)); GPR_ASSERT(port == 555); memset(&wild4.sin_addr.s_addr, 0xbd, 1); GPR_ASSERT( !grpc_sockaddr_is_wildcard((const struct sockaddr *)&wild4, &port)); /* Test [::]:555 */ port = -1; GPR_ASSERT(grpc_sockaddr_is_wildcard((const struct sockaddr *)&wild6, &port)); GPR_ASSERT(port == 555); memset(&wild6.sin6_addr.s6_addr, 0xbd, 1); GPR_ASSERT( !grpc_sockaddr_is_wildcard((const struct sockaddr *)&wild6, &port)); /* Test [::ffff:0.0.0.0]:555 */ port = -1; GPR_ASSERT( grpc_sockaddr_is_wildcard((const struct sockaddr *)&wild_mapped, &port)); GPR_ASSERT(port == 555); memset(&wild_mapped.sin6_addr.s6_addr, 0xbd, 1); GPR_ASSERT( !grpc_sockaddr_is_wildcard((const struct sockaddr *)&wild_mapped, &port)); /* Test AF_UNSPEC. */ port = -1; memset(&dummy, 0, sizeof(dummy)); GPR_ASSERT(!grpc_sockaddr_is_wildcard(&dummy, &port)); GPR_ASSERT(port == -1); }
/* Tries to issue one async connection, then schedules both an IOCP notification request for the connection, and one timeout alert. */ void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done, grpc_endpoint **endpoint, grpc_pollset_set *interested_parties, const struct sockaddr *addr, size_t addr_len, gpr_timespec deadline) { SOCKET sock = INVALID_SOCKET; BOOL success; int status; struct sockaddr_in6 addr6_v4mapped; struct sockaddr_in6 local_address; async_connect *ac; grpc_winsocket *socket = NULL; LPFN_CONNECTEX ConnectEx; GUID guid = WSAID_CONNECTEX; DWORD ioctl_num_bytes; const char *message = NULL; char *utf8_message; grpc_winsocket_callback_info *info; *endpoint = NULL; /* Use dualstack sockets where available. */ if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { addr = (const struct sockaddr *)&addr6_v4mapped; addr_len = sizeof(addr6_v4mapped); } sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); if (sock == INVALID_SOCKET) { message = "Unable to create socket: %s"; goto failure; } if (!grpc_tcp_prepare_socket(sock)) { message = "Unable to set socket options: %s"; goto failure; } /* Grab the function pointer for ConnectEx for that specific socket. It may change depending on the interface. */ status = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), &ConnectEx, sizeof(ConnectEx), &ioctl_num_bytes, NULL, NULL); if (status != 0) { message = "Unable to retrieve ConnectEx pointer: %s"; goto failure; } grpc_sockaddr_make_wildcard6(0, &local_address); status = bind(sock, (struct sockaddr *)&local_address, sizeof(local_address)); if (status != 0) { message = "Unable to bind socket: %s"; goto failure; } socket = grpc_winsocket_create(sock, "client"); info = &socket->write_info; success = ConnectEx(sock, addr, (int)addr_len, NULL, 0, NULL, &info->overlapped); /* It wouldn't be unusual to get a success immediately. But we'll still get an IOCP notification, so let's ignore it. */ if (!success) { int error = WSAGetLastError(); if (error != ERROR_IO_PENDING) { message = "ConnectEx failed: %s"; goto failure; } } ac = gpr_malloc(sizeof(async_connect)); ac->on_done = on_done; ac->socket = socket; gpr_mu_init(&ac->mu); ac->refs = 2; ac->addr_name = grpc_sockaddr_to_uri(addr); ac->endpoint = endpoint; grpc_closure_init(&ac->on_connect, on_connect, ac); grpc_timer_init(exec_ctx, &ac->alarm, deadline, on_alarm, ac, gpr_now(GPR_CLOCK_MONOTONIC)); grpc_socket_notify_on_write(exec_ctx, socket, &ac->on_connect); return; failure: utf8_message = gpr_format_message(WSAGetLastError()); gpr_log(GPR_ERROR, message, utf8_message); gpr_free(utf8_message); if (socket != NULL) { grpc_winsocket_destroy(socket); } else if (sock != INVALID_SOCKET) { closesocket(sock); } grpc_exec_ctx_enqueue(exec_ctx, on_done, 0); }
grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s, const grpc_resolved_address *addr, int *port) { // This function is mostly copied from tcp_server_windows.c grpc_tcp_listener *sp = NULL; uv_tcp_t *handle; grpc_resolved_address addr6_v4mapped; grpc_resolved_address wildcard; grpc_resolved_address *allocated_addr = NULL; grpc_resolved_address sockname_temp; unsigned port_index = 0; int status; grpc_error *error = GRPC_ERROR_NONE; if (s->tail != NULL) { port_index = s->tail->port_index + 1; } /* 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 (sp = s->head; sp; sp = sp->next) { sockname_temp.len = sizeof(struct sockaddr_storage); if (0 == uv_tcp_getsockname(sp->handle, (struct sockaddr *)&sockname_temp.addr, (int *)&sockname_temp.len)) { *port = grpc_sockaddr_get_port(&sockname_temp); if (*port > 0) { 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; } } } } if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { addr = &addr6_v4mapped; } /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ if (grpc_sockaddr_is_wildcard(addr, port)) { grpc_sockaddr_make_wildcard6(*port, &wildcard); addr = &wildcard; } handle = gpr_malloc(sizeof(uv_tcp_t)); status = uv_tcp_init(uv_default_loop(), handle); if (status == 0) { error = add_socket_to_server(s, handle, addr, port_index, &sp); } else { error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Failed to initialize UV tcp handle"); error = grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, grpc_slice_from_static_string(uv_strerror(status))); } gpr_free(allocated_addr); if (error != GRPC_ERROR_NONE) { grpc_error *error_out = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( "Failed to add port to server", &error, 1); GRPC_ERROR_UNREF(error); error = error_out; *port = -1; } else { GPR_ASSERT(sp != NULL); *port = sp->port; } return error; }
grpc_tcp_listener *grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, size_t addr_len) { grpc_tcp_listener *sp; grpc_tcp_listener *sp2 = NULL; 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; int port; if (((struct sockaddr *)addr)->sa_family == AF_UNIX) { unlink_if_unix_domain_socket(addr); } /* 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 (sp = s->head; sp; sp = sp->next) { sockname_len = sizeof(sockname_temp); if (0 == getsockname(sp->fd, (struct sockaddr *)&sockname_temp, &sockname_len)) { port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); if (port > 0) { allocated_addr = malloc(addr_len); memcpy(allocated_addr, addr, addr_len); grpc_sockaddr_set_port(allocated_addr, port); addr = allocated_addr; break; } } } } sp = NULL; if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { addr = (const struct sockaddr *)&addr6_v4mapped; addr_len = sizeof(addr6_v4mapped); } /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ if (grpc_sockaddr_is_wildcard(addr, &port)) { grpc_sockaddr_make_wildcards(port, &wild4, &wild6); /* Try listening on IPv6 first. */ addr = (struct sockaddr *)&wild6; addr_len = sizeof(wild6); fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode); sp = add_socket_to_server(s, fd, addr, addr_len); 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 && sp != NULL) { grpc_sockaddr_set_port((struct sockaddr *)&wild4, sp->port); sp2 = sp; } addr = (struct sockaddr *)&wild4; addr_len = sizeof(wild4); } fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode); if (fd < 0) { gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno)); } if (dsmode == GRPC_DSMODE_IPV4 && grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) { addr = (struct sockaddr *)&addr4_copy; addr_len = sizeof(addr4_copy); } sp = add_socket_to_server(s, fd, addr, addr_len); if (sp != NULL) sp->sibling = sp2; if (sp2 != NULL) sp2->is_sibling = 1; done: gpr_free(allocated_addr); return sp; }
void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *closure, grpc_endpoint **ep, grpc_pollset_set *interested_parties, const struct sockaddr *addr, size_t addr_len, gpr_timespec deadline) { int fd; grpc_dualstack_mode dsmode; int err; async_connect *ac; struct sockaddr_in6 addr6_v4mapped; struct sockaddr_in addr4_copy; grpc_fd *fdobj; char *name; char *addr_str; *ep = NULL; /* Use dualstack sockets where available. */ if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { addr = (const struct sockaddr *)&addr6_v4mapped; addr_len = sizeof(addr6_v4mapped); } fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode); if (fd < 0) { gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno)); } if (dsmode == GRPC_DSMODE_IPV4) { /* If we got an AF_INET socket, map the address back to IPv4. */ GPR_ASSERT(grpc_sockaddr_is_v4mapped(addr, &addr4_copy)); addr = (struct sockaddr *)&addr4_copy; addr_len = sizeof(addr4_copy); } if (!prepare_socket(addr, fd)) { grpc_exec_ctx_enqueue(exec_ctx, closure, 0); return; } do { GPR_ASSERT(addr_len < ~(socklen_t)0); err = connect(fd, addr, (socklen_t)addr_len); } while (err < 0 && errno == EINTR); addr_str = grpc_sockaddr_to_uri(addr); gpr_asprintf(&name, "tcp-client:%s", addr_str); fdobj = grpc_fd_create(fd, name); if (err >= 0) { *ep = grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str); grpc_exec_ctx_enqueue(exec_ctx, closure, 1); goto done; } if (errno != EWOULDBLOCK && errno != EINPROGRESS) { gpr_log(GPR_ERROR, "connect error to '%s': %s", addr_str, strerror(errno)); grpc_fd_orphan(exec_ctx, fdobj, NULL, "tcp_client_connect_error"); grpc_exec_ctx_enqueue(exec_ctx, closure, 0); goto done; } grpc_pollset_set_add_fd(exec_ctx, interested_parties, fdobj); ac = gpr_malloc(sizeof(async_connect)); ac->closure = closure; ac->ep = ep; ac->fd = fdobj; ac->interested_parties = interested_parties; ac->addr_str = addr_str; addr_str = NULL; gpr_mu_init(&ac->mu); ac->refs = 2; ac->write_closure.cb = on_writable; ac->write_closure.cb_arg = ac; if (grpc_tcp_trace) { gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: asynchronously connecting", ac->addr_str); } gpr_mu_lock(&ac->mu); grpc_alarm_init(exec_ctx, &ac->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), tc_on_alarm, ac, gpr_now(GPR_CLOCK_MONOTONIC)); grpc_fd_notify_on_write(exec_ctx, ac->fd, &ac->write_closure); gpr_mu_unlock(&ac->mu); done: gpr_free(name); gpr_free(addr_str); }
void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *ep), void *arg, const struct sockaddr *addr, int addr_len, gpr_timespec deadline) { int fd; grpc_dualstack_mode dsmode; int err; async_connect *ac; struct sockaddr_in6 addr6_v4mapped; struct sockaddr_in addr4_copy; /* Use dualstack sockets where available. */ if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { addr = (const struct sockaddr *)&addr6_v4mapped; addr_len = sizeof(addr6_v4mapped); } fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode); if (fd < 0) { gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno)); } if (dsmode == GRPC_DSMODE_IPV4) { /* If we got an AF_INET socket, map the address back to IPv4. */ GPR_ASSERT(grpc_sockaddr_is_v4mapped(addr, &addr4_copy)); addr = (struct sockaddr *)&addr4_copy; addr_len = sizeof(addr4_copy); } if (!prepare_socket(addr, fd)) { cb(arg, NULL); return; } do { err = connect(fd, addr, addr_len); } while (err < 0 && errno == EINTR); if (err >= 0) { gpr_log(GPR_DEBUG, "instant connect"); cb(arg, grpc_tcp_create(grpc_fd_create(fd), GRPC_TCP_DEFAULT_READ_SLICE_SIZE)); return; } if (errno != EWOULDBLOCK && errno != EINPROGRESS) { gpr_log(GPR_ERROR, "connect error: %s", strerror(errno)); close(fd); cb(arg, NULL); return; } ac = gpr_malloc(sizeof(async_connect)); ac->cb = cb; ac->cb_arg = arg; ac->fd = grpc_fd_create(fd); gpr_mu_init(&ac->mu); ac->refs = 2; ac->write_closure.cb = on_writable; ac->write_closure.cb_arg = ac; grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac, gpr_now()); grpc_fd_notify_on_write(ac->fd, &ac->write_closure); }
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_write_cb write_cb, grpc_udp_server_orphan_cb orphan_cb) { grpc_udp_listener *sp; int allocated_port1 = -1; int allocated_port2 = -1; int fd; grpc_dualstack_mode dsmode; 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 (sp = s->head; sp; sp = sp->next) { sockname_temp.len = sizeof(struct sockaddr_storage); if (0 == getsockname(sp->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(sizeof(grpc_resolved_address)); memcpy(allocated_addr, addr, sizeof(grpc_resolved_address)); grpc_sockaddr_set_port(allocated_addr, port); addr = allocated_addr; break; } } } } if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { addr = &addr6_v4mapped; } /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ if (grpc_sockaddr_is_wildcard(addr, &port)) { grpc_sockaddr_make_wildcards(port, &wild4, &wild6); /* Try listening on IPv6 first. */ addr = &wild6; // TODO(rjshade): Test and propagate the returned grpc_error*: GRPC_ERROR_UNREF(grpc_create_dualstack_socket_using_factory( s->socket_factory, addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd)); allocated_port1 = add_socket_to_server(s, fd, addr, read_cb, write_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(&wild4, allocated_port1); } addr = &wild4; } // TODO(rjshade): Test and propagate the returned grpc_error*: GRPC_ERROR_UNREF(grpc_create_dualstack_socket_using_factory( s->socket_factory, addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd)); if (fd < 0) { gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno)); } if (dsmode == GRPC_DSMODE_IPV4 && grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) { addr = &addr4_copy; } allocated_port2 = add_socket_to_server(s, fd, addr, read_cb, write_cb, orphan_cb); done: gpr_free(allocated_addr); return allocated_port1 >= 0 ? allocated_port1 : allocated_port2; }
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 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; int port; if (((struct sockaddr *)addr)->sa_family == AF_UNIX) { unlink_if_unix_domain_socket(addr); } /* 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); if (port > 0) { allocated_addr = malloc(addr_len); memcpy(allocated_addr, addr, addr_len); grpc_sockaddr_set_port(allocated_addr, port); addr = allocated_addr; break; } } } } if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { addr = (const struct sockaddr *)&addr6_v4mapped; addr_len = sizeof(addr6_v4mapped); } /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ if (grpc_sockaddr_is_wildcard(addr, &port)) { grpc_sockaddr_make_wildcards(port, &wild4, &wild6); /* Try listening on IPv6 first. */ addr = (struct sockaddr *)&wild6; addr_len = sizeof(wild6); fd = grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode); allocated_port1 = add_socket_to_server(s, fd, addr, addr_len, read_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); } addr = (struct sockaddr *)&wild4; addr_len = sizeof(wild4); } fd = grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode); if (fd < 0) { gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno)); } if (dsmode == GRPC_DSMODE_IPV4 && grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) { addr = (struct sockaddr *)&addr4_copy; addr_len = sizeof(addr4_copy); } allocated_port2 = add_socket_to_server(s, fd, addr, addr_len, read_cb); done: gpr_free(allocated_addr); return allocated_port1 >= 0 ? allocated_port1 : allocated_port2; }
static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx, grpc_closure *closure, grpc_endpoint **ep, grpc_pollset_set *interested_parties, const grpc_channel_args *channel_args, const grpc_resolved_address *addr, gpr_timespec deadline) { int fd; grpc_dualstack_mode dsmode; int err; async_connect *ac; grpc_resolved_address addr6_v4mapped; grpc_resolved_address addr4_copy; grpc_fd *fdobj; char *name; char *addr_str; grpc_error *error; *ep = NULL; /* Use dualstack sockets where available. */ if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { addr = &addr6_v4mapped; } error = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode, &fd); if (error != GRPC_ERROR_NONE) { grpc_closure_sched(exec_ctx, closure, error); return; } if (dsmode == GRPC_DSMODE_IPV4) { /* If we got an AF_INET socket, map the address back to IPv4. */ GPR_ASSERT(grpc_sockaddr_is_v4mapped(addr, &addr4_copy)); addr = &addr4_copy; } if ((error = prepare_socket(addr, fd, channel_args)) != GRPC_ERROR_NONE) { grpc_closure_sched(exec_ctx, closure, error); return; } do { GPR_ASSERT(addr->len < ~(socklen_t)0); err = connect(fd, (const struct sockaddr *)addr->addr, (socklen_t)addr->len); } while (err < 0 && errno == EINTR); addr_str = grpc_sockaddr_to_uri(addr); gpr_asprintf(&name, "tcp-client:%s", addr_str); fdobj = grpc_fd_create(fd, name); if (err >= 0) { *ep = grpc_tcp_client_create_from_fd(exec_ctx, fdobj, channel_args, addr_str); grpc_closure_sched(exec_ctx, closure, GRPC_ERROR_NONE); goto done; } if (errno != EWOULDBLOCK && errno != EINPROGRESS) { grpc_fd_orphan(exec_ctx, fdobj, NULL, NULL, "tcp_client_connect_error"); grpc_closure_sched(exec_ctx, closure, GRPC_OS_ERROR(errno, "connect")); goto done; } grpc_pollset_set_add_fd(exec_ctx, interested_parties, fdobj); ac = gpr_malloc(sizeof(async_connect)); ac->closure = closure; ac->ep = ep; ac->fd = fdobj; ac->interested_parties = interested_parties; ac->addr_str = addr_str; addr_str = NULL; gpr_mu_init(&ac->mu); ac->refs = 2; grpc_closure_init(&ac->write_closure, on_writable, ac, grpc_schedule_on_exec_ctx); ac->channel_args = grpc_channel_args_copy(channel_args); if (grpc_tcp_trace) { gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: asynchronously connecting", ac->addr_str); } gpr_mu_lock(&ac->mu); grpc_closure_init(&ac->on_alarm, tc_on_alarm, ac, grpc_schedule_on_exec_ctx); grpc_timer_init(exec_ctx, &ac->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), &ac->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC)); grpc_fd_notify_on_write(exec_ctx, ac->fd, &ac->write_closure); gpr_mu_unlock(&ac->mu); done: gpr_free(name); gpr_free(addr_str); }
/* Tries to issue one async connection, then schedules both an IOCP notification request for the connection, and one timeout alert. */ void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done, grpc_endpoint **endpoint, grpc_pollset_set *interested_parties, const grpc_channel_args *channel_args, const grpc_resolved_address *addr, gpr_timespec deadline) { SOCKET sock = INVALID_SOCKET; BOOL success; int status; grpc_resolved_address addr6_v4mapped; grpc_resolved_address local_address; async_connect *ac; grpc_winsocket *socket = NULL; LPFN_CONNECTEX ConnectEx; GUID guid = WSAID_CONNECTEX; DWORD ioctl_num_bytes; grpc_winsocket_callback_info *info; grpc_error *error = GRPC_ERROR_NONE; grpc_resource_quota *resource_quota = grpc_resource_quota_create(NULL); if (channel_args != NULL) { for (size_t i = 0; i < channel_args->num_args; i++) { if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) { grpc_resource_quota_internal_unref(exec_ctx, resource_quota); resource_quota = grpc_resource_quota_internal_ref( channel_args->args[i].value.pointer.p); } } } *endpoint = NULL; /* Use dualstack sockets where available. */ if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { addr = &addr6_v4mapped; } sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); if (sock == INVALID_SOCKET) { error = GRPC_WSA_ERROR(WSAGetLastError(), "WSASocket"); goto failure; } error = grpc_tcp_prepare_socket(sock); if (error != GRPC_ERROR_NONE) { goto failure; } /* Grab the function pointer for ConnectEx for that specific socket. It may change depending on the interface. */ status = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), &ConnectEx, sizeof(ConnectEx), &ioctl_num_bytes, NULL, NULL); if (status != 0) { error = GRPC_WSA_ERROR(WSAGetLastError(), "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER)"); goto failure; } grpc_sockaddr_make_wildcard6(0, &local_address); status = bind(sock, (struct sockaddr *)&local_address.addr, (int)local_address.len); if (status != 0) { error = GRPC_WSA_ERROR(WSAGetLastError(), "bind"); goto failure; } socket = grpc_winsocket_create(sock, "client"); info = &socket->write_info; success = ConnectEx(sock, (struct sockaddr *)&addr->addr, (int)addr->len, NULL, 0, NULL, &info->overlapped); /* It wouldn't be unusual to get a success immediately. But we'll still get an IOCP notification, so let's ignore it. */ if (!success) { int last_error = WSAGetLastError(); if (last_error != ERROR_IO_PENDING) { error = GRPC_WSA_ERROR(last_error, "ConnectEx"); goto failure; } } ac = gpr_malloc(sizeof(async_connect)); ac->on_done = on_done; ac->socket = socket; gpr_mu_init(&ac->mu); ac->refs = 2; ac->addr_name = grpc_sockaddr_to_uri(addr); ac->endpoint = endpoint; ac->resource_quota = resource_quota; grpc_closure_init(&ac->on_connect, on_connect, ac); grpc_timer_init(exec_ctx, &ac->alarm, deadline, on_alarm, ac, gpr_now(GPR_CLOCK_MONOTONIC)); grpc_socket_notify_on_write(exec_ctx, socket, &ac->on_connect); return; failure: GPR_ASSERT(error != GRPC_ERROR_NONE); char *target_uri = grpc_sockaddr_to_uri(addr); grpc_error *final_error = grpc_error_set_str( GRPC_ERROR_CREATE_REFERENCING("Failed to connect", &error, 1), GRPC_ERROR_STR_TARGET_ADDRESS, target_uri); GRPC_ERROR_UNREF(error); if (socket != NULL) { grpc_winsocket_destroy(socket); } else if (sock != INVALID_SOCKET) { closesocket(sock); } grpc_resource_quota_internal_unref(exec_ctx, resource_quota); grpc_exec_ctx_sched(exec_ctx, on_done, final_error, NULL); }
void grpc_tcp_client_connect(void(*cb)(void *arg, grpc_endpoint *tcp), void *arg, const struct sockaddr *addr, int addr_len, gpr_timespec deadline) { SOCKET sock = INVALID_SOCKET; BOOL success; int status; struct sockaddr_in6 addr6_v4mapped; struct sockaddr_in6 local_address; async_connect *ac; grpc_winsocket *socket = NULL; LPFN_CONNECTEX ConnectEx; GUID guid = WSAID_CONNECTEX; DWORD ioctl_num_bytes; const char *message = NULL; char *utf8_message; grpc_winsocket_callback_info *info; /* Use dualstack sockets where available. */ if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { addr = (const struct sockaddr *)&addr6_v4mapped; addr_len = sizeof(addr6_v4mapped); } sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); if (sock == INVALID_SOCKET) { message = "Unable to create socket: %s"; goto failure; } if (!grpc_tcp_prepare_socket(sock)) { message = "Unable to set socket options: %s"; goto failure; } status = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), &ConnectEx, sizeof(ConnectEx), &ioctl_num_bytes, NULL, NULL); if (status != 0) { message = "Unable to retreive ConnectEx pointer: %s"; goto failure; } grpc_sockaddr_make_wildcard6(0, &local_address); status = bind(sock, (struct sockaddr *) &local_address, sizeof(local_address)); if (status != 0) { message = "Unable to bind socket: %s"; goto failure; } socket = grpc_winsocket_create(sock); info = &socket->write_info; success = ConnectEx(sock, addr, addr_len, NULL, 0, NULL, &info->overlapped); if (!success) { int error = WSAGetLastError(); if (error != ERROR_IO_PENDING) { message = "ConnectEx failed: %s"; goto failure; } } ac = gpr_malloc(sizeof(async_connect)); ac->cb = cb; ac->cb_arg = arg; ac->socket = socket; gpr_mu_init(&ac->mu); ac->refs = 2; grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac, gpr_now()); grpc_socket_notify_on_write(socket, on_connect, ac); return; failure: utf8_message = gpr_format_message(WSAGetLastError()); gpr_log(GPR_ERROR, message, utf8_message); gpr_free(utf8_message); if (socket) { grpc_winsocket_orphan(socket); } else if (sock != INVALID_SOCKET) { closesocket(sock); } cb(arg, NULL); }
grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, size_t addr_len, int *out_port) { grpc_tcp_listener *sp; grpc_tcp_listener *sp2 = NULL; 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; int port; unsigned port_index = 0; unsigned fd_index = 0; grpc_error *errs[2] = {GRPC_ERROR_NONE, GRPC_ERROR_NONE}; if (s->tail != NULL) { port_index = s->tail->port_index + 1; } grpc_unlink_if_unix_domain_socket((struct sockaddr *)addr); /* 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 (sp = s->head; sp; sp = sp->next) { sockname_len = sizeof(sockname_temp); if (0 == getsockname(sp->fd, (struct sockaddr *)&sockname_temp, &sockname_len)) { port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); if (port > 0) { allocated_addr = gpr_malloc(addr_len); memcpy(allocated_addr, addr, addr_len); grpc_sockaddr_set_port(allocated_addr, port); addr = allocated_addr; break; } } } } sp = NULL; if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { addr = (const struct sockaddr *)&addr6_v4mapped; addr_len = sizeof(addr6_v4mapped); } /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ if (grpc_sockaddr_is_wildcard(addr, &port)) { grpc_sockaddr_make_wildcards(port, &wild4, &wild6); /* Try listening on IPv6 first. */ addr = (struct sockaddr *)&wild6; addr_len = sizeof(wild6); errs[0] = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode, &fd); if (errs[0] == GRPC_ERROR_NONE) { errs[0] = add_socket_to_server(s, fd, addr, addr_len, port_index, fd_index, &sp); if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) { goto done; } if (sp != NULL) { ++fd_index; } /* If we didn't get a dualstack socket, also listen on 0.0.0.0. */ if (port == 0 && sp != NULL) { grpc_sockaddr_set_port((struct sockaddr *)&wild4, sp->port); } } addr = (struct sockaddr *)&wild4; addr_len = sizeof(wild4); } errs[1] = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode, &fd); if (errs[1] == GRPC_ERROR_NONE) { if (dsmode == GRPC_DSMODE_IPV4 && grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) { addr = (struct sockaddr *)&addr4_copy; addr_len = sizeof(addr4_copy); } sp2 = sp; errs[1] = add_socket_to_server(s, fd, addr, addr_len, port_index, fd_index, &sp); if (sp2 != NULL && sp != NULL) { sp2->sibling = sp; sp->is_sibling = 1; } } done: gpr_free(allocated_addr); if (sp != NULL) { *out_port = sp->port; GRPC_ERROR_UNREF(errs[0]); GRPC_ERROR_UNREF(errs[1]); return GRPC_ERROR_NONE; } else { *out_port = -1; char *addr_str = grpc_sockaddr_to_uri(addr); grpc_error *err = grpc_error_set_str( GRPC_ERROR_CREATE_REFERENCING("Failed to add port to server", errs, GPR_ARRAY_SIZE(errs)), GRPC_ERROR_STR_TARGET_ADDRESS, addr_str); GRPC_ERROR_UNREF(errs[0]); GRPC_ERROR_UNREF(errs[1]); gpr_free(addr_str); return err; } }