aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/liburing/test/socket-io-cmd.c
diff options
context:
space:
mode:
authorthegeorg <thegeorg@yandex-team.com>2024-06-09 11:55:21 +0300
committerthegeorg <thegeorg@yandex-team.com>2024-06-09 12:07:55 +0300
commitafd4899380eea1c70e2a68714b5da1c9919ccdbd (patch)
treecd5120708784139bc6a0f8881da1ed8389a065b3 /contrib/libs/liburing/test/socket-io-cmd.c
parenta83bd2dd3c21e38c6c0807ec5e679497ab567f24 (diff)
downloadydb-afd4899380eea1c70e2a68714b5da1c9919ccdbd.tar.gz
Update contrib/libs/liburing to 2.6
3b51a9fb14de805208d11f1c077c78bb5d487e0f
Diffstat (limited to 'contrib/libs/liburing/test/socket-io-cmd.c')
-rw-r--r--contrib/libs/liburing/test/socket-io-cmd.c238
1 files changed, 238 insertions, 0 deletions
diff --git a/contrib/libs/liburing/test/socket-io-cmd.c b/contrib/libs/liburing/test/socket-io-cmd.c
new file mode 100644
index 0000000000..c4dd3bb8be
--- /dev/null
+++ b/contrib/libs/liburing/test/socket-io-cmd.c
@@ -0,0 +1,238 @@
+#include "../config-host.h"
+/* SPDX-License-Identifier: MIT */
+/*
+ * Check that CMD operations on sockets are consistent.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+#include <string.h>
+#include <unistd.h>
+#include <linux/sockios.h>
+#include <sys/ioctl.h>
+
+#include "liburing.h"
+#include "helpers.h"
+
+#define USERDATA 0x1234
+#define MSG "foobarbaz"
+
+static int no_io_cmd;
+
+struct fds {
+ int tx;
+ int rx;
+};
+
+/* Create 2 sockets (tx, rx) given the socket type */
+static struct fds create_sockets(bool stream)
+{
+ struct fds retval;
+ int fd[2];
+
+ t_create_socket_pair(fd, stream);
+
+ retval.tx = fd[0];
+ retval.rx = fd[1];
+
+ return retval;
+}
+
+static int create_sqe_and_submit(struct io_uring *ring, int32_t fd, int op)
+{
+ struct io_uring_sqe *sqe;
+ int ret;
+
+ assert(fd > 0);
+ sqe = io_uring_get_sqe(ring);
+ assert(sqe != NULL);
+
+ io_uring_prep_cmd_sock(sqe, op, fd, 0, 0, NULL, 0);
+ sqe->user_data = USERDATA;
+
+ /* Submitting SQE */
+ ret = io_uring_submit_and_wait(ring, 1);
+ if (ret <= 0)
+ return ret;
+
+ return 0;
+}
+
+static int receive_cqe(struct io_uring *ring)
+{
+ struct io_uring_cqe *cqe;
+ int err;
+
+ err = io_uring_wait_cqe(ring, &cqe);
+ assert(err == 0);
+ assert(cqe->user_data == USERDATA);
+ err = cqe->res;
+ io_uring_cqe_seen(ring, cqe);
+
+ /* Return the result of the operation */
+ return err;
+}
+
+static ssize_t send_data(struct fds *s, char *str)
+{
+ size_t written_bytes;
+
+ written_bytes = write(s->tx, str, strlen(str));
+ assert(written_bytes == strlen(MSG));
+
+ return written_bytes;
+}
+
+static int run_test(bool stream)
+{
+ struct fds sockfds;
+ ssize_t bytes_in, bytes_out;
+ struct io_uring ring;
+ size_t written_bytes;
+ int error;
+
+ /* Create three sockets */
+ sockfds = create_sockets(stream);
+ assert(sockfds.tx > 0);
+ assert(sockfds.rx > 0);
+ /* Send data sing the sockfds->send */
+ written_bytes = send_data(&sockfds, MSG);
+
+ /* Simply io_uring ring creation */
+ error = t_create_ring(1, &ring, 0);
+ if (error == T_SETUP_SKIP)
+ return error;
+ else if (error != T_SETUP_OK)
+ return T_EXIT_FAIL;
+
+ error = create_sqe_and_submit(&ring, sockfds.rx,
+ SOCKET_URING_OP_SIOCINQ);
+ if (error)
+ return T_EXIT_FAIL;
+ bytes_in = receive_cqe(&ring);
+ if (bytes_in < 0) {
+ if (bytes_in == -EINVAL || bytes_in == -EOPNOTSUPP) {
+ no_io_cmd = 1;
+ return T_EXIT_SKIP;
+ }
+ fprintf(stderr, "Bad return value %ld\n", (long) bytes_in);
+ return T_EXIT_FAIL;
+ }
+
+ error = create_sqe_and_submit(&ring, sockfds.tx,
+ SOCKET_URING_OP_SIOCOUTQ);
+ if (error)
+ return T_EXIT_FAIL;
+
+ bytes_out = receive_cqe(&ring);
+ if (bytes_in == -ENOTSUP || bytes_out == -ENOTSUP) {
+ fprintf(stderr, "Skipping tests. -ENOTSUP returned\n");
+ return T_EXIT_SKIP;
+ }
+
+ /*
+ * Assert the number of written bytes are either in the socket buffer
+ * or on the receive side
+ */
+ if (bytes_in + bytes_out != written_bytes) {
+ fprintf(stderr, "values does not match: %zu+%zu != %zu\n",
+ bytes_in, bytes_out, written_bytes);
+ return T_EXIT_FAIL;
+ }
+
+ io_uring_queue_exit(&ring);
+
+ return T_EXIT_PASS;
+}
+
+/*
+ * Make sure that siocoutq and siocinq returns the same value
+ * using ioctl(2) and uring commands for raw sockets
+ */
+static int run_test_raw(void)
+{
+ int ioctl_siocoutq, ioctl_siocinq;
+ int uring_siocoutq, uring_siocinq;
+ struct io_uring ring;
+ int retry = 0, sock, error;
+
+ sock = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
+ if (sock == -1) {
+ /* You need root to create raw socket */
+ perror("Not able to create a raw socket");
+ return T_EXIT_SKIP;
+ }
+
+ /* Get the same operation using uring cmd */
+ error = t_create_ring(1, &ring, 0);
+ if (error == T_SETUP_SKIP)
+ return error;
+ else if (error != T_SETUP_OK)
+ return T_EXIT_FAIL;
+
+again:
+ /* Simple SIOCOUTQ using ioctl */
+ error = ioctl(sock, SIOCOUTQ, &ioctl_siocoutq);
+ if (error < 0) {
+ fprintf(stderr, "Failed to run ioctl(SIOCOUTQ): %d\n", error);
+ return T_EXIT_FAIL;
+ }
+
+ error = ioctl(sock, SIOCINQ, &ioctl_siocinq);
+ if (error < 0) {
+ fprintf(stderr, "Failed to run ioctl(SIOCINQ): %d\n", error);
+ return T_EXIT_FAIL;
+ }
+
+ create_sqe_and_submit(&ring, sock, SOCKET_URING_OP_SIOCOUTQ);
+ uring_siocoutq = receive_cqe(&ring);
+
+ create_sqe_and_submit(&ring, sock, SOCKET_URING_OP_SIOCINQ);
+ uring_siocinq = receive_cqe(&ring);
+
+ /* Compare that both values (ioctl and uring CMD) should be similar */
+ if (uring_siocoutq != ioctl_siocoutq) {
+ if (!retry) {
+ retry = 1;
+ goto again;
+ }
+ fprintf(stderr, "values does not match: %d != %d\n",
+ uring_siocoutq, ioctl_siocoutq);
+ return T_EXIT_FAIL;
+ }
+ if (uring_siocinq != ioctl_siocinq) {
+ if (!retry) {
+ retry = 1;
+ goto again;
+ }
+ fprintf(stderr, "values does not match: %d != %d\n",
+ uring_siocinq, ioctl_siocinq);
+ return T_EXIT_FAIL;
+ }
+
+ return T_EXIT_PASS;
+}
+
+int main(int argc, char *argv[])
+{
+ int err;
+
+ if (argc > 1)
+ return 0;
+
+ /* Test SOCK_STREAM */
+ err = run_test(true);
+ if (err)
+ return err;
+ if (no_io_cmd)
+ return T_EXIT_SKIP;
+
+ /* Test SOCK_DGRAM */
+ err = run_test(false);
+ if (err)
+ return err;
+
+ /* Test raw sockets */
+ return run_test_raw();
+}