Files
UnrealEngineUWP/Engine/Source/Runtime/HTML5/Simulator/HTML5Win32/Private/SocketRaw.cpp
Max Preussner e68711fa9a fixed FSocket::HasPendingData wrongly returning true if ioctrl is unavailable and/or the pending data size is zero
#CodeReview: peter.sauerbrei, josh.adams

[CL 2052830 by Max Preussner in Main branch]
2014-04-23 20:01:57 -04:00

397 lines
10 KiB
C++

// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
#include "SocketRaw.h"
#include "IPAddressRaw.h"
#pragma warning( disable : 4530 )
#define WIN32_LEAN_AND_MEAN
#include <WinSock2.h>
#include <ws2tcpip.h>
#include <cstring>
#include <cassert>
#include <stdio.h>
#include "RawData.h"
#include <crtdbg.h>
/* Current Socket State */
namespace SocketRawEnum
{
enum Param
{
CanRead,
CanWrite,
HasError,
};
enum Return
{
Yes,
No,
EncounteredError,
};
}
SocketRawEnum::Return SocketCurrentState ( SOCKET Socket , SocketRawEnum::Param State, unsigned int WaitTimeMSec = 0)
{
timeval Time;
Time.tv_sec = (int)WaitTimeMSec/1000;
Time.tv_usec = WaitTimeMSec;
fd_set SocketSet;
// Set up the socket sets we are interested in (just this one)
FD_ZERO(&SocketSet);
FD_SET(Socket, &SocketSet);
// Check the status of the state
int SelectStatus = 0;
switch (State)
{
case SocketRawEnum::CanRead:
SelectStatus = select(Socket + 1, &SocketSet, NULL, NULL, &Time);
break;
case SocketRawEnum::CanWrite:
SelectStatus = select(Socket + 1, NULL, &SocketSet, NULL, &Time);
break;
case SocketRawEnum::HasError:
SelectStatus = select(Socket + 1, NULL, NULL, &SocketSet, &Time);
break;
}
// if the select returns a positive number, the socket had the state, 0 means didn't have it, and negative is API error condition (not socket's error state)
return SelectStatus > 0 ? SocketRawEnum::Yes :
SelectStatus == 0 ? SocketRawEnum::No :
SocketRawEnum::EncounteredError;
}
bool FSocketRaw::Close()
{
if (SocketRawData->socket != INVALID_SOCKET)
{
int error = closesocket(SocketRawData->socket);
SocketRawData->socket = INVALID_SOCKET;
return error == 0;
}
return false;
}
int FSocketRaw::Bind( const FInternetAddrRaw& Addr )
{
const FInternetAddrRawData* data = Addr.GetInternalData();
return bind(SocketRawData->socket, (const sockaddr*)&(data->Addr), sizeof(sockaddr_in));
}
unsigned int FSocketRaw::Connect( const FInternetAddrRaw& Addr )
{
const FInternetAddrRawData* data = Addr.GetInternalData();
int Return = connect(SocketRawData->socket, (const sockaddr*)&(data->Addr), sizeof(sockaddr_in));
return Return;
}
bool FSocketRaw::Listen( unsigned int MaxBacklog )
{
return listen(SocketRawData->socket, MaxBacklog) == 0 ;
}
bool FSocketRaw::HasPendingConnection( bool& bHasPendingConnection )
{
bool bHasSucceeded = false;
bHasPendingConnection = false;
// make sure socket has no error state
if (SocketCurrentState(SocketRawData->socket, SocketRawEnum::HasError) == SocketRawEnum::No)
{
// get the read state
SocketRawEnum::Return State = SocketCurrentState(SocketRawData->socket, SocketRawEnum::CanRead);
// turn the result into the outputs
bHasSucceeded = State != SocketRawEnum::EncounteredError;
bHasPendingConnection = State == SocketRawEnum::Yes;
}
return bHasSucceeded;
}
bool FSocketRaw::HasPendingData( unsigned int& PendingDataSize )
{
if (SocketCurrentState(SocketRawData->socket, SocketRawEnum::CanRead) == SocketRawEnum::Yes)
{
if (ioctlsocket(SocketRawData->socket, FIONREAD, (u_long*)(&PendingDataSize)) == 0)
{
return (PendingDataSize > 0);
}
}
return false;
}
FSocketRaw* FSocketRaw::Accept()
{
SOCKET NewSocket = accept(SocketRawData->socket,NULL,NULL);
if ( NewSocket != INVALID_SOCKET )
{
FSocketRawData *RawData = new FSocketRawData();
RawData->socket = NewSocket;
return new FSocketRaw(RawData);
}
return NULL;
}
FSocketRaw* FSocketRaw::Accept( FInternetAddrRaw& OutAddr )
{
int SizeOf = sizeof(sockaddr_in);
const FInternetAddrRawData *RawData = OutAddr.GetInternalData();
SOCKET NewSocket = accept(SocketRawData->socket, (sockaddr*)&(RawData->Addr), &SizeOf);
if (NewSocket != INVALID_SOCKET)
{
FSocketRawData *RawData = new FSocketRawData();
RawData->socket = NewSocket;
return new FSocketRaw(RawData);
}
return NULL;
}
FSocketRaw::FSocketRaw( FSocketRawData* InData )
{
SocketRawData = InData;
}
FSocketRaw::FSocketRaw(bool IsTCP)
{
SocketRawData = new FSocketRawData();
if ( IsTCP )
{
SocketRawData->socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
}
else
{
SocketRawData->socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
}
if (SocketRawData->socket == INVALID_SOCKET)
{
delete SocketRawData;
SocketRawData = NULL;
}
}
bool FSocketRaw::SendTo( const unsigned char* Data, unsigned int Count, unsigned int & BytesSent, const FInternetAddrRaw& Destination )
{
const FInternetAddrRawData *RawData = Destination.GetInternalData();
BytesSent = sendto(SocketRawData->socket, (const char*)Data, Count, 0, (sockaddr*)&(RawData->Addr), sizeof(sockaddr_in));
return BytesSent >= 0;
}
bool FSocketRaw::Send( const unsigned char* Data, unsigned int Count, unsigned int& BytesSent )
{
BytesSent = send(SocketRawData->socket,(const char*)Data,Count,0);
return BytesSent >= 0;
}
bool FSocketRaw::RecvFrom( unsigned char* Data, unsigned int BufferSize, unsigned int& BytesRead, FInternetAddrRaw& Source, unsigned int Flags )
{
int Size = sizeof(sockaddr_in);
sockaddr* Addr = (sockaddr*)&(Source.GetInternalData()->Addr);
// Read into the buffer and set the source address
int read = recvfrom(SocketRawData->socket, (char*)Data, BufferSize, Flags, Addr, &Size);
BytesRead = read;
return read >= 0;
}
bool FSocketRaw::Recv( unsigned char* Data, unsigned int BufferSize, unsigned int& BytesRead, unsigned int Flags )
{
BytesRead = recv(SocketRawData->socket, (char*)Data, BufferSize, Flags);
return BytesRead >= 0;
}
bool FSocketRaw::WaitForRead( int WaitTime )
{
if (SocketCurrentState(SocketRawData->socket,SocketRawEnum::CanRead, WaitTime) == SocketRawEnum::Yes)
{
return true;
}
return false;
}
bool FSocketRaw::WaitForWrite( int WaitTime )
{
if (SocketCurrentState(SocketRawData->socket,SocketRawEnum::CanWrite, WaitTime) == SocketRawEnum::Yes)
{
return true;
}
return false;
}
bool FSocketRaw::WaitForReadWrite( int WaitTime )
{
return WaitForRead( WaitTime ) || WaitForWrite(WaitTime);
}
bool FSocketRaw::GetAddress( FInternetAddrRaw& OutAddr )
{
sockaddr *Addr = (sockaddr *)&OutAddr.GetInternalData()->Addr;
int Size = sizeof(sockaddr_in);
return getsockname(SocketRawData->socket, Addr, &Size) == 0;
}
bool FSocketRaw::SetNonBlocking( bool bIsNonBlocking /*= true*/ )
{
u_long Value = bIsNonBlocking ? true : false;
return ioctlsocket(SocketRawData->socket,FIONBIO,&Value) == 0;
#if 0
int Flags = fcntl(Socket, F_GETFL, 0);
//Set the flag or clear it, without destroying the other flags.
Flags = bIsNonBlocking ? Flags | O_NONBLOCK : Flags ^ (Flags & O_NONBLOCK);
int err = fcntl(Socket, F_SETFL, Flags);
return (err == 0 ? true : false);
#endif
}
bool FSocketRaw::SetBroadcast( bool bAllowBroadcast /*= true*/ )
{
int Param = bAllowBroadcast ? 1 : 0;
return setsockopt(SocketRawData->socket,SOL_SOCKET,SO_BROADCAST,(char*)&Param,sizeof(Param)) == 0;
}
bool FSocketRaw::JoinMulticastGroup( const FInternetAddrRaw& GroupAddress )
{
ip_mreq imr;
const FInternetAddrRawData* RawData = GroupAddress.GetInternalData();
imr.imr_interface.s_addr = INADDR_ANY;
imr.imr_multiaddr = RawData->Addr.sin_addr;
return (setsockopt(SocketRawData->socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&imr, sizeof(imr)) == 0);
}
bool FSocketRaw::LeaveMulticastGroup( const FInternetAddrRaw& GroupAddress )
{
ip_mreq imr;
const FInternetAddrRawData* RawData = GroupAddress.GetInternalData();
imr.imr_interface.s_addr = INADDR_ANY;
imr.imr_multiaddr = RawData->Addr.sin_addr;
return (setsockopt(SocketRawData->socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*)&imr, sizeof(imr)) == 0);
}
bool FSocketRaw::SetMulticastLoopback( bool bLoopback )
{
return (setsockopt(SocketRawData->socket, IPPROTO_IP, IP_MULTICAST_LOOP, (char*)&bLoopback, sizeof(bLoopback)) == 0);
}
bool FSocketRaw::SetMulticastTtl( unsigned int TimeToLive )
{
return (setsockopt( SocketRawData->socket, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&TimeToLive, sizeof(TimeToLive)) == 0);
}
bool FSocketRaw::SetReuseAddr( bool bAllowReuse /*= true*/ )
{
int Param = bAllowReuse ? 1 : 0;
return setsockopt(SocketRawData->socket,SOL_SOCKET,SO_REUSEADDR,(char*)&Param,sizeof(Param)) == 0;
}
bool FSocketRaw::SetLinger( bool bShouldLinger /*= true*/, int Timeout /*= 0*/ )
{
linger ling;
ling.l_onoff = bShouldLinger;
ling.l_linger = (u_short)Timeout;
return setsockopt(SocketRawData->socket,SOL_SOCKET,SO_LINGER,(char*)&ling,sizeof(ling)) == 0;
}
bool FSocketRaw::SetSendBufferSize( unsigned int Size, unsigned int & NewSize )
{
int SizeSize = sizeof(SOCKLEN);
bool bOk = setsockopt(SocketRawData->socket,SOL_SOCKET,SO_RCVBUF,(char*)&Size,sizeof(SOCKLEN)) == 0;
// Read the value back in case the size was modified
getsockopt(SocketRawData->socket,SOL_SOCKET,SO_RCVBUF,(char*)&NewSize, &SizeSize);
return bOk;
}
bool FSocketRaw::SetReceiveBufferSize( unsigned int Size, unsigned int & NewSize )
{
int SizeSize = sizeof(SOCKLEN);
bool bOk = setsockopt(SocketRawData->socket,SOL_SOCKET,SO_RCVBUF,(char*)&Size,sizeof(SOCKLEN)) == 0;
// Read the value back in case the size was modified
getsockopt(SocketRawData->socket,SOL_SOCKET,SO_RCVBUF,(char*)&NewSize, &SizeSize);
return bOk;
}
unsigned int FSocketRaw::GetPortNo(bool& Succeeded )
{
sockaddr_in Addr;
SOCKLEN Size = sizeof(sockaddr_in);
// Figure out what ip/port we are bound to
Succeeded = getsockname(SocketRawData->socket, (sockaddr*)&Addr, &Size) == 0;
// Read the port number
return ntohs(Addr.sin_port);
}
bool FSocketRaw::IsValid()
{
if ( SocketRawData && SocketRawData->socket != INVALID_SOCKET )
return true;
return false;
}
bool FSocketRaw::GetHostByName( const char *NAME, FInternetAddrRaw& Address )
{
hostent* HostEnt = gethostbyname(NAME);
// Make sure it's a valid type
if (HostEnt->h_addrtype == PF_INET)
{
// Copy the data before letting go of the lock. This is safe only
// for the copy locally. If another thread is reading this while
// we are copying they will get munged data. This relies on the
// consumer of this class to call the resolved() accessor before
// attempting to read this data
(Address).SetIp(*(unsigned int *)(*HostEnt->h_addr_list));
return true;
}
else
{
return false;
}
}
bool FSocketRaw::GetHostName(const char *NAME )
{
bool bRead = gethostname(const_cast<char *>(NAME),256) == 0;
return bRead;
}
WSADATA wsaData;
bool FSocketRaw::Init()
{
_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_WNDW );
_CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
int iResult;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed: %d\n", iResult);
return false;
}
return true;
}