Skip to content

Commit

Permalink
hvpty: wrap WinSock functions in HyperVSocket class (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
Biswa96 committed Oct 9, 2019
1 parent 2b91f5e commit 864bbc0
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 124 deletions.
6 changes: 0 additions & 6 deletions hvpty/GetVmId.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,8 @@ HRESULT GetVmId(
const std::wstring &DistroName,
int *WslVersion)
{
int bRes;
HRESULT hRes;

WSADATA wsaData;
bRes = WSAStartup(MAKEWORD(2, 2), &wsaData);
assert(bRes == 0);

hRes = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
assert(hRes == 0);

Expand Down Expand Up @@ -197,6 +192,5 @@ HRESULT GetVmId(
if (wslSession)
wslSession->Release();
CoUninitialize();
WSACleanup();
return hRes;
}
144 changes: 144 additions & 0 deletions hvpty/HyperVSocket.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
* This file is part of wslbridge2 project
* Licensed under the GNU General Public License version 3
* Copyright (C) 2019 Biswapriyo Nath
*/

#include <winsock.h>
#include <assert.h>

#include "../hvsocket/hvsocket.h"
#include "HyperVSocket.hpp"

/* The range 49152–65535 contains dynamic ports */
#define DYNAMIC_PORT_LOW 49152
#define DYNAMIC_PORT_HIGH 65535
#define BIND_MAX_RETRIES 10

#define RANDOMPORT() \
rand() % (DYNAMIC_PORT_HIGH - DYNAMIC_PORT_LOW) + DYNAMIC_PORT_LOW

HyperVSocket::HyperVSocket(void)
{
m_hModule = LoadLibraryExW(
L"ws2_32.dll",
nullptr,
LOAD_LIBRARY_SEARCH_SYSTEM32);
assert(m_hModule != nullptr);

pfnAccept = (ACCEPTPROC)GetProcAddress(m_hModule, "accept");
pfnBind = (BINDPROC)GetProcAddress(m_hModule, "bind");
pfnCloseSocket = (CLOSESOCKETPROC)GetProcAddress(m_hModule, "closesocket");
pfnConnect = (CONNETCPROC)GetProcAddress(m_hModule, "connect");
pfnListen = (LISTENPROC)GetProcAddress(m_hModule, "listen");
pfnRecv = (RECVPROC)GetProcAddress(m_hModule, "recv");
pfnSend = (SENDPROC)GetProcAddress(m_hModule, "send");
pfnSocket = (SOCKETPROC)GetProcAddress(m_hModule, "socket");
pfnSetSockOpt = (SETSOCKOPTPROC)GetProcAddress(m_hModule, "setsockopt");
pfnWSAStartup = (WSASTARTUPPROC)GetProcAddress(m_hModule, "WSAStartup");
pfnWSACleanup = (WSACLEANUPPROC)GetProcAddress(m_hModule, "WSACleanup");

struct WSAData wdata;
const int wsaRet = pfnWSAStartup(MAKEWORD(2,2), &wdata);
assert(wsaRet == 0);
}

HyperVSocket::~HyperVSocket(void)
{
if (m_hModule)
FreeLibrary(m_hModule);
pfnWSACleanup();
}

SOCKET HyperVSocket::Create(void)
{
const SOCKET sock = pfnSocket(
AF_HYPERV,
SOCK_STREAM,
HV_PROTOCOL_RAW);
assert(sock > 0);

const int suspend = true;
const int suspendRet = pfnSetSockOpt(
sock,
HV_PROTOCOL_RAW,
HVSOCKET_CONNECTED_SUSPEND,
&suspend,
sizeof suspend);
assert(suspendRet == 0);

/* Return socket to caller */
return sock;
}

SOCKET HyperVSocket::Accept(const SOCKET sock)
{
const SOCKET cSock = pfnAccept(sock, nullptr, nullptr);
assert(cSock > 0);
return cSock;
}

void HyperVSocket::Connect(const SOCKET sock, const GUID *VmId, const int port)
{
const int timeout = 10 * 1000; /* Ten seconds */
const int timeRet = pfnSetSockOpt(
sock,
HV_PROTOCOL_RAW,
HVSOCKET_CONNECT_TIMEOUT,
&timeout,
sizeof timeout);
assert(timeRet == 0);

struct SOCKADDR_HV addr = {};
addr.Family = AF_HYPERV;
memcpy(&addr.VmId, VmId, sizeof addr.VmId);
memcpy(&addr.ServiceId, &HV_GUID_VSOCK_TEMPLATE, sizeof addr.ServiceId);
addr.ServiceId.Data1 = port;
const int connectRet = pfnConnect(sock, &addr, sizeof addr);
assert(connectRet == 0);
}

int HyperVSocket::Listen(const SOCKET sock, const GUID *VmId)
{
struct SOCKADDR_HV addr = {};
addr.Family = AF_HYPERV;
memcpy(&addr.VmId, VmId, sizeof addr.VmId);
memcpy(&addr.ServiceId, &HV_GUID_VSOCK_TEMPLATE, sizeof addr.ServiceId);

/* Try to bind to a dynamic port */
int nretries = 0;
int port;

while (nretries < BIND_MAX_RETRIES)
{
port = RANDOMPORT();
addr.ServiceId.Data1 = port;
const int bindRet = pfnBind(sock, &addr, sizeof addr);
if (bindRet == 0)
break;

nretries++;
}

const int listenRet = pfnListen(sock, -1);
assert(listenRet == 0);

/* Return port number to caller */
return port;
}

int HyperVSocket::Receive(const SOCKET sock, void *buf, int len)
{
return pfnRecv(sock, buf, len, 0);
}

int HyperVSocket::Send(const SOCKET sock, void *buf, int len)
{
return pfnSend(sock, buf, len, 0);
}

void HyperVSocket::Close(const SOCKET sock)
{
if (sock > 0)
pfnCloseSocket(sock);
}
56 changes: 56 additions & 0 deletions hvpty/HyperVSocket.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* This file is part of wslbridge2 project
* Licensed under the GNU General Public License version 3
* Copyright (C) 2019 Biswapriyo Nath
*/

#ifndef HYPERVSOCKET_HPP
#define HYPERVSOCKET_HPP

#ifndef SOCKET
#define SOCKET size_t
#endif

/* Windows socket functions pointers from ws2_32.dll file */
typedef SOCKET (WINAPI *ACCEPTPROC)(SOCKET, void*, int*);
typedef int (WINAPI *BINDPROC)(SOCKET, const void*, int);
typedef int (WINAPI *CLOSESOCKETPROC)(SOCKET);
typedef int (WINAPI *CONNETCPROC)(SOCKET, const void*, int);
typedef int (WINAPI *LISTENPROC)(SOCKET, int);
typedef int (WINAPI *RECVPROC)(SOCKET, void*, int, int);
typedef int (WINAPI *SENDPROC)(SOCKET, const void*, int, int);
typedef SOCKET (WINAPI *SOCKETPROC)(int, int, int);
typedef int (WINAPI *SETSOCKOPTPROC)(SOCKET, int, int, const void*, int);
typedef int (WINAPI *WSASTARTUPPROC)(WORD, void*);
typedef int (WINAPI *WSACLEANUPPROC)(void);

/* This wraps WinSock functions to separate identical Cygwin imports */
class HyperVSocket
{
public:
HyperVSocket(void);
~HyperVSocket(void);
SOCKET Create(void);
SOCKET Accept(const SOCKET sock);
void Connect(const SOCKET sock, const GUID *VmId, const int port);
int Listen(const SOCKET sock, const GUID *VmId);
int Receive(const SOCKET sock, void *buf, int len);
int Send(const SOCKET sock, void *buf, int len);
void Close(const SOCKET sock);

private:
HMODULE m_hModule;
ACCEPTPROC pfnAccept;
BINDPROC pfnBind;
CLOSESOCKETPROC pfnCloseSocket;
CONNETCPROC pfnConnect;
LISTENPROC pfnListen;
RECVPROC pfnRecv;
SENDPROC pfnSend;
SOCKETPROC pfnSocket;
SETSOCKOPTPROC pfnSetSockOpt;
WSASTARTUPPROC pfnWSAStartup;
WSACLEANUPPROC pfnWSACleanup;
};

#endif /* HYPERVSOCKET_HPP */
8 changes: 6 additions & 2 deletions hvpty/Makefile.frontend
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ ifdef RELEASE
LFLAGS += -static -static-libgcc -static-libstdc++
endif

LIBS = -liphlpapi -lole32 -lws2_32
LIBS = -liphlpapi -lole32
BINS = \
$(BINDIR)/GetIp.obj \
$(BINDIR)/GetVmId.obj \
$(BINDIR)/Helpers.obj \
$(BINDIR)/HyperVSocket.obj \
$(BINDIR)/hvpty.obj \
$(BINDIR)/SocketIo.obj \
$(BINDIR)/TerminalState.obj
Expand All @@ -34,13 +35,16 @@ $(NAME) : $(BINS)

$(BINDIR)/GetIp.obj : GetIp.cpp
$(CXX) -c $(CFLAGS) $< -o $@

$(BINDIR)/GetVmId.obj : GetVmId.cpp
$(CXX) -c $(CFLAGS) $< -o $@

$(BINDIR)/Helpers.obj : ../wslbridge/Helpers.cpp
$(CXX) -c $(CFLAGS) $(CCOPT) $< -o $@

$(BINDIR)/HyperVSocket.obj : HyperVSocket.cpp
$(CXX) -c $(CFLAGS) $(CCOPT) $< -o $@

$(BINDIR)/hvpty.obj : hvpty.cpp
$(CXX) -c $(CFLAGS) $(CCOPT) $< -o $@

Expand Down
Loading

0 comments on commit 864bbc0

Please sign in to comment.