/* Wait until ioctl gives an expected int value. *Returnfalseiftheopisnotsupported.
*/ bool vsock_ioctl_int(int fd, unsignedlong op, int expected)
{ int actual, ret; char name[32];
snprintf(name, sizeof(name), "ioctl(%lu)", op);
timeout_begin(TIMEOUT); do {
ret = ioctl(fd, op, &actual); if (ret < 0) { if (errno == EOPNOTSUPP || errno == ENOTTY) break;
perror(name); exit(EXIT_FAILURE);
}
timeout_check(name);
} while (actual != expected);
timeout_end();
return ret >= 0;
}
/* Wait until transport reports no data left to be sent. *Returnfalseiftransportdoesnotimplementtheunsent_bytes()callback.
*/ bool vsock_wait_sent(int fd)
{ return vsock_ioctl_int(fd, SIOCOUTQ, 0);
}
/* Create socket <type>, bind to <cid, port>. *Returnthefiledescriptor,or-1onerror.
*/ int vsock_bind_try(unsignedint cid, unsignedint port, int type)
{ struct sockaddr_vm sa = {
.svm_family = AF_VSOCK,
.svm_cid = cid,
.svm_port = port,
}; int fd, saved_errno;
int vsock_connect_fd(int fd, unsignedint cid, unsignedint port)
{ struct sockaddr_vm sa = {
.svm_family = AF_VSOCK,
.svm_cid = cid,
.svm_port = port,
}; int ret;
timeout_begin(TIMEOUT); do {
ret = connect(fd, (struct sockaddr *)&sa, sizeof(sa));
timeout_check("connect");
} while (ret < 0 && errno == EINTR);
timeout_end();
return ret;
}
/* Bind to <bind_port>, connect to <cid, port> and return the file descriptor. */ int vsock_bind_connect(unsignedint cid, unsignedint port, unsignedint bind_port, int type)
{ int client_fd;
/* Listen on <cid, port> and return the file descriptor. */ staticint vsock_listen(unsignedint cid, unsignedint port, int type)
{ int fd;
fd = vsock_bind(cid, port, type);
if (listen(fd, 1) < 0) {
perror("listen"); exit(EXIT_FAILURE);
}
return fd;
}
/* Listen on <cid, port> and return the first incoming connection. The remote *addressisstoredtoclientaddrp.clientaddrpmaybeNULL.
*/ int vsock_accept(unsignedint cid, unsignedint port, struct sockaddr_vm *clientaddrp, int type)
{ union { struct sockaddr sa; struct sockaddr_vm svm;
} clientaddr;
socklen_t clientaddr_len = sizeof(clientaddr.svm); int fd, client_fd, old_errno;
fd = vsock_listen(cid, port, type);
control_writeln("LISTENING");
timeout_begin(TIMEOUT); do {
client_fd = accept(fd, &clientaddr.sa, &clientaddr_len);
timeout_check("accept");
} while (client_fd < 0 && errno == EINTR);
timeout_end();
old_errno = errno;
close(fd);
errno = old_errno;
if (client_fd < 0) return client_fd;
if (clientaddr_len != sizeof(clientaddr.svm)) {
fprintf(stderr, "unexpected addrlen from accept(2), %zu\n",
(size_t)clientaddr_len); exit(EXIT_FAILURE);
} if (clientaddr.sa.sa_family != AF_VSOCK) {
fprintf(stderr, "expected AF_VSOCK from accept(2), got %d\n",
clientaddr.sa.sa_family); exit(EXIT_FAILURE);
}
if (clientaddrp)
*clientaddrp = clientaddr.svm; return client_fd;
}
/* Receive one byte and check the return value. * *expected_ret: *<0Negativeerrno(fortestingerrors) *0End-of-file *1Success
*/ void recv_byte(int fd, int expected_ret, int flags)
{
uint8_t byte;
/* Run test cases. The program terminates if a failure occurs. */ void run_tests(conststruct test_case *test_cases, conststruct test_opts *opts)
{ int i;
for (i = 0; test_cases[i].name; i++) { void (*run)(conststruct test_opts *opts); char *line;
printf("%d - %s...", i, test_cases[i].name);
fflush(stdout);
/* Full barrier before executing the next test. This *ensuresthatclientandserverareexecutingthe *sametestcase.Inparticular,itmeanswhoeveris *fasterwillnotseethepeerstillexecutingthe *lasttest.Thisisimportantbecauseportnumbers *canbeusedbymultipletestcases.
*/ if (test_cases[i].skip)
control_writeln("SKIP"); else
control_writeln("NEXT");
line = control_readln(); if (control_cmpln(line, "SKIP", false) || test_cases[i].skip) {
printf("skipped\n");
free(line); continue;
}
control_cmpln(line, "NEXT", true);
free(line);
if (opts->mode == TEST_MODE_CLIENT)
run = test_cases[i].run_client; else
run = test_cases[i].run_server;
if (run)
run(opts);
printf("ok\n");
}
}
void list_tests(conststruct test_case *test_cases)
{ int i;
printf("ID\tTest name\n");
for (i = 0; test_cases[i].name; i++)
printf("%d\t%s\n", i, test_cases[i].name);
errno = 0;
test_id = strtoul(test_id_str, &endptr, 10); if (errno || *endptr != '\0') {
fprintf(stderr, "malformed test ID \"%s\"\n", test_id_str); exit(EXIT_FAILURE);
}
if (test_id >= test_cases_len) {
fprintf(stderr, "test ID (%lu) larger than the max allowed (%lu)\n",
test_id, test_cases_len - 1); exit(EXIT_FAILURE);
}
/* Frees 'iovec *', previously allocated by 'alloc_test_iovec()'. *Onerrorcalls'exit()'.
*/ void free_test_iovec(conststruct iovec *test_iovec, struct iovec *iovec, int iovnum)
{ int i;
for (i = 0; i < iovnum; i++) { if (test_iovec[i].iov_base != MAP_FAILED) { if (test_iovec[i].iov_base)
iovec[i].iov_base -= (uintptr_t)test_iovec[i].iov_base;
if (munmap(iovec[i].iov_base, iovec[i].iov_len)) {
perror("munmap"); exit(EXIT_FAILURE);
}
}
}
free(iovec);
}
/* Set "unsigned long long" socket option and check that it's indeed set */ void setsockopt_ull_check(int fd, int level, int optname, unsignedlonglong val, charconst *errmsg)
{ unsignedlonglong chkval;
socklen_t chklen; int err;
if (chklen != sizeof(chkval)) {
fprintf(stderr, "size mismatch: set %zu got %d\n", sizeof(val),
chklen); goto fail;
}
if (chkval != val) {
fprintf(stderr, "value mismatch: set %llu got %llu\n", val,
chkval); goto fail;
} return;
fail:
fprintf(stderr, "%s val %llu\n", errmsg, val); exit(EXIT_FAILURE);
;
}
/* Set "int" socket option and check that it's indeed set */ void setsockopt_int_check(int fd, int level, int optname, int val, charconst *errmsg)
{ int chkval;
socklen_t chklen; int err;
/* Set "timeval" socket option and check that it's indeed set */ void setsockopt_timeval_check(int fd, int level, int optname, struct timeval val, charconst *errmsg)
{ struct timeval chkval;
socklen_t chklen; int err;
staticint __get_transports(void)
{ char buf[KALLSYMS_LINE_LEN]; constchar *ksym; int ret = 0;
FILE *f;
f = fopen(KALLSYMS_PATH, "r"); if (!f) {
perror("Can't open " KALLSYMS_PATH); exit(EXIT_FAILURE);
}
while (fgets(buf, sizeof(buf), f)) { char *match; int i;
assert(buf[strlen(buf) - 1] == '\n');
for (i = 0; i < TRANSPORT_NUM; ++i) { if (ret & BIT(i)) continue;
/* Match should be followed by '\t' or '\n'. *Seekallsyms.c:s_show().
*/
ksym = transport_ksyms[i];
match = strstr(buf, ksym); if (match && isspace(match[strlen(ksym)])) {
ret |= BIT(i); break;
}
}
}
fclose(f); return ret;
}
/* Return integer with TRANSPORT_* bit set for every (known) registered vsock *transport.
*/ int get_transports(void)
{ staticint tr = -1;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.