2014-03-14 14:13:41 -04:00
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
# include "NetworkFileSystemPrivatePCH.h"
2014-04-23 18:34:12 -04:00
# include "TargetPlatform.h"
2014-06-12 17:02:52 -04:00
# include "NetworkFileServerConnection.h"
class FNetworkFileServerClientConnectionThreaded
: public FNetworkFileServerClientConnection
, protected FRunnable
{
public :
FNetworkFileServerClientConnectionThreaded ( FSocket * InSocket , const FFileRequestDelegate & InFileRequestDelegate ,
const FRecompileShadersDelegate & InRecompileShadersDelegate , const TArray < ITargetPlatform * > & InActiveTargetPlatforms )
: FNetworkFileServerClientConnection ( InFileRequestDelegate , InRecompileShadersDelegate , InActiveTargetPlatforms )
, Socket ( InSocket )
{
Running . Set ( true ) ;
StopRequested . Reset ( ) ;
# if UE_BUILD_DEBUG
// this thread needs more space in debug builds as it tries to log messages and such
const static uint32 NetworkFileServerThreadSize = 2 * 1024 * 1024 ;
# else
const static uint32 NetworkFileServerThreadSize = 8 * 1024 ;
# endif
WorkerThread = FRunnableThread : : Create ( this , TEXT ( " FNetworkFileServerClientConnection " ) , NetworkFileServerThreadSize , TPri_AboveNormal ) ;
}
virtual bool Init ( )
{
return true ;
}
virtual uint32 Run ( )
{
while ( ! StopRequested . GetValue ( ) )
{
2014-08-07 12:57:57 -04:00
// read a header and payload pair
FArrayReader Payload ;
if ( ! FNFSMessageHeader : : ReceivePayload ( Payload , FSimpleAbstractSocket_FSocket ( Socket ) ) )
break ;
// now process the contents of the payload
FBufferArchive Out ;
if ( ! FNetworkFileServerClientConnection : : ProcessPayload ( Payload , Out ) )
{
// give the processing of the payload a chance to terminate the connection
// failed to process message
UE_LOG ( LogFileServer , Warning , TEXT ( " Unable to process payload terminating connection " ) ) ;
break ;
}
if ( ! FNFSMessageHeader : : WrapAndSendPayload ( Out , FSimpleAbstractSocket_FSocket ( Socket ) ) )
break ;
}
2014-06-12 17:02:52 -04:00
2014-08-07 12:57:57 -04:00
return true ;
2014-06-12 17:02:52 -04:00
}
2014-08-07 12:57:57 -04:00
virtual void Stop ( )
2014-06-12 17:02:52 -04:00
{
StopRequested . Set ( true ) ;
}
virtual void Exit ( )
{
Socket - > Close ( ) ;
ISocketSubsystem : : Get ( ) - > DestroySocket ( Socket ) ;
Running . Set ( false ) ;
}
bool IsRunning ( )
{
return ( Running . GetValue ( ) ! = 0 ) ;
}
2014-08-07 12:57:57 -04:00
void GetAddress ( FInternetAddr & Addr )
{
Socket - > GetAddress ( Addr ) ;
}
2014-06-12 17:02:52 -04:00
~ FNetworkFileServerClientConnectionThreaded ( )
{
WorkerThread - > Kill ( true ) ;
}
private :
FSocket * Socket ;
FThreadSafeCounter StopRequested ;
FThreadSafeCounter Running ;
FRunnableThread * WorkerThread ;
} ;
2014-03-14 14:13:41 -04:00
/* FNetworkFileServer constructors
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-06-12 17:02:52 -04:00
FNetworkFileServer : : FNetworkFileServer ( int32 InPort , const FFileRequestDelegate * InFileRequestDelegate , const FRecompileShadersDelegate * InRecompileShadersDelegate , const TArray < ITargetPlatform * > & InActiveTargetPlatforms )
: ActiveTargetPlatforms ( InActiveTargetPlatforms )
2014-03-14 14:13:41 -04:00
{
2014-07-07 15:39:19 -04:00
if ( InPort < 0 )
{
InPort = DEFAULT_TCP_FILE_SERVING_PORT ;
}
2014-06-12 17:02:52 -04:00
Running . Set ( false ) ;
StopRequested . Set ( false ) ;
2014-03-14 14:13:41 -04:00
UE_LOG ( LogFileServer , Warning , TEXT ( " Unreal Network File Server starting up... " ) ) ;
if ( InFileRequestDelegate & & InFileRequestDelegate - > IsBound ( ) )
{
FileRequestDelegate = * InFileRequestDelegate ;
}
if ( InRecompileShadersDelegate & & InRecompileShadersDelegate - > IsBound ( ) )
{
RecompileShadersDelegate = * InRecompileShadersDelegate ;
}
// make sure sockets are going
ISocketSubsystem * SocketSubsystem = ISocketSubsystem : : Get ( ) ;
if ( ! SocketSubsystem )
{
UE_LOG ( LogFileServer , Error , TEXT ( " Could not get socket subsystem. " ) ) ;
}
else
{
// create a server TCP socket
Socket = SocketSubsystem - > CreateSocket ( NAME_Stream , TEXT ( " FNetworkFileServer tcp-listen " ) ) ;
if ( ! Socket )
{
UE_LOG ( LogFileServer , Error , TEXT ( " Could not create listen socket. " ) ) ;
}
else
{
// listen on any IP address
ListenAddr = SocketSubsystem - > GetLocalBindAddr ( * GLog ) ;
ListenAddr - > SetPort ( InPort ) ;
Socket - > SetReuseAddr ( ) ;
// bind to the address
if ( ! Socket - > Bind ( * ListenAddr ) )
{
UE_LOG ( LogFileServer , Warning , TEXT ( " Failed to bind listen socket %s in FNetworkFileServer " ) , * ListenAddr - > ToString ( true ) ) ;
}
// listen for connections
else if ( ! Socket - > Listen ( 16 ) )
{
UE_LOG ( LogFileServer , Warning , TEXT ( " Failed to listen on socket %s in FNetworkFileServer " ) , * ListenAddr - > ToString ( true ) ) ;
}
else
{
// set the port on the listen address to be the same as the port on the socket
int32 port = Socket - > GetPortNo ( ) ;
check ( ( InPort = = 0 & & port ! = 0 ) | | port = = InPort ) ;
ListenAddr - > SetPort ( port ) ;
// now create a thread to accept connections
2014-05-12 08:39:12 -04:00
Thread = FRunnableThread : : Create ( this , TEXT ( " FNetworkFileServer " ) , 8 * 1024 , TPri_AboveNormal ) ;
2014-03-14 14:13:41 -04:00
UE_LOG ( LogFileServer , Display , TEXT ( " Unreal Network File Server is ready for client connections on %s! " ) , * ListenAddr - > ToString ( true ) ) ;
}
}
}
2014-06-12 17:02:52 -04:00
}
2014-03-14 14:13:41 -04:00
FNetworkFileServer : : ~ FNetworkFileServer ( )
{
// Kill the running thread.
if ( Thread ! = NULL )
{
Thread - > Kill ( true ) ;
delete Thread ;
Thread = NULL ;
}
// We are done with the socket.
Socket - > Close ( ) ;
ISocketSubsystem : : Get ( ) - > DestroySocket ( Socket ) ;
Socket = NULL ;
}
/* FRunnable overrides
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint32 FNetworkFileServer : : Run ( )
{
2014-06-12 17:02:52 -04:00
Running . Set ( true ) ;
2014-03-14 14:13:41 -04:00
// go until requested to be done
2014-06-12 17:02:52 -04:00
while ( ! StopRequested . GetValue ( ) )
2014-03-14 14:13:41 -04:00
{
bool bReadReady = false ;
// clean up closed connections
for ( int32 ConnectionIndex = 0 ; ConnectionIndex < Connections . Num ( ) ; + + ConnectionIndex )
{
2014-06-12 17:02:52 -04:00
FNetworkFileServerClientConnectionThreaded * Connection = Connections [ ConnectionIndex ] ;
2014-03-14 14:13:41 -04:00
2014-06-12 17:02:52 -04:00
if ( ! Connection - > IsRunning ( ) )
2014-03-14 14:13:41 -04:00
{
UE_LOG ( LogFileServer , Display , TEXT ( " Client %s disconnected. " ) , * Connection - > GetDescription ( ) ) ;
Connections . RemoveAtSwap ( ConnectionIndex ) ;
delete Connection ;
}
}
// check for incoming connections
if ( Socket - > HasPendingConnection ( bReadReady ) & & bReadReady )
{
FSocket * ClientSocket = Socket - > Accept ( TEXT ( " Remote Console Connection " ) ) ;
if ( ClientSocket ! = NULL )
{
2014-08-07 12:57:57 -04:00
TSharedPtr < FInternetAddr > Addr = ISocketSubsystem : : Get ( PLATFORM_SOCKETSUBSYSTEM ) - > CreateInternetAddr ( ) ; ;
ClientSocket - > GetAddress ( * Addr ) ;
for ( auto PreviousConnection : Connections )
{
TSharedPtr < FInternetAddr > PreviousAddr = ISocketSubsystem : : Get ( PLATFORM_SOCKETSUBSYSTEM ) - > CreateInternetAddr ( ) ; ;
PreviousConnection - > GetAddress ( * PreviousAddr ) ;
if ( * Addr = = * PreviousAddr )
{
// kill hte connection
PreviousConnection - > Stop ( ) ;
UE_LOG ( LogFileServer , Display , TEXT ( " Killing client connection %s because new client connected from same address. " ) , * PreviousConnection - > GetDescription ( ) ) ;
}
}
2014-06-12 17:02:52 -04:00
FNetworkFileServerClientConnectionThreaded * Connection = new FNetworkFileServerClientConnectionThreaded ( ClientSocket , FileRequestDelegate , RecompileShadersDelegate , ActiveTargetPlatforms ) ;
2014-03-14 14:13:41 -04:00
Connections . Add ( Connection ) ;
UE_LOG ( LogFileServer , Display , TEXT ( " Client %s connected. " ) , * Connection - > GetDescription ( ) ) ;
}
}
FPlatformProcess : : Sleep ( 0.25f ) ;
}
return 0 ;
}
void FNetworkFileServer : : Exit ( )
{
// close all connections
for ( int32 ConnectionIndex = 0 ; ConnectionIndex < Connections . Num ( ) ; ConnectionIndex + + )
{
delete Connections [ ConnectionIndex ] ;
}
Connections . Empty ( ) ;
}
/* INetworkFileServer overrides
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-07-07 15:39:19 -04:00
FString FNetworkFileServer : : GetSupportedProtocol ( ) const
{
return FString ( " tcp " ) ;
}
2014-03-14 14:13:41 -04:00
bool FNetworkFileServer : : GetAddressList ( TArray < TSharedPtr < FInternetAddr > > & OutAddresses ) const
{
if ( ListenAddr . IsValid ( ) )
{
FString ListenAddressString = ListenAddr - > ToString ( true ) ;
if ( ListenAddressString . StartsWith ( TEXT ( " 0.0.0.0 " ) ) )
{
if ( ISocketSubsystem : : Get ( ) - > GetLocalAdapterAddresses ( OutAddresses ) )
{
for ( int32 AddressIndex = 0 ; AddressIndex < OutAddresses . Num ( ) ; + + AddressIndex )
{
OutAddresses [ AddressIndex ] - > SetPort ( ListenAddr - > GetPort ( ) ) ;
}
}
}
else
{
OutAddresses . Add ( ListenAddr ) ;
}
}
return ( OutAddresses . Num ( ) > 0 ) ;
2014-06-12 17:02:52 -04:00
}
bool FNetworkFileServer : : IsItReadyToAcceptConnections ( void ) const
{
return ( Running . GetValue ( ) ! = 0 ) ;
}
int32 FNetworkFileServer : : NumConnections ( void ) const
{
return Connections . Num ( ) ;
}
void FNetworkFileServer : : Shutdown ( void )
{
Stop ( ) ;
}