blob: 2fbc12edf9ae30d2bad90ddb541a870c4e6c3738 [file] [log] [blame]
Jens Axboeda1ce8c2019-11-11 12:51:42 -07001#include <errno.h>
2#include <stdio.h>
3#include <unistd.h>
4#include <stdlib.h>
5#include <string.h>
6#include <fcntl.h>
7#include <assert.h>
8#include <pthread.h>
9#include <sys/socket.h>
10#include <netinet/tcp.h>
11#include <netinet/in.h>
12#include <poll.h>
13
Jens Axboea8f85362019-11-12 12:30:38 -070014#include "liburing.h"
Jens Axboeda1ce8c2019-11-11 12:51:42 -070015
16pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
17pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
18
19static int recv_thread_ready = 0;
20static int recv_thread_done = 0;
21
22static void signal_var(int *var)
23{
24 pthread_mutex_lock(&mutex);
25 *var = 1;
26 pthread_cond_signal(&cond);
27 pthread_mutex_unlock(&mutex);
28}
29
30static void wait_for_var(int *var)
31{
32 pthread_mutex_lock(&mutex);
33
34 while (!*var)
35 pthread_cond_wait(&cond, &mutex);
36
37 pthread_mutex_unlock(&mutex);
38}
39
Jens Axboe4bce8562019-11-11 16:00:58 -070040struct data {
41 unsigned expected[2];
42 unsigned just_positive[2];
43 unsigned long timeout;
44 int port;
45 int stop;
46};
47
Jens Axboeda1ce8c2019-11-11 12:51:42 -070048static void *send_thread(void *arg)
49{
Jens Axboe4bce8562019-11-11 16:00:58 -070050 struct data *data = arg;
51
Jens Axboeda1ce8c2019-11-11 12:51:42 -070052 wait_for_var(&recv_thread_ready);
53
Jens Axboe4bce8562019-11-11 16:00:58 -070054 if (data->stop)
55 return NULL;
56
Jens Axboeda1ce8c2019-11-11 12:51:42 -070057 int s0 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
58 assert(s0 != -1);
59
60 struct sockaddr_in addr;
61
Jens Axboe4bce8562019-11-11 16:00:58 -070062 addr.sin_family = AF_INET;
63 addr.sin_port = data->port;
64 addr.sin_addr.s_addr = 0x0100007fU;
Jens Axboeda1ce8c2019-11-11 12:51:42 -070065
66 assert(connect(s0, (struct sockaddr*)&addr, sizeof(addr)) != -1);
67
68 wait_for_var(&recv_thread_done);
69
70 close(s0);
Jens Axboe4bce8562019-11-11 16:00:58 -070071 return NULL;
Jens Axboeda1ce8c2019-11-11 12:51:42 -070072}
73
Jens Axboeda1ce8c2019-11-11 12:51:42 -070074void *recv_thread(void *arg)
75{
76 struct data *data = arg;
Jens Axboeda1ce8c2019-11-11 12:51:42 -070077 struct io_uring ring;
Jens Axboe4bce8562019-11-11 16:00:58 -070078 int i;
79
Jens Axboeda1ce8c2019-11-11 12:51:42 -070080 assert(io_uring_queue_init(8, &ring, 0) == 0);
81
82 int s0 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
83 assert(s0 != -1);
84
85 int32_t val = 1;
86 assert(setsockopt(s0, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val)) != -1);
87 assert(setsockopt(s0, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != -1);
88
89 struct sockaddr_in addr;
90
91 addr.sin_family = AF_INET;
Jens Axboeda1ce8c2019-11-11 12:51:42 -070092 addr.sin_addr.s_addr = 0x0100007fU;
93
Jens Axboe4bce8562019-11-11 16:00:58 -070094 i = 0;
95 do {
96 data->port = 1025 + (rand() % 64510);
97 addr.sin_port = data->port;
98
99 if (bind(s0, (struct sockaddr*)&addr, sizeof(addr)) != -1)
100 break;
101 } while (++i < 100);
102
103 if (i >= 100) {
104 printf("Can't find good port, skipped\n");
105 data->stop = 1;
106 signal_var(&recv_thread_ready);
107 goto out;
108 }
109
Jens Axboeda1ce8c2019-11-11 12:51:42 -0700110 assert(listen(s0, 128) != -1);
111
112 signal_var(&recv_thread_ready);
113
114 struct io_uring_sqe *sqe;
115
116 sqe = io_uring_get_sqe(&ring);
117 assert(sqe != NULL);
118
119 io_uring_prep_accept(sqe, s0, NULL, NULL, 0);
120 sqe->flags |= IOSQE_IO_LINK;
121 sqe->user_data = 1;
122
123 sqe = io_uring_get_sqe(&ring);
124 assert(sqe != NULL);
125
126 struct __kernel_timespec ts;
127 ts.tv_sec = data->timeout / 1000000000;
128 ts.tv_nsec = data->timeout % 1000000000;
129 io_uring_prep_link_timeout(sqe, &ts, 0);
130 sqe->user_data = 2;
131
132 assert(io_uring_submit(&ring) == 2);
133
134 for (int i = 0; i < 2; i++) {
135 struct io_uring_cqe *cqe;
136 int idx;
137
138 if (io_uring_wait_cqe(&ring, &cqe)) {
139 fprintf(stderr, "wait cqe failed\n");
140 goto err;
141 }
142 idx = cqe->user_data - 1;
143 if (cqe->res != data->expected[idx]) {
144 if (cqe->res > 0 && data->just_positive[idx])
145 goto ok;
Jens Axboe4bce8562019-11-11 16:00:58 -0700146 fprintf(stderr, "cqe %llu got %d, wanted %d\n",
147 cqe->user_data, cqe->res,
148 data->expected[idx]);
Jens Axboeda1ce8c2019-11-11 12:51:42 -0700149 goto err;
150 }
151ok:
152 if (cqe->user_data == 1 && cqe->res > 0)
153 close(cqe->res);
154
155 io_uring_cqe_seen(&ring, cqe);
156 }
157
158 signal_var(&recv_thread_done);
159
Jens Axboe4bce8562019-11-11 16:00:58 -0700160out:
Jens Axboeda1ce8c2019-11-11 12:51:42 -0700161 close(s0);
162 return NULL;
163err:
164 close(s0);
165 return (void *) 1;
166}
167
168static int test_accept_timeout(int do_connect, unsigned long timeout)
169{
170 pthread_t t1, t2;
171 struct data d;
172 void *tret;
173 int ret = 0;
174
175 recv_thread_ready = 0;
176 recv_thread_done = 0;
177
178 d.timeout = timeout;
179 if (!do_connect) {
180 d.expected[0] = -EINTR;
181 d.expected[1] = -EALREADY;
182 } else {
183 d.expected[0] = -1U;
184 d.just_positive[0] = 1;
185 d.expected[1] = -ECANCELED;
186 }
187
188 pthread_create(&t1, NULL, recv_thread, &d);
189
190 if (do_connect)
Jens Axboe4bce8562019-11-11 16:00:58 -0700191 pthread_create(&t2, NULL, send_thread, &d);
Jens Axboeda1ce8c2019-11-11 12:51:42 -0700192
193 pthread_join(t1, &tret);
194 if (tret)
195 ret++;
196
197 if (do_connect) {
198 pthread_join(t2, &tret);
199 if (tret)
200 ret++;
201 }
202
203 return ret;
204}
205
206int main(int argc, char *argv[])
207{
Jens Axboe4bce8562019-11-11 16:00:58 -0700208 if (test_accept_timeout(0, 200000000)) {
Jens Axboeda1ce8c2019-11-11 12:51:42 -0700209 fprintf(stderr, "accept timeout 0 failed\n");
210 return 1;
211 }
212
213 if (test_accept_timeout(1, 1000000000)) {
214 fprintf(stderr, "accept timeout 0 failed\n");
215 return 1;
216 }
217
218 return 0;
219}