bool FLiveEditorManager::ConnectToRemoteHost( FString IPAddress ) { IPAddress.Replace( TEXT(" "), TEXT("") ); TArray<FString> Parts; IPAddress.ParseIntoArray( Parts, TEXT("."), true ); if ( Parts.Num() != 4 ) return false; uint8 NumericParts[4]; for ( int32 i = 0; i < 4; ++i ) { NumericParts[i] = FCString::Atoi( *Parts[i] ); } FSocket* Socket = FTcpSocketBuilder(TEXT("FLiveEditorManager.RemoteConnection")); FIPv4Endpoint Endpoint(FIPv4Address(NumericParts[0], NumericParts[1], NumericParts[2], NumericParts[3]), LIVEEDITORLISTENSERVER_DEFAULT_PORT); if ( Socket->Connect(*Endpoint.ToInternetAddr()) ) { RemoteConnections.Add(IPAddress, Socket); return true; } else { return false; } }
void FLiveEditorManager::BroadcastValueUpdate( const FString &ClassName, const FString &PropertyName, const FString &PropertyValue ) { // remove closed connections for ( TMap<FString, class FSocket *>::TIterator ConnectionIt(RemoteConnections); ConnectionIt; ++ConnectionIt ) { FSocket *Connection = (*ConnectionIt).Value; if ( Connection->GetConnectionState() != SCS_Connected ) { RemoteConnections.Remove( (*ConnectionIt).Key ); } } //no one to talk to, exit if ( RemoteConnections.Num() == 0 ) { return; } nLiveEditorListenServer::FNetworkMessage Message; Message.Type = nLiveEditorListenServer::CLASSDEFAULT_OBJECT_PROPERTY; Message.Payload.ClassName = ClassName; Message.Payload.PropertyName = PropertyName; Message.Payload.PropertyValue = PropertyValue; TSharedPtr<FArrayWriter> Datagram = MakeShareable(new FArrayWriter(true)); *Datagram << Message; for ( TMap<FString, class FSocket *>::TIterator ConnectionIt(RemoteConnections); ConnectionIt; ++ConnectionIt ) { FSocket *Connection = (*ConnectionIt).Value; int32 BytesSent = 0; Connection->Send( Datagram->GetData(), Datagram->Num(), BytesSent ); } }
void PacketReceiverTCP::process() { FSocket *socket = pNetworkInterface_->socket(); uint32 DataSize = 0; while (socket->HasPendingData(DataSize)) { pBuffer_->resize(FMath::Min(DataSize, 65507u)); int32 BytesRead = 0; if (socket->Recv(pBuffer_->data(), pBuffer_->size(), BytesRead)) { pBuffer_->wpos(BytesRead); if (pNetworkInterface_->filter()) { pNetworkInterface_->filter()->recv(pMessageReader_, pBuffer_); } else { pMessageReader_->process(pBuffer_->data(), 0, BytesRead); } } } }
uint32 FNetworkFileServer::Run( ) { Running.Set(true); // go until requested to be done while (!StopRequested.GetValue()) { bool bReadReady = false; // clean up closed connections for (int32 ConnectionIndex = 0; ConnectionIndex < Connections.Num(); ++ConnectionIndex) { FNetworkFileServerClientConnectionThreaded* Connection = Connections[ConnectionIndex]; if (!Connection->IsRunning()) { 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) { TSharedPtr<FInternetAddr> Addr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr(); ClientSocket->GetAddress(*Addr); TSharedPtr<FInternetAddr> PeerAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr(); ClientSocket->GetPeerAddress(*PeerAddr); for ( auto PreviousConnection : Connections ) { TSharedPtr<FInternetAddr> PreviousAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();; PreviousConnection->GetAddress( *PreviousAddr ); TSharedPtr<FInternetAddr> PreviousPeerAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();; PreviousConnection->GetPeerAddress( *PreviousPeerAddr ); if ( ( *Addr == *PreviousAddr ) && (*PeerAddr == *PreviousPeerAddr ) ) { // kill hte connection PreviousConnection->Stop(); UE_LOG(LogFileServer, Warning, TEXT( "Killing client connection %s because new client connected from same address." ), *PreviousConnection->GetDescription() ); } } FNetworkFileServerClientConnectionThreaded* Connection = new FNetworkFileServerClientConnectionThreaded(ClientSocket, FileRequestDelegate, RecompileShadersDelegate, ActiveTargetPlatforms); Connections.Add(Connection); UE_LOG(LogFileServer, Display, TEXT( "Client %s connected." ), *Connection->GetDescription() ); } } FPlatformProcess::Sleep(0.25f); } return 0; }
FSocket* FSocket::NewLC(const StringBuffer& peer, int32_t port) { FSocket* self = new ( ELeave ) FSocket(); CleanupStack::PushL( self ); self->ConstructL(peer, port); return self; }
bool UNetworkManager::Start(int32 InPortNum) // Restart the server if configuration changed { if (InPortNum == this->PortNum && this->bIsListening) return true; // Already started if (ConnectionSocket) // Release previous connection { ConnectionSocket->Close(); ConnectionSocket = NULL; } if (TcpListener) // Delete previous configuration first { UE_LOG(LogUnrealCV, Warning, TEXT("Stop previous server")); TcpListener->Stop(); // TODO: test the robustness, will this operation successful? delete TcpListener; } this->PortNum = InPortNum; // Start a new TCPListener FIPv4Address IPAddress = FIPv4Address(0, 0, 0, 0); // int32 PortNum = this->PortNum; // Make this configuable FIPv4Endpoint Endpoint(IPAddress, PortNum); FSocket* ServerSocket = FTcpSocketBuilder(TEXT("FTcpListener server")) // TODO: Need to realease this socket // .AsReusable() .BoundToEndpoint(Endpoint) .Listening(8); if (ServerSocket) { int32 NewSize = 0; ServerSocket->SetReceiveBufferSize(2 * 1024 * 1024, NewSize); } else { this->bIsListening = false; UE_LOG(LogUnrealCV, Warning, TEXT("Cannot start listening on port %d, Port might be in use"), PortNum); return false; } TcpListener = new FTcpListener(*ServerSocket); // TcpListener = new FTcpListener(Endpoint); // This will be released after start // In FSocket, when a FSocket is set as reusable, it means SO_REUSEADDR, not SO_REUSEPORT. see SocketsBSD.cpp TcpListener->OnConnectionAccepted().BindUObject(this, &UNetworkManager::Connected); if (TcpListener->Init()) { this->bIsListening = true; UE_LOG(LogUnrealCV, Warning, TEXT("Start listening on %d"), PortNum); return true; } else { this->bIsListening = false; UE_LOG(LogUnrealCV, Error, TEXT("Can not start listening on port %d"), PortNum); return false; } }
FSocket* FSocket::NewL(const StringBuffer& peer, int32_t port) { FSocket* self = FSocket::NewLC(peer, port); CleanupStack::Pop( self ); if (self->getLastStatus() != KErrNone) { // Something wrong. LOG.debug("FSocket::NewL - error in ConstructL (status = %d)", self->getLastStatus()); delete self; return NULL; } return self; }
void FLiveEditorListenServer::RemoveHooks() { if ( Listener ) { Listener->Stop(); delete Listener; Listener = NULL; } if ( TransactionHistory ) { delete TransactionHistory; TransactionHistory = NULL; } if ( !PendingClients.IsEmpty() ) { FSocket *Client = NULL; while( PendingClients.Dequeue(Client) ) { Client->Close(); } } for ( TArray<class FSocket*>::TIterator ClientIt(Clients); ClientIt; ++ClientIt ) { (*ClientIt)->Close(); } delete TickObject; TickObject = NULL; delete ObjectCreateListener; ObjectCreateListener = NULL; delete ObjectDeleteListener; ObjectDeleteListener = NULL; FCoreUObjectDelegates::PostLoadMap.RemoveAll(MapLoadObserver.Get()); FCoreUObjectDelegates::PreLoadMap.RemoveAll(MapLoadObserver.Get()); MapLoadObserver = NULL; }
bool FPerfCounters::Tick(float DeltaTime) { // if we didn't get a socket, don't tick if (Socket == nullptr) { return false; } // accept any connections static const FString PerfCounterRequest = TEXT("FPerfCounters Request"); FSocket* IncomingConnection = Socket->Accept(PerfCounterRequest); if (IncomingConnection) { // make sure this is non-blocking bool bSuccess = false; IncomingConnection->SetNonBlocking(true); // read any data that's ready // NOTE: this is not a full HTTP implementation, just enough to be usable by curl uint8 Buffer[2*1024] = { 0 }; int32 DataLen = 0; if (IncomingConnection->Recv(Buffer, sizeof(Buffer)-1, DataLen, ESocketReceiveFlags::None)) { // scan the buffer for a line FUTF8ToTCHAR WideBuffer(reinterpret_cast<const ANSICHAR*>(Buffer)); const TCHAR* BufferEnd = FCString::Strstr(WideBuffer.Get(), TEXT("\r\n")); if (BufferEnd != nullptr) { // crack into pieces FString MainLine(BufferEnd - WideBuffer.Get(), WideBuffer.Get()); TArray<FString> Tokens; MainLine.ParseIntoArrayWS(Tokens); if (Tokens.Num() >= 2) { FString Body; int ResponseCode = 200; // handle the request if (Tokens[0] != TEXT("GET")) { Body = FString::Printf(TEXT("{ \"error\": \"Method %s not allowed\" }"), *Tokens[0]); ResponseCode = 405; } else if (Tokens[1] == TEXT("/stats")) { Body = ToJson(); } else { Body = FString::Printf(TEXT("{ \"error\": \"%s not found\" }"), *Tokens[1]); ResponseCode = 404; } // send the response headers FString Header = FString::Printf(TEXT("HTTP/1.0 %d\r\nContent-Length: %d\r\nContent-Type: application/json\r\n\r\n"), ResponseCode, Body.Len()); if (SendAsUtf8(IncomingConnection, Header) && SendAsUtf8(IncomingConnection, Body)) { bSuccess = true; } } } } // log if we didn't succeed if (!bSuccess) { UE_LOG(LogPerfCounters, Warning, TEXT("FPerfCounters was unable to send a JSON response (or sent partial response)")); } // close the socket (whether we processed or not IncomingConnection->Close(); ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(IncomingConnection); } // keep ticking return true; }
void FLiveEditorListenServer::Tick( float DeltaTime ) { #if !UE_BUILD_SHIPPING if ( !PendingClients.IsEmpty() ) { FSocket *Client = NULL; while( PendingClients.Dequeue(Client) ) { Clients.Add(Client); } } // remove closed connections for (int32 ClientIndex = Clients.Num() - 1; ClientIndex >= 0; --ClientIndex) { if ( Clients[ClientIndex]->GetConnectionState() != SCS_Connected ) { Clients.RemoveAtSwap(ClientIndex); } } //poll for data for ( TArray<class FSocket*>::TIterator ClientIt(Clients); ClientIt; ++ClientIt ) { FSocket *Client = *ClientIt; uint32 DataSize = 0; while ( Client->HasPendingData(DataSize) ) { FArrayReaderPtr Datagram = MakeShareable(new FArrayReader(true)); Datagram->Init(FMath::Min(DataSize, 65507u)); int32 BytesRead = 0; if ( Client->Recv(Datagram->GetData(), Datagram->Num(), BytesRead) ) { nLiveEditorListenServer::FNetworkMessage Message; *Datagram << Message; ReplicateChanges( Message ); TransactionHistory->AppendTransaction( Message.Payload.ClassName, Message.Payload.PropertyName, Message.Payload.PropertyValue ); } } } //Check for any newly Tracked objects TArray<UObject*> NewTrackedObjects; ObjectCache.EvaluatePendingCreations( NewTrackedObjects ); //If there are any newly tracked objects, stuff them with the list of latest changes we've accumulated so far for ( TArray<UObject*>::TIterator NewObjectIt(NewTrackedObjects); NewObjectIt; ++NewObjectIt ) { UObject *NewObject = *NewObjectIt; TMap<FString,FString> Transactions; TransactionHistory->FindTransactionsForObject( NewObject, Transactions ); for ( TMap<FString,FString>::TConstIterator TransactionIt(Transactions); TransactionIt; ++TransactionIt ) { const FString &PropertyName = (*TransactionIt).Key; const FString &PropertyValue = (*TransactionIt).Value; nLiveEditorListenServer::SetPropertyValue( NewObject, PropertyName, PropertyValue ); } } #endif }
void FPerfCounters::TickSocket(float DeltaTime) { checkf(Socket != nullptr, TEXT("FPerfCounters::TickSocket() called without a valid socket!")); // accept any connections static const FString PerfCounterRequest = TEXT("FPerfCounters Request"); FSocket* IncomingConnection = Socket->Accept(PerfCounterRequest); if (IncomingConnection) { if (0) { TSharedRef<FInternetAddr> FromAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr(); IncomingConnection->GetPeerAddress(*FromAddr); UE_LOG(LogPerfCounters, Log, TEXT("New connection from %s"), *FromAddr->ToString(true)); } // make sure this is non-blocking IncomingConnection->SetNonBlocking(true); new (Connections) FPerfConnection(IncomingConnection); } TArray<FPerfConnection> ConnectionsToClose; for (FPerfConnection& Connection : Connections) { FSocket* ExistingSocket = Connection.Connection; if (ExistingSocket && ExistingSocket->Wait(ESocketWaitConditions::WaitForRead, FTimespan::Zero())) { // read any data that's ready // NOTE: this is not a full HTTP implementation, just enough to be usable by curl uint8 Buffer[2 * 1024] = { 0 }; int32 DataLen = 0; if (ExistingSocket->Recv(Buffer, sizeof(Buffer) - 1, DataLen, ESocketReceiveFlags::None)) { FResponse Response; if (ProcessRequest(Buffer, DataLen, Response)) { if (SendAsUtf8(ExistingSocket, Response.Header)) { if (!SendAsUtf8(ExistingSocket, Response.Body)) { UE_LOG(LogPerfCounters, Warning, TEXT("Unable to send full HTTP response body")); } } else { UE_LOG(LogPerfCounters, Warning, TEXT("Unable to send HTTP response header: %s"), *Response.Header); } } } else { UE_LOG(LogPerfCounters, Warning, TEXT("Unable to immediately receive request header")); } ConnectionsToClose.Add(Connection); } else if (Connection.ElapsedTime > 5.0f) { ConnectionsToClose.Add(Connection); } Connection.ElapsedTime += DeltaTime; } for (FPerfConnection& Connection : ConnectionsToClose) { Connections.RemoveSingleSwap(Connection); FSocket* ClosingSocket = Connection.Connection; if (ClosingSocket) { // close the socket (whether we processed or not) ClosingSocket->Close(); ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(ClosingSocket); if (0) { UE_LOG(LogPerfCounters, Log, TEXT("Closed connection.")); } } } }