Adapting TCP/IP socket code to use virtual sockets

Updated: April 19, 2023

An application that uses TCP/IP sockets can be easily adapted to use virtual sockets (vsocks) by:
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;
}