mirror of
https://github.com/openharmony/third_party_liburing.git
synced 2026-07-21 07:05:34 -04:00
0ae77b95ef
Signed-off-by: fangzhiyi18 <fangzhiyi1@huawei.com>
238 lines
4.9 KiB
C
238 lines
4.9 KiB
C
/* 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();
|
|
}
|