Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/vsock/util.c
48946 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* vsock test utilities
4
*
5
* Copyright (C) 2017 Red Hat, Inc.
6
*
7
* Author: Stefan Hajnoczi <[email protected]>
8
*/
9
10
#include <ctype.h>
11
#include <errno.h>
12
#include <stdio.h>
13
#include <stdint.h>
14
#include <stdlib.h>
15
#include <string.h>
16
#include <signal.h>
17
#include <unistd.h>
18
#include <assert.h>
19
#include <sys/epoll.h>
20
#include <sys/ioctl.h>
21
#include <sys/mman.h>
22
#include <linux/sockios.h>
23
24
#include "timeout.h"
25
#include "control.h"
26
#include "util.h"
27
28
#define KALLSYMS_PATH "/proc/kallsyms"
29
#define KALLSYMS_LINE_LEN 512
30
31
/* Install signal handlers */
32
void init_signals(void)
33
{
34
struct sigaction act = {
35
.sa_handler = sigalrm,
36
};
37
38
sigaction(SIGALRM, &act, NULL);
39
signal(SIGPIPE, SIG_IGN);
40
}
41
42
static unsigned int parse_uint(const char *str, const char *err_str)
43
{
44
char *endptr = NULL;
45
unsigned long n;
46
47
errno = 0;
48
n = strtoul(str, &endptr, 10);
49
if (errno || *endptr != '\0') {
50
fprintf(stderr, "malformed %s \"%s\"\n", err_str, str);
51
exit(EXIT_FAILURE);
52
}
53
return n;
54
}
55
56
/* Parse a CID in string representation */
57
unsigned int parse_cid(const char *str)
58
{
59
return parse_uint(str, "CID");
60
}
61
62
/* Parse a port in string representation */
63
unsigned int parse_port(const char *str)
64
{
65
return parse_uint(str, "port");
66
}
67
68
/* Wait for the remote to close the connection */
69
void vsock_wait_remote_close(int fd)
70
{
71
struct epoll_event ev;
72
int epollfd, nfds;
73
74
epollfd = epoll_create1(0);
75
if (epollfd == -1) {
76
perror("epoll_create1");
77
exit(EXIT_FAILURE);
78
}
79
80
ev.events = EPOLLRDHUP | EPOLLHUP;
81
ev.data.fd = fd;
82
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
83
perror("epoll_ctl");
84
exit(EXIT_FAILURE);
85
}
86
87
nfds = epoll_wait(epollfd, &ev, 1, TIMEOUT * 1000);
88
if (nfds == -1) {
89
perror("epoll_wait");
90
exit(EXIT_FAILURE);
91
}
92
93
if (nfds == 0) {
94
fprintf(stderr, "epoll_wait timed out\n");
95
exit(EXIT_FAILURE);
96
}
97
98
assert(nfds == 1);
99
assert(ev.events & (EPOLLRDHUP | EPOLLHUP));
100
assert(ev.data.fd == fd);
101
102
close(epollfd);
103
}
104
105
/* Wait until ioctl gives an expected int value.
106
* Return false if the op is not supported.
107
*/
108
bool vsock_ioctl_int(int fd, unsigned long op, int expected)
109
{
110
int actual, ret;
111
char name[32];
112
113
snprintf(name, sizeof(name), "ioctl(%lu)", op);
114
115
timeout_begin(TIMEOUT);
116
do {
117
ret = ioctl(fd, op, &actual);
118
if (ret < 0) {
119
if (errno == EOPNOTSUPP || errno == ENOTTY)
120
break;
121
122
perror(name);
123
exit(EXIT_FAILURE);
124
}
125
timeout_check(name);
126
} while (actual != expected);
127
timeout_end();
128
129
return ret >= 0;
130
}
131
132
/* Wait until transport reports no data left to be sent.
133
* Return false if transport does not implement the unsent_bytes() callback.
134
*/
135
bool vsock_wait_sent(int fd)
136
{
137
return vsock_ioctl_int(fd, SIOCOUTQ, 0);
138
}
139
140
/* Create socket <type>, bind to <cid, port>.
141
* Return the file descriptor, or -1 on error.
142
*/
143
int vsock_bind_try(unsigned int cid, unsigned int port, int type)
144
{
145
struct sockaddr_vm sa = {
146
.svm_family = AF_VSOCK,
147
.svm_cid = cid,
148
.svm_port = port,
149
};
150
int fd, saved_errno;
151
152
fd = socket(AF_VSOCK, type, 0);
153
if (fd < 0) {
154
perror("socket");
155
exit(EXIT_FAILURE);
156
}
157
158
if (bind(fd, (struct sockaddr *)&sa, sizeof(sa))) {
159
saved_errno = errno;
160
close(fd);
161
errno = saved_errno;
162
fd = -1;
163
}
164
165
return fd;
166
}
167
168
/* Create socket <type>, bind to <cid, port> and return the file descriptor. */
169
int vsock_bind(unsigned int cid, unsigned int port, int type)
170
{
171
int fd;
172
173
fd = vsock_bind_try(cid, port, type);
174
if (fd < 0) {
175
perror("bind");
176
exit(EXIT_FAILURE);
177
}
178
179
return fd;
180
}
181
182
int vsock_connect_fd(int fd, unsigned int cid, unsigned int port)
183
{
184
struct sockaddr_vm sa = {
185
.svm_family = AF_VSOCK,
186
.svm_cid = cid,
187
.svm_port = port,
188
};
189
int ret;
190
191
timeout_begin(TIMEOUT);
192
do {
193
ret = connect(fd, (struct sockaddr *)&sa, sizeof(sa));
194
timeout_check("connect");
195
} while (ret < 0 && errno == EINTR);
196
timeout_end();
197
198
return ret;
199
}
200
201
/* Bind to <bind_port>, connect to <cid, port> and return the file descriptor. */
202
int vsock_bind_connect(unsigned int cid, unsigned int port, unsigned int bind_port, int type)
203
{
204
int client_fd;
205
206
client_fd = vsock_bind(VMADDR_CID_ANY, bind_port, type);
207
208
if (vsock_connect_fd(client_fd, cid, port)) {
209
perror("connect");
210
exit(EXIT_FAILURE);
211
}
212
213
return client_fd;
214
}
215
216
/* Connect to <cid, port> and return the file descriptor. */
217
int vsock_connect(unsigned int cid, unsigned int port, int type)
218
{
219
int fd;
220
221
control_expectln("LISTENING");
222
223
fd = socket(AF_VSOCK, type, 0);
224
if (fd < 0) {
225
perror("socket");
226
exit(EXIT_FAILURE);
227
}
228
229
if (vsock_connect_fd(fd, cid, port)) {
230
int old_errno = errno;
231
232
close(fd);
233
fd = -1;
234
errno = old_errno;
235
}
236
237
return fd;
238
}
239
240
int vsock_stream_connect(unsigned int cid, unsigned int port)
241
{
242
return vsock_connect(cid, port, SOCK_STREAM);
243
}
244
245
int vsock_seqpacket_connect(unsigned int cid, unsigned int port)
246
{
247
return vsock_connect(cid, port, SOCK_SEQPACKET);
248
}
249
250
/* Listen on <cid, port> and return the file descriptor. */
251
static int vsock_listen(unsigned int cid, unsigned int port, int type)
252
{
253
int fd;
254
255
fd = vsock_bind(cid, port, type);
256
257
if (listen(fd, 1) < 0) {
258
perror("listen");
259
exit(EXIT_FAILURE);
260
}
261
262
return fd;
263
}
264
265
/* Listen on <cid, port> and return the first incoming connection. The remote
266
* address is stored to clientaddrp. clientaddrp may be NULL.
267
*/
268
int vsock_accept(unsigned int cid, unsigned int port,
269
struct sockaddr_vm *clientaddrp, int type)
270
{
271
union {
272
struct sockaddr sa;
273
struct sockaddr_vm svm;
274
} clientaddr;
275
socklen_t clientaddr_len = sizeof(clientaddr.svm);
276
int fd, client_fd, old_errno;
277
278
fd = vsock_listen(cid, port, type);
279
280
control_writeln("LISTENING");
281
282
timeout_begin(TIMEOUT);
283
do {
284
client_fd = accept(fd, &clientaddr.sa, &clientaddr_len);
285
timeout_check("accept");
286
} while (client_fd < 0 && errno == EINTR);
287
timeout_end();
288
289
old_errno = errno;
290
close(fd);
291
errno = old_errno;
292
293
if (client_fd < 0)
294
return client_fd;
295
296
if (clientaddr_len != sizeof(clientaddr.svm)) {
297
fprintf(stderr, "unexpected addrlen from accept(2), %zu\n",
298
(size_t)clientaddr_len);
299
exit(EXIT_FAILURE);
300
}
301
if (clientaddr.sa.sa_family != AF_VSOCK) {
302
fprintf(stderr, "expected AF_VSOCK from accept(2), got %d\n",
303
clientaddr.sa.sa_family);
304
exit(EXIT_FAILURE);
305
}
306
307
if (clientaddrp)
308
*clientaddrp = clientaddr.svm;
309
return client_fd;
310
}
311
312
int vsock_stream_accept(unsigned int cid, unsigned int port,
313
struct sockaddr_vm *clientaddrp)
314
{
315
return vsock_accept(cid, port, clientaddrp, SOCK_STREAM);
316
}
317
318
int vsock_stream_listen(unsigned int cid, unsigned int port)
319
{
320
return vsock_listen(cid, port, SOCK_STREAM);
321
}
322
323
int vsock_seqpacket_accept(unsigned int cid, unsigned int port,
324
struct sockaddr_vm *clientaddrp)
325
{
326
return vsock_accept(cid, port, clientaddrp, SOCK_SEQPACKET);
327
}
328
329
/* Transmit bytes from a buffer and check the return value.
330
*
331
* expected_ret:
332
* <0 Negative errno (for testing errors)
333
* 0 End-of-file
334
* >0 Success (bytes successfully written)
335
*/
336
void send_buf(int fd, const void *buf, size_t len, int flags,
337
ssize_t expected_ret)
338
{
339
ssize_t nwritten = 0;
340
ssize_t ret;
341
342
timeout_begin(TIMEOUT);
343
do {
344
ret = send(fd, buf + nwritten, len - nwritten, flags);
345
timeout_check("send");
346
347
if (ret == 0 || (ret < 0 && errno != EINTR))
348
break;
349
350
nwritten += ret;
351
} while (nwritten < len);
352
timeout_end();
353
354
if (expected_ret < 0) {
355
if (ret != -1) {
356
fprintf(stderr, "bogus send(2) return value %zd (expected %zd)\n",
357
ret, expected_ret);
358
exit(EXIT_FAILURE);
359
}
360
if (errno != -expected_ret) {
361
perror("send");
362
exit(EXIT_FAILURE);
363
}
364
return;
365
}
366
367
if (ret < 0) {
368
perror("send");
369
exit(EXIT_FAILURE);
370
}
371
372
if (nwritten != expected_ret) {
373
if (ret == 0)
374
fprintf(stderr, "unexpected EOF while sending bytes\n");
375
376
fprintf(stderr, "bogus send(2) bytes written %zd (expected %zd)\n",
377
nwritten, expected_ret);
378
exit(EXIT_FAILURE);
379
}
380
}
381
382
/* Receive bytes in a buffer and check the return value.
383
*
384
* expected_ret:
385
* <0 Negative errno (for testing errors)
386
* 0 End-of-file
387
* >0 Success (bytes successfully read)
388
*/
389
void recv_buf(int fd, void *buf, size_t len, int flags, ssize_t expected_ret)
390
{
391
ssize_t nread = 0;
392
ssize_t ret;
393
394
timeout_begin(TIMEOUT);
395
do {
396
ret = recv(fd, buf + nread, len - nread, flags);
397
timeout_check("recv");
398
399
if (ret == 0 || (ret < 0 && errno != EINTR))
400
break;
401
402
nread += ret;
403
} while (nread < len);
404
timeout_end();
405
406
if (expected_ret < 0) {
407
if (ret != -1) {
408
fprintf(stderr, "bogus recv(2) return value %zd (expected %zd)\n",
409
ret, expected_ret);
410
exit(EXIT_FAILURE);
411
}
412
if (errno != -expected_ret) {
413
perror("recv");
414
exit(EXIT_FAILURE);
415
}
416
return;
417
}
418
419
if (ret < 0) {
420
perror("recv");
421
exit(EXIT_FAILURE);
422
}
423
424
if (nread != expected_ret) {
425
if (ret == 0)
426
fprintf(stderr, "unexpected EOF while receiving bytes\n");
427
428
fprintf(stderr, "bogus recv(2) bytes read %zd (expected %zd)\n",
429
nread, expected_ret);
430
exit(EXIT_FAILURE);
431
}
432
}
433
434
/* Transmit one byte and check the return value.
435
*
436
* expected_ret:
437
* <0 Negative errno (for testing errors)
438
* 0 End-of-file
439
* 1 Success
440
*/
441
void send_byte(int fd, int expected_ret, int flags)
442
{
443
static const uint8_t byte = 'A';
444
445
send_buf(fd, &byte, sizeof(byte), flags, expected_ret);
446
}
447
448
/* Receive one byte and check the return value.
449
*
450
* expected_ret:
451
* <0 Negative errno (for testing errors)
452
* 0 End-of-file
453
* 1 Success
454
*/
455
void recv_byte(int fd, int expected_ret, int flags)
456
{
457
uint8_t byte;
458
459
recv_buf(fd, &byte, sizeof(byte), flags, expected_ret);
460
461
if (byte != 'A') {
462
fprintf(stderr, "unexpected byte read 0x%02x\n", byte);
463
exit(EXIT_FAILURE);
464
}
465
}
466
467
/* Run test cases. The program terminates if a failure occurs. */
468
void run_tests(const struct test_case *test_cases,
469
const struct test_opts *opts)
470
{
471
int i;
472
473
for (i = 0; test_cases[i].name; i++) {
474
void (*run)(const struct test_opts *opts);
475
char *line;
476
477
printf("%d - %s...", i, test_cases[i].name);
478
fflush(stdout);
479
480
/* Full barrier before executing the next test. This
481
* ensures that client and server are executing the
482
* same test case. In particular, it means whoever is
483
* faster will not see the peer still executing the
484
* last test. This is important because port numbers
485
* can be used by multiple test cases.
486
*/
487
if (test_cases[i].skip)
488
control_writeln("SKIP");
489
else
490
control_writeln("NEXT");
491
492
line = control_readln();
493
if (control_cmpln(line, "SKIP", false) || test_cases[i].skip) {
494
495
printf("skipped\n");
496
497
free(line);
498
continue;
499
}
500
501
control_cmpln(line, "NEXT", true);
502
free(line);
503
504
if (opts->mode == TEST_MODE_CLIENT)
505
run = test_cases[i].run_client;
506
else
507
run = test_cases[i].run_server;
508
509
if (run)
510
run(opts);
511
512
printf("ok\n");
513
}
514
515
printf("All tests have been executed. Waiting other peer...");
516
fflush(stdout);
517
518
/*
519
* Final full barrier, to ensure that all tests have been run and
520
* that even the last one has been successful on both sides.
521
*/
522
control_writeln("COMPLETED");
523
control_expectln("COMPLETED");
524
525
printf("ok\n");
526
}
527
528
void list_tests(const struct test_case *test_cases)
529
{
530
int i;
531
532
printf("ID\tTest name\n");
533
534
for (i = 0; test_cases[i].name; i++)
535
printf("%d\t%s\n", i, test_cases[i].name);
536
537
exit(EXIT_FAILURE);
538
}
539
540
static unsigned long parse_test_id(const char *test_id_str, size_t test_cases_len)
541
{
542
unsigned long test_id;
543
char *endptr = NULL;
544
545
errno = 0;
546
test_id = strtoul(test_id_str, &endptr, 10);
547
if (errno || *endptr != '\0') {
548
fprintf(stderr, "malformed test ID \"%s\"\n", test_id_str);
549
exit(EXIT_FAILURE);
550
}
551
552
if (test_id >= test_cases_len) {
553
fprintf(stderr, "test ID (%lu) larger than the max allowed (%lu)\n",
554
test_id, test_cases_len - 1);
555
exit(EXIT_FAILURE);
556
}
557
558
return test_id;
559
}
560
561
void skip_test(struct test_case *test_cases, size_t test_cases_len,
562
const char *test_id_str)
563
{
564
unsigned long test_id = parse_test_id(test_id_str, test_cases_len);
565
test_cases[test_id].skip = true;
566
}
567
568
void pick_test(struct test_case *test_cases, size_t test_cases_len,
569
const char *test_id_str)
570
{
571
static bool skip_all = true;
572
unsigned long test_id;
573
574
if (skip_all) {
575
unsigned long i;
576
577
for (i = 0; i < test_cases_len; ++i)
578
test_cases[i].skip = true;
579
580
skip_all = false;
581
}
582
583
test_id = parse_test_id(test_id_str, test_cases_len);
584
test_cases[test_id].skip = false;
585
}
586
587
unsigned long hash_djb2(const void *data, size_t len)
588
{
589
unsigned long hash = 5381;
590
int i = 0;
591
592
while (i < len) {
593
hash = ((hash << 5) + hash) + ((unsigned char *)data)[i];
594
i++;
595
}
596
597
return hash;
598
}
599
600
size_t iovec_bytes(const struct iovec *iov, size_t iovnum)
601
{
602
size_t bytes;
603
int i;
604
605
for (bytes = 0, i = 0; i < iovnum; i++)
606
bytes += iov[i].iov_len;
607
608
return bytes;
609
}
610
611
unsigned long iovec_hash_djb2(const struct iovec *iov, size_t iovnum)
612
{
613
unsigned long hash;
614
size_t iov_bytes;
615
size_t offs;
616
void *tmp;
617
int i;
618
619
iov_bytes = iovec_bytes(iov, iovnum);
620
621
tmp = malloc(iov_bytes);
622
if (!tmp) {
623
perror("malloc");
624
exit(EXIT_FAILURE);
625
}
626
627
for (offs = 0, i = 0; i < iovnum; i++) {
628
memcpy(tmp + offs, iov[i].iov_base, iov[i].iov_len);
629
offs += iov[i].iov_len;
630
}
631
632
hash = hash_djb2(tmp, iov_bytes);
633
free(tmp);
634
635
return hash;
636
}
637
638
/* Allocates and returns new 'struct iovec *' according pattern
639
* in the 'test_iovec'. For each element in the 'test_iovec' it
640
* allocates new element in the resulting 'iovec'. 'iov_len'
641
* of the new element is copied from 'test_iovec'. 'iov_base' is
642
* allocated depending on the 'iov_base' of 'test_iovec':
643
*
644
* 'iov_base' == NULL -> valid buf: mmap('iov_len').
645
*
646
* 'iov_base' == MAP_FAILED -> invalid buf:
647
* mmap('iov_len'), then munmap('iov_len').
648
* 'iov_base' still contains result of
649
* mmap().
650
*
651
* 'iov_base' == number -> unaligned valid buf:
652
* mmap('iov_len') + number.
653
*
654
* 'iovnum' is number of elements in 'test_iovec'.
655
*
656
* Returns new 'iovec' or calls 'exit()' on error.
657
*/
658
struct iovec *alloc_test_iovec(const struct iovec *test_iovec, int iovnum)
659
{
660
struct iovec *iovec;
661
int i;
662
663
iovec = malloc(sizeof(*iovec) * iovnum);
664
if (!iovec) {
665
perror("malloc");
666
exit(EXIT_FAILURE);
667
}
668
669
for (i = 0; i < iovnum; i++) {
670
iovec[i].iov_len = test_iovec[i].iov_len;
671
672
iovec[i].iov_base = mmap(NULL, iovec[i].iov_len,
673
PROT_READ | PROT_WRITE,
674
MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE,
675
-1, 0);
676
if (iovec[i].iov_base == MAP_FAILED) {
677
perror("mmap");
678
exit(EXIT_FAILURE);
679
}
680
681
if (test_iovec[i].iov_base != MAP_FAILED)
682
iovec[i].iov_base += (uintptr_t)test_iovec[i].iov_base;
683
}
684
685
/* Unmap "invalid" elements. */
686
for (i = 0; i < iovnum; i++) {
687
if (test_iovec[i].iov_base == MAP_FAILED) {
688
if (munmap(iovec[i].iov_base, iovec[i].iov_len)) {
689
perror("munmap");
690
exit(EXIT_FAILURE);
691
}
692
}
693
}
694
695
for (i = 0; i < iovnum; i++) {
696
int j;
697
698
if (test_iovec[i].iov_base == MAP_FAILED)
699
continue;
700
701
for (j = 0; j < iovec[i].iov_len; j++)
702
((uint8_t *)iovec[i].iov_base)[j] = rand() & 0xff;
703
}
704
705
return iovec;
706
}
707
708
/* Frees 'iovec *', previously allocated by 'alloc_test_iovec()'.
709
* On error calls 'exit()'.
710
*/
711
void free_test_iovec(const struct iovec *test_iovec,
712
struct iovec *iovec, int iovnum)
713
{
714
int i;
715
716
for (i = 0; i < iovnum; i++) {
717
if (test_iovec[i].iov_base != MAP_FAILED) {
718
if (test_iovec[i].iov_base)
719
iovec[i].iov_base -= (uintptr_t)test_iovec[i].iov_base;
720
721
if (munmap(iovec[i].iov_base, iovec[i].iov_len)) {
722
perror("munmap");
723
exit(EXIT_FAILURE);
724
}
725
}
726
}
727
728
free(iovec);
729
}
730
731
/* Set "unsigned long long" socket option and check that it's indeed set */
732
void setsockopt_ull_check(int fd, int level, int optname,
733
unsigned long long val, char const *errmsg)
734
{
735
unsigned long long chkval;
736
socklen_t chklen;
737
int err;
738
739
err = setsockopt(fd, level, optname, &val, sizeof(val));
740
if (err) {
741
fprintf(stderr, "setsockopt err: %s (%d)\n",
742
strerror(errno), errno);
743
goto fail;
744
}
745
746
chkval = ~val; /* just make storage != val */
747
chklen = sizeof(chkval);
748
749
err = getsockopt(fd, level, optname, &chkval, &chklen);
750
if (err) {
751
fprintf(stderr, "getsockopt err: %s (%d)\n",
752
strerror(errno), errno);
753
goto fail;
754
}
755
756
if (chklen != sizeof(chkval)) {
757
fprintf(stderr, "size mismatch: set %zu got %d\n", sizeof(val),
758
chklen);
759
goto fail;
760
}
761
762
if (chkval != val) {
763
fprintf(stderr, "value mismatch: set %llu got %llu\n", val,
764
chkval);
765
goto fail;
766
}
767
return;
768
fail:
769
fprintf(stderr, "%s val %llu\n", errmsg, val);
770
exit(EXIT_FAILURE);
771
}
772
773
/* Set "int" socket option and check that it's indeed set */
774
void setsockopt_int_check(int fd, int level, int optname, int val,
775
char const *errmsg)
776
{
777
int chkval;
778
socklen_t chklen;
779
int err;
780
781
err = setsockopt(fd, level, optname, &val, sizeof(val));
782
if (err) {
783
fprintf(stderr, "setsockopt err: %s (%d)\n",
784
strerror(errno), errno);
785
goto fail;
786
}
787
788
chkval = ~val; /* just make storage != val */
789
chklen = sizeof(chkval);
790
791
err = getsockopt(fd, level, optname, &chkval, &chklen);
792
if (err) {
793
fprintf(stderr, "getsockopt err: %s (%d)\n",
794
strerror(errno), errno);
795
goto fail;
796
}
797
798
if (chklen != sizeof(chkval)) {
799
fprintf(stderr, "size mismatch: set %zu got %d\n", sizeof(val),
800
chklen);
801
goto fail;
802
}
803
804
if (chkval != val) {
805
fprintf(stderr, "value mismatch: set %d got %d\n", val, chkval);
806
goto fail;
807
}
808
return;
809
fail:
810
fprintf(stderr, "%s val %d\n", errmsg, val);
811
exit(EXIT_FAILURE);
812
}
813
814
static void mem_invert(unsigned char *mem, size_t size)
815
{
816
size_t i;
817
818
for (i = 0; i < size; i++)
819
mem[i] = ~mem[i];
820
}
821
822
/* Set "timeval" socket option and check that it's indeed set */
823
void setsockopt_timeval_check(int fd, int level, int optname,
824
struct timeval val, char const *errmsg)
825
{
826
struct timeval chkval;
827
socklen_t chklen;
828
int err;
829
830
err = setsockopt(fd, level, optname, &val, sizeof(val));
831
if (err) {
832
fprintf(stderr, "setsockopt err: %s (%d)\n",
833
strerror(errno), errno);
834
goto fail;
835
}
836
837
/* just make storage != val */
838
chkval = val;
839
mem_invert((unsigned char *)&chkval, sizeof(chkval));
840
chklen = sizeof(chkval);
841
842
err = getsockopt(fd, level, optname, &chkval, &chklen);
843
if (err) {
844
fprintf(stderr, "getsockopt err: %s (%d)\n",
845
strerror(errno), errno);
846
goto fail;
847
}
848
849
if (chklen != sizeof(chkval)) {
850
fprintf(stderr, "size mismatch: set %zu got %d\n", sizeof(val),
851
chklen);
852
goto fail;
853
}
854
855
if (memcmp(&chkval, &val, sizeof(val)) != 0) {
856
fprintf(stderr, "value mismatch: set %ld:%ld got %ld:%ld\n",
857
val.tv_sec, val.tv_usec, chkval.tv_sec, chkval.tv_usec);
858
goto fail;
859
}
860
return;
861
fail:
862
fprintf(stderr, "%s val %ld:%ld\n", errmsg, val.tv_sec, val.tv_usec);
863
exit(EXIT_FAILURE);
864
}
865
866
void enable_so_zerocopy_check(int fd)
867
{
868
setsockopt_int_check(fd, SOL_SOCKET, SO_ZEROCOPY, 1,
869
"setsockopt SO_ZEROCOPY");
870
}
871
872
void enable_so_linger(int fd, int timeout)
873
{
874
struct linger optval = {
875
.l_onoff = 1,
876
.l_linger = timeout
877
};
878
879
if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &optval, sizeof(optval))) {
880
perror("setsockopt(SO_LINGER)");
881
exit(EXIT_FAILURE);
882
}
883
}
884
885
static int __get_transports(void)
886
{
887
char buf[KALLSYMS_LINE_LEN];
888
const char *ksym;
889
int ret = 0;
890
FILE *f;
891
892
f = fopen(KALLSYMS_PATH, "r");
893
if (!f) {
894
perror("Can't open " KALLSYMS_PATH);
895
exit(EXIT_FAILURE);
896
}
897
898
while (fgets(buf, sizeof(buf), f)) {
899
char *match;
900
int i;
901
902
assert(buf[strlen(buf) - 1] == '\n');
903
904
for (i = 0; i < TRANSPORT_NUM; ++i) {
905
if (ret & BIT(i))
906
continue;
907
908
/* Match should be followed by '\t' or '\n'.
909
* See kallsyms.c:s_show().
910
*/
911
ksym = transport_ksyms[i];
912
match = strstr(buf, ksym);
913
if (match && isspace(match[strlen(ksym)])) {
914
ret |= BIT(i);
915
break;
916
}
917
}
918
}
919
920
fclose(f);
921
return ret;
922
}
923
924
/* Return integer with TRANSPORT_* bit set for every (known) registered vsock
925
* transport.
926
*/
927
int get_transports(void)
928
{
929
static int tr = -1;
930
931
if (tr == -1)
932
tr = __get_transports();
933
934
return tr;
935
}
936
937