Make tcp client posix test more robust (#31804)

* Make tcp client posix test more robust

* review comments

* fix

* update

* review comments

* update

* fix sanity

* fix clang tidy

* readability

* minor update
pull/31899/head
Vignesh Babu 2 years ago committed by GitHub
parent b72da316bb
commit 71f7bbd86c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 92
      test/core/iomgr/tcp_client_posix_test.cc

@ -18,16 +18,20 @@
#include <gtest/gtest.h>
#include "src/core/lib/address_utils/parse_address.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gprpp/time.h"
#include "src/core/lib/iomgr/port.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
// This test won't work except with posix sockets enabled
#ifdef GRPC_POSIX_SOCKET_TCP_CLIENT
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <poll.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
@ -207,27 +211,88 @@ void test_fails(void) {
void test_connect_cancellation_succeeds(void) {
gpr_log(GPR_ERROR, "---- starting test_connect_cancellation_succeeds() ----");
auto target_ipv6_addr_uri = *grpc_core::URI::Parse(absl::StrCat(
"ipv6:[::1]:", std::to_string(grpc_pick_unused_port_or_die())));
auto target_ipv4_addr_uri = *grpc_core::URI::Parse(absl::StrCat(
"ipv4:127.0.0.1:", std::to_string(grpc_pick_unused_port_or_die())));
grpc_resolved_address resolved_addr;
struct sockaddr_in* addr =
reinterpret_cast<struct sockaddr_in*>(resolved_addr.addr);
int svr_fd;
grpc_closure done;
grpc_core::ExecCtx exec_ctx;
memset(&resolved_addr, 0, sizeof(resolved_addr));
resolved_addr.len = static_cast<socklen_t>(sizeof(struct sockaddr_in));
addr->sin_family = AF_INET;
bool tried_ipv4 = false;
ASSERT_TRUE(grpc_parse_uri(target_ipv6_addr_uri, &resolved_addr));
auto try_bind = [&](int sock) {
return (sock >= 0 &&
bind(sock, reinterpret_cast<sockaddr*>(resolved_addr.addr),
resolved_addr.len) == 0);
};
/* create a phony server */
svr_fd = socket(AF_INET, SOCK_STREAM, 0);
ASSERT_GE(svr_fd, 0);
ASSERT_EQ(bind(svr_fd, (struct sockaddr*)addr, (socklen_t)resolved_addr.len),
0);
svr_fd = socket(AF_INET6, SOCK_STREAM, 0);
// Try ipv6
if (!try_bind(svr_fd)) {
if (svr_fd >= 0) {
close(svr_fd);
}
// Failed to bind ipv6. Try ipv4
ASSERT_TRUE(grpc_parse_uri(target_ipv4_addr_uri, &resolved_addr));
svr_fd = socket(AF_INET, SOCK_STREAM, 0);
tried_ipv4 = true;
if (!try_bind(svr_fd)) {
if (svr_fd >= 0) {
close(svr_fd);
}
gpr_log(GPR_ERROR,
"Skipping test. Failed to create a phony server bound to ipv6 or "
"ipv4 address");
return;
}
}
ASSERT_EQ(listen(svr_fd, 1), 0);
std::vector<int> client_sockets;
bool create_more_client_connections = true;
// Create and connect client sockets until the connection attempt times out.
// Even if the backlog specified to listen is 1, the kernel continues to
// accept a certain number of SYN packets before dropping them. This loop
// attempts to identify the number of new connection attempts that will
// be allowed by the kernel before any subsequent connection attempts
// become pending indefinitely.
while (create_more_client_connections) {
const int kOne = 1;
int client_socket = socket(tried_ipv4 ? AF_INET : AF_INET6, SOCK_STREAM, 0);
ASSERT_GE(client_socket, 0);
setsockopt(client_socket, SOL_SOCKET, SO_REUSEADDR, &kOne, sizeof(kOne));
// Make fd non-blocking.
int flags = fcntl(client_socket, F_GETFL, 0);
ASSERT_EQ(fcntl(client_socket, F_SETFL, flags | O_NONBLOCK), 0);
if (connect(client_socket, reinterpret_cast<sockaddr*>(resolved_addr.addr),
resolved_addr.len) == -1) {
if (errno == EINPROGRESS) {
struct pollfd pfd;
pfd.fd = client_socket;
pfd.events = POLLOUT;
pfd.revents = 0;
int ret = poll(&pfd, 1, 1000);
if (ret == -1) {
FAIL() << "poll() failed during connect; errno=" << errno;
} else if (ret == 0) {
// current connection attempt timed out. It indicates that the
// kernel will cause any subsequent connection attempts to
// become pending indefinitely.
create_more_client_connections = false;
}
} else {
FAIL() << "Failed to connect to the server. errno=%d" << errno;
}
}
client_sockets.push_back(client_socket);
}
// connect to it. accept() is not called on the bind socket. So the connection
// should appear to be stuck giving ample time to try to cancel it.
ASSERT_EQ(getsockname(svr_fd, (struct sockaddr*)addr,
ASSERT_EQ(getsockname(svr_fd, reinterpret_cast<sockaddr*>(resolved_addr.addr),
(socklen_t*)&resolved_addr.len),
0);
GRPC_CLOSURE_INIT(&done, must_succeed, nullptr, grpc_schedule_on_exec_ctx);
@ -240,6 +305,9 @@ void test_connect_cancellation_succeeds(void) {
&resolved_addr, grpc_core::Timestamp::InfFuture());
ASSERT_GT(connection_handle, 0);
ASSERT_EQ(grpc_tcp_client_cancel_connect(connection_handle), true);
for (auto sock : client_sockets) {
close(sock);
}
close(svr_fd);
gpr_log(GPR_ERROR, "---- finished test_connect_cancellation_succeeds() ----");
}

Loading…
Cancel
Save