Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/vsock/util.c
26282 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
516
void list_tests(const struct test_case *test_cases)
517
{
518
int i;
519
520
printf("ID\tTest name\n");
521
522
for (i = 0; test_cases[i].name; i++)
523
printf("%d\t%s\n", i, test_cases[i].name);
524
525
exit(EXIT_FAILURE);
526
}
527
528
static unsigned long parse_test_id(const char *test_id_str, size_t test_cases_len)
529
{
530
unsigned long test_id;
531
char *endptr = NULL;
532
533
errno = 0;
534
test_id = strtoul(test_id_str, &endptr, 10);
535
if (errno || *endptr != '\0') {
536
fprintf(stderr, "malformed test ID \"%s\"\n", test_id_str);
537
exit(EXIT_FAILURE);
538
}
539
540
if (test_id >= test_cases_len) {
541
fprintf(stderr, "test ID (%lu) larger than the max allowed (%lu)\n",
542
test_id, test_cases_len - 1);
543
exit(EXIT_FAILURE);
544
}
545
546
return test_id;
547
}
548
549
void skip_test(struct test_case *test_cases, size_t test_cases_len,
550
const char *test_id_str)
551
{
552
unsigned long test_id = parse_test_id(test_id_str, test_cases_len);
553
test_cases[test_id].skip = true;
554
}
555
556
void pick_test(struct test_case *test_cases, size_t test_cases_len,
557
const char *test_id_str)
558
{
559
static bool skip_all = true;
560
unsigned long test_id;
561
562
if (skip_all) {
563
unsigned long i;
564
565
for (i = 0; i < test_cases_len; ++i)
566
test_cases[i].skip = true;
567
568
skip_all = false;
569
}
570
571
test_id = parse_test_id(test_id_str, test_cases_len);
572
test_cases[test_id].skip = false;
573
}
574
575
unsigned long hash_djb2(const void *data, size_t len)
576
{
577
unsigned long hash = 5381;
578
int i = 0;
579
580
while (i < len) {
581
hash = ((hash << 5) + hash) + ((unsigned char *)data)[i];
582
i++;
583
}
584
585
return hash;
586
}
587
588
size_t iovec_bytes(const struct iovec *iov, size_t iovnum)
589
{
590
size_t bytes;
591
int i;
592
593
for (bytes = 0, i = 0; i < iovnum; i++)
594
bytes += iov[i].iov_len;
595
596
return bytes;
597
}
598
599
unsigned long iovec_hash_djb2(const struct iovec *iov, size_t iovnum)
600
{
601
unsigned long hash;
602
size_t iov_bytes;
603
size_t offs;
604
void *tmp;
605
int i;
606
607
iov_bytes = iovec_bytes(iov, iovnum);
608
609
tmp = malloc(iov_bytes);
610
if (!tmp) {
611
perror("malloc");
612
exit(EXIT_FAILURE);
613
}
614
615
for (offs = 0, i = 0; i < iovnum; i++) {
616
memcpy(tmp + offs, iov[i].iov_base, iov[i].iov_len);
617
offs += iov[i].iov_len;
618
}
619
620
hash = hash_djb2(tmp, iov_bytes);
621
free(tmp);
622
623
return hash;
624
}
625
626
/* Allocates and returns new 'struct iovec *' according pattern
627
* in the 'test_iovec'. For each element in the 'test_iovec' it
628
* allocates new element in the resulting 'iovec'. 'iov_len'
629
* of the new element is copied from 'test_iovec'. 'iov_base' is
630
* allocated depending on the 'iov_base' of 'test_iovec':
631
*
632
* 'iov_base' == NULL -> valid buf: mmap('iov_len').
633
*
634
* 'iov_base' == MAP_FAILED -> invalid buf:
635
* mmap('iov_len'), then munmap('iov_len').
636
* 'iov_base' still contains result of
637
* mmap().
638
*
639
* 'iov_base' == number -> unaligned valid buf:
640
* mmap('iov_len') + number.
641
*
642
* 'iovnum' is number of elements in 'test_iovec'.
643
*
644
* Returns new 'iovec' or calls 'exit()' on error.
645
*/
646
struct iovec *alloc_test_iovec(const struct iovec *test_iovec, int iovnum)
647
{
648
struct iovec *iovec;
649
int i;
650
651
iovec = malloc(sizeof(*iovec) * iovnum);
652
if (!iovec) {
653
perror("malloc");
654
exit(EXIT_FAILURE);
655
}
656
657
for (i = 0; i < iovnum; i++) {
658
iovec[i].iov_len = test_iovec[i].iov_len;
659
660
iovec[i].iov_base = mmap(NULL, iovec[i].iov_len,
661
PROT_READ | PROT_WRITE,
662
MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE,
663
-1, 0);
664
if (iovec[i].iov_base == MAP_FAILED) {
665
perror("mmap");
666
exit(EXIT_FAILURE);
667
}
668
669
if (test_iovec[i].iov_base != MAP_FAILED)
670
iovec[i].iov_base += (uintptr_t)test_iovec[i].iov_base;
671
}
672
673
/* Unmap "invalid" elements. */
674
for (i = 0; i < iovnum; i++) {
675
if (test_iovec[i].iov_base == MAP_FAILED) {
676
if (munmap(iovec[i].iov_base, iovec[i].iov_len)) {
677
perror("munmap");
678
exit(EXIT_FAILURE);
679
}
680
}
681
}
682
683
for (i = 0; i < iovnum; i++) {
684
int j;
685
686
if (test_iovec[i].iov_base == MAP_FAILED)
687
continue;
688
689
for (j = 0; j < iovec[i].iov_len; j++)
690
((uint8_t *)iovec[i].iov_base)[j] = rand() & 0xff;
691
}
692
693
return iovec;
694
}
695
696
/* Frees 'iovec *', previously allocated by 'alloc_test_iovec()'.
697
* On error calls 'exit()'.
698
*/
699
void free_test_iovec(const struct iovec *test_iovec,
700
struct iovec *iovec, int iovnum)
701
{
702
int i;
703
704
for (i = 0; i < iovnum; i++) {
705
if (test_iovec[i].iov_base != MAP_FAILED) {
706
if (test_iovec[i].iov_base)
707
iovec[i].iov_base -= (uintptr_t)test_iovec[i].iov_base;
708
709
if (munmap(iovec[i].iov_base, iovec[i].iov_len)) {
710
perror("munmap");
711
exit(EXIT_FAILURE);
712
}
713
}
714
}
715
716
free(iovec);
717
}
718
719
/* Set "unsigned long long" socket option and check that it's indeed set */
720
void setsockopt_ull_check(int fd, int level, int optname,
721
unsigned long long val, char const *errmsg)
722
{
723
unsigned long long chkval;
724
socklen_t chklen;
725
int err;
726
727
err = setsockopt(fd, level, optname, &val, sizeof(val));
728
if (err) {
729
fprintf(stderr, "setsockopt err: %s (%d)\n",
730
strerror(errno), errno);
731
goto fail;
732
}
733
734
chkval = ~val; /* just make storage != val */
735
chklen = sizeof(chkval);
736
737
err = getsockopt(fd, level, optname, &chkval, &chklen);
738
if (err) {
739
fprintf(stderr, "getsockopt err: %s (%d)\n",
740
strerror(errno), errno);
741
goto fail;
742
}
743
744
if (chklen != sizeof(chkval)) {
745
fprintf(stderr, "size mismatch: set %zu got %d\n", sizeof(val),
746
chklen);
747
goto fail;
748
}
749
750
if (chkval != val) {
751
fprintf(stderr, "value mismatch: set %llu got %llu\n", val,
752
chkval);
753
goto fail;
754
}
755
return;
756
fail:
757
fprintf(stderr, "%s val %llu\n", errmsg, val);
758
exit(EXIT_FAILURE);
759
;
760
}
761
762
/* Set "int" socket option and check that it's indeed set */
763
void setsockopt_int_check(int fd, int level, int optname, int val,
764
char const *errmsg)
765
{
766
int chkval;
767
socklen_t chklen;
768
int err;
769
770
err = setsockopt(fd, level, optname, &val, sizeof(val));
771
if (err) {
772
fprintf(stderr, "setsockopt err: %s (%d)\n",
773
strerror(errno), errno);
774
goto fail;
775
}
776
777
chkval = ~val; /* just make storage != val */
778
chklen = sizeof(chkval);
779
780
err = getsockopt(fd, level, optname, &chkval, &chklen);
781
if (err) {
782
fprintf(stderr, "getsockopt err: %s (%d)\n",
783
strerror(errno), errno);
784
goto fail;
785
}
786
787
if (chklen != sizeof(chkval)) {
788
fprintf(stderr, "size mismatch: set %zu got %d\n", sizeof(val),
789
chklen);
790
goto fail;
791
}
792
793
if (chkval != val) {
794
fprintf(stderr, "value mismatch: set %d got %d\n", val, chkval);
795
goto fail;
796
}
797
return;
798
fail:
799
fprintf(stderr, "%s val %d\n", errmsg, val);
800
exit(EXIT_FAILURE);
801
}
802
803
static void mem_invert(unsigned char *mem, size_t size)
804
{
805
size_t i;
806
807
for (i = 0; i < size; i++)
808
mem[i] = ~mem[i];
809
}
810
811
/* Set "timeval" socket option and check that it's indeed set */
812
void setsockopt_timeval_check(int fd, int level, int optname,
813
struct timeval val, char const *errmsg)
814
{
815
struct timeval chkval;
816
socklen_t chklen;
817
int err;
818
819
err = setsockopt(fd, level, optname, &val, sizeof(val));
820
if (err) {
821
fprintf(stderr, "setsockopt err: %s (%d)\n",
822
strerror(errno), errno);
823
goto fail;
824
}
825
826
/* just make storage != val */
827
chkval = val;
828
mem_invert((unsigned char *)&chkval, sizeof(chkval));
829
chklen = sizeof(chkval);
830
831
err = getsockopt(fd, level, optname, &chkval, &chklen);
832
if (err) {
833
fprintf(stderr, "getsockopt err: %s (%d)\n",
834
strerror(errno), errno);
835
goto fail;
836
}
837
838
if (chklen != sizeof(chkval)) {
839
fprintf(stderr, "size mismatch: set %zu got %d\n", sizeof(val),
840
chklen);
841
goto fail;
842
}
843
844
if (memcmp(&chkval, &val, sizeof(val)) != 0) {
845
fprintf(stderr, "value mismatch: set %ld:%ld got %ld:%ld\n",
846
val.tv_sec, val.tv_usec, chkval.tv_sec, chkval.tv_usec);
847
goto fail;
848
}
849
return;
850
fail:
851
fprintf(stderr, "%s val %ld:%ld\n", errmsg, val.tv_sec, val.tv_usec);
852
exit(EXIT_FAILURE);
853
}
854
855
void enable_so_zerocopy_check(int fd)
856
{
857
setsockopt_int_check(fd, SOL_SOCKET, SO_ZEROCOPY, 1,
858
"setsockopt SO_ZEROCOPY");
859
}
860
861
void enable_so_linger(int fd, int timeout)
862
{
863
struct linger optval = {
864
.l_onoff = 1,
865
.l_linger = timeout
866
};
867
868
if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &optval, sizeof(optval))) {
869
perror("setsockopt(SO_LINGER)");
870
exit(EXIT_FAILURE);
871
}
872
}
873
874
static int __get_transports(void)
875
{
876
char buf[KALLSYMS_LINE_LEN];
877
const char *ksym;
878
int ret = 0;
879
FILE *f;
880
881
f = fopen(KALLSYMS_PATH, "r");
882
if (!f) {
883
perror("Can't open " KALLSYMS_PATH);
884
exit(EXIT_FAILURE);
885
}
886
887
while (fgets(buf, sizeof(buf), f)) {
888
char *match;
889
int i;
890
891
assert(buf[strlen(buf) - 1] == '\n');
892
893
for (i = 0; i < TRANSPORT_NUM; ++i) {
894
if (ret & BIT(i))
895
continue;
896
897
/* Match should be followed by '\t' or '\n'.
898
* See kallsyms.c:s_show().
899
*/
900
ksym = transport_ksyms[i];
901
match = strstr(buf, ksym);
902
if (match && isspace(match[strlen(ksym)])) {
903
ret |= BIT(i);
904
break;
905
}
906
}
907
}
908
909
fclose(f);
910
return ret;
911
}
912
913
/* Return integer with TRANSPORT_* bit set for every (known) registered vsock
914
* transport.
915
*/
916
int get_transports(void)
917
{
918
static int tr = -1;
919
920
if (tr == -1)
921
tr = __get_transports();
922
923
return tr;
924
}
925
926