Badminton-Scoreboard/Libraries/libil2cpp/include/os/Socket.h
2023-10-08 10:24:48 +08:00

463 lines
17 KiB
C++

#pragma once
#include <string>
#include <vector>
#include "il2cpp-config.h"
#include "os/ErrorCodes.h"
#include "os/Atomic.h"
#include "os/Mutex.h"
#include "os/WaitStatus.h"
#include "utils/Expected.h"
#include "utils/NonCopyable.h"
namespace il2cpp
{
namespace os
{
class SocketImpl;
enum AddressFamily
{
kAddressFamilyError = -1,
kAddressFamilyUnspecified = 0,// AF_UNSPEC
kAddressFamilyUnix = 1,// AF_UNIX
kAddressFamilyInterNetwork = 2,// AF_INET
kAddressFamilyIpx = 3,// AF_IPX
kAddressFamilySna = 4,// AF_SNA
kAddressFamilyDecNet = 5,// AF_DECnet
kAddressFamilyAppleTalk = 6,// AF_APPLETALK
kAddressFamilyInterNetworkV6 = 7,// AF_INET6
kAddressFamilyIrda = 8,// AF_IRDA
};
enum SocketType
{
kSocketTypeError = -1,
kSocketTypeStream = 0,// SOCK_STREAM
kSocketTypeDgram = 1,// SOCK_DGRAM
kSocketTypeRaw = 2,// SOCK_RAW
kSocketTypeRdm = 3,// SOCK_RDM
kSocketTypeSeqpacket = 4,// SOCK_SEQPACKET
};
enum ProtocolType
{
kProtocolTypeUnknown = -1,
kProtocolTypeIP = 0,
kProtocolTypeIcmp = 1,
kProtocolTypeIgmp = 2,
kProtocolTypeGgp = 3,
kProtocolTypeTcp = 6,
kProtocolTypePup = 12,
kProtocolTypeUdp = 17,
kProtocolTypeIdp = 22,
kProtocolTypeND = 77,
kProtocolTypeRaw = 255,
kProtocolTypeUnspecified = 0,
kProtocolTypeIpx = 1000,
kProtocolTypeSpx = 1256,
kProtocolTypeSpxII = 1257,
// #if NET_1_1
kProtocolTypeIPv6 = 41,
// #endif
// #if NET_2_0
kProtocolTypeIPv4 = 4,
kProtocolTypeIPv6RoutingHeader = 43,
kProtocolTypeIPv6FragmentHeader = 44,
kProtocolTypeIPSecEncapsulatingSecurityPayload = 50,
kProtocolTypeIPSecAuthenticationHeader = 51,
kProtocolTypeIcmpV6 = 58,
kProtocolTypeIPv6NoNextHeader = 59,
kProtocolTypeIPv6DestinationOptions = 60,
kProtocolTypeIPv6HopByHopOptions = 0,
// #endif
};
enum SocketFlags
{
kSocketFlagsNone = 0x00000000,
kSocketFlagsOutOfBand = 0x00000001,
kSocketFlagsPeek = 0x00000002,
kSocketFlagsDontRoute = 0x00000004,
kSocketFlagsMaxIOVectorLength = 0x00000010,
// #if NET_2_0
kSocketFlagsTruncated = 0x00000100,
kSocketFlagsControlDataTruncated = 0x00000200,
kSocketFlagsBroadcast = 0x00000400,
kSocketFlagsMulticast = 0x00000800,
// #endif
kSocketFlagsPartial = 0x00008000,
};
enum SocketOptionLevel
{
kSocketOptionLevelSocket = 65535,
kSocketOptionLevelIP = 0,
kSocketOptionLevelTcp = 6,
kSocketOptionLevelUdp = 17,
//#if NET_1_1
kSocketOptionLevelIPv6 = 41,
//#endif
};
enum SocketOptionName
{
kSocketOptionNameDebug = 1,
kSocketOptionNameAcceptConnection = 2,
kSocketOptionNameReuseAddress = 4,
kSocketOptionNameKeepAlive = 8,
kSocketOptionNameDontRoute = 16,
kSocketOptionNameBroadcast = 32,
kSocketOptionNameUseLoopback = 64,
kSocketOptionNameLinger = 128,
kSocketOptionNameOutOfBandInline = 256,
kSocketOptionNameDontLinger = -129,
kSocketOptionNameExclusiveAddressUse = -5,
kSocketOptionNameSendBuffer = 4097,
kSocketOptionNameReceiveBuffer = 4098,
kSocketOptionNameSendLowWater = 4099,
kSocketOptionNameReceiveLowWater = 4100,
kSocketOptionNameSendTimeout = 4101,
kSocketOptionNameReceiveTimeout = 4102,
kSocketOptionNameError = 4103,
kSocketOptionNameType = 4104,
kSocketOptionNameMaxConnections = 2147483647,
kSocketOptionNameIPOptions = 1,
kSocketOptionNameHeaderIncluded = 2,
kSocketOptionNameTypeOfService = 3,
kSocketOptionNameIpTimeToLive = 4,
kSocketOptionNameMulticastInterface = 9,
kSocketOptionNameMulticastTimeToLive = 10,
kSocketOptionNameMulticastLoopback = 11,
kSocketOptionNameAddMembership = 12,
kSocketOptionNameDropMembership = 13,
kSocketOptionNameDontFragment = 14,
kSocketOptionNameAddSourceMembership = 15,
kSocketOptionNameDropSourceMembership = 16,
kSocketOptionNameBlockSource = 17,
kSocketOptionNameUnblockSource = 18,
kSocketOptionNamePacketInformation = 19,
kSocketOptionNameNoDelay = 1,
kSocketOptionNameBsdUrgent = 2,
kSocketOptionNameExpedited = 2,
kSocketOptionNameNoChecksum = 1,
kSocketOptionNameChecksumCoverage = 20,
kSocketOptionNameIPv6Only = 27,
// #if NET_2_0
kSocketOptionNameHopLimit = 21,
kSocketOptionNameUpdateAcceptContext = 28683,
kSocketOptionNameUpdateConnectContext = 28688,
// #endif
};
enum PollFlags
{
kPollFlagsNone = 0,
kPollFlagsIn = 1,
kPollFlagsPri = 2,
kPollFlagsOut = 4,
kPollFlagsErr = 8,
kPollFlagsHup = 0x10,
kPollFlagsNVal = 0x20,
kPollFlagsAny = 0xffffffff
};
enum SocketError
{
kInterrupted = 4,// EINTR on POSIX and WSAEINTR on Windows
kInvalidHandle = 9 // EBADF on POSIX and WSAEBADF on Windows
};
inline void operator|=(PollFlags& left, PollFlags right)
{
left = static_cast<PollFlags>(static_cast<int>(left) | static_cast<int>(right));
}
enum TransmitFileOptions
{
kTransmitFileOptionsUseDefaultWorkerThread = 0x00000000,
kTransmitFileOptionsDisconnect = 0x00000001,
kTransmitFileOptionsReuseSocket = 0x00000002,
kTransmitFileOptionsWriteBehind = 0x00000004,
kTransmitFileOptionsUseSystemThread = 0x00000010,
kTransmitFileOptionsUseKernelApc = 0x00000020,
};
class Socket;
struct PollRequest
{
PollRequest()
: fd(-1)
, events(kPollFlagsNone)
, revents(kPollFlagsNone)
{}
PollRequest(int64_t value)
: fd(value)
, events(kPollFlagsNone)
, revents(kPollFlagsNone)
{}
int64_t fd;
PollFlags events;
PollFlags revents;
};
#if IL2CPP_SUPPORT_IPV6
struct IPv6Address
{
uint8_t addr[16];
};
#endif
// TODO: this should really be UNIX_PATH_MAX or SUN_LEN(n)
#define END_POINT_MAX_PATH_LEN 255
#if IL2CPP_COMPILER_MSVC
#pragma warning( push )
#pragma warning( disable : 4200 )
#endif
struct EndPointInfo
{
AddressFamily family;
union
{
struct
{
uint32_t port;
uint32_t address;
} inet;
char path[END_POINT_MAX_PATH_LEN];
uint8_t raw[IL2CPP_ZERO_LEN_ARRAY];
} data;
};
#if IL2CPP_COMPILER_MSVC
#pragma warning( pop )
#endif
// NOTE(gab): this must be binary compatible with Windows's WSABUF
struct WSABuf
{
uint32_t length;
void *buffer;
};
// NOTE(gab): this must be binary compatible with Window's TRANSMIT_FILE_BUFFERS
struct TransmitFileBuffers
{
void *head;
uint32_t head_length;
void *tail;
uint32_t tail_length;
};
// Note: this callback can be invoked by the os-specific implementation when an
// interrupt is received or when the native code is looping in a potentially long
// loop.
// If the callback retun false, the executiong of the os-specific method is
// gracefully interrupted, and an error is supposed to be returned by the
// os-specific implementation.
// The callback is allowed to throw exceptions (for example a ThreadAborted exception):
// in this case, it is up to the os-specific implementation to properly deal with
// cleaning up the temporarely allocated memory (if any).
typedef bool (*ThreadStatusCallback)();
/// Sockets should generally be referenced through SocketHandles for thread-safety.
/// Handles are stored in a table and can be safely used even when the socket has already
/// been deleted.
typedef intptr_t SocketHandle;
class Socket : public il2cpp::utils::NonCopyable
{
public:
Socket(ThreadStatusCallback thread_status_callback);
~Socket();
// Note: this Create is only used internally
WaitStatus Create(int64_t fd, int32_t family, int32_t type, int32_t protocol);
WaitStatus Create(AddressFamily family, SocketType type, ProtocolType protocol);
bool IsClosed();
void Close();
int64_t GetDescriptor();
ErrorCode GetLastError() const;
WaitStatus SetBlocking(bool blocking);
WaitStatus Listen(int32_t blacklog);
WaitStatus Bind(const char *path);
WaitStatus Bind(uint32_t address, uint16_t port);
WaitStatus Bind(const char *address, uint16_t port);
utils::Expected<WaitStatus> Bind(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port);
WaitStatus Connect(const char *path);
WaitStatus Connect(uint32_t address, uint16_t port);
utils::Expected<WaitStatus> Connect(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port);
WaitStatus Disconnect(bool reuse);
WaitStatus Shutdown(int32_t how);
WaitStatus GetLocalEndPointInfo(EndPointInfo &info);
WaitStatus GetRemoteEndPointInfo(EndPointInfo &info);
WaitStatus Receive(const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
WaitStatus Send(const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
WaitStatus SendArray(WSABuf *wsabufs, int32_t count, int32_t *sent, SocketFlags c_flags);
WaitStatus ReceiveArray(WSABuf *wsabufs, int32_t count, int32_t *len, SocketFlags c_flags);
WaitStatus SendTo(uint32_t address, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
utils::Expected<WaitStatus> SendTo(const char *path, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
utils::Expected<WaitStatus> SendTo(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
WaitStatus RecvFrom(uint32_t address, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len, os::EndPointInfo &ep);
utils::Expected<WaitStatus> RecvFrom(const char *path, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len, os::EndPointInfo &ep);
utils::Expected<WaitStatus> RecvFrom(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len, os::EndPointInfo &ep);
WaitStatus Available(int32_t *amount);
WaitStatus Accept(Socket **socket);
WaitStatus Ioctl(int32_t command, const uint8_t *in_data, int32_t in_len, uint8_t *out_data, int32_t out_len, int32_t *written);
WaitStatus GetSocketOption(SocketOptionLevel level, SocketOptionName name, uint8_t *buffer, int32_t *length);
WaitStatus GetSocketOptionFull(SocketOptionLevel level, SocketOptionName name, int32_t *first, int32_t *second);
WaitStatus SetSocketOption(SocketOptionLevel level, SocketOptionName name, int32_t value);
WaitStatus SetSocketOptionLinger(SocketOptionLevel level, SocketOptionName name, bool enabled, int32_t seconds);
WaitStatus SetSocketOptionArray(SocketOptionLevel level, SocketOptionName name, const uint8_t *buffer, int32_t length);
WaitStatus SetSocketOptionMembership(SocketOptionLevel level, SocketOptionName name, uint32_t group_address, uint32_t local_address);
#if IL2CPP_SUPPORT_IPV6
WaitStatus SetSocketOptionMembership(SocketOptionLevel level, SocketOptionName name, IPv6Address ipv6, uint64_t interfaceOffset);
#endif
WaitStatus SendFile(const char *filename, TransmitFileBuffers *buffers, TransmitFileOptions options);
#if IL2CPP_SUPPORT_IPV6_SUPPORT_QUERY
static bool IsIPv6Supported();
#endif
static WaitStatus Poll(std::vector<PollRequest> &requests, int32_t count, int32_t timeout, int32_t *result, int32_t *error);
static WaitStatus Poll(std::vector<PollRequest> &requests, int32_t timeout, int32_t *result, int32_t *error);
static WaitStatus Poll(PollRequest &request, int32_t timeout, int32_t *result, int32_t *error);
static WaitStatus GetHostName(std::string &name);
static WaitStatus GetHostByName(const std::string &host, std::string &name, std::vector<std::string> &aliases, std::vector<std::string> &addresses);
// The pointers in addr_list are allocated with the il2cpp::utils::Memory::Malloc method. They should he freed by the caller using il2cpp::utils::Memory::Free.
static WaitStatus GetHostByName(const std::string &host, std::string &name, int32_t &family, std::vector<std::string> &aliases, std::vector<void*> &addr_list, int32_t &addr_size);
static WaitStatus GetHostByAddr(const std::string &address, std::string &name, std::vector<std::string> &aliases, std::vector<std::string> &addr_list);
static void Startup();
static void Cleanup();
private:
SocketImpl* m_Socket;
friend Socket* AcquireSocketHandle(SocketHandle handle);
friend void ReleaseSocketHandle(SocketHandle handle, Socket* socketToRelease, bool forceTableRemove);
uint32_t m_RefCount;
};
enum
{
kInvalidSocketHandle = -1
};
SocketHandle CreateSocketHandle(Socket* socket);
Socket* AcquireSocketHandle(SocketHandle handle);
void ReleaseSocketHandle(SocketHandle handle, Socket* socketToRelease, bool forceTableRemove = false);
inline SocketHandle PointerToSocketHandle(void* ptr)
{
// Double cast to avoid warnings.
return static_cast<SocketHandle>(reinterpret_cast<size_t>(ptr));
}
/// Helper to automatically acquire and release a Socket within a scope.
struct SocketHandleWrapper
{
SocketHandleWrapper()
: m_Handle(kInvalidSocketHandle)
, m_Socket(NULL) {}
SocketHandleWrapper(SocketHandle handle)
: m_Handle(handle)
{
m_Socket = AcquireSocketHandle(handle);
}
SocketHandleWrapper(const SocketHandleWrapper& other)
{
m_Handle = other.m_Handle;
if (m_Handle != kInvalidSocketHandle)
m_Socket = AcquireSocketHandle(m_Handle);
else
m_Socket = NULL;
}
~SocketHandleWrapper()
{
Release();
}
void Acquire(SocketHandle handle)
{
Release();
m_Handle = handle;
m_Socket = AcquireSocketHandle(handle);
}
void Release()
{
if (m_Socket)
ReleaseSocketHandle(m_Handle, m_Socket);
m_Socket = NULL;
m_Handle = kInvalidSocketHandle;
}
bool IsValid() const
{
return (m_Socket != NULL);
}
SocketHandle GetHandle() const
{
return m_Handle;
}
Socket* GetSocket() const
{
return m_Socket;
}
Socket* operator->() const
{
return GetSocket();
}
SocketHandleWrapper& operator=(const SocketHandleWrapper& other)
{
Acquire(other.GetHandle());
return *this;
}
private:
SocketHandle m_Handle;
Socket* m_Socket;
};
}
}