2V1-a: port the EterLib network layer and the Crypto++ packet cipher

NetStream/NetAddress/NetDevice/NetPacketHeaderMap and EterBase/cipher.cpp
are mechanical copies. The winsock shim maps Winsock onto BSD sockets and
keeps the Winsock semantics CNetworkStream relies on: select ignores nfds,
a socket whose connect failed is not writable (40250 times out instead),
EINPROGRESS reads as WSAEWOULDBLOCK, and SIGPIPE is ignored.

port.net covers loopback connect, send/recv, peer close, the refused
connect timeout and the client/server key agreement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-09-23 14:27:57 +09:00
co-authored by Claude Opus 5.5
parent afe63bfa61
commit cd3b8b506f
10 changed files with 3881 additions and 1 deletions
+62 -1
View File
@@ -1,14 +1,75 @@
#pragma once
// Shim for <winsock.h> on non-Windows targets: the BSD socket types under their Winsock names.
// Shim for <winsock.h> on non-Windows targets: the BSD socket API under its Winsock names, with the
// Winsock semantics 40250 relies on where the two differ (see the notes on each function).
#include "windows.h"
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
typedef int SOCKET;
typedef struct sockaddr SOCKADDR;
typedef struct sockaddr* PSOCKADDR;
typedef struct sockaddr_in SOCKADDR_IN;
typedef struct in_addr IN_ADDR;
typedef struct timeval TIMEVAL;
typedef struct hostent HOSTENT;
#define INVALID_SOCKET (-1)
#define SOCKET_ERROR (-1)
#define WSAEWOULDBLOCK EWOULDBLOCK
typedef struct WSAData
{
WORD wVersion;
WORD wHighVersion;
} WSADATA;
// There is no Winsock DLL to start. A send on a socket the peer has closed raises SIGPIPE on POSIX
// where Winsock returns an error, so the process ignores it from here on.
inline int WSAStartup(WORD version, WSADATA* data)
{
signal(SIGPIPE, SIG_IGN);
if (data)
data->wVersion = data->wHighVersion = version;
return 0;
}
inline int WSACleanup() { return 0; }
// A non-blocking connect() answers WSAEWOULDBLOCK on Winsock and EINPROGRESS on POSIX.
inline int WSAGetLastError() { return errno == EINPROGRESS ? WSAEWOULDBLOCK : errno; }
inline int closesocket(SOCKET s) { return close(s); }
inline int ioctlsocket(SOCKET s, long cmd, DWORD* argp)
{
int value = static_cast<int>(*argp);
return ioctl(s, static_cast<unsigned long>(cmd), &value);
}
// Winsock ignores nfds, and a socket whose connect failed is reported only in exceptfds; POSIX needs
// nfds and marks such a socket writable. Callers pass 0 and treat "writable" as "connected"
// (CNetworkStream::Process), so writable sockets without a peer are dropped from the write set.
inline int mt_winsock_select(fd_set* readfds, fd_set* writefds, fd_set* exceptfds, TIMEVAL* timeout)
{
int ret = ::select(FD_SETSIZE, readfds, writefds, exceptfds, timeout);
if (ret <= 0 || !writefds)
return ret;
for (int fd = 0; fd < FD_SETSIZE; ++fd)
{
if (!FD_ISSET(fd, writefds))
continue;
sockaddr_in peer;
socklen_t len = sizeof(peer);
if (getpeername(fd, reinterpret_cast<sockaddr*>(&peer), &len) != 0)
FD_CLR(fd, writefds);
}
return ret;
}
#define select(nfds, readfds, writefds, exceptfds, timeout) mt_winsock_select(readfds, writefds, exceptfds, timeout)