// Copyright Epic Games, Inc. All Rights Reserved. #include "Trace/Config.h" #if TRACE_PRIVATE_MINIMAL_ENABLED && PLATFORM_APPLE #include #include #include #include #include #include #include #include #include #include #include #include #include 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(Entry)) != 0) { return 0; } return reinterpret_cast(ThreadHandle); } //////////////////////////////////////////////////////////////////////////////// void ThreadSleep(uint32 Milliseconds) { usleep(Milliseconds * 1000U); } //////////////////////////////////////////////////////////////////////////////// void ThreadJoin(UPTRINT Handle) { pthread_join(reinterpret_cast(Handle), nullptr); } //////////////////////////////////////////////////////////////////////////////// void ThreadDestroy(UPTRINT Handle) { // no-op } //////////////////////////////////////////////////////////////////////////////// uint64 TimeGetFrequency() { mach_timebase_info_data_t Info; mach_timebase_info(&Info); return (uint64(1 * 1000 * 1000 * 1000) * uint64(Info.denom)) / uint64(Info.numer); } //////////////////////////////////////////////////////////////////////////////// TRACELOG_API uint64 TimeGetTimestamp() { return mach_absolute_time(); } //////////////////////////////////////////////////////////////////////////////// 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) { #if PLATFORM_MAC // We're only accepting named hosts on desktop platforms struct FAddrInfoPtr { ~FAddrInfoPtr() { 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)) { return 0; } if (&Info == nullptr) { return 0; } auto* SockAddr = (sockaddr_in*)Info->ai_addr; SockAddr->sin_port = htons(Port); int SockAddrSize = int(Info->ai_addrlen); #else sockaddr_in SockAddrIp; SockAddrIp.sin_family = AF_INET; SockAddrIp.sin_addr.s_addr = inet_addr(Host); SockAddrIp.sin_port = htons(Port); auto* SockAddr = &SockAddrIp; int SockAddrSize = sizeof(SockAddrIp); #endif int Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (Socket < 0) { return 0; } int Result = connect(Socket, (sockaddr*)SockAddr, SockAddrSize); 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), 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 = int(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 = int(Socket - 1); fd_set FdSet; FD_ZERO(&FdSet); FD_SET(Inner, &FdSet); timeval TimeVal = {}; int result = select(Inner + 1, &FdSet, nullptr, nullptr, &TimeVal); return ((result != 0) || ((result == -1) && (errno == ETIMEDOUT))); } //////////////////////////////////////////////////////////////////////////////// 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|O_SHLOCK; 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 = 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