Files
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

278 lines
6.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Trace/Config.h"
#if TRACE_PRIVATE_MINIMAL_ENABLED && PLATFORM_UNIX
#include <cstring>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <pthread.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#if defined(_GNU_SOURCE)
#include <sys/syscall.h>
#endif // _GNU_SOURCE
namespace UE {
namespace Trace {
namespace Private {
////////////////////////////////////////////////////////////////////////////////
UPTRINT ThreadCreate(const ANSICHAR* Name, void (*Entry)())
{
void* (*PthreadThunk)(void*) = [] (void* Param) -> void * {
typedef void (*EntryType)(void);
(EntryType(Param))();
return nullptr;
};
pthread_t ThreadHandle;
if (pthread_create(&ThreadHandle, nullptr, PthreadThunk, reinterpret_cast<void *>(Entry)) != 0)
{
return 0;
}
return static_cast<UPTRINT>(ThreadHandle);
}
////////////////////////////////////////////////////////////////////////////////
void ThreadSleep(uint32 Milliseconds)
{
usleep(Milliseconds * 1000U);
}
////////////////////////////////////////////////////////////////////////////////
void ThreadJoin(UPTRINT Handle)
{
pthread_join(static_cast<pthread_t>(Handle), nullptr);
}
////////////////////////////////////////////////////////////////////////////////
void ThreadDestroy(UPTRINT Handle)
{
// no-op
}
////////////////////////////////////////////////////////////////////////////////
uint64 TimeGetFrequency()
{
return 10000000ull;
}
////////////////////////////////////////////////////////////////////////////////
TRACELOG_API uint64 TimeGetTimestamp()
{
// should stay in sync with FPlatformTime::Cycles64() or the timeline will be broken!
struct timespec TimeSpec;
clock_gettime(CLOCK_MONOTONIC, &TimeSpec);
return static_cast<uint64>(static_cast<uint64>(TimeSpec.tv_sec) * 10000000ULL + static_cast<uint64>(TimeSpec.tv_nsec) / 100ULL);
}
////////////////////////////////////////////////////////////////////////////////
static bool TcpSocketSetNonBlocking(int Socket, bool bNonBlocking)
{
int Flags = fcntl(Socket, F_GETFL, 0);
if (Flags == -1)
{
return false;
}
Flags = bNonBlocking ? (Flags|O_NONBLOCK) : (Flags & ~O_NONBLOCK);
return fcntl(Socket, F_SETFL, Flags) >= 0;
}
////////////////////////////////////////////////////////////////////////////////
UPTRINT TcpSocketConnect(const ANSICHAR* Host, uint16 Port)
{
struct FAddrInfoPtr
{
~FAddrInfoPtr()
{
if (Value != nullptr)
{
freeaddrinfo(Value);
}
}
addrinfo* operator -> () { return Value; }
addrinfo** operator & () { return &Value; }
addrinfo* Value;
};
FAddrInfoPtr Info;
addrinfo Hints = {};
Hints.ai_family = AF_INET;
Hints.ai_socktype = SOCK_STREAM;
Hints.ai_protocol = IPPROTO_TCP;
if (getaddrinfo(Host, nullptr, &Hints, &Info))
{
Info.Value = nullptr;
return 0;
}
if (&Info == nullptr)
{
return 0;
}
auto* SockAddr = (sockaddr_in*)Info->ai_addr;
SockAddr->sin_port = htons(Port);
int Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (Socket < 0)
{
return 0;
}
int Result = connect(Socket, Info->ai_addr, int(Info->ai_addrlen));
if (Result < 0)
{
close(Socket);
return 0;
}
if (!TcpSocketSetNonBlocking(Socket, false))
{
close(Socket);
return 0;
}
return UPTRINT(Socket + 1);
}
////////////////////////////////////////////////////////////////////////////////
UPTRINT TcpSocketListen(uint16 Port)
{
int Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (Socket < 0)
{
return 0;
}
sockaddr_in SockAddr;
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = 0;
SockAddr.sin_port = htons(Port);
int Result = bind(Socket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr));
if (Result < 0)
{
close(Socket);
return 0;
}
Result = listen(Socket, 1);
if (Result < 0)
{
close(Socket);
return 0;
}
if (!TcpSocketSetNonBlocking(Socket, true))
{
close(Socket);
return 0;
}
return UPTRINT(Socket + 1);
}
////////////////////////////////////////////////////////////////////////////////
int32 TcpSocketAccept(UPTRINT Socket, UPTRINT& Out)
{
int Inner = Socket - 1;
Inner = accept(Inner, nullptr, nullptr);
if (Inner < 0)
{
return (errno == EAGAIN || errno == EWOULDBLOCK) - 1; // 0 if would block else -1
}
if (!TcpSocketSetNonBlocking(Inner, false))
{
close(Inner);
return 0;
}
Out = UPTRINT(Inner + 1);
return 1;
}
////////////////////////////////////////////////////////////////////////////////
bool TcpSocketHasData(UPTRINT Socket)
{
int Inner = Socket - 1;
fd_set FdSet;
FD_ZERO(&FdSet);
FD_SET(Inner, &FdSet);
timeval TimeVal = {};
return (select(Inner + 1, &FdSet, nullptr, nullptr, &TimeVal) != 0);
}
////////////////////////////////////////////////////////////////////////////////
bool IoWrite(UPTRINT Handle, const void* Data, uint32 Size)
{
int Inner = int(Handle) - 1;
return write(Inner, Data, Size) == Size;
}
////////////////////////////////////////////////////////////////////////////////
int32 IoRead(UPTRINT Handle, void* Data, uint32 Size)
{
int Inner = int(Handle) - 1;
return read(Inner, Data, Size);
}
////////////////////////////////////////////////////////////////////////////////
void IoClose(UPTRINT Handle)
{
int Inner = int(Handle) - 1;
close(Inner);
}
////////////////////////////////////////////////////////////////////////////////
UPTRINT FileOpen(const ANSICHAR* Path)
{
int Flags = O_CREAT|O_WRONLY|O_TRUNC;
int Mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
int Out = open(Path, Flags, Mode);
if (Out < 0)
{
return 0;
}
return UPTRINT(Out + 1);
}
////////////////////////////////////////////////////////////////////////////////
int32 GetLastErrorCode()
{
return errno;
}
////////////////////////////////////////////////////////////////////////////////
bool GetErrorMessage(char* OutBuffer, uint32 BufferSize, int32 ErrorCode)
{
const char* ErrorMessage = std::strerror(ErrorCode);
const bool bResult = strncpy(OutBuffer, ErrorMessage, BufferSize) != 0;
OutBuffer[BufferSize-1] = 0;
return bResult;
}
} // namespace Private
} // namespace Trace
} // namespace UE
#endif // TRACE_PRIVATE_MINIMAL_ENABLED