tests: net: tcp: Add test case for connect timeout

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 <jukka.rissanen@nordicsemi.no>
This commit is contained in:
Jukka Rissanen 2023-10-16 14:50:45 +03:00 committed by Chris Friedt
parent 5bf18e39ad
commit b510073db3

View file

@ -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();
}
@ -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);