Jens Axboe | f2ee043 | 2019-10-17 17:21:25 -0600 | [diff] [blame^] | 1 | /* |
| 2 | * Check that IORING_OP_ACCEPT works, and send some data across to verify we |
| 3 | * didn't get a junk fd. |
| 4 | */ |
| 5 | #include <stdio.h> |
| 6 | #include <stdlib.h> |
| 7 | #include <stdint.h> |
| 8 | #include <assert.h> |
| 9 | |
| 10 | #include <errno.h> |
| 11 | #include <fcntl.h> |
| 12 | #include <unistd.h> |
| 13 | #include <sys/socket.h> |
| 14 | #include <sys/un.h> |
| 15 | #include <netinet/tcp.h> |
| 16 | #include <netinet/in.h> |
| 17 | |
| 18 | #include <liburing.h> |
| 19 | |
| 20 | static void queue_send(struct io_uring *ring, int fd) |
| 21 | { |
| 22 | struct io_uring_sqe *sqe; |
| 23 | char send_buff[128]; |
| 24 | struct iovec iov; |
| 25 | |
| 26 | iov.iov_base = send_buff; |
| 27 | iov.iov_len = sizeof(send_buff); |
| 28 | |
| 29 | sqe = io_uring_get_sqe(ring); |
| 30 | io_uring_prep_writev(sqe, fd, &iov, 1, 0); |
| 31 | } |
| 32 | |
| 33 | static void queue_recv(struct io_uring *ring, int fd) |
| 34 | { |
| 35 | struct io_uring_sqe *sqe; |
| 36 | char recv_buff[128]; |
| 37 | struct iovec iov; |
| 38 | |
| 39 | iov.iov_base = recv_buff; |
| 40 | iov.iov_len = sizeof(recv_buff); |
| 41 | |
| 42 | sqe = io_uring_get_sqe(ring); |
| 43 | io_uring_prep_readv(sqe, fd, &iov, 1, 0); |
| 44 | } |
| 45 | |
| 46 | static int accept_conn(struct io_uring *ring, int fd) |
| 47 | { |
| 48 | struct io_uring_sqe *sqe; |
| 49 | struct io_uring_cqe *cqe; |
| 50 | int ret; |
| 51 | |
| 52 | sqe = io_uring_get_sqe(ring); |
| 53 | io_uring_prep_accept(sqe, fd, NULL, NULL, 0); |
| 54 | |
| 55 | assert(io_uring_submit(ring) != -1); |
| 56 | |
| 57 | assert(!io_uring_wait_cqe(ring, &cqe)); |
| 58 | ret = cqe->res; |
| 59 | io_uring_cqe_seen(ring, cqe); |
| 60 | return ret; |
| 61 | } |
| 62 | |
| 63 | int main(int argc, char *argv[]) |
| 64 | { |
| 65 | struct io_uring m_io_uring; |
| 66 | struct io_uring_cqe *cqe; |
| 67 | uint32_t head; |
| 68 | uint32_t count = 0; |
| 69 | int done = 0; |
| 70 | int p_fd[2]; |
| 71 | |
| 72 | int32_t recv_s0 = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP); |
| 73 | |
| 74 | int32_t val = 1; |
| 75 | assert(setsockopt(recv_s0, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val)) != -1); |
| 76 | assert(setsockopt(recv_s0, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != -1); |
| 77 | |
| 78 | struct sockaddr_in addr; |
| 79 | |
| 80 | addr.sin_family = AF_INET; |
| 81 | addr.sin_port = 0x1235; |
| 82 | addr.sin_addr.s_addr = 0x0100007fU; |
| 83 | |
| 84 | assert(bind(recv_s0, (struct sockaddr*)&addr, sizeof(addr)) != -1); |
| 85 | assert(listen(recv_s0, 128) != -1); |
| 86 | |
| 87 | p_fd[1] = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP); |
| 88 | |
| 89 | val = 1; |
| 90 | assert(setsockopt(p_fd[1], IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) != -1); |
| 91 | |
| 92 | int32_t flags = fcntl(p_fd[1], F_GETFL, 0); |
| 93 | assert(flags != -1); |
| 94 | |
| 95 | flags |= O_NONBLOCK; |
| 96 | assert(fcntl(p_fd[1], F_SETFL, flags) != -1); |
| 97 | |
| 98 | assert(connect(p_fd[1], (struct sockaddr*)&addr, sizeof(addr)) == -1); |
| 99 | |
| 100 | flags = fcntl(p_fd[1], F_GETFL, 0); |
| 101 | assert(flags != -1); |
| 102 | |
| 103 | flags &= ~O_NONBLOCK; |
| 104 | assert(fcntl(p_fd[1], F_SETFL, flags) != -1); |
| 105 | |
| 106 | assert(io_uring_queue_init(32, &m_io_uring, 0) >= 0); |
| 107 | |
| 108 | p_fd[0] = accept_conn(&m_io_uring, recv_s0); |
| 109 | if (p_fd[0] == -EINVAL) { |
| 110 | fprintf(stdout, "Accept not supported, skipping\n"); |
| 111 | goto out; |
| 112 | } |
| 113 | assert(p_fd[0] >= 0); |
| 114 | |
| 115 | queue_send(&m_io_uring, p_fd[1]); |
| 116 | queue_recv(&m_io_uring, p_fd[0]); |
| 117 | |
| 118 | assert(io_uring_submit_and_wait(&m_io_uring, 2) != -1); |
| 119 | |
| 120 | while (count < 2) { |
| 121 | io_uring_for_each_cqe(&m_io_uring, head, cqe) { |
| 122 | if (cqe->res < 0) { |
| 123 | fprintf(stderr, "Got cqe res %d\n", cqe->res); |
| 124 | done = 1; |
| 125 | break; |
| 126 | } |
| 127 | assert(cqe->res == 128); |
| 128 | count++; |
| 129 | } |
| 130 | |
| 131 | assert(count <= 2); |
| 132 | io_uring_cq_advance(&m_io_uring, count); |
| 133 | if (done) |
| 134 | goto err; |
| 135 | } |
| 136 | |
| 137 | out: |
| 138 | io_uring_queue_exit(&m_io_uring); |
| 139 | return 0; |
| 140 | err: |
| 141 | io_uring_queue_exit(&m_io_uring); |
| 142 | return 1; |
| 143 | } |