New socket platform API and named-pipe linux file

This commit is contained in:
Max Raulea 2026-07-22 11:32:39 +02:00
parent 1abac35edc
commit 6683c2dc3d
11 changed files with 450 additions and 62 deletions

View file

@ -0,0 +1,83 @@
/**
* @file platform-socket.c
* @author Max Raulea (max.raulea@hyperdbg.org)
* @brief User mode cross-platform implementation of the TCP remote-debugging transport
* @details See platform-socket.h. The few Winsock/POSIX primitives that diverge
* (close, shutdown flag, last-error) are mapped onto a common spelling
* by the macros below so each wrapper body is written once; only the
* startup/cleanup lifecycle, whose structure genuinely differs, keeps a
* small in-body guard. The portable socket calls themselves stay at the
* tcpclient/tcpserver call sites unchanged.
*
* @version 0.21
* @date 2026-07-22
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#include "pch.h"
#if defined(__linux__)
# include "../header/platform-socket.h"
# include <errno.h>
#endif // defined(__linux__)
//
// Map the Winsock/POSIX primitives that diverge onto a common spelling.
//
#if defined(_WIN32)
# define PLATFORM_CLOSE_SOCKET(Socket) closesocket(Socket)
# define PLATFORM_SHUTDOWN_SEND_FLAG SD_SEND
# define PLATFORM_LAST_SOCKET_ERROR WSAGetLastError()
#elif defined(__linux__)
# define PLATFORM_CLOSE_SOCKET(Socket) close(Socket)
# define PLATFORM_SHUTDOWN_SEND_FLAG SHUT_WR
# define PLATFORM_LAST_SOCKET_ERROR errno
#endif
INT
PlatformSocketInitialize(VOID)
{
#if defined(_WIN32)
WSADATA WsaData;
//
// Request Winsock 2.2; the WSADATA is not needed by the caller.
//
return WSAStartup(MAKEWORD(2, 2), &WsaData);
#else
//
// No global socket-library initialization is needed on Linux.
//
return 0;
#endif
}
VOID
PlatformSocketCleanup(VOID)
{
#if defined(_WIN32)
WSACleanup();
#endif
//
// Nothing to tear down on Linux.
//
}
INT
PlatformCloseSocket(SOCKET Socket)
{
return PLATFORM_CLOSE_SOCKET(Socket);
}
INT
PlatformShutdownSocketSend(SOCKET Socket)
{
return shutdown(Socket, PLATFORM_SHUTDOWN_SEND_FLAG);
}
INT
PlatformGetSocketError(VOID)
{
return PLATFORM_LAST_SOCKET_ERROR;
}

View file

@ -0,0 +1,78 @@
/**
* @file platform-socket.h
* @author Max Raulea (max.raulea@hyperdbg.org)
* @brief User mode cross-platform interface for the TCP remote-debugging transport
* @details The remote-debugging command/result exchange in tcpclient.cpp /
* tcpserver.cpp is written against the BSD-socket API, which Winsock and
* POSIX share almost verbatim (socket / connect / bind / listen / accept /
* send / recv / shutdown / getaddrinfo). Only a handful of things diverge:
* Winsock's startup/cleanup lifecycle, closesocket vs close(2), the
* SD_SEND vs SHUT_WR shutdown flag, WSAGetLastError vs errno, and the
* address-length out-parameter type of accept() (int vs socklen_t). Those
* are isolated behind the Platform* wrappers / typedef below so the socket
* call sites stay shared. On Linux this header also pulls in the POSIX
* socket headers that back the portable calls; on Windows they come from
* <winsock2.h>/<ws2tcpip.h> (included by pch.h).
*
* @version 0.21
* @date 2026-07-22
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#pragma once
#if defined(__linux__)
# include "../../../../include/SDK/HyperDbgSdk.h"
# include <sys/socket.h>
# include <netdb.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# include <unistd.h>
#endif // defined(__linux__)
//
// Length type for the address-size out-parameter of accept() (and friends).
// Winsock uses int; POSIX uses socklen_t. Kept as a platform typedef so the
// call sites declare the right type without an inline #ifdef.
//
#if defined(_WIN32)
typedef int PLATFORM_SOCKLEN;
#elif defined(__linux__)
typedef socklen_t PLATFORM_SOCKLEN;
#endif
//
// INITIALIZE the socket subsystem before any socket call. Mirrors WSAStartup:
// returns 0 on success and non-zero on failure. The Winsock version request is
// kept internal. No-op on Linux (always returns 0).
//
INT
PlatformSocketInitialize(VOID);
//
// CLEAN UP the socket subsystem (Winsock WSACleanup; no-op on Linux).
//
VOID
PlatformSocketCleanup(VOID);
//
// CLOSE a socket (Winsock closesocket; POSIX close(2)).
//
INT
PlatformCloseSocket(SOCKET Socket);
//
// SHUT DOWN the sending side of a socket (Winsock shutdown(.., SD_SEND);
// POSIX shutdown(.., SHUT_WR)). Returns 0 on success, SOCKET_ERROR on failure.
//
INT
PlatformShutdownSocketSend(SOCKET Socket);
//
// LAST socket error for the calling thread (Winsock WSAGetLastError; POSIX
// errno). See the last-error caveat in platform-lib-calls.h: the numeric code
// spaces still differ; callers that only log or check non-zero are fine.
//
INT
PlatformGetSocketError(VOID);

View file

@ -32,6 +32,7 @@ set(SourceFiles
"../include/platform/user/code/platform-serial.c"
"../include/platform/user/code/platform-ioctl.c"
"../include/platform/user/code/platform-signal.c"
"../include/platform/user/code/platform-socket.c"
"../include/platform/user/code/windows-only/windows-privilege.c"
"../script-eval/code/Functions.c"
"../script-eval/code/Keywords.c"
@ -177,6 +178,7 @@ set_source_files_properties(
"../include/platform/user/code/platform-serial.c"
"../include/platform/user/code/platform-ioctl.c"
"../include/platform/user/code/platform-signal.c"
"../include/platform/user/code/platform-socket.c"
"../include/platform/user/code/windows-only/windows-privilege.c"
"../script-eval/code/Functions.c"
"../script-eval/code/Keywords.c"

View file

@ -0,0 +1,179 @@
/**
* @file namedpipe-linux.cpp
* @author Max Raulea (max.raulea@hyperdbg.org)
* @brief Linux stub implementations of the named-pipe transport (namedpipe.cpp)
* @details The Windows implementation (namedpipe.cpp) is a thin wrapper over the
* Win32 named-pipe IPC API: the server side uses
* CreateNamedPipe/ConnectNamedPipe/ReadFile/WriteFile, and the client
* side uses CreateFileA against the "\\.\pipe\..." name plus overlapped
* ReadFile/WriteFile with the g_OverlappedIoStructureFor*Debugger
* events. None of that maps 1:1 onto Linux, so the whole translation
* unit is swapped out on Linux (CMake `if(UNIX)` REMOVE_ITEM
* namedpipe.cpp + APPEND namedpipe-linux.cpp), mirroring the
* symbol.cpp -> symbol-linux.cpp / pe-parser.cpp -> pe-parser-linux.cpp
* / install.cpp -> install-linux.cpp pattern. namedpipe.cpp itself is
* left 100% untouched for the Windows build. Only the 10 public
* functions declared in namedpipe.h are provided here; the two internal
* *Example() demo functions are not part of the interface and simply do
* not exist in the Linux TU.
*
* The Create* entry points return INVALID_HANDLE_VALUE, so every caller
* bails before reaching the send/read/close paths those stay silent to
* avoid spamming a message on each loop iteration; only the Create*
* functions emit the "not supported" note.
*
* TODO(Linux) to make these real: back the transport with either a
* filesystem FIFO (mkfifo(3), matching the "named pipe" naming most
* closely) or, more usefully for bidirectional message framing, a Unix
* domain socket (AF_UNIX, socket/bind/listen/accept on the server side,
* socket/connect on the client side) whose path is derived from the
* "\\.\pipe\NAME" string. The overlapped/event machinery collapses to
* plain blocking read()/write() (or poll()) since a dedicated thread
* already owns each direction.
*
* @version 0.1
* @date 2026-07-22
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#include "pch.h"
#ifdef __linux__
////////////////////////////////////////////////////////////////////////////
// Server Side //
////////////////////////////////////////////////////////////////////////////
/**
* @brief Create a named-pipe server endpoint.
* @return HANDLE INVALID_HANDLE_VALUE named pipes are not supported on Linux
* yet (see file header for the FIFO / AF_UNIX plan).
*/
HANDLE
NamedPipeServerCreatePipe(LPCSTR PipeName, UINT32 OutputBufferSize, UINT32 InputBufferSize)
{
UNREFERENCED_PARAMETER(PipeName);
UNREFERENCED_PARAMETER(OutputBufferSize);
UNREFERENCED_PARAMETER(InputBufferSize);
ShowMessages("err, named-pipe communication is not supported on Linux yet\n");
return INVALID_HANDLE_VALUE;
}
/**
* @brief Wait for a client to connect to the server pipe.
* @return BOOLEAN FALSE not supported on Linux yet.
*/
BOOLEAN
NamedPipeServerWaitForClientConntection(HANDLE PipeHandle)
{
UNREFERENCED_PARAMETER(PipeHandle);
return FALSE;
}
/**
* @brief Read a message sent by the connected client.
* @return UINT32 0 not supported on Linux yet.
*/
UINT32
NamedPipeServerReadClientMessage(HANDLE PipeHandle, CHAR * BufferToSave, INT MaximumReadBufferLength)
{
UNREFERENCED_PARAMETER(PipeHandle);
UNREFERENCED_PARAMETER(BufferToSave);
UNREFERENCED_PARAMETER(MaximumReadBufferLength);
return 0;
}
/**
* @brief Send a message to the connected client.
* @return BOOLEAN FALSE not supported on Linux yet.
*/
BOOLEAN
NamedPipeServerSendMessageToClient(HANDLE PipeHandle,
CHAR * BufferToSend,
INT BufferSize)
{
UNREFERENCED_PARAMETER(PipeHandle);
UNREFERENCED_PARAMETER(BufferToSend);
UNREFERENCED_PARAMETER(BufferSize);
return FALSE;
}
/**
* @brief Close the server pipe handle.
* @return VOID no-op not supported on Linux yet.
*/
VOID
NamedPipeServerCloseHandle(HANDLE PipeHandle)
{
UNREFERENCED_PARAMETER(PipeHandle);
}
////////////////////////////////////////////////////////////////////////////
// Client Side //
////////////////////////////////////////////////////////////////////////////
/**
* @brief Connect to a named-pipe server endpoint.
* @return HANDLE INVALID_HANDLE_VALUE not supported on Linux yet.
*/
HANDLE
NamedPipeClientCreatePipe(LPCSTR PipeName)
{
UNREFERENCED_PARAMETER(PipeName);
ShowMessages("err, named-pipe communication is not supported on Linux yet\n");
return INVALID_HANDLE_VALUE;
}
/**
* @brief Connect to a named-pipe server endpoint using overlapped I/O.
* @return HANDLE INVALID_HANDLE_VALUE not supported on Linux yet.
*/
HANDLE
NamedPipeClientCreatePipeOverlappedIo(LPCSTR PipeName)
{
UNREFERENCED_PARAMETER(PipeName);
ShowMessages("err, named-pipe communication is not supported on Linux yet\n");
return INVALID_HANDLE_VALUE;
}
/**
* @brief Send a message to the server over the client pipe.
* @return BOOLEAN FALSE not supported on Linux yet.
*/
BOOLEAN
NamedPipeClientSendMessage(HANDLE PipeHandle, CHAR * BufferToSend, INT BufferSize)
{
UNREFERENCED_PARAMETER(PipeHandle);
UNREFERENCED_PARAMETER(BufferToSend);
UNREFERENCED_PARAMETER(BufferSize);
return FALSE;
}
/**
* @brief Read a message from the server over the client pipe.
* @return UINT32 0 not supported on Linux yet.
*/
UINT32
NamedPipeClientReadMessage(HANDLE PipeHandle, CHAR * BufferToRead, INT MaximumSizeOfBuffer)
{
UNREFERENCED_PARAMETER(PipeHandle);
UNREFERENCED_PARAMETER(BufferToRead);
UNREFERENCED_PARAMETER(MaximumSizeOfBuffer);
return 0;
}
/**
* @brief Close the client pipe handle.
* @return VOID no-op not supported on Linux yet.
*/
VOID
NamedPipeClientClosePipe(HANDLE PipeHandle)
{
UNREFERENCED_PARAMETER(PipeHandle);
}
#endif // __linux__

View file

@ -134,7 +134,7 @@ RemoteConnectionListen(PCSTR Port)
//
// Zero the buffer for next command
//
RtlZeroMemory(recvbuf, COMMUNICATION_BUFFER_SIZE);
PlatformZeroMemory(recvbuf, COMMUNICATION_BUFFER_SIZE);
while (true)
{
@ -175,7 +175,7 @@ RemoteConnectionListen(PCSTR Port)
//
// Zero the buffer for next command
//
RtlZeroMemory(recvbuf, COMMUNICATION_BUFFER_SIZE);
PlatformZeroMemory(recvbuf, COMMUNICATION_BUFFER_SIZE);
}
//
@ -271,13 +271,13 @@ RemoteConnectionThreadListeningToDebuggee(LPVOID lpParam)
//
// Trigger the event
//
SetEvent(g_EndOfMessageReceivedEvent);
PlatformSetEvent(g_EndOfMessageReceivedEvent);
}
//
// Clear the buffer
//
RtlZeroMemory(RecvBuf, COMMUNICATION_BUFFER_SIZE);
PlatformZeroMemory(RecvBuf, COMMUNICATION_BUFFER_SIZE);
}
//
@ -314,7 +314,6 @@ RemoteConnectionThreadListeningToDebuggee(LPVOID lpParam)
VOID
RemoteConnectionConnect(PCSTR Ip, PCSTR Port)
{
DWORD ThreadId;
CHAR Recv[3] = {0};
UINT32 BuffRecv = 0;
@ -412,7 +411,7 @@ RemoteConnectionConnect(PCSTR Ip, PCSTR Port)
//
if (g_EndOfMessageReceivedEvent == NULL)
{
g_EndOfMessageReceivedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
g_EndOfMessageReceivedEvent = PlatformCreateEvent(FALSE, FALSE);
}
//
@ -420,13 +419,9 @@ RemoteConnectionConnect(PCSTR Ip, PCSTR Port)
// the remote debuggee for new messages
// Listen for upcoming messages
//
g_RemoteDebuggeeListeningThread = CreateThread(
NULL,
0,
g_RemoteDebuggeeListeningThread = PlatformCreateThread(
RemoteConnectionThreadListeningToDebuggee,
NULL,
0,
&ThreadId);
NULL);
ShowMessages("connected to %s:%s\n", Ip, Port);
}
@ -458,7 +453,7 @@ RemoteConnectionSendCommand(const CHAR * sendbuf, INT len)
//
// We wait for the debuggee to send the message
//
WaitForSingleObject(
PlatformWaitForSingleObject(
g_EndOfMessageReceivedEvent,
INFINITE);

View file

@ -22,7 +22,6 @@
INT
CommunicationClientConnectToServer(PCSTR Ip, PCSTR Port, SOCKET * ConnectSocketArg)
{
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo *result = NULL, *ptr = NULL, hints;
INT IResult;
@ -30,14 +29,14 @@ CommunicationClientConnectToServer(PCSTR Ip, PCSTR Port, SOCKET * ConnectSocketA
//
// Initialize Winsock
//
IResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
IResult = PlatformSocketInitialize();
if (IResult != 0)
{
ShowMessages("err, WSAStartup failed (%x)\n", IResult);
return 1;
}
ZeroMemory(&hints, sizeof(hints));
PlatformZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
@ -49,7 +48,7 @@ CommunicationClientConnectToServer(PCSTR Ip, PCSTR Port, SOCKET * ConnectSocketA
if (IResult != 0)
{
ShowMessages("getaddrinfo failed (%x)\n", IResult);
WSACleanup();
PlatformSocketCleanup();
return 1;
}
@ -64,8 +63,8 @@ CommunicationClientConnectToServer(PCSTR Ip, PCSTR Port, SOCKET * ConnectSocketA
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET)
{
ShowMessages("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
ShowMessages("socket failed with error: %ld\n", PlatformGetSocketError());
PlatformSocketCleanup();
return 1;
}
@ -75,7 +74,7 @@ CommunicationClientConnectToServer(PCSTR Ip, PCSTR Port, SOCKET * ConnectSocketA
IResult = connect(ConnectSocket, ptr->ai_addr, (INT)ptr->ai_addrlen);
if (IResult == SOCKET_ERROR)
{
closesocket(ConnectSocket);
PlatformCloseSocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
@ -87,7 +86,7 @@ CommunicationClientConnectToServer(PCSTR Ip, PCSTR Port, SOCKET * ConnectSocketA
if (ConnectSocket == INVALID_SOCKET)
{
ShowMessages("unable to connect to the server\n");
WSACleanup();
PlatformSocketCleanup();
return 1;
}
@ -118,9 +117,9 @@ CommunicationClientSendMessage(SOCKET ConnectSocket, const CHAR * sendbuf, INT b
IResult = send(ConnectSocket, sendbuf, buflen, 0);
if (IResult == SOCKET_ERROR)
{
ShowMessages("err, send failed (%x)\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
ShowMessages("err, send failed (%x)\n", PlatformGetSocketError());
PlatformCloseSocket(ConnectSocket);
PlatformSocketCleanup();
return 1;
}
@ -141,7 +140,7 @@ CommunicationClientShutdownConnection(SOCKET ConnectSocket)
//
// shutdown the connection since no more data will be sent
//
IResult = shutdown(ConnectSocket, SD_SEND);
IResult = PlatformShutdownSocketSend(ConnectSocket);
if (IResult == SOCKET_ERROR)
{
//
@ -150,11 +149,11 @@ CommunicationClientShutdownConnection(SOCKET ConnectSocket)
//
/*
ShowMessages("err, shutdown failed (%x)\n", WSAGetLastError());
ShowMessages("err, shutdown failed (%x)\n", PlatformGetSocketError());
*/
closesocket(ConnectSocket);
WSACleanup();
PlatformCloseSocket(ConnectSocket);
PlatformSocketCleanup();
return 1;
}
return 0;
@ -197,7 +196,7 @@ CommunicationClientReceiveMessage(SOCKET ConnectSocket, CHAR * RecvBuf, UINT32 M
}
else
{
ShowMessages("\nrecv failed with error: %d\n", WSAGetLastError());
ShowMessages("\nrecv failed with error: %d\n", PlatformGetSocketError());
ShowMessages("the remote system closes the connection.\n\n");
return 1;
@ -218,8 +217,8 @@ CommunicationClientCleanup(SOCKET ConnectSocket)
//
// cleanup
//
closesocket(ConnectSocket);
WSACleanup();
PlatformCloseSocket(ConnectSocket);
PlatformSocketCleanup();
return 0;
}

View file

@ -32,8 +32,7 @@ CommunicationServerCreateServerAndWaitForClient(PCSTR Port,
SOCKET * ClientSocketArg,
SOCKET * ListenSocketArg)
{
WSADATA wsaData;
INT IResult;
INT IResult;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
@ -44,14 +43,14 @@ CommunicationServerCreateServerAndWaitForClient(PCSTR Port,
//
// Initialize Winsock
//
IResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
IResult = PlatformSocketInitialize();
if (IResult != 0)
{
ShowMessages("err, WSAStartup failed (%x)\n", IResult);
return 1;
}
ZeroMemory(&hints, sizeof(hints));
PlatformZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
@ -64,7 +63,7 @@ CommunicationServerCreateServerAndWaitForClient(PCSTR Port,
if (IResult != 0)
{
ShowMessages("err, getaddrinfo failed (%x)\n", IResult);
WSACleanup();
PlatformSocketCleanup();
return 1;
}
@ -75,9 +74,9 @@ CommunicationServerCreateServerAndWaitForClient(PCSTR Port,
socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET)
{
ShowMessages("socket failed with error: %ld\n", WSAGetLastError());
ShowMessages("socket failed with error: %ld\n", PlatformGetSocketError());
freeaddrinfo(result);
WSACleanup();
PlatformSocketCleanup();
return 1;
}
@ -87,10 +86,10 @@ CommunicationServerCreateServerAndWaitForClient(PCSTR Port,
IResult = ::bind(ListenSocket, result->ai_addr, (INT)result->ai_addrlen);
if (IResult == SOCKET_ERROR)
{
ShowMessages("err, bind failed (%x)\n", WSAGetLastError());
ShowMessages("err, bind failed (%x)\n", PlatformGetSocketError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
PlatformCloseSocket(ListenSocket);
PlatformSocketCleanup();
return 1;
}
@ -99,25 +98,25 @@ CommunicationServerCreateServerAndWaitForClient(PCSTR Port,
IResult = listen(ListenSocket, SOMAXCONN);
if (IResult == SOCKET_ERROR)
{
ShowMessages("err, listen failed (%x)\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
ShowMessages("err, listen failed (%x)\n", PlatformGetSocketError());
PlatformCloseSocket(ListenSocket);
PlatformSocketCleanup();
return 1;
}
//
// Accept a client socket
//
sockaddr_in name = {0};
INT AddrLen = sizeof(name);
sockaddr_in name = {0};
PLATFORM_SOCKLEN AddrLen = sizeof(name);
ClientSocket = accept(ListenSocket, (struct sockaddr *)&name, &AddrLen);
if (ClientSocket == INVALID_SOCKET)
{
ShowMessages("err, accept failed (%x)\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
ShowMessages("err, accept failed (%x)\n", PlatformGetSocketError());
PlatformCloseSocket(ListenSocket);
PlatformSocketCleanup();
return 1;
}
@ -166,9 +165,9 @@ CommunicationServerReceiveMessage(SOCKET ClientSocket, CHAR * recvbuf, INT recvb
}
else
{
ShowMessages("err, recv failed (%x)\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
ShowMessages("err, recv failed (%x)\n", PlatformGetSocketError());
PlatformCloseSocket(ClientSocket);
PlatformSocketCleanup();
return 1;
}
@ -196,9 +195,9 @@ CommunicationServerSendMessage(SOCKET ClientSocket, const CHAR * sendbuf, INT le
if (ISendResult == SOCKET_ERROR)
{
/*
ShowMessages("err, send failed (%x)\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
ShowMessages("err, send failed (%x)\n", PlatformGetSocketError());
PlatformCloseSocket(ClientSocket);
PlatformSocketCleanup();
*/
return 1;
}
@ -221,12 +220,12 @@ CommunicationServerShutdownAndCleanupConnection(SOCKET ClientSocket,
//
// No longer need server socket
//
closesocket(ListenSocket);
PlatformCloseSocket(ListenSocket);
//
// shutdown the connection since we're done
//
IResult = shutdown(ClientSocket, SD_SEND);
IResult = PlatformShutdownSocketSend(ClientSocket);
if (IResult == SOCKET_ERROR)
{
//
@ -235,19 +234,19 @@ CommunicationServerShutdownAndCleanupConnection(SOCKET ClientSocket,
//
/*
ShowMessages("err, shutdown failed (%x)\n", WSAGetLastError());
ShowMessages("err, shutdown failed (%x)\n", PlatformGetSocketError());
*/
closesocket(ClientSocket);
WSACleanup();
PlatformCloseSocket(ClientSocket);
PlatformSocketCleanup();
return 1;
}
//
// cleanup
//
closesocket(ClientSocket);
WSACleanup();
PlatformCloseSocket(ClientSocket);
PlatformSocketCleanup();
return 0;
}

View file

@ -137,6 +137,7 @@ msbuild "$(SolutionDir)dependencies\zydis\msvc\Zydis.sln" /m /p:Configuration="R
<ClInclude Include="..\include\platform\user\header\platform-serial.h" />
<ClInclude Include="..\include\platform\user\header\platform-ioctl.h" />
<ClInclude Include="..\include\platform\user\header\platform-signal.h" />
<ClInclude Include="..\include\platform\user\header\platform-socket.h" />
<ClInclude Include="..\include\platform\general\header\nt-list.h" />
<ClInclude Include="..\include\platform\user\header\windows-only\windows-privilege.h" />
<ClInclude Include="..\include\platform\user\header\Windows.h" />
@ -179,6 +180,7 @@ msbuild "$(SolutionDir)dependencies\zydis\msvc\Zydis.sln" /m /p:Configuration="R
<ClCompile Include="..\include\platform\user\code\platform-serial.c" />
<ClCompile Include="..\include\platform\user\code\platform-ioctl.c" />
<ClCompile Include="..\include\platform\user\code\platform-signal.c" />
<ClCompile Include="..\include\platform\user\code\platform-socket.c" />
<ClCompile Include="..\include\platform\user\code\windows-only\windows-privilege.c" />
<ClCompile Include="..\script-eval\code\Functions.c" />
<ClCompile Include="..\script-eval\code\Keywords.c" />

View file

@ -179,6 +179,9 @@
<ClInclude Include="..\include\platform\user\header\platform-signal.h">
<Filter>header\platform</Filter>
</ClInclude>
<ClInclude Include="..\include\platform\user\header\platform-socket.h">
<Filter>header\platform</Filter>
</ClInclude>
<ClInclude Include="..\include\platform\general\header\nt-list.h">
<Filter>header\platform</Filter>
</ClInclude>
@ -721,6 +724,9 @@
<ClCompile Include="..\include\platform\user\code\platform-signal.c">
<Filter>code\platform</Filter>
</ClCompile>
<ClCompile Include="..\include\platform\user\code\platform-socket.c">
<Filter>code\platform</Filter>
</ClCompile>
<ClCompile Include="code\app\messaging.cpp">
<Filter>code\app</Filter>
</ClCompile>

View file

@ -173,6 +173,11 @@ typedef const wchar_t *LPCWCHAR, *PCWCHAR;
//
#include "platform/user/header/platform-signal.h"
//
// Platform socket transport (cross-platform TCP remote-debugging I/O)
//
#include "platform/user/header/platform-socket.h"
//
// NT-style intrusive linked-list helpers + CONTAINING_RECORD (self-guards to
// non-Windows; Windows gets these from <windows.h> / the native-SDK shim)

View file

@ -52,6 +52,7 @@ User-mode abstractions in `include/platform/user/` (`header/` = interface,
| `platform-serial.{h,c}` | Serial byte transport for remote kernel debugging | **Stub** — Linux branch returns false; termios impl TODO |
| `platform-ioctl.{h,c}` | Local kernel-driver IOCTL interface (`PlatformDeviceIoControl`) + device open (`PlatformOpenDevice`) | **Stub** — no Linux kernel module yet; `PlatformOpenDevice` returns `INVALID_HANDLE_VALUE` |
| `platform-signal.{h,c}` | Console control handler (Ctrl-C / Ctrl-Break) | Implemented (blocks signals + `sigwait` thread) |
| `platform-socket.{h,c}` | TCP remote-debugging transport: the few Winsock ops that diverge from POSIX (`WSAStartup`/`WSACleanup` lifecycle, `closesocket`, `SD_SEND` shutdown, `WSAGetLastError`) + the `accept()` length-type (`PLATFORM_SOCKLEN`). Also owns the Linux POSIX socket-header includes | Implemented (BSD sockets) — the portable socket calls stay at the tcpclient/tcpserver call sites |
Kernel-mode equivalents live in `include/platform/kernel/`. Two were extended for
the port because the shared `script-eval/` code compiles in both user and kernel
@ -371,6 +372,45 @@ Followed pattern-2 (like symbol/pe-parser/install): new `namedpipe-linux.cpp`
6 callers link the stubs transparently (forwarding/kd/debug/export/tests/test).
See the Linux-replacement-files table above for the FIFO/AF_UNIX TODO.
### TCP transport (tcpclient/tcpserver/remote-connection) — DONE (2026-07-22)
The TCP remote-debugging path. Unlike namedpipe, the socket code is genuinely
cross-platform — Winsock and POSIX share the BSD-socket API almost verbatim — so
it stays as shared `.cpp` (no `-linux.cpp` fork). A new **`platform-socket.{h,c}`
module** (sibling to platform-serial/-signal; wired into pch.h, top-level +
libhyperdbg CMake, and the Windows `.vcxproj`/`.filters`) isolates the handful of
things that actually diverge. User chose the platform-API route over Winsock-name
shims in `Environment.h`.
- **`communication/tcpclient.cpp` / `tcpserver.cpp`** — the portable calls
(`socket`/`connect`/`bind`/`listen`/`accept`/`send`/`recv`/`shutdown`/
`getaddrinfo`) stay at the call sites unchanged. Swapped only the divergent
ones to `Platform*`: `WSAStartup(MAKEWORD(2,2),&wsaData)``PlatformSocketInitialize()`
(WSADATA local + MAKEWORD dropped; keeps the `IResult != 0` shape — wrapper
returns 0 on success), `WSACleanup()``PlatformSocketCleanup()`,
`closesocket``PlatformCloseSocket`, `shutdown(...,SD_SEND)``PlatformShutdownSocketSend`,
`WSAGetLastError()``PlatformGetSocketError()`, plus the bucket-1
`ZeroMemory``PlatformZeroMemory`. tcpserver's `accept()` length out-param
`INT AddrLen``PLATFORM_SOCKLEN AddrLen` — the one genuine type incompatibility
(Winsock `int*` vs POSIX `socklen_t*`).
- **`communication/remote-connection.cpp`** — bucket-1 sweep (`.listen`/`.connect`
command layer over the sockets): `RtlZeroMemory`×3→`PlatformZeroMemory`,
`SetEvent``PlatformSetEvent`, `CreateEvent(NULL,FALSE,FALSE,NULL)``PlatformCreateEvent(FALSE,FALSE)`,
`CreateThread(...)``PlatformCreateThread(fn,NULL)` (unused `DWORD ThreadId` local
dropped), `WaitForSingleObject``PlatformWaitForSingleObject`.
- **`platform-socket.{h,c}`** (pure addition): `PlatformSocketInitialize`/
`PlatformSocketCleanup`/`PlatformCloseSocket`/`PlatformShutdownSocketSend`/
`PlatformGetSocketError` + the `PLATFORM_SOCKLEN` typedef. The `.c` maps the
divergent primitives (close / shutdown-flag / last-error) via small per-OS
macros so each wrapper body is written once; only the WSAStartup vs no-op
lifecycle keeps a small in-body guard. The `.h` also owns the Linux POSIX
socket-header includes (`<sys/socket.h>`/`<netdb.h>`/`<netinet/in.h>`/
`<arpa/inet.h>`/`<unistd.h>`), so any TU using sockets gets them via pch.
⚠️ Linux branches not yet exercised at runtime (compile-verified only).
Note the pre-existing latent teardown-ordering issue is unchanged; see the
`PlatformTerminateThread` TODO below (remote-connection's listening thread).
---
## TODO ledger — revisit before Linux is functional