Skip to content

Commit

Permalink
tests: net: tcp: Add test case for connect timeout
Browse files Browse the repository at this point in the history
This checks that if connect() timeouts, we check TCP pointer
properly in select() and poll() in order to catch the situation.

Signed-off-by: Jukka Rissanen <[email protected]>
(cherry picked from commit b510073)
  • Loading branch information
jukkar authored and github-actions[bot] committed Oct 24, 2023
1 parent 3cadc5e commit a05d2bf
Showing 1 changed file with 140 additions and 1 deletion.
141 changes: 140 additions & 1 deletion tests/net/socket/tcp/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -933,11 +933,18 @@ ZTEST(net_socket_tcp, test_connect_timeout)

test_close(c_sock);

/* If we have preemptive option set, then sleep here in order to allow
* other part of the system to run and update itself.
*/
if (IS_ENABLED(CONFIG_NET_TC_THREAD_PREEMPTIVE)) {
k_sleep(K_MSEC(10));
}

/* After the client socket closing, the context count should be 0 */
net_context_foreach(calc_net_context, &count_after);

zassert_equal(count_after, 0,
"net_context still in use");
"net_context %d still in use", count_after);

restore_packet_loss_ratio();
}
Expand Down Expand Up @@ -2068,6 +2075,138 @@ ZTEST(net_socket_tcp, test_ioctl_fionread_v6)
test_ioctl_fionread_common(AF_INET6);
}

/* Connect to peer which is not listening the test port and
* make sure select() returns proper error for the closed
* connection.
*/
ZTEST(net_socket_tcp, test_connect_and_wait_for_v4_select)
{
struct sockaddr_in addr = { 0 };
struct in_addr v4addr;
int fd, flags, ret, optval;
socklen_t optlen = sizeof(optval);

fd = socket(AF_INET, SOCK_STREAM, 0);

flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);

inet_pton(AF_INET, "127.0.0.1", (void *)&v4addr);

addr.sin_family = AF_INET;
net_ipaddr_copy(&addr.sin_addr, &v4addr);

/* There should be nobody serving this port */
addr.sin_port = htons(8088);

ret = connect(fd, (const struct sockaddr *)&addr, sizeof(addr));
zassert_equal(ret, -1, "connect succeed, %d", errno);
zassert_equal(errno, EINPROGRESS, "connect succeed, %d", errno);

/* Wait for the connection (this should fail eventually) */
while (1) {
fd_set wfds;
struct timeval tv = {
.tv_sec = 1,
.tv_usec = 0
};

FD_ZERO(&wfds);
FD_SET(fd, &wfds);

/* Check if the connection is there, this should timeout */
ret = select(fd + 1, NULL, &wfds, NULL, &tv);
if (ret < 0) {
break;
}

if (ret > 0) {
if (FD_ISSET(fd, &wfds)) {
break;
}
}
}

zassert_true(ret > 0, "select failed, %d", errno);

/* Get the reason for the connect */
ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &optval, &optlen);
zassert_equal(ret, 0, "getsockopt failed, %d", errno);

/* If SO_ERROR is 0, then it means that connect succeed. Any
* other value (errno) means that it failed.
*/
zassert_equal(optval, ECONNREFUSED, "unexpected connect status, %d", optval);

ret = close(fd);
zassert_equal(ret, 0, "close failed, %d", errno);
}

/* Connect to peer which is not listening the test port and
* make sure poll() returns proper error for the closed
* connection.
*/
ZTEST(net_socket_tcp, test_connect_and_wait_for_v4_poll)
{
struct sockaddr_in addr = { 0 };
struct pollfd fds[1];
struct in_addr v4addr;
int fd, flags, ret, optval;
bool closed = false;
socklen_t optlen = sizeof(optval);

fd = socket(AF_INET, SOCK_STREAM, 0);

flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);

inet_pton(AF_INET, "127.0.0.1", (void *)&v4addr);

addr.sin_family = AF_INET;
net_ipaddr_copy(&addr.sin_addr, &v4addr);

/* There should be nobody serving this port */
addr.sin_port = htons(8088);

ret = connect(fd, (const struct sockaddr *)&addr, sizeof(addr));
zassert_equal(ret, -1, "connect succeed, %d", errno);
zassert_equal(errno, EINPROGRESS, "connect succeed, %d", errno);

/* Wait for the connection (this should fail eventually) */
while (1) {
memset(fds, 0, sizeof(fds));
fds[0].fd = fd;
fds[0].events = POLLOUT;

/* Check if the connection is there, this should timeout */
ret = poll(fds, 1, 10);
if (ret < 0) {
break;
}

if (fds[0].revents > 0) {
if (fds[0].revents & POLLERR) {
closed = true;
break;
}
}
}

zassert_true(closed, "poll failed, %d", errno);

/* Get the reason for the connect */
ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &optval, &optlen);
zassert_equal(ret, 0, "getsockopt failed, %d", errno);

/* If SO_ERROR is 0, then it means that connect succeed. Any
* other value (errno) means that it failed.
*/
zassert_equal(optval, ECONNREFUSED, "unexpected connect status, %d", optval);

ret = close(fd);
zassert_equal(ret, 0, "close failed, %d", errno);
}

static void after(void *arg)
{
ARG_UNUSED(arg);
Expand Down

0 comments on commit a05d2bf

Please sign in to comment.