Add a test demonstrating connect timeout functionality
diff --git a/test/connect.c b/test/connect.c
index 474d1c8..34e3954 100644
--- a/test/connect.c
+++ b/test/connect.c
@@ -105,12 +105,9 @@
return 0;
}
-static int connect_socket(struct io_uring *ring, int fd, int *code)
+static int configure_connect(int fd, struct sockaddr_in* addr)
{
- struct io_uring_sqe *sqe;
- struct sockaddr_in addr;
- int ret, res, val = 1;
- socklen_t code_len = sizeof(*code);
+ int ret, val = 1;
ret = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
if (ret == -1) {
@@ -124,10 +121,23 @@
return -1;
}
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = 0x1234;
- addr.sin_addr.s_addr = 0x0100007fU;
+ memset(addr, 0, sizeof(*addr));
+ addr->sin_family = AF_INET;
+ addr->sin_port = 0x1234;
+ addr->sin_addr.s_addr = 0x0100007fU;
+
+ return 0;
+}
+
+static int connect_socket(struct io_uring *ring, int fd, int *code)
+{
+ struct sockaddr_in addr;
+ int ret, res;
+ socklen_t code_len = sizeof(*code);
+ struct io_uring_sqe *sqe;
+
+ if (configure_connect(fd, &addr) == -1)
+ return -1;
sqe = io_uring_get_sqe(ring);
if (!sqe) {
@@ -235,6 +245,102 @@
return -1;
}
+static int test_connect_timeout(struct io_uring *ring)
+{
+ int fd = -1, connect_fd = -1, accept_fd = -1;
+ int ret;
+ struct sockaddr_in addr;
+ struct io_uring_sqe *sqe;
+ struct __kernel_timespec ts = {.tv_sec = 0, .tv_nsec = 100000};
+
+ connect_fd = create_socket();
+ if (connect_fd == -1)
+ return -1;
+
+ accept_fd = create_socket();
+ if (accept_fd == -1)
+ goto err;
+
+ if (configure_connect(connect_fd, &addr) == -1)
+ goto err;
+
+ ret = bind(accept_fd, (struct sockaddr*)&addr, sizeof(addr));
+ if (ret == -1) {
+ perror("bind()");
+ goto err;
+ }
+
+ ret = listen(accept_fd, 0); // no backlog in order to block connect_fd
+ if (ret == -1) {
+ perror("listen()");
+ goto err;
+ }
+
+ // Fill up available place in the accept queue (backlog)
+ fd = create_socket();
+ if (connect(fd, &addr, sizeof(addr)) == -1) {
+ fprintf(stderr, "unable to connect %d\n", errno);
+ goto err;
+ }
+
+ sqe = io_uring_get_sqe(ring);
+ if (!sqe) {
+ fprintf(stderr, "unable to get sqe\n");
+ goto err;
+ }
+
+ io_uring_prep_connect(sqe, connect_fd, (struct sockaddr*)&addr, sizeof(addr));
+ sqe->user_data = 1;
+ sqe->flags |= IOSQE_IO_LINK;
+
+ sqe = io_uring_get_sqe(ring);
+ if (!sqe) {
+ fprintf(stderr, "unable to get sqe\n");
+ goto err;
+ }
+ sqe->user_data = 2;
+
+ io_uring_prep_link_timeout(sqe, &ts, 0);
+ ret = io_uring_submit(ring);
+ if (ret != 2) {
+ fprintf(stderr, "submitted %d\n", ret);
+ return -1;
+ }
+
+ for (int i = 0; i < 2; i++) {
+ int expected;
+ struct io_uring_cqe *cqe;
+
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait_cqe=%d\n", ret);
+ return -1;
+ }
+
+ expected = (cqe->user_data == 1) ? -ECANCELED : -ETIME;
+ if (expected != cqe->res) {
+ fprintf(stderr, "cqe %d, res %d, wanted %d\n",
+ (int)cqe->user_data, cqe->res, expected);
+ goto err;
+ }
+ io_uring_cqe_seen(ring, cqe);
+ }
+
+ close(connect_fd);
+ close(accept_fd);
+ close(fd);
+
+ return 0;
+
+err:
+ close(connect_fd);
+ if (accept_fd != -1)
+ close(accept_fd);
+ if (fd != -1)
+ close(fd);
+ return -1;
+}
+
int main(int argc, char *argv[])
{
struct io_uring ring;
@@ -263,6 +369,12 @@
return 1;
}
+ ret = test_connect_timeout(&ring);
+ if (ret == -1) {
+ fprintf(stderr, "test_connect_timeout(): failed\n");
+ return 1;
+ }
+
io_uring_queue_exit(&ring);
return 0;
}