/* Tests a tcp server with multiple ports. TODO(daniel-j-born): Multiple fds for the same port should be tested. */ static void test_connect(unsigned n) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; struct sockaddr_storage addr; struct sockaddr_storage addr1; socklen_t addr_len = sizeof(addr); unsigned svr_fd_count; int svr_port; unsigned svr1_fd_count; int svr1_port; grpc_tcp_server *s = grpc_tcp_server_create(NULL); unsigned i; server_weak_ref weak_ref; server_weak_ref_init(&weak_ref); LOG_TEST("test_connect"); gpr_log(GPR_INFO, "clients=%d", n); memset(&addr, 0, sizeof(addr)); memset(&addr1, 0, sizeof(addr1)); addr.ss_family = addr1.ss_family = AF_INET; svr_port = grpc_tcp_server_add_port(s, (struct sockaddr *)&addr, addr_len); GPR_ASSERT(svr_port > 0); /* Cannot use wildcard (port==0), because add_port() will try to reuse the same port as a previous add_port(). */ svr1_port = grpc_pick_unused_port_or_die(); grpc_sockaddr_set_port((struct sockaddr *)&addr1, svr1_port); GPR_ASSERT(grpc_tcp_server_add_port(s, (struct sockaddr *)&addr1, addr_len) == svr1_port); /* Bad port_index. */ GPR_ASSERT(grpc_tcp_server_port_fd_count(s, 2) == 0); GPR_ASSERT(grpc_tcp_server_port_fd(s, 2, 0) < 0); /* Bad fd_index. */ GPR_ASSERT(grpc_tcp_server_port_fd(s, 0, 100) < 0); GPR_ASSERT(grpc_tcp_server_port_fd(s, 1, 100) < 0); /* Got at least one fd per port. */ svr_fd_count = grpc_tcp_server_port_fd_count(s, 0); GPR_ASSERT(svr_fd_count >= 1); svr1_fd_count = grpc_tcp_server_port_fd_count(s, 1); GPR_ASSERT(svr1_fd_count >= 1); for (i = 0; i < svr_fd_count; ++i) { int fd = grpc_tcp_server_port_fd(s, 0, i); GPR_ASSERT(fd >= 0); if (i == 0) { GPR_ASSERT(getsockname(fd, (struct sockaddr *)&addr, &addr_len) == 0); GPR_ASSERT(addr_len <= sizeof(addr)); } } for (i = 0; i < svr1_fd_count; ++i) { int fd = grpc_tcp_server_port_fd(s, 1, i); GPR_ASSERT(fd >= 0); if (i == 0) { GPR_ASSERT(getsockname(fd, (struct sockaddr *)&addr1, &addr_len) == 0); GPR_ASSERT(addr_len <= sizeof(addr1)); } } grpc_tcp_server_start(&exec_ctx, s, &g_pollset, 1, on_connect, NULL); for (i = 0; i < n; i++) { on_connect_result result; int svr_fd; on_connect_result_init(&result); tcp_connect(&exec_ctx, (struct sockaddr *)&addr, addr_len, &result); GPR_ASSERT(result.server_fd >= 0); svr_fd = result.server_fd; GPR_ASSERT(grpc_tcp_server_port_fd(s, result.port_index, result.fd_index) == result.server_fd); GPR_ASSERT(result.port_index == 0); GPR_ASSERT(result.fd_index < svr_fd_count); GPR_ASSERT(result.server == s); if (weak_ref.server == NULL) { server_weak_ref_set(&weak_ref, result.server); } grpc_tcp_server_unref(&exec_ctx, result.server); on_connect_result_init(&result); tcp_connect(&exec_ctx, (struct sockaddr *)&addr1, addr_len, &result); GPR_ASSERT(result.server_fd >= 0); GPR_ASSERT(result.server_fd != svr_fd); GPR_ASSERT(grpc_tcp_server_port_fd(s, result.port_index, result.fd_index) == result.server_fd); GPR_ASSERT(result.port_index == 1); GPR_ASSERT(result.fd_index < svr_fd_count); GPR_ASSERT(result.server == s); grpc_tcp_server_unref(&exec_ctx, result.server); } /* Weak ref to server valid until final unref. */ GPR_ASSERT(weak_ref.server != NULL); GPR_ASSERT(grpc_tcp_server_port_fd(s, 0, 0) >= 0); grpc_tcp_server_unref(&exec_ctx, s); /* Weak ref lost. */ GPR_ASSERT(weak_ref.server == NULL); grpc_exec_ctx_finish(&exec_ctx); }
/* Tests a tcp server on "::" listeners with multiple ports. If channel_args is non-NULL, pass them to the server. If dst_addrs is non-NULL, use valid addrs as destination addrs (port is not set). If dst_addrs is NULL, use listener addrs as destination addrs. If test_dst_addrs is true, test connectivity with each destination address, set grpc_resolved_address::len=0 for failures, but don't fail the overall unitest. */ static void test_connect(size_t num_connects, const grpc_channel_args *channel_args, test_addrs *dst_addrs, bool test_dst_addrs) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_resolved_address resolved_addr; grpc_resolved_address resolved_addr1; struct sockaddr_storage *const addr = (struct sockaddr_storage *)resolved_addr.addr; struct sockaddr_storage *const addr1 = (struct sockaddr_storage *)resolved_addr1.addr; unsigned svr_fd_count; int port; int svr_port; unsigned svr1_fd_count; int svr1_port; grpc_tcp_server *s; const unsigned num_ports = 2; GPR_ASSERT(GRPC_ERROR_NONE == grpc_tcp_server_create(&exec_ctx, NULL, channel_args, &s)); unsigned port_num; server_weak_ref weak_ref; server_weak_ref_init(&weak_ref); server_weak_ref_set(&weak_ref, s); LOG_TEST("test_connect"); gpr_log(GPR_INFO, "clients=%lu, num chan args=%lu, remote IP=%s, test_dst_addrs=%d", (unsigned long)num_connects, (unsigned long)(channel_args != NULL ? channel_args->num_args : 0), dst_addrs != NULL ? "<specific>" : "::", test_dst_addrs); memset(&resolved_addr, 0, sizeof(resolved_addr)); memset(&resolved_addr1, 0, sizeof(resolved_addr1)); resolved_addr.len = sizeof(struct sockaddr_storage); resolved_addr1.len = sizeof(struct sockaddr_storage); addr->ss_family = addr1->ss_family = AF_INET; GPR_ASSERT(GRPC_LOG_IF_ERROR( "grpc_tcp_server_add_port", grpc_tcp_server_add_port(s, &resolved_addr, &svr_port))); gpr_log(GPR_INFO, "Allocated port %d", svr_port); GPR_ASSERT(svr_port > 0); /* Cannot use wildcard (port==0), because add_port() will try to reuse the same port as a previous add_port(). */ svr1_port = grpc_pick_unused_port_or_die(); GPR_ASSERT(svr1_port > 0); gpr_log(GPR_INFO, "Picked unused port %d", svr1_port); grpc_sockaddr_set_port(&resolved_addr1, svr1_port); GPR_ASSERT(grpc_tcp_server_add_port(s, &resolved_addr1, &port) == GRPC_ERROR_NONE && port == svr1_port); /* Bad port_index. */ GPR_ASSERT(grpc_tcp_server_port_fd_count(s, 2) == 0); GPR_ASSERT(grpc_tcp_server_port_fd(s, 2, 0) < 0); /* Bad fd_index. */ GPR_ASSERT(grpc_tcp_server_port_fd(s, 0, 100) < 0); GPR_ASSERT(grpc_tcp_server_port_fd(s, 1, 100) < 0); /* Got at least one fd per port. */ svr_fd_count = grpc_tcp_server_port_fd_count(s, 0); GPR_ASSERT(svr_fd_count >= 1); svr1_fd_count = grpc_tcp_server_port_fd_count(s, 1); GPR_ASSERT(svr1_fd_count >= 1); grpc_tcp_server_start(&exec_ctx, s, &g_pollset, 1, on_connect, NULL); if (dst_addrs != NULL) { int ports[] = {svr_port, svr1_port}; for (port_num = 0; port_num < num_ports; ++port_num) { size_t dst_idx; size_t num_tested = 0; for (dst_idx = 0; dst_idx < dst_addrs->naddrs; ++dst_idx) { test_addr dst = dst_addrs->addrs[dst_idx]; on_connect_result result; grpc_error *err; if (dst.addr.len == 0) { gpr_log(GPR_DEBUG, "Skipping test of non-functional local IP %s", dst.str); continue; } GPR_ASSERT(grpc_sockaddr_set_port(&dst.addr, ports[port_num])); test_addr_init_str(&dst); ++num_tested; on_connect_result_init(&result); if ((err = tcp_connect(&exec_ctx, &dst, &result)) == GRPC_ERROR_NONE && result.server_fd >= 0 && result.server == s) { continue; } gpr_log(GPR_ERROR, "Failed to connect to %s: %s", dst.str, grpc_error_string(err)); GPR_ASSERT(test_dst_addrs); dst_addrs->addrs[dst_idx].addr.len = 0; GRPC_ERROR_UNREF(err); } GPR_ASSERT(num_tested > 0); } } else { for (port_num = 0; port_num < num_ports; ++port_num) { const unsigned num_fds = grpc_tcp_server_port_fd_count(s, port_num); unsigned fd_num; for (fd_num = 0; fd_num < num_fds; ++fd_num) { int fd = grpc_tcp_server_port_fd(s, port_num, fd_num); size_t connect_num; test_addr dst; GPR_ASSERT(fd >= 0); dst.addr.len = sizeof(dst.addr.addr); GPR_ASSERT(getsockname(fd, (struct sockaddr *)dst.addr.addr, (socklen_t *)&dst.addr.len) == 0); GPR_ASSERT(dst.addr.len <= sizeof(dst.addr.addr)); test_addr_init_str(&dst); gpr_log(GPR_INFO, "(%d, %d) fd %d family %s listening on %s", port_num, fd_num, fd, sock_family_name(addr->ss_family), dst.str); for (connect_num = 0; connect_num < num_connects; ++connect_num) { on_connect_result result; on_connect_result_init(&result); GPR_ASSERT(GRPC_LOG_IF_ERROR("tcp_connect", tcp_connect(&exec_ctx, &dst, &result))); GPR_ASSERT(result.server_fd == fd); GPR_ASSERT(result.port_index == port_num); GPR_ASSERT(result.fd_index == fd_num); GPR_ASSERT(result.server == s); GPR_ASSERT( grpc_tcp_server_port_fd(s, result.port_index, result.fd_index) == result.server_fd); } } } } /* Weak ref to server valid until final unref. */ GPR_ASSERT(weak_ref.server != NULL); GPR_ASSERT(grpc_tcp_server_port_fd(s, 0, 0) >= 0); grpc_tcp_server_unref(&exec_ctx, s); grpc_exec_ctx_finish(&exec_ctx); /* Weak ref lost. */ GPR_ASSERT(weak_ref.server == NULL); }