1 /* SPDX-License-Identifier: MIT */
2 /*
3 * Check that writev on a socket that has been shutdown(2) fails
4 *
5 */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <stdint.h>
9 #include <assert.h>
10
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <unistd.h>
14 #include <sys/socket.h>
15 #include <sys/un.h>
16 #include <netinet/tcp.h>
17 #include <netinet/in.h>
18
19 #include "liburing.h"
20
sig_pipe(int sig)21 static void sig_pipe(int sig)
22 {
23 }
24
main(int argc,char * argv[])25 int main(int argc, char *argv[])
26 {
27 int p_fd[2], ret;
28 int32_t recv_s0;
29 int32_t val = 1;
30 struct sockaddr_in addr;
31
32 if (argc > 1)
33 return 0;
34
35 srand(getpid());
36
37 recv_s0 = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
38
39 ret = setsockopt(recv_s0, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
40 assert(ret != -1);
41 ret = setsockopt(recv_s0, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
42 assert(ret != -1);
43
44 addr.sin_family = AF_INET;
45 addr.sin_port = (rand() % 61440) + 4096;
46 addr.sin_addr.s_addr = 0x0100007fU;
47
48 ret = bind(recv_s0, (struct sockaddr*)&addr, sizeof(addr));
49 assert(ret != -1);
50 ret = listen(recv_s0, 128);
51 assert(ret != -1);
52
53 p_fd[1] = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
54
55 val = 1;
56 ret = setsockopt(p_fd[1], IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
57 assert(ret != -1);
58
59 int32_t flags = fcntl(p_fd[1], F_GETFL, 0);
60 assert(flags != -1);
61
62 flags |= O_NONBLOCK;
63 ret = fcntl(p_fd[1], F_SETFL, flags);
64 assert(ret != -1);
65
66 ret = connect(p_fd[1], (struct sockaddr*)&addr, sizeof(addr));
67 assert(ret == -1);
68
69 flags = fcntl(p_fd[1], F_GETFL, 0);
70 assert(flags != -1);
71
72 flags &= ~O_NONBLOCK;
73 ret = fcntl(p_fd[1], F_SETFL, flags);
74 assert(ret != -1);
75
76 p_fd[0] = accept(recv_s0, NULL, NULL);
77 assert(p_fd[0] != -1);
78
79 signal(SIGPIPE, sig_pipe);
80
81 while (1) {
82 int32_t code;
83 socklen_t code_len = sizeof(code);
84
85 ret = getsockopt(p_fd[1], SOL_SOCKET, SO_ERROR, &code, &code_len);
86 assert(ret != -1);
87
88 if (!code)
89 break;
90 }
91
92 struct io_uring m_io_uring;
93
94 ret = io_uring_queue_init(32, &m_io_uring, 0);
95 assert(ret >= 0);
96
97 {
98 struct io_uring_cqe *cqe;
99 struct io_uring_sqe *sqe;
100 int res;
101
102 sqe = io_uring_get_sqe(&m_io_uring);
103 io_uring_prep_shutdown(sqe, p_fd[1], SHUT_WR);
104 sqe->user_data = 1;
105
106 res = io_uring_submit_and_wait(&m_io_uring, 1);
107 assert(res != -1);
108
109 res = io_uring_wait_cqe(&m_io_uring, &cqe);
110 if (res < 0) {
111 fprintf(stderr, "wait: %s\n", strerror(-ret));
112 goto err;
113 }
114
115 if (cqe->res) {
116 if (cqe->res == -EINVAL) {
117 fprintf(stdout, "Shutdown not supported, skipping\n");
118 goto done;
119 }
120 fprintf(stderr, "writev: %d\n", cqe->res);
121 goto err;
122 }
123
124 io_uring_cqe_seen(&m_io_uring, cqe);
125 }
126
127 {
128 struct io_uring_cqe *cqe;
129 struct io_uring_sqe *sqe;
130 struct iovec iov[1];
131 char send_buff[128];
132 int res;
133
134 iov[0].iov_base = send_buff;
135 iov[0].iov_len = sizeof(send_buff);
136
137 sqe = io_uring_get_sqe(&m_io_uring);
138 assert(sqe != NULL);
139
140 io_uring_prep_writev(sqe, p_fd[1], iov, 1, 0);
141 res = io_uring_submit_and_wait(&m_io_uring, 1);
142 assert(res != -1);
143
144 res = io_uring_wait_cqe(&m_io_uring, &cqe);
145 if (res < 0) {
146 fprintf(stderr, "wait: %s\n", strerror(-ret));
147 goto err;
148 }
149
150 if (cqe->res != -EPIPE) {
151 fprintf(stderr, "writev: %d\n", cqe->res);
152 goto err;
153 }
154 io_uring_cqe_seen(&m_io_uring, cqe);
155 }
156
157 done:
158 io_uring_queue_exit(&m_io_uring);
159 return 0;
160 err:
161 io_uring_queue_exit(&m_io_uring);
162 return 1;
163 }
164