UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
Socket.inl
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5// {{{1 platforms ..............................................................
6
7#define IAS_HTTP_SOCKET_FORWARD(Src, Dest) \
8 template <typename... ArgTypes> \
9 static auto Socket_##Src(ArgTypes&&... Args) { \
10 return Dest(Forward<ArgTypes>(Args)...); \
11 }
12
13#if PLATFORM_MICROSOFT
14# if !defined(NO_UE_INCLUDES)
16# include <winsock2.h>
17# include <ws2tcpip.h>
18# include <mswsock.h>
20# else
21# include <winsock2.h>
22# include <ws2tcpip.h>
23# pragma comment(lib, "Ws2_32.lib")
24# endif // NO_UE_INCLUDES
25
26 // Winsock defines "PF_MAX" indicating the protocol family count. This
27 // however competes with UE definitions related to pixel formats.
28 #if defined(PF_MAX)
29 # undef PF_MAX
30 #endif
31
32 namespace UE::IoStore::HTTP
33 {
34 using MsgFlagType = int;
35
36 enum {
38 MSG_NOSIGNAL = 0,
39 };
40
41# define IAS_HTTP_USE_POLL
42 template <typename... ArgTypes>
43 static auto poll(ArgTypes&&... Args)
44 {
45 return WSAPoll(Forward<ArgTypes>(Args)...);
46 }
47 } // namespace UE::IoStore::HTTP
48# include "Overlapped.inl"
49#elif PLATFORM_APPLE | PLATFORM_UNIX | PLATFORM_ANDROID
50# include <arpa/inet.h>
51# include <fcntl.h>
52# include <netdb.h>
53# include <netinet/tcp.h>
54# include <poll.h>
55# include <sys/select.h>
56# include <sys/socket.h>
57# include <unistd.h>
58 namespace UE::IoStore::HTTP
59 {
60 using SocketType = int;
61 using MsgFlagType = int;
62 static int32 closesocket(int32 Socket) { return close(Socket); }
63 }
64# define IAS_HTTP_USE_POLL
65#else
66# include "CoreHttp/Http.inl"
67#endif
68
69#if defined(IAS_HTTP_SOCKET_FORWARD)
70 namespace UE::IoStore::HTTP {
81 IAS_HTTP_SOCKET_FORWARD(Socket, socket)
82
84 static PollType Poll_CreateContext() { return 0; }
85 static void Poll_DestroyContext(PollType) {}
86 static bool Poll_Register(...) { return true; }
87
88#if defined(IAS_HTTP_USE_POLL)
89 template <typename... ArgTypes>
90 static auto Poll_Wait(PollType, ArgTypes&&... Args)
91 {
92 return poll(Forward<ArgTypes>(Args)...);
93 }
94#endif
95 } // namespace UE::IoStore::HTTP
96#endif // IAS_HTTP_SOCKET_FORWARD
97
98namespace UE::IoStore::HTTP {
99
101static const SocketType InvalidSocket = SocketType(~0ull);
102
103static_assert(sizeof(sockaddr_in::sin_addr) == sizeof(uint32));
104
105#if PLATFORM_MICROSOFT
106 static int32 LastSocketResult() { return WSAGetLastError(); }
107# define IsSocketResult(err) (LastSocketResult() == WSA##err)
108#else
109 static int32 LastSocketResult() { return errno; }
110# define IsSocketResult(err) int32(LastSocketResult() == err)
111 static_assert(EWOULDBLOCK == EAGAIN);
112#endif
113
114// hton* can sometimes be implemented as a macro which does not work with the
115// forward approach above. Hence we have our own here. Thanks for reading!
118
119} // namespace UE::IoStore::HTTP
120
121// }}}
122
123namespace UE::IoStore::HTTP
124{
125
126// {{{1 wait ...................................................................
127
130{
131public:
132 FWaitable() = default;
133 FWaitable(FWaitable&&) = default;
135
136private:
137 friend class FSocket;
138 friend class FWaiter;
139 friend class FPoller;
141 SocketType Socket = InvalidSocket;
142
143private:
144 FWaitable(const FWaitable&) = delete;
145 FWaitable& operator = (const FWaitable&) = delete;
146};
147
150: Socket(InSocket)
151{
152}
153
154
155
156// {{{1 poll ...................................................................
157
159#if defined(IAS_HTTP_USE_POLL)
160 using FPollFdBase = pollfd;
161#else
163 {
167 static const int16 POLLIN = 1 << 0;
168 static const int16 POLLOUT = 1 << 1;
169 static const int16 POLLERR = 1 << 2;
170 static const int16 POLLHUP = POLLERR;
171 static const int16 POLLNVAL= POLLERR;
172 };
173#endif
174
177 : public FPollFdBase
178{
179 static const int16 PollIn = int16(POLLIN);
180 static const int16 PollOut = int16(POLLOUT);
181 static const int16 PollErr = int16(POLLERR);
182 static const int16 PollHup = int16(POLLHUP);
183 static const int16 PollNVal= int16(POLLNVAL);
185
186 FPollFd(SocketType Socket, int16 Events)
187 {
188 fd = FdType(Socket);
189 events = EventType(Events);
190 revents = EventType(0);
191 }
192
193 bool HasTrigger() const { return !!revents; }
194 bool HasSendTrigger() const { return !!(revents & EventType(PollOut)); }
195 bool HasRecvTrigger() const { return !!(revents & EventType(PollIn)); }
196
197private:
198 // The following is odd because POLLFD varies subtly from one platform to
199 // the next. With typedefs we can cleanly set members and not get narrowing
200 // warnings from the compiler.
201 using FdType = decltype(fd);
202 using EventType = decltype(events);
203};
204
207{
208public:
209 FPoller() { Handle = Poll_CreateContext(); }
210 FPoller(FPoller&& Rhs) { Swap(Handle, Rhs.Handle); }
211 ~FPoller() { Poll_DestroyContext(Handle); }
212 FPoller& operator = (FPoller&& Rhs) { Swap(Handle, Rhs.Handle); return *this; }
213 bool Register(const FWaitable& Waitable) { return Poll_Register(Handle, Waitable.Socket); }
215
216private:
217 FPoller(const FPoller&) = delete;
218 FPoller& operator = (const FPoller&) = delete;
219 PollType Handle = 0;
220};
221
224{
225#if defined(IAS_HTTP_USE_POLL)
226 static_assert(sizeof(FPollFd) == sizeof(pollfd));
227 return Poll_Wait(Handle, Polls, Num, TimeOutMs);
228#else
229 timeval TimeVal = {};
230 timeval* TimeValPtr = (TimeOutMs >= 0 ) ? &TimeVal : nullptr;
231 if (TimeOutMs > 0)
232 {
233 int32 TimeoutUs = TimeOutMs << 10;
234 TimeVal = { TimeOutMs >> 10, TimeoutUs & ((1 << 20) - 1) };
235 }
236
240
241 SocketType MaxFd = 0;
242 for (FPollFd& Poll : MakeArrayView(Polls, Num))
243 {
244 fd_set* RwSet = (Poll.events & FPollFd::PollIn) ? &FdSetRead : &FdSetWrite;
245 FD_SET(Poll.fd, RwSet);
246 FD_SET(Poll.fd, &FdSetExcept);
247 MaxFd = FMath::Max(Poll.fd, MaxFd);
248 }
249
251 if (Result <= 0)
252 {
253 return Result;
254 }
255
256 for (FPollFd& Poll : MakeArrayView(Polls, Num))
257 {
258 if (FD_ISSET(Poll.fd, &FdSetExcept))
259 {
260 Poll.revents = FPollFd::PollErr;
261 continue;
262 }
263
264 fd_set* RwSet = (Poll.events & FPollFd::PollIn) ? &FdSetRead : &FdSetWrite;
265 if (FD_ISSET(Poll.fd, RwSet))
266 {
267 Poll.revents = Poll.events;
268 }
269 }
270
271 return Result;
272#endif // IAS_HTTP_USE_POLL
273}
274
275
276
277// {{{1 waiter .................................................................
278
281{
282public:
283 enum class EWhat : uint8
284 {
285 None = 0b00,
286 Send = 0b01,
287 Recv = 0b10,
288 Both = Send|Recv
289 };
290
291 static int32 Wait(TArrayView<FWaiter> Waiters, FPoller& Poller, int32 TimeoutMs);
292
293 FWaiter() = default;
295 FWaiter(FWaiter&&) = default;
297 bool IsValid() const { return Socket != InvalidSocket; }
298 bool IsReady() const { return Ready != 0; }
299 void WaitFor(EWhat What) { WaitOn = What; }
301 uint32 GetIndex() const { return Index; }
302
303private:
304 SocketType Socket = InvalidSocket;
305 uint16 Index = 0;
306 EWhat WaitOn = EWhat::None;
307 uint8 Ready = 0;
308
309private:
310 FWaiter(const FWaiter&) = delete;
311 FWaiter& operator = (const FWaiter&) = delete;
312};
313
316: Socket(Waitable.Socket)
317{
318}
319
322{
323 uint16 Events[] = {
328 };
330 for (FWaiter& Waiter : Waiters)
331 {
332 Polls.Emplace(Waiter.Socket, Events[uint32(Waiter.WaitOn)]);
333 }
334
335 // Poll the sockets
336 int32 Result = Poller.Wait(Polls.GetData(), Polls.Num(), TimeoutMs);
337 if (Result <= 0)
338 {
339 return Result;
340 }
341
342 // Transfer poll results to the input sockets. We don't transfer across error
343 // states. Subsequent sockets ops can take care of that instead.
344 for (uint32 i = 0, n = Waiters.Num(); i < n; ++i)
345 {
346 const FPollFd& Poll = Polls[i];
347 if (!Poll.HasTrigger())
348 {
349 continue;
350 }
351
352 uint8 Value = 0;
353 if (Poll.HasSendTrigger()) Value |= uint8(EWhat::Send);
354 if (Poll.HasRecvTrigger()) Value |= uint8(EWhat::Recv);
355 Waiters[i].Ready = Value ? Value : uint8(EWhat::Both);
356 }
357
358 return Result;
359}
360
361
362
363// {{{1 socket .................................................................
364
367{
368public:
369 FSocket() = default;
371 FSocket(FSocket&& Rhs) { Move(MoveTemp(Rhs)); }
372 FSocket& operator = (FSocket&& Rhs) { Move(MoveTemp(Rhs)); return *this; }
373 bool IsValid() const { return Socket != InvalidSocket; }
374 FWaitable GetWaitable() const { return { Socket }; }
375 bool Create();
376 void Destroy();
378 void Disconnect();
379 FOutcome Send(const char* Data, uint32 Size);
380 FOutcome Recv(char* Dest, uint32 Size);
381 bool SetBlocking(bool bBlocking);
384
385private:
386 void Move(FSocket&& Rhs);
387 SocketType Socket = InvalidSocket;
388
389 FSocket(const FSocket&) = delete;
390 FSocket& operator = (const FSocket&) = delete;
391};
392
394void FSocket::Move(FSocket&& Rhs)
395{
396 check(!IsValid() || !Rhs.IsValid()); // currently we only want to pass one around
397 Swap(Socket, Rhs.Socket);
398}
399
402{
403 check(!IsValid());
405
406 if (!IsValid())
407 {
408 return false;
409 }
410
411 int32 Yes = 1;
412 Socket_SetSockOpt(Socket, IPPROTO_TCP, TCP_NODELAY, &(char&)(Yes), int32(sizeof(Yes)));
413
414 Trace(Socket, ETrace::SocketCreate);
415 return true;
416}
417
420{
421 if (Socket == InvalidSocket)
422 {
423 return;
424 }
425
426 Trace(Socket, ETrace::SocketDestroy);
427
428 Socket_Close(Socket);
429 Socket = InvalidSocket;
430}
431
434{
435 check(IsValid());
436
437 Trace(Socket, ETrace::Connect);
438 auto Return = [this] (FOutcome Outcome) {
439 Trace(Socket, ETrace::Connect, &Outcome);
440 return Outcome;
441 };
442
444
445 sockaddr_in AddrInet = { sizeof(sockaddr_in) };
446 AddrInet.sin_family = AF_INET;
447 AddrInet.sin_port = Socket_HtoNs(uint16(Port));
448 memcpy(&(AddrInet.sin_addr), &IpAddress, sizeof(IpAddress));
449
450 int32 Result = Socket_Connect(Socket, &(sockaddr&)AddrInet, uint32(sizeof(AddrInet)));
451
453 {
454 return Return(FOutcome::Waiting());
455 }
456
457 if (Result < 0)
458 {
459 return Return(FOutcome::Error("Socket connect failed", Result));
460 }
461
462 return Return(FOutcome::Ok());
463}
464
467{
468 check(IsValid());
469 Socket_Shutdown(Socket, SHUT_RDWR);
470}
471
474{
475 Trace(Socket, ETrace::Send);
476 int32 Result = Socket_Send(Socket, Data, Size, MsgFlagType(MSG_NOSIGNAL));
477
478 auto Return = [this] (FOutcome Outcome) {
479 Trace(Socket, ETrace::Send, &Outcome);
480 return Outcome;
481 };
482
483 if (Result > 0) return Return(FOutcome::Ok(Result));
484 if (Result == 0) return Return(FOutcome::Error("Send ATH0"));
485 if (IsSocketResult(EWOULDBLOCK)) return Return(FOutcome::Waiting());
486
488 {
489 int32 Error = 0;
490 socklen_t ErrorSize = sizeof(Error);
491 Result = Socket_GetSockOpt(Socket, SOL_SOCKET, SO_ERROR, (char*)&Error, &ErrorSize);
492 if (Result < 0 || Error != 0)
493 {
494 Result = (Result < 0) ? LastSocketResult() : Error;
495 return Return(FOutcome::Error("Error while connecting", Result));
496 }
497
498 return Return(FOutcome::Waiting());
499 }
500
501 Result = LastSocketResult();
502 return Return(FOutcome::Error("Send", Result));
503}
504
507{
508 Trace(Socket, ETrace::Recv);
509 int32 Result = Socket_Recv(Socket, Dest, Size, MsgFlagType(0));
510
511 auto Return = [this] (FOutcome Outcome) {
512 Trace(Socket, ETrace::Recv, &Outcome);
513 return Outcome;
514 };
515
516 if (Result > 0) return Return(FOutcome::Ok(Result));
517 if (Result == 0) return Return(FOutcome::Error("Recv ATH0"));
518 if (IsSocketResult(EWOULDBLOCK)) return Return(FOutcome::Waiting());
519
520 Result = LastSocketResult();
521 return Return(FOutcome::Error("Recv", Result));
522}
523
525bool FSocket::SetBlocking(bool bBlocking)
526{
527#if defined(IAS_HTTP_HAS_NONBLOCK_IMPL)
528 return SetNonBlockingSocket(Socket, !bBlocking);
529#elif PLATFORM_MICROSOFT
530 unsigned long NonBlockingMode = (bBlocking != true);
531 return (ioctlsocket(Socket, FIONBIO, &NonBlockingMode) != SOCKET_ERROR);
532#else
533 int32 Flags = fcntl(Socket, F_GETFL, 0);
534 if (Flags == -1)
535 {
536 return false;
537 }
538
539 int32 NewFlags = bBlocking
540 ? (Flags & ~int32(O_NONBLOCK))
541 : (Flags | int32(O_NONBLOCK));
542 return (Flags == NewFlags) || (fcntl(Socket, F_SETFL, Flags) >= 0);
543#endif
544}
545
548{
549 return 0 == Socket_SetSockOpt(Socket, SOL_SOCKET, SO_SNDBUF, &(char&)Size, int32(sizeof(Size)));
550}
551
554{
555 return 0 == Socket_SetSockOpt(Socket, SOL_SOCKET, SO_RCVBUF, &(char&)Size, int32(sizeof(Size)));
556}
557
558
559
561static FLaneEstate* GSocketLaneEstate = LaneEstate_New({
562 .Name = "Iax/Socket",
563 .Group = "Iax",
564 .Channel = GetIaxTraceChannel(),
565 .Weight = 12,
566});
567
569static void Trace(UPTRINT Socket, ETrace Action, const FOutcome* Outcome)
570{
571 static uint32 SockScopeId = LaneTrace_NewScope("Iax/Socket");
572 static uint32 ConnScopeId = LaneTrace_NewScope("Iax/Connect");
573 static uint32 SendScopeId = LaneTrace_NewScope("Iax/Send");
574 static uint32 RecvScopeId = LaneTrace_NewScope("Iax/Recv");
575 static uint32 WaitScopeId = LaneTrace_NewScope("Iax/Wait");
576 static uint32 IdleScopeId = LaneTrace_NewScope("Iax/Idle");
577
578 if (Action == ETrace::SocketCreate)
579 {
580 FLaneTrace* Lane = LaneEstate_Build(GSocketLaneEstate, Socket);
583 return;
584 }
585
586 if (Action == ETrace::SocketDestroy)
587 {
588 LaneEstate_Demolish(GSocketLaneEstate, Socket);
589 return;
590 }
591
592 FLaneTrace* Lane = LaneEstate_Lookup(GSocketLaneEstate, Socket);
593
594 if (Action == ETrace::Send)
595 {
596 (Outcome == nullptr)
599 return;
600 }
601
602 if (Action == ETrace::Connect)
603 {
604 if (Outcome == nullptr)
605 {
607 }
608 else if (!Outcome->IsWaiting())
609 {
611 }
612 return;
613 }
614
615 if (Outcome == nullptr)
616 {
618 return;
619 }
620
621 if (Outcome->IsWaiting())
622 {
624 return;
625 }
626
628}
629
630// }}}
631
632} // namespace UE::IoStore::HTTP
constexpr auto MakeArrayView(OtherRangeType &&Other)
Definition ArrayView.h:873
#define check(expr)
Definition AssertionMacros.h:314
T ByteSwap(T Value)
FPlatformTypes::int16 int16
A 16-bit signed integer.
Definition Platform.h:1123
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
FPlatformTypes::UPTRINT UPTRINT
An unsigned integer the same size as a pointer.
Definition Platform.h:1146
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
JsonWriter Close()
UE_API void LaneTrace_Leave(FLaneTrace *Lane) LANETRACE_OFF_IMPL()
UE_API uint32 LaneTrace_NewScope(const FAnsiStringView &Name) LANETRACE_OFF_IMPL(1)
UE_API FLaneTrace * LaneEstate_Lookup(FLaneEstate *Estate, FLanePostcode Postcode) LANETRACE_OFF_IMPL(nullptr)
UE_API FLaneEstate * LaneEstate_New(const FLaneTraceSpec &Spec) LANETRACE_OFF_IMPL(nullptr)
UE_API void LaneEstate_Demolish(FLaneEstate *Estate, FLanePostcode Postcode) LANETRACE_OFF_IMPL()
UE_API void LaneTrace_Enter(FLaneTrace *Lane, uint32 ScopeId) LANETRACE_OFF_IMPL()
UE_API void LaneTrace_Change(FLaneTrace *Lane, uint32 ScopeId) LANETRACE_OFF_IMPL()
UE_API FLaneTrace * LaneEstate_Build(FLaneEstate *Estate, FLanePostcode Postcode) LANETRACE_OFF_IMPL(nullptr)
@ Num
Definition MetalRHIPrivate.h:234
#define SOCKET_ERROR
Definition SocketSubsystemBSDPrivate.h:43
int32 closesocket(SOCKET Socket)
Definition SocketSubsystemBSDPrivate.h:51
#define ioctlsocket
Definition SocketSubsystemBSDPrivate.h:40
#define IsSocketResult(err)
Definition Socket.inl:110
#define IAS_HTTP_SOCKET_FORWARD(Src, Dest)
Definition Socket.inl:7
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
uint32 Size
Definition VulkanMemory.cpp:4034
memcpy(InputBufferBase, BinkBlocksData, BinkBlocksSize)
uint8_t uint8
Definition binka_ue_file_header.h:8
uint16_t uint16
Definition binka_ue_file_header.h:7
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition Sockets.h:19
Definition ArrayView.h:139
Definition Array.h:670
UE_FORCEINLINE_HINT SizeType Emplace(ArgsType &&... Args)
Definition Array.h:2561
Definition Misc.inl:73
static FOutcome Ok(int32 Result=0)
Definition Misc.inl:113
static FOutcome Error(const char *Message, int32 Code=-1)
Definition Misc.inl:151
static FOutcome Waiting(int32 Result=0)
Definition Misc.inl:122
Definition Socket.inl:207
bool Register(const FWaitable &Waitable)
Definition Socket.inl:213
FPoller(FPoller &&Rhs)
Definition Socket.inl:210
FPoller & operator=(FPoller &&Rhs)
Definition Socket.inl:212
FPoller()
Definition Socket.inl:209
int32 Wait(FPollFd *Polls, int32 Num, int32 TimeOutMs)
Definition Socket.inl:223
~FPoller()
Definition Socket.inl:211
Definition Socket.inl:367
bool SetSendBufSize(int32 Size)
Definition Socket.inl:547
FOutcome Recv(char *Dest, uint32 Size)
Definition Socket.inl:506
FOutcome Connect(uint32 Ip, uint32 Port)
Definition Socket.inl:433
bool SetBlocking(bool bBlocking)
Definition Socket.inl:525
void Disconnect()
Definition Socket.inl:466
FOutcome Send(const char *Data, uint32 Size)
Definition Socket.inl:473
~FSocket()
Definition Socket.inl:370
bool SetRecvBufSize(int32 Size)
Definition Socket.inl:553
FWaitable GetWaitable() const
Definition Socket.inl:374
FSocket(FSocket &&Rhs)
Definition Socket.inl:371
bool Create()
Definition Socket.inl:401
bool IsValid() const
Definition Socket.inl:373
FSocket & operator=(FSocket &&Rhs)
Definition Socket.inl:372
void Destroy()
Definition Socket.inl:419
Definition Socket.inl:130
FWaitable & operator=(FWaitable &&)=default
FWaitable(FWaitable &&)=default
Definition Socket.inl:281
uint32 GetIndex() const
Definition Socket.inl:301
FWaiter(FWaiter &&)=default
EWhat
Definition Socket.inl:284
void WaitFor(EWhat What)
Definition Socket.inl:299
static int32 Wait(TArrayView< FWaiter > Waiters, FPoller &Poller, int32 TimeoutMs)
Definition Socket.inl:321
void SetIndex(uint32 InIndex)
Definition Socket.inl:300
bool IsValid() const
Definition Socket.inl:297
FWaiter & operator=(FWaiter &&)=default
bool IsReady() const
Definition Socket.inl:298
int
Definition TestServer.py:515
Definition Client.h:20
SOCKET SocketType
Definition Overlapped.inl:10
ETrace
Definition Misc.inl:12
uint16 Socket_HtoNs(uint16 v)
Definition Socket.inl:117
uint32 Socket_HtoNl(uint32 v)
Definition Socket.inl:116
UPTRINT PollType
Definition Socket.inl:83
IOSTOREHTTPCLIENT_API const void * GetIaxTraceChannel()
Definition Misc.inl:49
float v
Definition radaudio_mdct.cpp:62
U16 Index
Definition radfft.cpp:71
Definition Socket.inl:163
SocketType fd
Definition Socket.inl:164
static const int16 POLLNVAL
Definition Socket.inl:171
static const int16 POLLERR
Definition Socket.inl:169
int16 revents
Definition Socket.inl:166
static const int16 POLLHUP
Definition Socket.inl:170
static const int16 POLLOUT
Definition Socket.inl:168
static const int16 POLLIN
Definition Socket.inl:167
int16 events
Definition Socket.inl:165
Definition Socket.inl:178
bool HasSendTrigger() const
Definition Socket.inl:194
static const int16 PollNVal
Definition Socket.inl:183
static const int16 PollIn
Definition Socket.inl:179
static const int16 PollHup
Definition Socket.inl:182
bool HasTrigger() const
Definition Socket.inl:193
FPollFd(SocketType Socket, int16 Events)
Definition Socket.inl:186
bool HasRecvTrigger() const
Definition Socket.inl:195
static const int16 PollOut
Definition Socket.inl:180
static const int16 PollErr
Definition Socket.inl:181
static const int16 PollAll
Definition Socket.inl:184