Socket.h
16.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
#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/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)();
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);
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);
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);
WaitStatus SendTo(const char *path, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
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);
WaitStatus RecvFrom(const char *path, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len, os::EndPointInfo &ep);
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;
};
/// 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 uint32_t SocketHandle;
enum
{
kInvalidSocketHandle = 0
};
SocketHandle CreateSocketHandle(Socket* socket);
Socket* AcquireSocketHandle(SocketHandle handle);
void ReleaseSocketHandle(SocketHandle handle);
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 = 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;
};
}
}