Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/kern/socket_splice.c
39536 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2024 Stormshield
5
*/
6
7
#include <sys/capsicum.h>
8
#include <sys/event.h>
9
#include <sys/filio.h>
10
#include <sys/socket.h>
11
#include <sys/wait.h>
12
13
#include <netinet/in.h>
14
#include <netinet/tcp.h>
15
16
#include <errno.h>
17
#include <poll.h>
18
#include <pthread.h>
19
#include <signal.h>
20
#include <stdio.h>
21
#include <stdlib.h>
22
#include <string.h>
23
#include <time.h>
24
25
#include <atf-c.h>
26
27
static void
28
checked_close(int fd)
29
{
30
int error;
31
32
error = close(fd);
33
ATF_REQUIRE_MSG(error == 0, "close failed: %s", strerror(errno));
34
}
35
36
static int
37
fionread(int fd)
38
{
39
int data, error;
40
41
data = 0;
42
error = ioctl(fd, FIONREAD, &data);
43
ATF_REQUIRE_MSG(error == 0, "ioctl failed: %s", strerror(errno));
44
ATF_REQUIRE(data >= 0);
45
return (data);
46
}
47
48
static void
49
noblocking(int fd)
50
{
51
int flags, error;
52
53
flags = fcntl(fd, F_GETFL);
54
ATF_REQUIRE_MSG(flags != -1, "fcntl failed: %s", strerror(errno));
55
flags |= O_NONBLOCK;
56
error = fcntl(fd, F_SETFL, flags);
57
ATF_REQUIRE_MSG(error == 0, "fcntl failed: %s", strerror(errno));
58
}
59
60
/*
61
* Create a pair of connected TCP sockets, returned via the "out" array.
62
*/
63
static void
64
tcp_socketpair(int out[2], int domain)
65
{
66
struct sockaddr_in sin;
67
struct sockaddr_in6 sin6;
68
struct sockaddr *sinp;
69
int error, sd[2];
70
71
sd[0] = socket(domain, SOCK_STREAM, 0);
72
ATF_REQUIRE_MSG(sd[0] >= 0, "socket failed: %s", strerror(errno));
73
sd[1] = socket(domain, SOCK_STREAM, 0);
74
ATF_REQUIRE_MSG(sd[1] >= 0, "socket failed: %s", strerror(errno));
75
76
error = setsockopt(sd[0], IPPROTO_TCP, TCP_NODELAY, &(int){ 1 },
77
sizeof(int));
78
ATF_REQUIRE_MSG(error == 0, "setsockopt failed: %s", strerror(errno));
79
error = setsockopt(sd[1], IPPROTO_TCP, TCP_NODELAY, &(int){ 1 },
80
sizeof(int));
81
ATF_REQUIRE_MSG(error == 0, "setsockopt failed: %s", strerror(errno));
82
83
if (domain == PF_INET) {
84
memset(&sin, 0, sizeof(sin));
85
sin.sin_family = AF_INET;
86
sin.sin_len = sizeof(sin);
87
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
88
sin.sin_port = htons(0);
89
sinp = (struct sockaddr *)&sin;
90
} else {
91
ATF_REQUIRE(domain == PF_INET6);
92
memset(&sin6, 0, sizeof(sin6));
93
sin6.sin6_family = AF_INET6;
94
sin6.sin6_len = sizeof(sin6);
95
sin6.sin6_addr = in6addr_loopback;
96
sin6.sin6_port = htons(0);
97
sinp = (struct sockaddr *)&sin6;
98
}
99
100
error = bind(sd[0], sinp, sinp->sa_len);
101
ATF_REQUIRE_MSG(error == 0, "bind failed: %s", strerror(errno));
102
error = listen(sd[0], 1);
103
ATF_REQUIRE_MSG(error == 0, "listen failed: %s", strerror(errno));
104
105
error = getsockname(sd[0], sinp, &(socklen_t){ sinp->sa_len });
106
ATF_REQUIRE_MSG(error == 0, "getsockname failed: %s", strerror(errno));
107
108
error = connect(sd[1], sinp, sinp->sa_len);
109
ATF_REQUIRE_MSG(error == 0, "connect failed: %s", strerror(errno));
110
out[0] = accept(sd[0], NULL, NULL);
111
ATF_REQUIRE_MSG(out[0] >= 0, "accept failed: %s", strerror(errno));
112
checked_close(sd[0]);
113
out[1] = sd[1];
114
}
115
116
static void
117
tcp4_socketpair(int out[2])
118
{
119
tcp_socketpair(out, PF_INET);
120
}
121
122
static void
123
tcp6_socketpair(int out[2])
124
{
125
tcp_socketpair(out, PF_INET6);
126
}
127
128
static off_t
129
nspliced(int sd)
130
{
131
off_t n;
132
socklen_t len;
133
int error;
134
135
len = sizeof(n);
136
error = getsockopt(sd, SOL_SOCKET, SO_SPLICE, &n, &len);
137
ATF_REQUIRE_MSG(error == 0, "getsockopt failed: %s", strerror(errno));
138
ATF_REQUIRE_MSG(len == sizeof(n), "unexpected length: %d", len);
139
return (n);
140
}
141
142
/*
143
* Use a macro so that ATF_REQUIRE_MSG prints a useful line number.
144
*/
145
#define check_nspliced(sd, n) do { \
146
off_t sofar; \
147
\
148
sofar = nspliced(sd); \
149
ATF_REQUIRE_MSG(sofar == (off_t)n, "spliced %jd bytes, expected %jd", \
150
(intmax_t)sofar, (intmax_t)n); \
151
} while (0)
152
153
static void
154
splice_init(struct splice *sp, int fd, off_t max, struct timeval *tv)
155
{
156
memset(sp, 0, sizeof(*sp));
157
sp->sp_fd = fd;
158
sp->sp_max = max;
159
if (tv != NULL)
160
sp->sp_idle = *tv;
161
else
162
sp->sp_idle.tv_sec = sp->sp_idle.tv_usec = 0;
163
}
164
165
static void
166
unsplice(int fd)
167
{
168
struct splice sp;
169
int error;
170
171
splice_init(&sp, -1, 0, NULL);
172
error = setsockopt(fd, SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
173
ATF_REQUIRE_MSG(error == 0, "setsockopt failed: %s", strerror(errno));
174
}
175
176
static void
177
unsplice_pair(int fd1, int fd2)
178
{
179
unsplice(fd1);
180
unsplice(fd2);
181
}
182
183
static void
184
splice_pair(int fd1, int fd2, off_t max, struct timeval *tv)
185
{
186
struct splice sp;
187
int error;
188
189
splice_init(&sp, fd1, max, tv);
190
error = setsockopt(fd2, SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
191
ATF_REQUIRE_MSG(error == 0, "setsockopt failed: %s", strerror(errno));
192
193
splice_init(&sp, fd2, max, tv);
194
error = setsockopt(fd1, SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
195
ATF_REQUIRE_MSG(error == 0, "setsockopt failed: %s", strerror(errno));
196
}
197
198
/*
199
* A structure representing a spliced pair of connections. left[1] is
200
* bidirectionally spliced with right[0].
201
*/
202
struct splice_conn {
203
int left[2];
204
int right[2];
205
};
206
207
/*
208
* Initialize a splice connection with the given maximum number of bytes to
209
* splice and the given idle timeout. For now we're forced to use TCP socket,
210
* but at some point it would be nice (and simpler) to use pairs of PF_LOCAL
211
* sockets.
212
*/
213
static void
214
splice_conn_init_limits(struct splice_conn *sc, off_t max, struct timeval *tv)
215
{
216
memset(sc, 0, sizeof(*sc));
217
tcp4_socketpair(sc->left);
218
tcp4_socketpair(sc->right);
219
splice_pair(sc->left[1], sc->right[0], max, tv);
220
}
221
222
static void
223
splice_conn_init(struct splice_conn *sc)
224
{
225
splice_conn_init_limits(sc, 0, NULL);
226
}
227
228
static void
229
splice_conn_check_empty(struct splice_conn *sc)
230
{
231
int data;
232
233
data = fionread(sc->left[0]);
234
ATF_REQUIRE_MSG(data == 0, "unexpected data on left[0]: %d", data);
235
data = fionread(sc->left[1]);
236
ATF_REQUIRE_MSG(data == 0, "unexpected data on left[1]: %d", data);
237
data = fionread(sc->right[0]);
238
ATF_REQUIRE_MSG(data == 0, "unexpected data on right[0]: %d", data);
239
data = fionread(sc->right[1]);
240
ATF_REQUIRE_MSG(data == 0, "unexpected data on right[1]: %d", data);
241
}
242
243
static void
244
splice_conn_fini(struct splice_conn *sc)
245
{
246
checked_close(sc->left[0]);
247
checked_close(sc->left[1]);
248
checked_close(sc->right[0]);
249
checked_close(sc->right[1]);
250
}
251
252
static void
253
splice_conn_noblocking(struct splice_conn *sc)
254
{
255
noblocking(sc->left[0]);
256
noblocking(sc->left[1]);
257
noblocking(sc->right[0]);
258
noblocking(sc->right[1]);
259
}
260
261
/* Pass a byte through a pair of spliced connections. */
262
ATF_TC_WITHOUT_HEAD(splice_basic);
263
ATF_TC_BODY(splice_basic, tc)
264
{
265
struct splice_conn sc;
266
ssize_t n;
267
char c;
268
269
splice_conn_init(&sc);
270
271
check_nspliced(sc.left[1], 0);
272
check_nspliced(sc.right[0], 0);
273
274
/* Left-to-right. */
275
c = 'M';
276
n = write(sc.left[0], &c, 1);
277
ATF_REQUIRE_MSG(n == 1, "write failed: %s", strerror(errno));
278
n = read(sc.right[1], &c, 1);
279
ATF_REQUIRE_MSG(n == 1, "read failed: %s", strerror(errno));
280
ATF_REQUIRE_MSG(c == 'M', "unexpected character: %c", c);
281
check_nspliced(sc.left[1], 1);
282
check_nspliced(sc.right[0], 0);
283
284
/* Right-to-left. */
285
c = 'J';
286
n = write(sc.right[1], &c, 1);
287
ATF_REQUIRE_MSG(n == 1, "write failed: %s", strerror(errno));
288
n = read(sc.left[0], &c, 1);
289
ATF_REQUIRE_MSG(n == 1, "read failed: %s", strerror(errno));
290
ATF_REQUIRE_MSG(c == 'J', "unexpected character: %c", c);
291
check_nspliced(sc.left[1], 1);
292
check_nspliced(sc.right[0], 1);
293
294
/* Unsplice and verify that the byte counts haven't changed. */
295
unsplice(sc.left[1]);
296
unsplice(sc.right[0]);
297
check_nspliced(sc.left[1], 1);
298
check_nspliced(sc.right[0], 1);
299
300
splice_conn_fini(&sc);
301
}
302
303
static void
304
remove_rights(int fd, const cap_rights_t *toremove)
305
{
306
cap_rights_t rights;
307
int error;
308
309
error = cap_rights_get(fd, &rights);
310
ATF_REQUIRE_MSG(error == 0, "cap_rights_get failed: %s",
311
strerror(errno));
312
cap_rights_remove(&rights, toremove);
313
error = cap_rights_limit(fd, &rights);
314
ATF_REQUIRE_MSG(error == 0, "cap_rights_limit failed: %s",
315
strerror(errno));
316
}
317
318
/*
319
* Verify that splicing fails when the socket is missing the necessary rights.
320
*/
321
ATF_TC_WITHOUT_HEAD(splice_capsicum);
322
ATF_TC_BODY(splice_capsicum, tc)
323
{
324
struct splice sp;
325
cap_rights_t rights;
326
off_t n;
327
int error, left[2], right[2];
328
329
tcp4_socketpair(left);
330
tcp4_socketpair(right);
331
332
/*
333
* Make sure that we can't splice a socket that's missing recv rights.
334
*/
335
remove_rights(left[1], cap_rights_init(&rights, CAP_RECV));
336
splice_init(&sp, right[0], 0, NULL);
337
error = setsockopt(left[1], SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
338
ATF_REQUIRE_ERRNO(ENOTCAPABLE, error == -1);
339
340
/* Make sure we can still splice left[1] in the other direction. */
341
splice_init(&sp, left[1], 0, NULL);
342
error = setsockopt(right[0], SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
343
ATF_REQUIRE_MSG(error == 0, "setsockopt failed: %s", strerror(errno));
344
splice_init(&sp, -1, 0, NULL);
345
error = setsockopt(right[0], SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
346
ATF_REQUIRE_MSG(error == 0, "setsockopt failed: %s", strerror(errno));
347
348
/*
349
* Now remove send rights from left[1] and verify that splicing is no
350
* longer possible.
351
*/
352
remove_rights(left[1], cap_rights_init(&rights, CAP_SEND));
353
splice_init(&sp, left[1], 0, NULL);
354
error = setsockopt(right[0], SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
355
ATF_REQUIRE_ERRNO(ENOTCAPABLE, error == -1);
356
357
/*
358
* It's still ok to query the SO_SPLICE state though.
359
*/
360
n = -1;
361
error = getsockopt(left[1], SOL_SOCKET, SO_SPLICE, &n,
362
&(socklen_t){ sizeof(n) });
363
ATF_REQUIRE_MSG(error == 0, "getsockopt failed: %s", strerror(errno));
364
ATF_REQUIRE(n == 0);
365
366
/*
367
* Make sure that we can unsplice a spliced pair without any rights
368
* other than CAP_SETSOCKOPT.
369
*/
370
splice_pair(left[0], right[1], 0, NULL);
371
error = cap_rights_limit(left[0],
372
cap_rights_init(&rights, CAP_SETSOCKOPT));
373
ATF_REQUIRE_MSG(error == 0, "cap_rights_limit failed: %s",
374
strerror(errno));
375
unsplice(left[0]);
376
377
checked_close(left[0]);
378
checked_close(left[1]);
379
checked_close(right[0]);
380
checked_close(right[1]);
381
}
382
383
/*
384
* Check various error cases in splice configuration.
385
*/
386
ATF_TC_WITHOUT_HEAD(splice_error);
387
ATF_TC_BODY(splice_error, tc)
388
{
389
struct splice_conn sc;
390
struct splice sp;
391
char path[PATH_MAX];
392
int error, fd, sd, usd[2];
393
394
memset(&sc, 0, sizeof(sc));
395
tcp4_socketpair(sc.left);
396
tcp4_socketpair(sc.right);
397
398
/* A negative byte limit is invalid. */
399
splice_init(&sp, sc.right[0], -3, NULL);
400
error = setsockopt(sc.left[1], SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
401
ATF_REQUIRE_ERRNO(EINVAL, error == -1);
402
403
/* Can't unsplice a never-spliced socket. */
404
splice_init(&sp, -1, 0, NULL);
405
error = setsockopt(sc.left[1], SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
406
ATF_REQUIRE_ERRNO(ENOTCONN, error == -1);
407
408
/* Can't double-unsplice a socket. */
409
splice_init(&sp, sc.right[0], 0, NULL);
410
error = setsockopt(sc.left[1], SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
411
ATF_REQUIRE_MSG(error == 0, "setsockopt failed: %s", strerror(errno));
412
unsplice(sc.left[1]);
413
splice_init(&sp, -1, 0, NULL);
414
error = setsockopt(sc.left[1], SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
415
ATF_REQUIRE_ERRNO(ENOTCONN, error == -1);
416
417
/* Can't splice a spliced socket */
418
splice_init(&sp, sc.right[0], 0, NULL);
419
error = setsockopt(sc.left[1], SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
420
ATF_REQUIRE_MSG(error == 0, "setsockopt failed: %s", strerror(errno));
421
splice_init(&sp, sc.right[1], 0, NULL);
422
error = setsockopt(sc.left[1], SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
423
ATF_REQUIRE_ERRNO(EBUSY, error == -1);
424
splice_init(&sp, sc.right[0], 0, NULL);
425
error = setsockopt(sc.left[0], SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
426
ATF_REQUIRE_ERRNO(EBUSY, error == -1);
427
splice_init(&sp, -1, 0, NULL);
428
error = setsockopt(sc.left[1], SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
429
430
/* Can't splice to a non-socket. */
431
snprintf(path, sizeof(path), "/tmp/splice_error.XXXXXX");
432
fd = mkstemp(path);
433
ATF_REQUIRE_MSG(fd >= 0, "mkstemp failed: %s", strerror(errno));
434
splice_init(&sp, fd, 0, NULL);
435
error = setsockopt(sc.left[1], SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
436
ATF_REQUIRE_ERRNO(ENOTSOCK, error == -1);
437
438
/* Can't splice to an invalid fd. */
439
checked_close(fd);
440
splice_init(&sp, fd, 0, NULL);
441
error = setsockopt(sc.left[1], SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
442
ATF_REQUIRE_ERRNO(EBADF, error == -1);
443
444
/* Can't splice a unix stream socket. */
445
error = socketpair(AF_UNIX, SOCK_STREAM, 0, usd);
446
ATF_REQUIRE_MSG(error == 0, "socketpair failed: %s", strerror(errno));
447
splice_init(&sp, usd[0], 0, NULL);
448
error = setsockopt(sc.left[1], SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
449
ATF_REQUIRE_ERRNO(EPROTONOSUPPORT, error == -1);
450
error = setsockopt(usd[1], SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
451
ATF_REQUIRE_ERRNO(EPROTONOSUPPORT, error == -1);
452
checked_close(usd[0]);
453
checked_close(usd[1]);
454
455
/* Can't splice an unconnected TCP socket. */
456
sd = socket(PF_INET, SOCK_STREAM, 0);
457
ATF_REQUIRE_MSG(sd >= 0, "socket failed: %s", strerror(errno));
458
splice_init(&sp, sd, 0, NULL);
459
error = setsockopt(sc.left[1], SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
460
ATF_REQUIRE_ERRNO(ENOTCONN, error == -1);
461
splice_init(&sp, sc.right[0], 0, NULL);
462
error = setsockopt(sd, SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
463
ATF_REQUIRE_ERRNO(ENOTCONN, error == -1);
464
465
splice_conn_fini(&sc);
466
}
467
468
/*
469
* Make sure that kevent() doesn't report read I/O events on spliced sockets.
470
*/
471
ATF_TC_WITHOUT_HEAD(splice_kevent);
472
ATF_TC_BODY(splice_kevent, tc)
473
{
474
struct splice_conn sc;
475
struct kevent kev;
476
struct timespec ts;
477
ssize_t n;
478
int error, nev, kq;
479
uint8_t b;
480
481
splice_conn_init(&sc);
482
483
kq = kqueue();
484
ATF_REQUIRE_MSG(kq >= 0, "kqueue failed: %s", strerror(errno));
485
486
EV_SET(&kev, sc.left[1], EVFILT_READ, EV_ADD, 0, 0, NULL);
487
error = kevent(kq, &kev, 1, NULL, 0, NULL);
488
ATF_REQUIRE_MSG(error == 0, "kevent failed: %s", strerror(errno));
489
490
memset(&ts, 0, sizeof(ts));
491
nev = kevent(kq, NULL, 0, &kev, 1, &ts);
492
ATF_REQUIRE_MSG(nev >= 0, "kevent failed: %s", strerror(errno));
493
ATF_REQUIRE(nev == 0);
494
495
b = 'M';
496
n = write(sc.left[0], &b, 1);
497
ATF_REQUIRE_MSG(n == 1, "write failed: %s", strerror(errno));
498
n = read(sc.right[1], &b, 1);
499
ATF_REQUIRE_MSG(n == 1, "read failed: %s", strerror(errno));
500
ATF_REQUIRE(b == 'M');
501
502
nev = kevent(kq, NULL, 0, &kev, 1, &ts);
503
ATF_REQUIRE_MSG(nev >= 0, "kevent failed: %s", strerror(errno));
504
ATF_REQUIRE(nev == 0);
505
506
b = 'J';
507
n = write(sc.right[1], &b, 1);
508
ATF_REQUIRE_MSG(n == 1, "write failed: %s", strerror(errno));
509
n = read(sc.left[0], &b, 1);
510
ATF_REQUIRE_MSG(n == 1, "read failed: %s", strerror(errno));
511
ATF_REQUIRE(b == 'J');
512
513
splice_conn_fini(&sc);
514
checked_close(kq);
515
}
516
517
/*
518
* Verify that a splice byte limit is applied.
519
*/
520
ATF_TC_WITHOUT_HEAD(splice_limit_bytes);
521
ATF_TC_BODY(splice_limit_bytes, tc)
522
{
523
struct splice_conn sc;
524
ssize_t n;
525
uint8_t b, buf[128];
526
527
splice_conn_init_limits(&sc, sizeof(buf) + 1, NULL);
528
529
memset(buf, 'A', sizeof(buf));
530
for (size_t total = sizeof(buf); total > 0; total -= n) {
531
n = write(sc.left[0], buf, total);
532
ATF_REQUIRE_MSG(n > 0, "write failed: %s", strerror(errno));
533
}
534
for (size_t total = sizeof(buf); total > 0; total -= n) {
535
n = read(sc.right[1], buf, sizeof(buf));
536
ATF_REQUIRE_MSG(n > 0, "read failed: %s", strerror(errno));
537
}
538
539
check_nspliced(sc.left[1], sizeof(buf));
540
check_nspliced(sc.right[0], 0);
541
542
/* Trigger an unsplice by writing the last byte. */
543
b = 'B';
544
n = write(sc.left[0], &b, 1);
545
ATF_REQUIRE_MSG(n == 1, "write failed: %s", strerror(errno));
546
n = read(sc.right[1], &b, 1);
547
ATF_REQUIRE_MSG(n == 1, "read failed: %s", strerror(errno));
548
ATF_REQUIRE(b == 'B');
549
550
/*
551
* The next byte should appear on the other side of the connection
552
* rather than the splice.
553
*/
554
b = 'C';
555
n = write(sc.left[0], &b, 1);
556
ATF_REQUIRE_MSG(n == 1, "write failed: %s", strerror(errno));
557
n = read(sc.left[1], &b, 1);
558
ATF_REQUIRE_MSG(n == 1, "write failed: %s", strerror(errno));
559
ATF_REQUIRE(b == 'C');
560
561
splice_conn_check_empty(&sc);
562
563
splice_conn_fini(&sc);
564
}
565
566
/*
567
* Verify that a splice timeout limit is applied.
568
*/
569
ATF_TC_WITHOUT_HEAD(splice_limit_timeout);
570
ATF_TC_BODY(splice_limit_timeout, tc)
571
{
572
struct splice_conn sc;
573
ssize_t n;
574
int error;
575
uint8_t b, buf[128];
576
577
splice_conn_init_limits(&sc, 0,
578
&(struct timeval){ .tv_sec = 0, .tv_usec = 500000 /* 500ms */ });
579
580
/* Write some data through the splice. */
581
memset(buf, 'A', sizeof(buf));
582
for (size_t total = sizeof(buf); total > 0; total -= n) {
583
n = write(sc.left[0], buf, total);
584
ATF_REQUIRE_MSG(n > 0, "write failed: %s", strerror(errno));
585
}
586
for (size_t total = sizeof(buf); total > 0; total -= n) {
587
n = read(sc.right[1], buf, sizeof(buf));
588
ATF_REQUIRE_MSG(n > 0, "read failed: %s", strerror(errno));
589
}
590
591
check_nspliced(sc.left[1], sizeof(buf));
592
check_nspliced(sc.right[0], 0);
593
594
/* Wait for the splice to time out. */
595
error = usleep(550000);
596
ATF_REQUIRE_MSG(error == 0, "usleep failed: %s", strerror(errno));
597
598
/*
599
* The next byte should appear on the other side of the connection
600
* rather than the splice.
601
*/
602
b = 'C';
603
n = write(sc.left[0], &b, 1);
604
ATF_REQUIRE_MSG(n == 1, "write failed: %s", strerror(errno));
605
n = read(sc.left[1], &b, 1);
606
ATF_REQUIRE_MSG(n == 1, "write failed: %s", strerror(errno));
607
ATF_REQUIRE(b == 'C');
608
609
splice_conn_fini(&sc);
610
}
611
612
/*
613
* Make sure that listen() fails on spliced sockets, and that SO_SPLICE can't be
614
* used with listening sockets.
615
*/
616
ATF_TC_WITHOUT_HEAD(splice_listen);
617
ATF_TC_BODY(splice_listen, tc)
618
{
619
struct splice sp;
620
struct splice_conn sc;
621
int error, sd[3];
622
623
/*
624
* These should fail regardless since the sockets are connected, but it
625
* doesn't hurt to check.
626
*/
627
splice_conn_init(&sc);
628
error = listen(sc.left[1], 1);
629
ATF_REQUIRE_ERRNO(EINVAL, error == -1);
630
error = listen(sc.right[0], 1);
631
ATF_REQUIRE_ERRNO(EINVAL, error == -1);
632
splice_conn_fini(&sc);
633
634
tcp4_socketpair(sd);
635
sd[2] = socket(PF_INET, SOCK_STREAM, 0);
636
ATF_REQUIRE_MSG(sd[2] >= 0, "socket failed: %s", strerror(errno));
637
error = listen(sd[2], 1);
638
ATF_REQUIRE_MSG(error == 0, "listen failed: %s", strerror(errno));
639
640
/*
641
* Make sure a listening socket can't be spliced in either direction.
642
*/
643
splice_init(&sp, sd[2], 0, NULL);
644
error = setsockopt(sd[1], SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
645
ATF_REQUIRE_ERRNO(EINVAL, error == -1);
646
splice_init(&sp, sd[1], 0, NULL);
647
error = setsockopt(sd[2], SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
648
ATF_REQUIRE_ERRNO(EINVAL, error == -1);
649
650
/*
651
* Make sure we can't try to unsplice a listening socket.
652
*/
653
splice_init(&sp, -1, 0, NULL);
654
error = setsockopt(sd[2], SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
655
ATF_REQUIRE_ERRNO(EINVAL, error == -1);
656
657
checked_close(sd[0]);
658
checked_close(sd[1]);
659
checked_close(sd[2]);
660
}
661
662
static void
663
sigalarm(int sig __unused)
664
{
665
}
666
667
/*
668
* Our SO_SPLICE implementation doesn't do anything to prevent loops. We should
669
* however make sure that they are interruptible.
670
*/
671
ATF_TC_WITHOUT_HEAD(splice_loop);
672
ATF_TC_BODY(splice_loop, tc)
673
{
674
ssize_t n;
675
int sd[2], status;
676
pid_t child;
677
char c;
678
679
tcp_socketpair(sd, PF_INET);
680
splice_pair(sd[0], sd[1], 0, NULL);
681
682
/*
683
* Let the child process trigger an infinite loop. It should still be
684
* possible to kill the child with a signal, causing the connection to
685
* be dropped and ending the loop.
686
*/
687
child = fork();
688
ATF_REQUIRE_MSG(child >= 0, "fork failed: %s", strerror(errno));
689
if (child == 0) {
690
alarm(2);
691
c = 42;
692
n = write(sd[0], &c, 1);
693
if (n != 1)
694
_exit(2);
695
c = 24;
696
n = write(sd[1], &c, 1);
697
if (n != 1)
698
_exit(3);
699
700
for (;;) {
701
/* Wait for SIGALARM. */
702
sleep(100);
703
}
704
705
_exit(0);
706
} else {
707
checked_close(sd[0]);
708
checked_close(sd[1]);
709
710
child = waitpid(child, &status, 0);
711
ATF_REQUIRE_MSG(child >= 0,
712
"waitpid failed: %s", strerror(errno));
713
ATF_REQUIRE(WIFSIGNALED(status));
714
ATF_REQUIRE(WTERMSIG(status) == SIGALRM);
715
}
716
}
717
718
/*
719
* Simple I/O test.
720
*/
721
ATF_TC_WITHOUT_HEAD(splice_nonblock);
722
ATF_TC_BODY(splice_nonblock, tc)
723
{
724
struct splice_conn sc;
725
char buf[200];
726
size_t sofar;
727
ssize_t n;
728
729
splice_conn_init(&sc);
730
splice_conn_noblocking(&sc);
731
732
memset(buf, 'A', sizeof(buf));
733
for (sofar = 0;;) {
734
n = write(sc.left[0], buf, sizeof(buf));
735
if (n < 0) {
736
ATF_REQUIRE_ERRNO(EAGAIN, n == -1);
737
break;
738
}
739
sofar += n;
740
}
741
742
while (sofar > 0) {
743
n = read(sc.right[1], buf, sizeof(buf));
744
if (n < 0) {
745
ATF_REQUIRE_ERRNO(EAGAIN, n == -1);
746
usleep(100);
747
} else {
748
for (size_t i = 0; i < (size_t)n; i++)
749
ATF_REQUIRE(buf[i] == 'A');
750
sofar -= n;
751
}
752
}
753
754
splice_conn_fini(&sc);
755
}
756
757
ATF_TC_WITHOUT_HEAD(splice_resplice);
758
ATF_TC_BODY(splice_resplice, tc)
759
{
760
struct splice_conn sc;
761
ssize_t n;
762
char c;
763
764
splice_conn_init(&sc);
765
766
/* Left-to-right. */
767
c = 'M';
768
n = write(sc.left[0], &c, 1);
769
ATF_REQUIRE_MSG(n == 1, "write failed: %s", strerror(errno));
770
n = read(sc.right[1], &c, 1);
771
ATF_REQUIRE_MSG(n == 1, "read failed: %s", strerror(errno));
772
ATF_REQUIRE_MSG(c == 'M', "unexpected character: %c", c);
773
check_nspliced(sc.left[1], 1);
774
check_nspliced(sc.right[0], 0);
775
776
/* Right-to-left. */
777
c = 'J';
778
n = write(sc.right[1], &c, 1);
779
ATF_REQUIRE_MSG(n == 1, "write failed: %s", strerror(errno));
780
n = read(sc.left[0], &c, 1);
781
ATF_REQUIRE_MSG(n == 1, "read failed: %s", strerror(errno));
782
ATF_REQUIRE_MSG(c == 'J', "unexpected character: %c", c);
783
check_nspliced(sc.left[1], 1);
784
check_nspliced(sc.right[0], 1);
785
786
/* Unsplice and verify that the byte counts haven't changed. */
787
unsplice(sc.left[1]);
788
unsplice(sc.right[0]);
789
check_nspliced(sc.left[1], 1);
790
check_nspliced(sc.right[0], 1);
791
792
/* Splice again, check that byte counts are reset. */
793
splice_pair(sc.left[1], sc.right[0], 0, NULL);
794
check_nspliced(sc.left[1], 0);
795
check_nspliced(sc.right[0], 0);
796
797
/* Left-to-right. */
798
c = 'M';
799
n = write(sc.left[0], &c, 1);
800
ATF_REQUIRE_MSG(n == 1, "write failed: %s", strerror(errno));
801
n = read(sc.right[1], &c, 1);
802
ATF_REQUIRE_MSG(n == 1, "read failed: %s", strerror(errno));
803
ATF_REQUIRE_MSG(c == 'M', "unexpected character: %c", c);
804
check_nspliced(sc.left[1], 1);
805
check_nspliced(sc.right[0], 0);
806
807
/* Right-to-left. */
808
c = 'J';
809
n = write(sc.right[1], &c, 1);
810
ATF_REQUIRE_MSG(n == 1, "write failed: %s", strerror(errno));
811
n = read(sc.left[0], &c, 1);
812
ATF_REQUIRE_MSG(n == 1, "read failed: %s", strerror(errno));
813
ATF_REQUIRE_MSG(c == 'J', "unexpected character: %c", c);
814
check_nspliced(sc.left[1], 1);
815
check_nspliced(sc.right[0], 1);
816
817
splice_conn_fini(&sc);
818
}
819
820
struct xfer_args {
821
pthread_barrier_t *barrier;
822
uint32_t bytes;
823
int fd;
824
};
825
826
static void *
827
xfer(void *arg)
828
{
829
struct xfer_args *xfer;
830
uint8_t *buf;
831
size_t sz;
832
ssize_t n;
833
uint32_t resid;
834
int error;
835
836
xfer = arg;
837
838
error = fcntl(xfer->fd, F_SETFL, O_NONBLOCK);
839
ATF_REQUIRE_MSG(error == 0, "fcntl failed: %s", strerror(errno));
840
841
sz = MIN(xfer->bytes, 1024 * 1024);
842
buf = malloc(sz);
843
ATF_REQUIRE(buf != NULL);
844
arc4random_buf(buf, sz);
845
846
pthread_barrier_wait(xfer->barrier);
847
848
for (resid = xfer->bytes; xfer->bytes > 0 || resid > 0;) {
849
n = write(xfer->fd, buf, MIN(sz, xfer->bytes));
850
if (n < 0) {
851
ATF_REQUIRE_ERRNO(EAGAIN, n == -1);
852
usleep(1000);
853
} else {
854
ATF_REQUIRE(xfer->bytes >= (size_t)n);
855
xfer->bytes -= n;
856
}
857
858
n = read(xfer->fd, buf, sz);
859
if (n < 0) {
860
ATF_REQUIRE_ERRNO(EAGAIN, n == -1);
861
usleep(1000);
862
} else {
863
ATF_REQUIRE(resid >= (size_t)n);
864
resid -= n;
865
}
866
}
867
868
free(buf);
869
return (NULL);
870
}
871
872
/*
873
* Use two threads to transfer data between two spliced connections.
874
*/
875
ATF_TC_WITHOUT_HEAD(splice_throughput);
876
ATF_TC_BODY(splice_throughput, tc)
877
{
878
struct xfer_args xfers[2];
879
pthread_t thread[2];
880
pthread_barrier_t barrier;
881
struct splice_conn sc;
882
uint32_t bytes;
883
int error;
884
885
/* Transfer an amount between 1B and 1GB. */
886
bytes = arc4random_uniform(1024 * 1024 * 1024) + 1;
887
splice_conn_init(&sc);
888
889
error = pthread_barrier_init(&barrier, NULL, 2);
890
ATF_REQUIRE(error == 0);
891
xfers[0] = (struct xfer_args){
892
.barrier = &barrier,
893
.bytes = bytes,
894
.fd = sc.left[0]
895
};
896
xfers[1] = (struct xfer_args){
897
.barrier = &barrier,
898
.bytes = bytes,
899
.fd = sc.right[1]
900
};
901
902
error = pthread_create(&thread[0], NULL, xfer, &xfers[0]);
903
ATF_REQUIRE_MSG(error == 0,
904
"pthread_create failed: %s", strerror(errno));
905
error = pthread_create(&thread[1], NULL, xfer, &xfers[1]);
906
ATF_REQUIRE_MSG(error == 0,
907
"pthread_create failed: %s", strerror(errno));
908
909
error = pthread_join(thread[0], NULL);
910
ATF_REQUIRE_MSG(error == 0,
911
"pthread_join failed: %s", strerror(errno));
912
error = pthread_join(thread[1], NULL);
913
ATF_REQUIRE_MSG(error == 0,
914
"pthread_join failed: %s", strerror(errno));
915
916
error = pthread_barrier_destroy(&barrier);
917
ATF_REQUIRE(error == 0);
918
splice_conn_fini(&sc);
919
}
920
921
/*
922
* Make sure it's possible to splice v4 and v6 sockets together.
923
*/
924
ATF_TC_WITHOUT_HEAD(splice_v4v6);
925
ATF_TC_BODY(splice_v4v6, tc)
926
{
927
struct splice sp;
928
ssize_t n;
929
int sd4[2], sd6[2];
930
int error;
931
uint8_t b;
932
933
tcp4_socketpair(sd4);
934
tcp6_socketpair(sd6);
935
936
splice_init(&sp, sd6[0], 0, NULL);
937
error = setsockopt(sd4[1], SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
938
ATF_REQUIRE_MSG(error == 0, "setsockopt failed: %s", strerror(errno));
939
940
splice_init(&sp, sd4[1], 0, NULL);
941
error = setsockopt(sd6[0], SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp));
942
ATF_REQUIRE_MSG(error == 0, "setsockopt failed: %s", strerror(errno));
943
944
b = 'M';
945
n = write(sd4[0], &b, 1);
946
ATF_REQUIRE_MSG(n == 1, "write failed: %s", strerror(errno));
947
n = read(sd6[1], &b, 1);
948
ATF_REQUIRE_MSG(n == 1, "read failed: %s", strerror(errno));
949
ATF_REQUIRE(b == 'M');
950
951
b = 'J';
952
n = write(sd6[1], &b, 1);
953
ATF_REQUIRE_MSG(n == 1, "write failed: %s", strerror(errno));
954
n = read(sd4[0], &b, 1);
955
ATF_REQUIRE_MSG(n == 1, "read failed: %s", strerror(errno));
956
ATF_REQUIRE(b == 'J');
957
958
checked_close(sd4[0]);
959
checked_close(sd4[1]);
960
checked_close(sd6[0]);
961
checked_close(sd6[1]);
962
}
963
964
ATF_TP_ADD_TCS(tp)
965
{
966
ATF_TP_ADD_TC(tp, splice_basic);
967
ATF_TP_ADD_TC(tp, splice_capsicum);
968
ATF_TP_ADD_TC(tp, splice_error);
969
ATF_TP_ADD_TC(tp, splice_kevent);
970
ATF_TP_ADD_TC(tp, splice_limit_bytes);
971
ATF_TP_ADD_TC(tp, splice_limit_timeout);
972
ATF_TP_ADD_TC(tp, splice_listen);
973
ATF_TP_ADD_TC(tp, splice_loop);
974
ATF_TP_ADD_TC(tp, splice_nonblock);
975
ATF_TP_ADD_TC(tp, splice_resplice);
976
ATF_TP_ADD_TC(tp, splice_throughput);
977
ATF_TP_ADD_TC(tp, splice_v4v6);
978
return (atf_no_error());
979
}
980
981