diff --git a/include/condy/async_operations.hpp b/include/condy/async_operations.hpp index c78c1d48..c453a8d5 100644 --- a/include/condy/async_operations.hpp +++ b/include/condy/async_operations.hpp @@ -833,6 +833,22 @@ inline auto async_socket_direct(int domain, int type, int protocol, file_index, flags); } +#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13 +/** + * @brief See io_uring_prep_uring_cmd + */ +template +inline auto async_uring_cmd(int cmd_op, Fd fd, CmdFunc &&cmd_func) { + auto prep_func = [cmd_op, fd, cmd_func = std::forward(cmd_func)]( + io_uring_sqe *sqe) { + io_uring_prep_uring_cmd(sqe, cmd_op, fd); + cmd_func(sqe); + }; + auto op = make_op_awaiter(std::move(prep_func)); + return detail::maybe_flag_fixed_fd(std::move(op), fd); +} +#endif + #if !IO_URING_CHECK_VERSION(2, 5) // >= 2.5 /** * @brief See io_uring_prep_cmd_sock @@ -846,6 +862,19 @@ inline auto async_cmd_sock(int cmd_op, Fd fd, int level, int optname, } #endif +#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13 +/** + * @brief See io_uring_prep_cmd_getsockname + */ +template +inline auto async_cmd_getsockname(Fd fd, struct sockaddr *sockaddr, + socklen_t *sockaddr_len, int peer) { + auto op = make_op_awaiter(io_uring_prep_cmd_getsockname, fd, sockaddr, + sockaddr_len, peer); + return detail::maybe_flag_fixed_fd(std::move(op), fd); +} +#endif + #if !IO_URING_CHECK_VERSION(2, 6) // >= 2.6 /** * @brief See io_uring_prep_waitid diff --git a/tests/test_async_operations.4.cpp b/tests/test_async_operations.4.cpp index 9e09a7b7..5dc2ab5f 100644 --- a/tests/test_async_operations.4.cpp +++ b/tests/test_async_operations.4.cpp @@ -267,13 +267,75 @@ TEST_CASE("test async_operations - test socket - direct") { condy::sync_wait(func()); } +#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13 +TEST_CASE("test async_operations - test uring_cmd - basic") { + auto my_async_cmd_sock = [](int cmd_op, int fd, int level, int optname, + void *optval, int optlen) { + return condy::async_uring_cmd(cmd_op, fd, [=](io_uring_sqe *sqe) { + sqe->optval = (unsigned long)(uintptr_t)optval; + sqe->optname = optname; + sqe->optlen = optlen; + sqe->level = level; + }); + }; + + int listen_fd = socket(AF_INET, SOCK_STREAM, 0); + REQUIRE(listen_fd >= 0); + + auto func = [&]() -> condy::Coro { + int val = 1; + int r = co_await my_async_cmd_sock(SOCKET_URING_OP_SETSOCKOPT, + listen_fd, SOL_SOCKET, SO_REUSEADDR, + &val, sizeof(val)); + REQUIRE(r == 0); + }; + condy::sync_wait(func()); + + close(listen_fd); +} +#endif + +#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13 +TEST_CASE("test async_operations - test uring_cmd - fixed fd") { + auto my_async_cmd_sock_fixed = [](int cmd_op, int fd, int level, + int optname, void *optval, int optlen) { + return condy::async_uring_cmd( + cmd_op, condy::fixed(fd), [=](io_uring_sqe *sqe) { + sqe->optval = (unsigned long)(uintptr_t)optval; + sqe->optname = optname; + sqe->optlen = optlen; + sqe->level = level; + }); + }; + + int listen_fd = create_accept_socket(); + + auto func = [&]() -> condy::Coro { + auto &fd_table = condy::current_runtime().fd_table(); + fd_table.init(1); + int r = co_await condy::async_files_update(&listen_fd, 1, 0); + REQUIRE(r == 1); + + int val = 1; + r = co_await my_async_cmd_sock_fixed(SOCKET_URING_OP_SETSOCKOPT, 0, + SOL_SOCKET, SO_REUSEADDR, &val, + sizeof(val)); + REQUIRE(r == 0); + }; + + condy::sync_wait(func()); + + close(listen_fd); +} +#endif + #if !IO_URING_CHECK_VERSION(2, 5) // >= 2.5 TEST_CASE("test async_operations - test cmd_sock - basic") { int listen_fd = socket(AF_INET, SOCK_STREAM, 0); REQUIRE(listen_fd >= 0); auto func = [&]() -> condy::Coro { - int val; + int val = 1; int r = co_await condy::async_cmd_sock(SOCKET_URING_OP_SETSOCKOPT, listen_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); @@ -295,7 +357,7 @@ TEST_CASE("test async_operations - test cmd_sock - fixed fd") { int r = co_await condy::async_files_update(&listen_fd, 1, 0); REQUIRE(r == 1); - int val; + int val = 1; r = co_await condy::async_cmd_sock(SOCKET_URING_OP_SETSOCKOPT, condy::fixed(0), SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); @@ -306,6 +368,49 @@ TEST_CASE("test async_operations - test cmd_sock - fixed fd") { } #endif +#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13 +TEST_CASE("test async_operations - test cmd_getsockname - basic") { + int listen_fd = create_accept_socket(); + + auto func = [&]() -> condy::Coro { + struct sockaddr_in addr {}; + socklen_t addrlen = sizeof(addr); + int r = co_await condy::async_cmd_getsockname( + listen_fd, (struct sockaddr *)&addr, &addrlen, 0); + REQUIRE(r == 0); + REQUIRE(addrlen == sizeof(addr)); + REQUIRE(addr.sin_family == AF_INET); + }; + condy::sync_wait(func()); + + close(listen_fd); +} +#endif + +#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13 +TEST_CASE("test async_operations - test cmd_getsockname - fixed fd") { + int listen_fd = create_accept_socket(); + + auto func = [&]() -> condy::Coro { + auto &fd_table = condy::current_runtime().fd_table(); + fd_table.init(1); + int r = co_await condy::async_files_update(&listen_fd, 1, 0); + REQUIRE(r == 1); + + struct sockaddr_in addr {}; + socklen_t addrlen = sizeof(addr); + r = co_await condy::async_cmd_getsockname( + condy::fixed(0), (struct sockaddr *)&addr, &addrlen, 0); + REQUIRE(r == 0); + REQUIRE(addrlen == sizeof(addr)); + REQUIRE(addr.sin_family == AF_INET); + }; + condy::sync_wait(func()); + + close(listen_fd); +} +#endif + #if !IO_URING_CHECK_VERSION(2, 6) // >= 2.6 TEST_CASE("test async_operations - test waitid") { pid_t pid = fork();