From 8b07a68e9e725d8f2b21f70cd89a4dc43f4fe421 Mon Sep 17 00:00:00 2001 From: jiangjianfeng Date: Thu, 5 Dec 2024 06:31:19 +0000 Subject: [PATCH] Add regression test for keepalive and tcp nodelay --- test/apps/network/sockoption.c | 197 ++++++++++++++++++++++++++++++--- 1 file changed, 180 insertions(+), 17 deletions(-) diff --git a/test/apps/network/sockoption.c b/test/apps/network/sockoption.c index 0c840a69b..0fcd3308d 100644 --- a/test/apps/network/sockoption.c +++ b/test/apps/network/sockoption.c @@ -6,22 +6,58 @@ #include #include #include +#include #include "test.h" -int sockfd; -int option; +int sk_unbound; +int sk_listen; +int sk_connected; +int sk_accepted; + +struct sockaddr_in listen_addr; +#define LISTEN_PORT htons(0x1242) FN_SETUP(general) { - sockfd = CHECK(socket(AF_INET, SOCK_STREAM, 0)); + sk_unbound = CHECK(socket(AF_INET, SOCK_STREAM, 0)); + + listen_addr.sin_family = AF_INET; + listen_addr.sin_port = LISTEN_PORT; + CHECK(inet_aton("127.0.0.1", &listen_addr.sin_addr)); + + sk_listen = CHECK(socket(AF_INET, SOCK_STREAM, 0)); + CHECK(bind(sk_listen, (struct sockaddr *)&listen_addr, + sizeof(listen_addr))); + CHECK(listen(sk_listen, 3)); + + sk_connected = CHECK(socket(AF_INET, SOCK_STREAM, 0)); + CHECK(connect(sk_connected, (struct sockaddr *)&listen_addr, + sizeof(listen_addr))); + + sk_accepted = CHECK(accept(sk_listen, NULL, NULL)); } END_SETUP() +int refresh_connection() +{ + close(sk_connected); + close(sk_accepted); + + sk_connected = CHECK(socket(AF_INET, SOCK_STREAM, 0)); + CHECK(connect(sk_connected, (struct sockaddr *)&listen_addr, + sizeof(listen_addr))); + + sk_accepted = CHECK(accept(sk_listen, NULL, NULL)); + + return 0; +} + FN_TEST(buffer_size) { int sendbuf; socklen_t sendbuf_len = sizeof(sendbuf); - TEST_RES(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuf, + + TEST_RES(getsockopt(sk_unbound, SOL_SOCKET, SO_SNDBUF, &sendbuf, &sendbuf_len), sendbuf_len == sizeof(sendbuf)); } @@ -31,39 +67,166 @@ FN_TEST(socket_error) { int error; socklen_t error_len = sizeof(error); - TEST_RES(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &error_len), + + TEST_RES(getsockopt(sk_unbound, SOL_SOCKET, SO_ERROR, &error, + &error_len), error_len == sizeof(error) && error == 0); } END_TEST() FN_TEST(nagle) { - // Disable Nagle algorithm - option = 1; - CHECK(setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &option, - sizeof(option))); - - // Get new value + int option = 1; int nagle; socklen_t nagle_len = sizeof(nagle); - TEST_RES(getsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &nagle, + + // 1. Check default values + refresh_connection(); + TEST_RES(getsockopt(sk_connected, IPPROTO_TCP, TCP_NODELAY, &nagle, + &nagle_len), + nagle == 0); + TEST_RES(getsockopt(sk_accepted, IPPROTO_TCP, TCP_NODELAY, &nagle, + &nagle_len), + nagle == 0); + + // 2. Disable Nagle algorithm on unbound socket + CHECK(setsockopt(sk_unbound, IPPROTO_TCP, TCP_NODELAY, &option, + sizeof(option))); + TEST_RES(getsockopt(sk_unbound, IPPROTO_TCP, TCP_NODELAY, &nagle, &nagle_len), nagle == 1); + + // 3. Disable Nagle algorithm on connected socket + CHECK(setsockopt(sk_connected, IPPROTO_TCP, TCP_NODELAY, &option, + sizeof(option))); + TEST_RES(getsockopt(sk_connected, IPPROTO_TCP, TCP_NODELAY, &nagle, + &nagle_len), + nagle == 1); + + // 4. Disable Nagle algorithm on listening socket before connection + CHECK(setsockopt(sk_listen, IPPROTO_TCP, TCP_NODELAY, &option, + sizeof(option))); + TEST_RES(getsockopt(sk_listen, IPPROTO_TCP, TCP_NODELAY, &nagle, + &nagle_len), + nagle == 1); + + refresh_connection(); + TEST_RES(getsockopt(sk_connected, IPPROTO_TCP, TCP_NODELAY, &nagle, + &nagle_len), + nagle == 0); + TEST_RES(getsockopt(sk_accepted, IPPROTO_TCP, TCP_NODELAY, &nagle, + &nagle_len), + nagle == 1); + + // 5. Disable Nagle algorithm on listening socket after connection + option = 0; + CHECK(setsockopt(sk_listen, IPPROTO_TCP, TCP_NODELAY, &option, + sizeof(option))); + + close(sk_connected); + close(sk_accepted); + + sk_connected = CHECK(socket(AF_INET, SOCK_STREAM, 0)); + CHECK(connect(sk_connected, (struct sockaddr *)&listen_addr, + sizeof(listen_addr))); + + option = 1; + CHECK(setsockopt(sk_listen, IPPROTO_TCP, TCP_NODELAY, &option, + sizeof(option))); + + sk_accepted = CHECK(accept(sk_listen, NULL, NULL)); + + TEST_RES(getsockopt(sk_connected, IPPROTO_TCP, TCP_NODELAY, &nagle, + &nagle_len), + nagle == 0); + TEST_RES(getsockopt(sk_accepted, IPPROTO_TCP, TCP_NODELAY, &nagle, + &nagle_len), + nagle == 0); } END_TEST() FN_TEST(reuseaddr) { - // Enable reuse address - option = 1; - CHECK(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &option, + int option = 1; + CHECK(setsockopt(sk_unbound, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option))); - // Get new value int reuseaddr; socklen_t reuseaddr_len = sizeof(reuseaddr); - TEST_RES(getsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, + + TEST_RES(getsockopt(sk_unbound, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, &reuseaddr_len), reuseaddr == 1); } END_TEST() + +FN_TEST(keepalive) +{ + int option = 1; + int keepalive; + socklen_t keepalive_len = sizeof(keepalive); + + // 1. Check default values + refresh_connection(); + TEST_RES(getsockopt(sk_connected, SOL_SOCKET, SO_KEEPALIVE, &keepalive, + &keepalive_len), + keepalive == 0); + TEST_RES(getsockopt(sk_accepted, SOL_SOCKET, SO_KEEPALIVE, &keepalive, + &keepalive_len), + keepalive == 0); + + // 2. Enable keepalive on unbound socket + CHECK(setsockopt(sk_unbound, SOL_SOCKET, SO_KEEPALIVE, &option, + sizeof(option))); + TEST_RES(getsockopt(sk_unbound, SOL_SOCKET, SO_KEEPALIVE, &keepalive, + &keepalive_len), + keepalive == 1); + + // 3. Enable keepalive on connected socket + CHECK(setsockopt(sk_connected, SOL_SOCKET, SO_KEEPALIVE, &option, + sizeof(option))); + TEST_RES(getsockopt(sk_connected, SOL_SOCKET, SO_KEEPALIVE, &keepalive, + &keepalive_len), + keepalive == 1); + + // 4. Enable keepalive on listening socket + CHECK(setsockopt(sk_listen, SOL_SOCKET, SO_KEEPALIVE, &option, + sizeof(option))); + TEST_RES(getsockopt(sk_listen, SOL_SOCKET, SO_KEEPALIVE, &keepalive, + &keepalive_len), + keepalive == 1); + + refresh_connection(); + TEST_RES(getsockopt(sk_connected, SOL_SOCKET, SO_KEEPALIVE, &keepalive, + &keepalive_len), + keepalive == 0); + TEST_RES(getsockopt(sk_accepted, SOL_SOCKET, SO_KEEPALIVE, &keepalive, + &keepalive_len), + keepalive == 1); + + // 5. Setting keepalive after connection comes + option = 0; + CHECK(setsockopt(sk_listen, SOL_SOCKET, SO_KEEPALIVE, &option, + sizeof(option))); + + close(sk_connected); + close(sk_accepted); + + sk_connected = CHECK(socket(AF_INET, SOCK_STREAM, 0)); + CHECK(connect(sk_connected, (struct sockaddr *)&listen_addr, + sizeof(listen_addr))); + + option = 1; + CHECK(setsockopt(sk_listen, SOL_SOCKET, SO_KEEPALIVE, &option, + sizeof(option))); + + sk_accepted = CHECK(accept(sk_listen, NULL, NULL)); + + TEST_RES(getsockopt(sk_connected, SOL_SOCKET, SO_KEEPALIVE, &keepalive, + &keepalive_len), + keepalive == 0); + TEST_RES(getsockopt(sk_accepted, SOL_SOCKET, SO_KEEPALIVE, &keepalive, + &keepalive_len), + keepalive == 0); +} +END_TEST()