Files
UnrealEngine/Engine/Source/Runtime/Sockets/Private/BSDSockets/SocketSubsystemBSD.cpp
2025-05-18 13:04:45 +08:00

615 lines
19 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "BSDSockets/SocketSubsystemBSD.h"
#if PLATFORM_HAS_BSD_SOCKETS || PLATFORM_HAS_BSD_IPV6_SOCKETS
#include "BSDSockets/IPAddressBSD.h"
#include "BSDSockets/SocketsBSD.h"
#include "Misc/CString.h"
#include <errno.h>
TAutoConsoleVariable<int32> CVarDisableIPv6(
TEXT("net.DisableIPv6"),
1,
TEXT("If true, IPv6 will not resolve and its usage will be avoided when possible"));
FSocketBSD* FSocketSubsystemBSD::InternalBSDSocketFactory(SOCKET Socket, ESocketType SocketType, const FString& SocketDescription, const FName& SocketProtocol)
{
// return a new socket object
return new FSocketBSD(Socket, SocketType, SocketDescription, SocketProtocol, this);
}
FSocket* FSocketSubsystemBSD::CreateSocket(const FName& SocketType, const FString& SocketDescription, const FName& ProtocolType)
{
SOCKET Socket = INVALID_SOCKET;
FSocket* NewSocket = nullptr;
int PlatformSpecificTypeFlags = 0;
FName SocketProtocolType = ProtocolType;
// For platforms that have two subsystems (ex: Steam) but don't explicitly inherit from SocketSubsystemBSD
// so they don't know which protocol to end up using and pass in None.
// This is invalid, so we need to attempt to still resolve it.
if (ProtocolType != FNetworkProtocolTypes::IPv4 && ProtocolType != FNetworkProtocolTypes::IPv6)
{
SocketProtocolType = GetDefaultSocketProtocolFamily();
// Check to make sure this is still valid.
if (SocketProtocolType != FNetworkProtocolTypes::IPv4 && SocketProtocolType != FNetworkProtocolTypes::IPv6)
{
UE_LOG(LogSockets, Warning, TEXT("Provided socket protocol type is unsupported! Returning null socket"));
return nullptr;
}
}
#if PLATFORM_HAS_BSD_SOCKET_FEATURE_CLOSE_ON_EXEC
PlatformSpecificTypeFlags = SOCK_CLOEXEC;
#endif // PLATFORM_HAS_BSD_SOCKET_FEATURE_CLOSE_ON_EXEC
bool bIsUDP = SocketType.GetComparisonIndex() == NAME_DGram;
int32 SocketTypeFlag = (bIsUDP) ? SOCK_DGRAM : SOCK_STREAM;
Socket = socket(GetProtocolFamilyValue(SocketProtocolType), SocketTypeFlag | PlatformSpecificTypeFlags, ((bIsUDP) ? IPPROTO_UDP : IPPROTO_TCP));
NewSocket = (Socket != INVALID_SOCKET) ? InternalBSDSocketFactory(Socket, ((bIsUDP) ? SOCKTYPE_Datagram : SOCKTYPE_Streaming), SocketDescription, SocketProtocolType) : nullptr;
if (!NewSocket)
{
UE_LOG(LogSockets, Warning, TEXT("Failed to create socket %s [%s]"), *SocketType.ToString(), *SocketDescription);
}
return NewSocket;
}
void FSocketSubsystemBSD::DestroySocket(FSocket* Socket)
{
delete Socket;
}
FAddressInfoResult FSocketSubsystemBSD::GetAddressInfo(const TCHAR* HostName, const TCHAR* ServiceName,
EAddressInfoFlags QueryFlags, const FName ProtocolTypeName, ESocketType SocketType)
{
FAddressInfoResult AddrQueryResult = FAddressInfoResult(HostName, ServiceName);
if (HostName == nullptr && ServiceName == nullptr)
{
UE_LOG(LogSockets, Warning, TEXT("GetAddressInfo was passed with both a null host and service, returning empty result"));
return AddrQueryResult;
}
#if PLATFORM_HAS_BSD_SOCKET_FEATURE_GETADDRINFO
addrinfo* AddrInfo = nullptr;
// Make sure we filter out IPv6 if the platform is not officially supported
const bool bCanUseIPv6 = (CVarDisableIPv6.GetValueOnAnyThread() == 0 && PLATFORM_HAS_BSD_IPV6_SOCKETS);
// Determine if we can save time with numericserv
if (ServiceName != nullptr && FString(ServiceName).IsNumeric())
{
QueryFlags |= EAddressInfoFlags::NoResolveService;
}
#if PLATFORM_HAS_BSD_SOCKET_FEATURE_GETNAMEINFO
// On Windows getaddrinfo will likely return a hostname instead of FQDN in ai_canonname.
// Try getnameinfo on every associated ip address and choose a first name with a dot if ai_canonname didn't contain FQDN.
bool bTryGetFQDN = EnumHasAnyFlags(QueryFlags, EAddressInfoFlags::FQDomainName);
#endif
addrinfo HintAddrInfo;
FMemory::Memzero(&HintAddrInfo, sizeof(HintAddrInfo));
HintAddrInfo.ai_family = GetProtocolFamilyValue(ProtocolTypeName);
HintAddrInfo.ai_flags = GetAddressInfoHintFlag(QueryFlags);
if (SocketType != ESocketType::SOCKTYPE_Unknown)
{
bool bIsUDP = (SocketType == ESocketType::SOCKTYPE_Datagram);
HintAddrInfo.ai_protocol = bIsUDP ? IPPROTO_UDP : IPPROTO_TCP;
HintAddrInfo.ai_socktype = bIsUDP ? SOCK_DGRAM : SOCK_STREAM;
}
int32 ErrorCode = getaddrinfo(TCHAR_TO_UTF8(HostName), TCHAR_TO_UTF8(ServiceName), &HintAddrInfo, &AddrInfo);
AddrQueryResult.ReturnCode = TranslateGAIErrorCode(ErrorCode);
UE_LOG(LogSockets, Verbose, TEXT("Executed getaddrinfo with HostName: %s ServiceName: %s Return: %d"), HostName ? HostName : TEXT("null"), ServiceName ? ServiceName : TEXT("null"), ErrorCode);
if (AddrQueryResult.ReturnCode == SE_NO_ERROR)
{
addrinfo* AddrInfoHead = AddrInfo;
// The canonical name will always be stored in only the first result in a getaddrinfo query
if (AddrInfo != nullptr && AddrInfo->ai_canonname != nullptr)
{
AddrQueryResult.CanonicalNameResult = UTF8_TO_TCHAR(AddrInfo->ai_canonname);
UE_LOG(LogSockets, Verbose, TEXT("getaddrinfo ai_canonname returns: %s"), *AddrQueryResult.CanonicalNameResult);
#if PLATFORM_HAS_BSD_SOCKET_FEATURE_GETNAMEINFO
// ai_canonname contained a dot, likely to be the best FQDN
int32 DotPosition;
if (AddrQueryResult.CanonicalNameResult.FindChar(TEXT('.'), DotPosition))
{
bTryGetFQDN = false;
}
#endif
}
for (; AddrInfo != nullptr; AddrInfo = AddrInfo->ai_next)
{
if (AddrInfo->ai_family == AF_INET || (AddrInfo->ai_family == AF_INET6 && bCanUseIPv6))
{
sockaddr_storage* AddrData = reinterpret_cast<sockaddr_storage*>(AddrInfo->ai_addr);
if (AddrData != nullptr)
{
TSharedRef<FInternetAddrBSD> NewAddress = MakeShareable(new FInternetAddrBSD(this));
NewAddress->Set(*AddrData, AddrInfo->ai_addrlen);
FAddressInfoResultData NewAddressData(NewAddress, AddrInfo->ai_addrlen, GetProtocolFamilyTypeName(AddrInfo->ai_family), GetSocketType(AddrInfo->ai_protocol));
// While the FNames are the correct way to enumerate over address types, we still need to support the old format.
PRAGMA_DISABLE_DEPRECATION_WARNINGS
NewAddressData.AddressProtocol = GetProtocolFamilyType(AddrInfo->ai_family);
PRAGMA_ENABLE_DEPRECATION_WARNINGS
if (AddrQueryResult.Results.Add(NewAddressData) != INDEX_NONE)
{
sockaddr_in6* IPv6AddrData = reinterpret_cast<sockaddr_in6*>(AddrInfo->ai_addr);
UE_LOG(LogSockets, Verbose, TEXT("# Family: %s Address: %s And scope %d"), ((AddrInfo->ai_family == AF_INET) ? TEXT("IPv4") : TEXT("IPv6")), *(NewAddress->ToString(true)), ((AddrInfo->ai_family == AF_INET) ? -1 : IPv6AddrData->sin6_scope_id));
#if PLATFORM_HAS_BSD_SOCKET_FEATURE_GETNAMEINFO
// Try to acquire the FQDN
if (bTryGetFQDN && (AddrData->ss_family == AF_INET || AddrData->ss_family == AF_INET6))
{
char HostBuffer[NI_MAXHOST];
if (getnameinfo(
reinterpret_cast<const sockaddr*>(AddrData), AddrInfo->ai_addrlen,
HostBuffer, sizeof(HostBuffer),
nullptr, 0,
NI_NAMEREQD) == 0)
{
// Use HostName as FQDN if it contains a dot
int32 DotPosition;
if (FAnsiStringView(HostBuffer).FindChar(TEXT('.'), DotPosition))
{
AddrQueryResult.CanonicalNameResult = StringCast<TCHAR>(HostBuffer);
bTryGetFQDN = false;
UE_LOG(LogSockets, Verbose, TEXT("Using getnameinfo hostname '%s'"), *AddrQueryResult.CanonicalNameResult);
}
}
}
#endif
}
}
}
}
freeaddrinfo(AddrInfoHead);
}
else
{
UE_LOG(LogSockets, Warning, TEXT("GetAddressInfo failed to resolve host with error %s [%d]"), GetSocketError(AddrQueryResult.ReturnCode), ErrorCode);
}
#else
UE_LOG(LogSockets, Error, TEXT("Platform has no getaddrinfo(), but did not override FSocketSubsystem::GetAddressInfo()"));
#endif
return AddrQueryResult;
}
TSharedPtr<FInternetAddr> FSocketSubsystemBSD::GetAddressFromString(const FString& InAddress)
{
sockaddr_storage NetworkBuffer;
FMemory::Memzero(NetworkBuffer);
void* UniversalNetBufferPtr = nullptr;
int32 AddrFamily = AF_INET;
#if PLATFORM_HAS_BSD_IPV6_SOCKETS
int32 ColonIndex;
if (InAddress.FindChar(TEXT(':'), ColonIndex))
{
AddrFamily = AF_INET6;
UniversalNetBufferPtr = &(((sockaddr_in6*)&NetworkBuffer)->sin6_addr);
}
else
#endif
{
UniversalNetBufferPtr = &(((sockaddr_in*)&NetworkBuffer)->sin_addr);
}
// The type of ss_family varies by platform.
NetworkBuffer.ss_family = IntCastChecked<decltype(NetworkBuffer.ss_family)>(AddrFamily);
if (inet_pton(AddrFamily, TCHAR_TO_ANSI(*InAddress), UniversalNetBufferPtr))
{
TSharedRef<FInternetAddrBSD> ReturnAddress = StaticCastSharedRef<FInternetAddrBSD>(CreateInternetAddr());
ReturnAddress->Set(NetworkBuffer);
return ReturnAddress;
}
ESocketErrors LastError = GetLastErrorCode();
UE_LOG(LogSockets, Warning, TEXT("Could not serialize %s, got error code %s [%d]"), *InAddress, GetSocketError(LastError), LastError);
return nullptr;
}
bool FSocketSubsystemBSD::GetMultihomeAddress(TSharedRef<FInternetAddr>& Addr)
{
// This function is overwritten to make sure that functions that use GetLocalHostAddr/GetLocalBindAddr
// are able to use that function to pull something like the adapter interface from all code paths.
if (ISocketSubsystem::GetMultihomeAddress(Addr))
{
// Only IPv6 protocols need to handle the scope id.
if (Addr->GetProtocolType() == FNetworkProtocolTypes::IPv6)
{
TArray<TSharedPtr<FInternetAddr>> AdapterAddresses;
if (GetLocalAdapterAddresses(AdapterAddresses))
{
uint32 ScopeId = 0;
for (const TSharedPtr<FInternetAddr>& AdapterAddress : AdapterAddresses)
{
// If the endpoint is the same, then we want to make sure that we write the scope id into it
if (Addr->CompareEndpoints(*AdapterAddress))
{
ScopeId = StaticCastSharedPtr<FInternetAddrBSD>(AdapterAddress)->GetScopeId();
break;
}
}
StaticCastSharedRef<FInternetAddrBSD>(Addr)->SetScopeId(ScopeId);
}
}
return true;
}
return false;
}
bool FSocketSubsystemBSD::GetHostName(FString& HostName)
{
#if PLATFORM_HAS_BSD_SOCKET_FEATURE_GETHOSTNAME
ANSICHAR Buffer[256];
bool bRead = gethostname(Buffer,256) == 0;
if (bRead == true)
{
HostName = UTF8_TO_TCHAR(Buffer);
}
return bRead;
#else
UE_LOG(LogSockets, Error, TEXT("Platform has no gethostname(), but did not override FSocketSubsystem::GetHostName()"));
return false;
#endif
}
const TCHAR* FSocketSubsystemBSD::GetSocketAPIName() const
{
return TEXT("BSD IPv4/6");
}
TSharedRef<FInternetAddr> FSocketSubsystemBSD::CreateInternetAddr()
{
return MakeShareable(new FInternetAddrBSD(this));
}
TSharedRef<FInternetAddr> FSocketSubsystemBSD::CreateInternetAddr(const FName ProtocolType)
{
return MakeShareable(new FInternetAddrBSD(this, ProtocolType));
}
bool FSocketSubsystemBSD::IsSocketWaitSupported() const
{
return true;
}
ESocketErrors FSocketSubsystemBSD::GetLastErrorCode()
{
return TranslateErrorCode(errno);
}
ESocketErrors FSocketSubsystemBSD::TranslateErrorCode(int32 Code)
{
// @todo sockets: Windows for some reason doesn't seem to have all of the standard error messages,
// but it overrides this function anyway - however, this
#if !PLATFORM_HAS_BSD_SOCKET_FEATURE_WINSOCKETS
// handle the generic -1 error
if (Code == SOCKET_ERROR)
{
return GetLastErrorCode();
}
switch (Code)
{
case 0: return SE_NO_ERROR;
case EINTR: return SE_EINTR;
case EBADF: return SE_EBADF;
case EACCES: return SE_EACCES;
case EFAULT: return SE_EFAULT;
case EINVAL: return SE_EINVAL;
case EMFILE: return SE_EMFILE;
case EWOULDBLOCK: return SE_EWOULDBLOCK;
case EINPROGRESS: return SE_EINPROGRESS;
case EALREADY: return SE_EALREADY;
case ENOTSOCK: return SE_ENOTSOCK;
case EDESTADDRREQ: return SE_EDESTADDRREQ;
case EMSGSIZE: return SE_EMSGSIZE;
case EPROTOTYPE: return SE_EPROTOTYPE;
case ENOPROTOOPT: return SE_ENOPROTOOPT;
case EPROTONOSUPPORT: return SE_EPROTONOSUPPORT;
case ESOCKTNOSUPPORT: return SE_ESOCKTNOSUPPORT;
case EOPNOTSUPP: return SE_EOPNOTSUPP;
case EPFNOSUPPORT: return SE_EPFNOSUPPORT;
case EAFNOSUPPORT: return SE_EAFNOSUPPORT;
case EADDRINUSE: return SE_EADDRINUSE;
case EADDRNOTAVAIL: return SE_EADDRNOTAVAIL;
case ENETDOWN: return SE_ENETDOWN;
case ENETUNREACH: return SE_ENETUNREACH;
case ENETRESET: return SE_ENETRESET;
case ECONNABORTED: return SE_ECONNABORTED;
case ECONNRESET: return SE_ECONNRESET;
case ENOBUFS: return SE_ENOBUFS;
case EISCONN: return SE_EISCONN;
case ENOTCONN: return SE_ENOTCONN;
case ESHUTDOWN: return SE_ESHUTDOWN;
case ETOOMANYREFS: return SE_ETOOMANYREFS;
case ETIMEDOUT: return SE_ETIMEDOUT;
case ECONNREFUSED: return SE_ECONNREFUSED;
case ELOOP: return SE_ELOOP;
case ENAMETOOLONG: return SE_ENAMETOOLONG;
case EHOSTDOWN: return SE_EHOSTDOWN;
case EHOSTUNREACH: return SE_EHOSTUNREACH;
case ENOTEMPTY: return SE_ENOTEMPTY;
case EUSERS: return SE_EUSERS;
case EDQUOT: return SE_EDQUOT;
case ESTALE: return SE_ESTALE;
case EREMOTE: return SE_EREMOTE;
case ENODEV: return SE_NODEV;
#if !PLATFORM_HAS_NO_EPROCLIM
case EPROCLIM: return SE_EPROCLIM;
#endif
case EPIPE: return SE_ECONNRESET; // for when backgrounding with an open pipe to a server
}
#if PLATFORM_HAS_BSD_SOCKET_FEATURE_GETHOSTNAME
switch (Code)
{
// some platforms may duplicate error codes, so by moving these, these error will be
// returned, but if there are duplicate defines, it's already going to be unclear what
// should be returned
case HOST_NOT_FOUND: return SE_HOST_NOT_FOUND;
case TRY_AGAIN: return SE_TRY_AGAIN;
case NO_RECOVERY: return SE_NO_RECOVERY;
}
#endif
#endif
UE_LOG(LogSockets, Warning, TEXT("Unhandled socket error! Error Code: %d. Returning SE_EINVAL!"), Code);
return SE_EINVAL;
}
ESocketErrors FSocketSubsystemBSD::TranslateGAIErrorCode(int32 Code) const
{
#if PLATFORM_HAS_BSD_SOCKET_FEATURE_GETADDRINFO
switch (Code)
{
// getaddrinfo() has its own error codes
case EAI_AGAIN: return SE_TRY_AGAIN;
case EAI_BADFLAGS: return SE_EINVAL;
case EAI_FAIL: return SE_NO_RECOVERY;
case EAI_FAMILY: return SE_EAFNOSUPPORT;
case EAI_MEMORY: return SE_ENOBUFS;
case EAI_NONAME: return SE_HOST_NOT_FOUND;
case EAI_SERVICE: return SE_EPFNOSUPPORT;
case EAI_SOCKTYPE: return SE_ESOCKTNOSUPPORT;
#if PLATFORM_HAS_BSD_SOCKET_FEATURE_WINSOCKETS
case WSANO_DATA: return SE_NO_DATA;
case WSANOTINITIALISED: return SE_NOTINITIALISED;
#else
case EAI_NODATA: return SE_NO_DATA;
case EAI_ADDRFAMILY: return SE_ADDRFAMILY;
case EAI_SYSTEM: return SE_SYSTEM;
#endif
case 0: break; // 0 means success
default:
UE_LOG(LogSockets, Warning, TEXT("Unhandled getaddrinfo() socket error! Code: %d"), Code);
return SE_EINVAL;
}
#endif // PLATFORM_HAS_BSD_SOCKET_FEATURE_GETADDRINFO
return SE_NO_ERROR;
}
int32 FSocketSubsystemBSD::GetProtocolFamilyValue(const FName& InProtocol) const
{
if (InProtocol == FNetworkProtocolTypes::IPv4)
{
return AF_INET;
}
else if (InProtocol == FNetworkProtocolTypes::IPv6)
{
return AF_INET6;
}
return AF_UNSPEC;
}
const FName FSocketSubsystemBSD::GetProtocolFamilyTypeName(int32 InProtocol) const
{
switch (InProtocol)
{
default:
case AF_UNSPEC: return NAME_None;
case AF_INET: return FNetworkProtocolTypes::IPv4;
case AF_INET6: return FNetworkProtocolTypes::IPv6;
}
}
PRAGMA_DISABLE_DEPRECATION_WARNINGS
int32 FSocketSubsystemBSD::GetProtocolFamilyValue(ESocketProtocolFamily InProtocol) const
{
switch (InProtocol)
{
default:
case ESocketProtocolFamily::None: return AF_UNSPEC;
case ESocketProtocolFamily::IPv4: return AF_INET;
case ESocketProtocolFamily::IPv6: return AF_INET6;
}
}
ESocketProtocolFamily FSocketSubsystemBSD::GetProtocolFamilyType(int32 InProtocol) const
{
switch (InProtocol)
{
default:
case AF_UNSPEC: return ESocketProtocolFamily::None;
case AF_INET: return ESocketProtocolFamily::IPv4;
case AF_INET6: return ESocketProtocolFamily::IPv6;
}
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
ESocketType FSocketSubsystemBSD::GetSocketType(int32 InSocketType) const
{
switch (InSocketType)
{
case SOCK_STREAM:
case IPPROTO_TCP: return ESocketType::SOCKTYPE_Streaming;
case SOCK_DGRAM:
case IPPROTO_UDP: return ESocketType::SOCKTYPE_Datagram;
default: return SOCKTYPE_Unknown;
}
}
int32 FSocketSubsystemBSD::GetAddressInfoHintFlag(EAddressInfoFlags InFlags) const
{
int32 ReturnFlagsCode = 0;
#if PLATFORM_HAS_BSD_SOCKET_FEATURE_GETADDRINFO
if (InFlags == EAddressInfoFlags::Default)
{
return ReturnFlagsCode;
}
if (EnumHasAnyFlags(InFlags, EAddressInfoFlags::NoResolveHost))
{
ReturnFlagsCode |= AI_NUMERICHOST;
}
if (EnumHasAnyFlags(InFlags, EAddressInfoFlags::NoResolveService))
{
ReturnFlagsCode |= AI_NUMERICSERV;
}
if (EnumHasAnyFlags(InFlags, EAddressInfoFlags::OnlyUsableAddresses))
{
ReturnFlagsCode |= AI_ADDRCONFIG;
}
if (EnumHasAnyFlags(InFlags, EAddressInfoFlags::BindableAddress))
{
ReturnFlagsCode |= AI_PASSIVE;
}
/* This means nothing unless AI_ALL is also specified. */
if (EnumHasAnyFlags(InFlags, EAddressInfoFlags::AllowV4MappedAddresses))
{
ReturnFlagsCode |= AI_V4MAPPED;
}
if (EnumHasAnyFlags(InFlags, EAddressInfoFlags::AllResults))
{
ReturnFlagsCode |= AI_ALL;
}
if (EnumHasAnyFlags(InFlags, EAddressInfoFlags::CanonicalName))
{
ReturnFlagsCode |= AI_CANONNAME;
}
if (EnumHasAnyFlags(InFlags, EAddressInfoFlags::FQDomainName))
{
#ifdef AI_FQDN
ReturnFlagsCode |= AI_FQDN;
#else
ReturnFlagsCode |= AI_CANONNAME;
#endif
}
#endif
return ReturnFlagsCode;
}
TSharedRef<FInternetAddr> FSocketSubsystemBSD::GetLocalHostAddr(FOutputDevice& Out, bool& bCanBindAll)
{
TSharedRef<FInternetAddr> HostAddr = CreateInternetAddr();
bCanBindAll = false;
if (!GetMultihomeAddress(HostAddr))
{
// First try to get the host address via connect
if (!GetLocalHostAddrViaConnect(HostAddr))
{
bCanBindAll = true;
TArray<TSharedPtr<FInternetAddr>> AdapterAddresses;
if (!GetLocalAdapterAddresses(AdapterAddresses) || (AdapterAddresses.Num() == 0))
{
Out.Logf(TEXT("Could not fetch the local adapter addresses"));
HostAddr->SetAnyAddress();
}
else
{
if (AdapterAddresses.Num() > 0)
{
HostAddr = AdapterAddresses[0]->Clone();
}
}
}
}
UE_LOG(LogSockets, VeryVerbose, TEXT("GetLocalHostAddr: %s"), *HostAddr->ToString(true));
return HostAddr;
}
bool FSocketSubsystemBSD::GetLocalHostAddrViaConnect(TSharedRef<FInternetAddr>& HostAddr)
{
bool bReturnValue = false;
const bool bDisableIPv6 = CVarDisableIPv6.GetValueOnAnyThread() == 1;
TSharedRef<FInternetAddr> ConnectAddr = bDisableIPv6 ? CreateInternetAddr(FNetworkProtocolTypes::IPv4) : CreateInternetAddr();
bool bIsValid = false;
// any IP will do, doesn't even need to be reachable
if (ConnectAddr->GetProtocolType() == FNetworkProtocolTypes::IPv6)
{
ConnectAddr->SetIp(TEXT("::ffff:172.31.255.255"), bIsValid);
}
else if (ConnectAddr->GetProtocolType() == FNetworkProtocolTypes::IPv4)
{
ConnectAddr->SetIp(TEXT("172.31.255.255"), bIsValid);
}
if (bIsValid)
{
ConnectAddr->SetPort(256);
FUniqueSocket TestSocket = CreateUniqueSocket(NAME_DGram, TEXT("GetLocalHostAddrViaConnect"), ConnectAddr->GetProtocolType());
if (TestSocket.IsValid())
{
if (TestSocket->Connect(*ConnectAddr))
{
TestSocket->GetAddress(*HostAddr);
HostAddr->SetPort(0);
bReturnValue = true;
UE_LOG(LogSockets, VeryVerbose, TEXT("GetLocalHostAddrViaConnect: %s"), *HostAddr->ToString(true));
}
TestSocket->Close();
}
}
return bReturnValue;
}
#endif //PLATFORM_HAS_BSD_SOCKETS