An application that uses TCP/IP sockets can be easily adapted to use virtual sockets (vsocks) by:
- Changing the address family from AF_INET to AF_VSOCK in data structures and
function arguments. Note that the current implementation supports only the connection-oriented and reliable socket type
(SOCK_STREAM).
- Using the struct sockaddr_vm data type to store vsock data, and passing this structure's address into
the relevant API calls, such as bind() and connect().
The vsock data include the AF_VSOCK address family, the CID of the guest or host in which the other
application runs, and the port number of this application.
- When calling setsockopt() or getsockopt(), using PF_VSOCK
instead of SOL_SOCKET.
For example, suppose a guest application wants to send the contents of a binary file to another application in another guest or
the host. The sender (i.e., the client) would use code like the following to connect and send data to the other application
(i.e., the server):
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <vm_socket.h>
#define VSOCK_SEND_BUFFER_SIZE 64
int vsock_sendbinaryfile( char* filename, int destcid, int destport )
{
int vsock_fd;
if ( vsock_fd = socket( AF_VSOCK, SOCK_STREAM, 0 ) == -1 )
{
/* Error-handling code goes here */
return -1;
}
struct sockaddr_vm sa = {
.svm_family = AF_VSOCK,
.svm_cid = destcid,
.svm_port = destport
};
if ( connect( vsock_fd, (struct sockaddr*)&sa, sizeof(sa) ) == -1 )
{
close(vsock_fd);
/* Error-handling code goes here */
return -1;
}
/* Open specified file for reading, and treat it as binary */
FILE *fd = fopen(filename, "rb");
if (!fd)
{
close(vsock_fd);
/* Error-handling code goes here */
return -1;
}
char buf[VSOCK_SEND_BUFFER_SIZE];
memset(buf, 0, sizeof(buf));
int n;
while ( (n = fread( buf, sizeof(char), VSOCK_SEND_BUFFER_SIZE, fd )) > 0 )
{
if (n != VSOCK_SEND_BUFFER_SIZE && ferror(fd))
{
/* Error-handling code goes here */
return -1;
}
if ( send( vsock_fd, buf, n, 0 ) == -1 )
{
/* Error-handling code goes here */
return -1;
}
/* Clear buffer memory so last content from file will be followed by zeros */
memset(buf, 0, sizeof(buf));
}
fclose(fd);
close(vsock_fd);
return 0;
}
At the other end of the vsock connection, the receiver (i.e., the server) would use code like the following:
int vsock_accept_client( int port_num )
{
struct sockaddr_vm sa_listen = {
.svm_family = AF_VSOCK,
.svm_cid = VMADDR_CID_ANY,
.svm_port = port_num
};
int listen_fd;
listen_fd = socket( AF_VSOCK, SOCK_STREAM, 0 );
if (listen_fd < 0) {
/* Error-handling code goes here */
return -1;
}
if ( bind( listen_fd, (struct sockaddr*)&sa_listen, sizeof(sa_listen) ) != 0 )
{
/* Error-handling code goes here */
close(listen_fd);
return -1;
}
if ( listen( listen_fd, 1 ) != 0 )
{
/* Error-handling code goes here */
close(listen_fd);
return -1;
}
struct sockaddr_vm sa_client;
socklen_t socklen_client = sizeof(sa_client);
int client_fd;
client_fd = accept( listen_fd, (struct sockaddr*)&sa_client, &socklen_client );
if (client_fd < 0)
{
/* Error-handling code goes here */
close(listen_fd);
return -1;
}
char buf[VSOCK_SEND_BUFFER_SIZE];
memset(buf, 0, sizeof(buf));
ssize_t nbytes;
do {
nbytes = recv(client_fd, buf, sizeof(buf), 0);
/* Do something with each data buffer received */
} while (nbytes > 0);
if (nbytes == -1) {
/* Error-handling code goes here */
}
close(client_fd);
close(listen_fd);
return 0;
}