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 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.")); } } } }