// Copyright Epic Games, Inc. All Rights Reserved. #include "SocketSubsystemWindows.h" #include "SocketSubsystemModule.h" #include "Modules/ModuleManager.h" #include "BSDSockets/IPAddressBSD.h" #include "Windows/AllowWindowsPlatformTypes.h" THIRD_PARTY_INCLUDES_START #include "Iphlpapi.h" THIRD_PARTY_INCLUDES_END #include "Windows/HideWindowsPlatformTypes.h" FSocketSubsystemWindows* FSocketSubsystemWindows::SocketSingleton = nullptr; FName CreateSocketSubsystem( FSocketSubsystemModule& SocketSubsystemModule ) { FName SubsystemName(TEXT("WINDOWS")); // Create and register our singleton factory with the main online subsystem for easy access FSocketSubsystemWindows* SocketSubsystem = FSocketSubsystemWindows::Create(); FString Error; if (SocketSubsystem->Init(Error)) { SocketSubsystemModule.RegisterSocketSubsystem(SubsystemName, SocketSubsystem); return SubsystemName; } FSocketSubsystemWindows::Destroy(); return NAME_None; } void DestroySocketSubsystem( FSocketSubsystemModule& SocketSubsystemModule ) { SocketSubsystemModule.UnregisterSocketSubsystem(FName(TEXT("WINDOWS"))); FSocketSubsystemWindows::Destroy(); } /* FSocketSubsystemWindows interface *****************************************************************************/ FSocketSubsystemWindows* FSocketSubsystemWindows::Create() { if (SocketSingleton == nullptr) { SocketSingleton = new FSocketSubsystemWindows(); } return SocketSingleton; } void FSocketSubsystemWindows::Destroy() { if (SocketSingleton != nullptr) { SocketSingleton->Shutdown(); delete SocketSingleton; SocketSingleton = nullptr; } } /* FSocketSubsystemBSD overrides *****************************************************************************/ FSocket* FSocketSubsystemWindows::CreateSocket(const FName& SocketType, const FString& SocketDescription, const FName& ProtocolType) { FSocketWindows* NewSocket = (FSocketWindows*)FSocketSubsystemBSD::CreateSocket(SocketType, SocketDescription, ProtocolType); if (NewSocket != nullptr) { ::SetHandleInformation((HANDLE)NewSocket->GetNativeSocket(), HANDLE_FLAG_INHERIT, 0); NewSocket->SetIPv6Only(false); } else { UE_LOG(LogSockets, Warning, TEXT("Failed to create socket %s [%s]"), *SocketType.ToString(), *SocketDescription); } return NewSocket; } bool FSocketSubsystemWindows::Init(FString& Error) { bool bSuccess = false; if (bTriedToInit == false) { bTriedToInit = true; WSADATA WSAData; // initialize WSA int32 Code = WSAStartup(0x0101, &WSAData); if (Code == 0) { bSuccess = true; UE_LOG(LogInit, Log, TEXT("%s: version %i.%i (%i.%i), MaxSocks=%i, MaxUdp=%i"), GetSocketAPIName(), WSAData.wVersion >> 8, WSAData.wVersion & 0xFF, WSAData.wHighVersion >> 8, WSAData.wHighVersion & 0xFF, WSAData.iMaxSockets, WSAData.iMaxUdpDg); } else { Error = FString::Printf(TEXT("WSAStartup failed (%s)"), GetSocketError(TranslateErrorCode(Code))); } } return bSuccess; } void FSocketSubsystemWindows::Shutdown(void) { WSACleanup(); } ESocketErrors FSocketSubsystemWindows::GetLastErrorCode() { return TranslateErrorCode(WSAGetLastError()); } bool FSocketSubsystemWindows::GetLocalAdapterAddresses(TArray>& OutAddresses) { ULONG Flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME; ULONG Result; ULONG Size = 0; ULONG Family = (PLATFORM_HAS_BSD_IPV6_SOCKETS && CVarDisableIPv6.GetValueOnAnyThread() == 0) ? AF_UNSPEC : AF_INET; // determine the required size of the address list buffer Result = GetAdaptersAddresses(Family, Flags, NULL, NULL, &Size); if (Result != ERROR_BUFFER_OVERFLOW) { return false; } PIP_ADAPTER_ADDRESSES AdapterAddresses = (PIP_ADAPTER_ADDRESSES)FMemory::Malloc(Size); // get the actual list of adapters Result = GetAdaptersAddresses(Family, Flags, NULL, AdapterAddresses, &Size); if (Result != ERROR_SUCCESS) { FMemory::Free(AdapterAddresses); return false; } // extract the list of physical addresses from each adapter for (PIP_ADAPTER_ADDRESSES AdapterAddress = AdapterAddresses; AdapterAddress != NULL; AdapterAddress = AdapterAddress->Next) { if ((AdapterAddress->IfType == IF_TYPE_ETHERNET_CSMACD || AdapterAddress->IfType == IF_TYPE_IEEE80211) && AdapterAddress->OperStatus == IfOperStatusUp) { for (PIP_ADAPTER_UNICAST_ADDRESS UnicastAddress = AdapterAddress->FirstUnicastAddress; UnicastAddress != NULL; UnicastAddress = UnicastAddress->Next) { if ((UnicastAddress->Flags & IP_ADAPTER_ADDRESS_DNS_ELIGIBLE) != 0) { const sockaddr_storage* RawAddress = (const sockaddr_storage*)(UnicastAddress->Address.lpSockaddr); TSharedRef NewAddress = MakeShareable(new FInternetAddrBSD(this)); NewAddress->SetIp(*RawAddress); NewAddress->SetScopeId((RawAddress->ss_family == AF_INET) ? ntohl(AdapterAddress->IfIndex) : ntohl(AdapterAddress->Ipv6IfIndex)); UE_LOG(LogSockets, Verbose, TEXT("Adapter address added: %s"), *NewAddress->ToString(false)); OutAddresses.Add(NewAddress); } } } } FMemory::Free(AdapterAddresses); return true; } ESocketErrors FSocketSubsystemWindows::TranslateErrorCode(int32 Code) { // handle the generic -1 error if (Code == SOCKET_ERROR) { return GetLastErrorCode(); } switch (Code) { case 0: return SE_NO_ERROR; case ERROR_INVALID_HANDLE: return SE_ECONNRESET; // invalid socket handle catch case WSAEINTR: return SE_EINTR; case WSAEBADF: return SE_EBADF; case WSAEACCES: return SE_EACCES; case WSAEFAULT: return SE_EFAULT; case WSAEINVAL: return SE_EINVAL; case WSAEMFILE: return SE_EMFILE; case WSAEWOULDBLOCK: return SE_EWOULDBLOCK; case WSAEINPROGRESS: return SE_EINPROGRESS; case WSAEALREADY: return SE_EALREADY; case WSAENOTSOCK: return SE_ENOTSOCK; case WSAEDESTADDRREQ: return SE_EDESTADDRREQ; case WSAEMSGSIZE: return SE_EMSGSIZE; case WSAEPROTOTYPE: return SE_EPROTOTYPE; case WSAENOPROTOOPT: return SE_ENOPROTOOPT; case WSAEPROTONOSUPPORT: return SE_EPROTONOSUPPORT; case WSAESOCKTNOSUPPORT: return SE_ESOCKTNOSUPPORT; case WSAEOPNOTSUPP: return SE_EOPNOTSUPP; case WSAEPFNOSUPPORT: return SE_EPFNOSUPPORT; case WSAEAFNOSUPPORT: return SE_EAFNOSUPPORT; case WSAEADDRINUSE: return SE_EADDRINUSE; case WSAEADDRNOTAVAIL: return SE_EADDRNOTAVAIL; case WSAENETDOWN: return SE_ENETDOWN; case WSAENETUNREACH: return SE_ENETUNREACH; case WSAENETRESET: return SE_ENETRESET; case WSAECONNABORTED: return SE_ECONNABORTED; case WSAECONNRESET: return SE_ECONNRESET; case WSAENOBUFS: return SE_ENOBUFS; case WSAEISCONN: return SE_EISCONN; case WSAENOTCONN: return SE_ENOTCONN; case WSAESHUTDOWN: return SE_ESHUTDOWN; case WSAETOOMANYREFS: return SE_ETOOMANYREFS; case WSAETIMEDOUT: return SE_ETIMEDOUT; case WSAECONNREFUSED: return SE_ECONNREFUSED; case WSAELOOP: return SE_ELOOP; case WSAENAMETOOLONG: return SE_ENAMETOOLONG; case WSAEHOSTDOWN: return SE_EHOSTDOWN; case WSAEHOSTUNREACH: return SE_EHOSTUNREACH; case WSAENOTEMPTY: return SE_ENOTEMPTY; case WSAEPROCLIM: return SE_EPROCLIM; case WSAEUSERS: return SE_EUSERS; case WSAEDQUOT: return SE_EDQUOT; case WSAESTALE: return SE_ESTALE; case WSAEREMOTE: return SE_EREMOTE; case WSAEDISCON: return SE_EDISCON; case WSASYSNOTREADY: return SE_SYSNOTREADY; case WSAVERNOTSUPPORTED: return SE_VERNOTSUPPORTED; case WSANOTINITIALISED: return SE_NOTINITIALISED; case WSAHOST_NOT_FOUND: return SE_HOST_NOT_FOUND; case WSATRY_AGAIN: return SE_TRY_AGAIN; case WSANO_RECOVERY: return SE_NO_RECOVERY; case WSANO_DATA: return SE_NO_DATA; // case : return SE_UDP_ERR_PORT_UNREACH; //@TODO Find it's replacement } UE_LOG(LogSockets, Warning, TEXT("Unhandled socket error! Error Code: %d"), Code); check(0); return SE_NO_ERROR; } bool FSocketSubsystemWindows::HasNetworkDevice() { return true; } const TCHAR* FSocketSubsystemWindows::GetSocketAPIName() const { return TEXT("WinSock"); } FSocketBSD* FSocketSubsystemWindows::InternalBSDSocketFactory(SOCKET Socket, ESocketType SocketType, const FString& SocketDescription, const FName& SocketProtocol) { // return a new socket object return new FSocketWindows(Socket, SocketType, SocketDescription, SocketProtocol, this); }