1 #include <errno.h>
2 #include <fcntl.h>
3 #include <netdb.h>
4 #include <stdbool.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/select.h>
9 #include <sys/socket.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12
13 #include <linux/vm_sockets.h>
14
15 // This is a simple vsock 'sibling' tester. It's used to verify
16 // vsock communications between two VMs on a host.
17
18 #define BUFSIZE 1024 // for storing some temp strings for testing
19
20 // Checks a socket handle, and prints error / quits if failure
check_socket(char * name,int fd)21 int check_socket(char *name, int fd) {
22 if (fd < 0) {
23 fprintf(stderr, "error initializing socket: %s: %s\n", name,
24 strerror(errno));
25 exit(0);
26 }
27 return fd;
28 }
29
30 // Checks error code is nonzero, and if so, print a message,
31 // closing a socket handle if provided as well.
check_error(char * operation,int result,int fd)32 int check_error(char *operation, int result, int fd) {
33 if (result != 0) {
34 fprintf(stderr, "error for operation %s: %s\n", operation, strerror(errno));
35 if (fd != -1) close(fd);
36 exit(0);
37 }
38 return result;
39 }
40
41 // Main execution path for server test mode. This mode runs
42 // a listener for vsock socket on the specified port, then
43 // prints the value received before echoing the same value
44 // back to the client for testing.
main_server(int port)45 int main_server(int port) {
46 printf("Starting a vsock server on port %d\n", port);
47
48 struct sockaddr_vm sa_listen = {
49 .svm_family = AF_VSOCK, .svm_cid = VMADDR_CID_ANY, .svm_port = port};
50 struct sockaddr_vm sa_client;
51 socklen_t socklen_client = sizeof(sa_client);
52
53 int listen_fd = check_socket("listen_fd", socket(AF_VSOCK, SOCK_STREAM, 0));
54
55 check_error("binding main listen socket",
56 bind(listen_fd, (struct sockaddr *)&sa_listen, sizeof(sa_listen)),
57 listen_fd);
58
59 check_error("listen on main socket", listen(listen_fd, 1), listen_fd);
60
61 int client_fd =
62 accept(listen_fd, (struct sockaddr *)&sa_client, &socklen_client);
63
64 check_error("accept() on main socket", client_fd < 0, listen_fd);
65
66 fprintf(stderr, "Connection from cid %u port %u...\n", sa_client.svm_cid,
67 sa_client.svm_port);
68
69 close(listen_fd);
70
71 char buf[BUFSIZE];
72 memset(buf, 0, BUFSIZE);
73 int len = read(client_fd, buf, BUFSIZE - 1);
74
75 printf("Read %d bytes, str is '%s':\n", len, buf);
76
77 printf("Echoing back data...\n");
78
79 write(client_fd, buf, len);
80
81 printf("Data sent.\n");
82
83 close(client_fd);
84
85 return 0;
86 }
87
88 // Main execution path for 'client' test mode. This mode
89 // connects to specified vsock cid and port, and sends a string
90 // to a 'server', which is a peer listening on specified vsock port.
91 // Client mode also waits for server to echo back the same
92 // value and prints this when received.
main_client(int cid,int port,char * str)93 int main_client(int cid, int port, char *str) {
94 struct sockaddr_vm sa = {.svm_family = AF_VSOCK,
95 .svm_flags = VMADDR_FLAG_TO_HOST,
96 .svm_cid = cid,
97 .svm_port = port};
98
99 printf("Connecting to cid %d port %d\n", cid, port);
100
101 int fd = check_socket("main socket", socket(AF_VSOCK, SOCK_STREAM, 0));
102
103 check_error("connect", connect(fd, (struct sockaddr *)&sa, sizeof(sa)), fd);
104
105 printf("Connected, sending data '%s' to server...\n", str);
106
107 write(fd, str, strlen(str));
108
109 printf("Data sent. Waiting for response...\n");
110
111 char buf[BUFSIZE];
112 memset(buf, 0, BUFSIZE);
113 int len = read(fd, buf, BUFSIZE - 1);
114
115 printf("Read %d bytes back from server, str is '%s':\n", len, buf);
116
117 close(fd);
118
119 return 0;
120 }
121
122 #define safer_atoi(x) strtol(x, NULL, 10)
123
main(int argc,char * argv[])124 int main(int argc, char *argv[]) {
125 if (argc == 2) {
126 main_server(safer_atoi(argv[1]));
127 } else if (argc == 4) {
128 main_client(safer_atoi(argv[1]), safer_atoi(argv[2]), argv[3]);
129 } else {
130 printf(
131 "Welcome to vsock-test! This utility helps test/verify "
132 "'sibling' (vm to vm) vsock comms.\n\n"
133 "Please run this command via one of the 2 following forms:\n\n"
134 "\tvsock-test [port]\n"
135 "\t\tThis format runs a vsock server, where [port] is the "
136 "vsock port to listen on.\n\n"
137 "\tvsock-test [cid] [port] [str]\n"
138 "\t\tThis format runs a vsock client, where:\n"
139 "\t\t\t[cid] is the CID of server to connect to\n"
140 "\t\t\t[port] is vsock port to connect to\n"
141 "\t\t\t[str] is any string to send from client for testing\n\n");
142 }
143 }
144