From 5bbf28be59b7c04f89399c22d3b5502a75e8e4f1 Mon Sep 17 00:00:00 2001 From: Eugene Syromyatnikov Date: Wed, 10 Aug 2022 12:21:35 +0200 Subject: tests: expand so_error test checks Check decoding with various optlen values. * tests/so_error.c: Add checks. --- tests/so_error.c | 116 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 73 insertions(+), 43 deletions(-) diff --git a/tests/so_error.c b/tests/so_error.c index 03211ab91..f6bc2875e 100644 --- a/tests/so_error.c +++ b/tests/so_error.c @@ -47,58 +47,88 @@ reserve_ephemeral_port(void) int main(void) { - in_port_t port = reserve_ephemeral_port (); - - /* - * Connect to the reserved port in NONBLOCK mode. - * The port is reserved but not listened. So - * the client doing "connect" gets error asynchronously. - */ - int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (fd < 0) - perror_msg_and_skip("socket AF_UNIX SOCK_STREAM"); - - int flag = fcntl(fd, F_GETFL); - if (flag < 0) - perror_msg_and_skip("fcntl F_GETFL"); - flag |= O_NONBLOCK; - if (fcntl(fd, F_SETFL, flag) < 0) - perror_msg_and_skip("fcntl F_SETFL"); + static const int sizes[] = { + -1, 0, 1, + sizeof(int) - 1, + sizeof(int), + sizeof(int) + 1, + }; - struct sockaddr_in addr = { + TAIL_ALLOC_OBJECT_CONST_PTR(int, sock_errno); + in_port_t port = reserve_ephemeral_port(); + const struct sockaddr_in addr = { .sin_family = AF_INET, .sin_addr.s_addr = htonl(INADDR_LOOPBACK), .sin_port = htons(port), }; - if (connect(fd, (void *) &addr, sizeof(addr)) == 0) - error_msg_and_skip("connect unexpectedly succeeded"); - if (errno != EINPROGRESS) - perror_msg_and_skip("connect failed for unexpected reason"); - struct timeval to = { - .tv_sec = 1, - .tv_usec = 0, - }; - fd_set wfds; - FD_ZERO(&wfds); - FD_SET(fd, &wfds); - if (select(fd + 1, NULL, &wfds, NULL, &to) < 0) - perror_msg_and_skip("select"); + for (size_t i = 0; i < ARRAY_SIZE(sizes); i++) { + /* + * Connect to the reserved port in NONBLOCK mode. + * The port is reserved but not listened. So + * the client doing "connect" gets error asynchronously. + */ + int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (fd < 0) + perror_msg_and_skip("socket AF_UNIX SOCK_STREAM"); + + int flag = fcntl(fd, F_GETFL); + if (flag < 0) + perror_msg_and_skip("fcntl F_GETFL"); + flag |= O_NONBLOCK; + if (fcntl(fd, F_SETFL, flag) < 0) + perror_msg_and_skip("fcntl F_SETFL"); + + if (connect(fd, (void *) &addr, sizeof(addr)) == 0) + error_msg_and_skip("connect unexpectedly succeeded"); + if (errno != EINPROGRESS) + perror_msg_and_skip("connect failed for unexpected reason"); + + struct timeval to = { + .tv_sec = 1, + .tv_usec = 0, + }; + fd_set wfds; + FD_ZERO(&wfds); + FD_SET(fd, &wfds); + if (select(fd + 1, NULL, &wfds, NULL, &to) < 0) + perror_msg_and_skip("select"); + + *sock_errno = 0xbadc0ded; + socklen_t optlen = sizes[i]; + long rc = getsockopt(fd, SOL_SOCKET, SO_ERROR, sock_errno, + &optlen); + const char *errstr = sprintrc(rc); + if (sizes[i] > 0 && rc < 0) + perror_msg_and_skip("getsockopt"); + if (sizes[i] >= (int) sizeof(*sock_errno) + && *sock_errno != ECONNREFUSED) { + errno = *sock_errno; + perror_msg_and_skip("unexpected socket error"); + } + if (sizes[i] >= (int) sizeof(*sock_errno) + && optlen != sizeof(*sock_errno)) { + error_msg_and_skip("unexpected data size for error" + " option: %d", optlen); + } + + printf("getsockopt(%d, SOL_SOCKET, SO_ERROR, ", fd); + if (sizes[i] <= 0) { + printf("%p, [%d]", sock_errno, sizes[i]); + } else if (sizes[i] < (int) sizeof(*sock_errno)) { + print_quoted_hex(sock_errno, sizes[i]); + printf(", [%u]", sizes[i]); + } else if (sizes[i] == sizeof(*sock_errno)) { + printf("[ECONNREFUSED], [%zu]", sizeof(*sock_errno)); + } else { + printf("[ECONNREFUSED], [%u => %zu]", + sizes[i], sizeof(*sock_errno)); + } + printf(") = %s\n", errstr); - int sock_errno; - socklen_t optlen = sizeof(sock_errno); - if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &sock_errno, &optlen) < 0) - perror_msg_and_skip("getsockopt"); - if (sock_errno != ECONNREFUSED) { - errno = sock_errno; - perror_msg_and_skip("unexpected socket error"); + close(fd); } - if (optlen != sizeof(sock_errno)) - error_msg_and_skip("unexpected data size for error option: %d", - optlen); - printf("getsockopt(%d, SOL_SOCKET, SO_ERROR, [ECONNREFUSED], [%u]) = 0\n", - fd, optlen); puts("+++ exited with 0 +++"); return 0; } -- cgit v1.2.1