All articles

Practical Hyper-V Socket Communication

Programming with sockets is not a new thing. In a nutshell, programming with sockets boils down to simple flow of create a socket, connect, bind, listen, accept, send, and receive packets. Getting started requires visiting multiple sources and pulling together pieces of information. I found useful to compare the Winsock sample code with the Hyper-V socket API and see the differences between them. You can use this sample code to get a head start on your own code.

Starting with Windows 10, a new set of sockets arrived to facilitate the communication between your host and one or more virtual machines free of any network connection. Here you can find an article regarding the Hyper-V sockets and how can you make your own integration services. In addition, MSDN offers sample code to create a basic client/server TCP communication.

Familiarize yourself with Complete Winsock Client Code.aspx) and Complete Winsock Server Code.aspx) first. In this blog I discuss the similarities of the code. If you follow the guidance, you will be able to create your own better version to create host to virtual machine communication using Hyper-V sockets.


Hyper-V Socket Client Code

Start by making your own integration service. Instead of defining the DEFAULT_PORT, define the virtual machine ID and service GUID. These values can be collected as command line input in your code. For clarity in the sample code I used fixed values.

// Vm ID: {CDEE5C88-C5A5-4CC8-9D2D-C15816A01349}
DEFINE_GUID(VmId,
    0xcdee5c88, 0xc5a5, 0x4cc8, 0x9d, 0x2d, 0xc1, 0x58, 0x16, 0xa0, 0x13, 0x49);

// Service GUID: {8BA03980-174A-43E7-852A-E5EC79A671C7}
DEFINE_GUID(ServiceId,
    0x8ba03980, 0x174a, 0x43e7, 0x85, 0x2a, 0xe5, 0xec, 0x79, 0xa6, 0x71, 0xc7);

In this context, the getaddrinfo doesn't exist because it is specific to network communication and there is no need to resolve any server address and port. The Hyper-V socket secret sauce resides in the definition and initialization of the socket.

SOCKADDR_HV clientService;

ZeroMemory(&clientService, sizeof(clientService));
clientService.Family = AF_HYPERV;
clientService.VmId = VmId;
clientService.ServiceId = ServiceId;

The only one change remaining is in the connection, where the clientService variable is used.

iResult = connect(connectSocket, (SOCKADDR *)(&clientService), sizeof(clientService));

Hyper-V Socket Server Code

We need to make the same modifications for the server code except now the VmId should be the HV_GUID_PARENT. The connect function is not called in the server code, instead we use the bind function. The code looks like this.

iResult = bind(ListenSocket, (SOCKADDR *)(&clientService), sizeof(clientService));

Running the Code Sample

The following links contain the complete sample source code for the basic Hyper-V socket communication. The code is the same as Winsock sample to make the differences between them very clear.

Complete Hyper-V Socket Client Code

#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <stdafx.h>
#include <ws2tcpip.h>
#include <objbase.h>
 
#define DEFAULT_BUFLEN 512
 
// Vm ID: {CDEE5C88-C5A5-4CC8-9D2D-C15816A01349}
DEFINE_GUID(VmId,
    0xcdee5c88, 0xc5a5, 0x4cc8, 0x9d, 0x2d, 0xc1, 0x58, 0x16, 0xa0, 0x13, 0x49);
 
// Service GUID: {8BA03980-174A-43E7-852A-E5EC79A671C7}
DEFINE_GUID(ServiceId,
    0x8ba03980, 0x174a, 0x43e7, 0x85, 0x2a, 0xe5, 0xec, 0x79, 0xa6, 0x71, 0xc7);
 
int __cdecl main(void)
{
    WSADATA wsaData;
    SOCKET ConnectSocket = INVALID_SOCKET;
    struct addrinfo hints;
    SOCKADDR_HV clientService;
    char *sendbuf = "this is a test";
    char recvbuf[DEFAULT_BUFLEN];
    int iResult;
    int recvbuflen = DEFAULT_BUFLEN;
 
    // add your own input here
    CONST GUID *vmId = &VmId;
    CONST GUID *serviceId = &ServiceId;
 
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed with error: %d\n", iResult);
        return 1;
    }
 
    ZeroMemory(&clientService, sizeof(clientService));
    clientService.Family = AF_HYPERV;
    clientService.VmId = *vmId;
    clientService.ServiceId = *serviceId;
 
    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_HYPERV;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = HV_PROTOCOL_RAW;
 
    hints.ai_addrlen = sizeof(SOCKADDR_HV);
    hints.ai_addr = reinterpret_cast<SOCKADDR *>(&clientService);
 
    // Create a SOCKET for connecting to server
    ConnectSocket = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol);
    if (ConnectSocket == INVALID_SOCKET) {
        printf("socket failed with error: %ld\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }
 
    // Connect to server.
    iResult = connect(ConnectSocket, hints.ai_addr, (int)hints.ai_addrlen);
    if (iResult == SOCKET_ERROR) {
        closesocket(ConnectSocket);
        ConnectSocket = INVALID_SOCKET;
    }
 
    if (ConnectSocket == INVALID_SOCKET) {
        printf("Unable to connect to server!\n");
        WSACleanup();
        return 1;
    }
 
    // Send an initial buffer
    iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0);
    if (iResult == SOCKET_ERROR) {
        printf("send failed with error: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }
 
    printf("Bytes Sent: %ld\n", iResult);
 
    // shutdown the connection since no more data will be sent
    iResult = shutdown(ConnectSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed with error: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }
 
    // Receive until the peer closes the connection
    do {
 
        iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
        if (iResult > 0)
            printf("Bytes received: %d\n", iResult);
        else if (iResult == 0)
            printf("Connection closed\n");
        else
            printf("recv failed with error: %d\n", WSAGetLastError());
 
    } while (iResult > 0);
 
    // cleanup
    closesocket(ConnectSocket);
    WSACleanup();
 
    return 0;
}

Complete Hyper-V Socket Server Code

#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <stdafx.h>
#include <ws2tcpip.h>
#include <objbase.h>
 
#define DEFAULT_BUFLEN 512
 
// Service GUID: {8BA03980-174A-43E7-852A-E5EC79A671C7}
DEFINE_GUID(ServiceId,
    0x8ba03980, 0x174a, 0x43e7, 0x85, 0x2a, 0xe5, 0xec, 0x79, 0xa6, 0x71, 0xc7);
 
int main(void)
{
    WSADATA wsaData;
     
    int iResult;
    int iSendResult;
    char recvbuf[DEFAULT_BUFLEN];
    int recvbuflen = DEFAULT_BUFLEN;
 
    SOCKET ListenSocket = INVALID_SOCKET;
    SOCKET ClientSocket = INVALID_SOCKET;
 
    struct addrinfo hints;
    SOCKADDR_HV clientService;
 
    // add your own input here
    CONST GUID *serviceId = &ServiceId;
 
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed with error: %d\n", iResult);
        return 1;
    }
 
    ZeroMemory(&clientService, sizeof(clientService));
    clientService.Family = AF_HYPERV;
    clientService.VmId = HV_GUID_PARENT;
    clientService.ServiceId = *serviceId;
 
    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_HYPERV;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = HV_PROTOCOL_RAW;
 
    hints.ai_addrlen = sizeof(SOCKADDR_HV);
    hints.ai_addr = reinterpret_cast<SOCKADDR *>(&clientService);
 
    // Create a SOCKET for connecting to server
    ListenSocket = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol);
    if (ListenSocket == INVALID_SOCKET) {
        printf("socket failed with error: %ld\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }
 
    // Setup the Hyper-V listening socket
    iResult = bind(ListenSocket, hints.ai_addr, (int)hints.ai_addrlen);
    if (iResult == SOCKET_ERROR) {
        printf("bind failed with error: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
 
    iResult = listen(ListenSocket, SOMAXCONN);
    if (iResult == SOCKET_ERROR) {
        printf("listen failed with error: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
 
    // Accept a client socket
    ClientSocket = accept(ListenSocket, NULL, NULL);
    if (ClientSocket == INVALID_SOCKET) {
        printf("accept failed with error: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
 
    // No longer need server socket
    closesocket(ListenSocket);
     
    // Receive until the peer shuts down the connection
    do {
 
        iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
        if (iResult > 0) {
            printf("Bytes received: %d\n", iResult);
 
            // Echo the buffer back to the sender
            iSendResult = send(ClientSocket, recvbuf, iResult, 0);
            if (iSendResult == SOCKET_ERROR) {
                printf("send failed with error: %d\n", WSAGetLastError());
                closesocket(ClientSocket);
                WSACleanup();
                return 1;
            }
            printf("Bytes sent: %d\n", iSendResult);
        }
        else if (iResult == 0)
            printf("Connection closing...\n");
        else {
            printf("recv failed with error: %d\n", WSAGetLastError());
            closesocket(ClientSocket);
            WSACleanup();
            return 1;
        }
 
    } while (iResult > 0);
 
    // shutdown the connection since we're done
    iResult = shutdown(ClientSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed with error: %d\n", WSAGetLastError());
        closesocket(ClientSocket);
        WSACleanup();
        return 1;
    }
 
    // cleanup
    closesocket(ClientSocket);
    WSACleanup();
 
    return 0;
}

Originally published August 29, 2016

Continue Reading

A Correction, in Public: Revisiting AI Oversight in the United States

A follow-up to "The Global AI Risk Assessment Convergence." The original argued that three jurisdictions—the EU, South Korea, and the United States—were converging on human oversight for high-risk AI. Two of those pillars hold. The third does not: the US section rested on Executive Order 14110, which had already been revoked at the time of publication. This piece corrects the record in the open, reframes the US not as converging but as contested, and draws the durable engineering lesson underneath a changing regulatory landscape.

The Grade That Changed Everything

In 1992 Bucharest, a student bluffed his way through a math exam with the only theorem he knew. Thirty years later, that theorem turned out to be a structural pillar of modern AI. A personal account of the Cauchy-Bunyakovsky-Schwarz inequality — why it governs how AI understands similarity, attention, and language — and what a wise professor's five out of ten can mean across a lifetime.

Agentic AI Is Distributed Systems. Part 2: Building on Uncertain Ground — Practical Semantic Correctness for Agentic Systems

You cannot mathematically prove an LLM correct. But you can architect around it. Part 2 surveys the three research communities approaching semantic correctness for LLM outputs — formal verification, runtime guardrails, and post-condition verification — maps their results honestly, and delivers a concrete engineering playbook: four patterns engineers can implement today to build agentic systems that fail visibly, recover gracefully, and escalate correctly.