// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "UbaMemory.h" #include "UbaNetwork.h" #if PLATFORM_WINDOWS typedef struct sockaddr SOCKADDR; #else struct sockaddr; #endif namespace uba { class Logger; class StringBufferBase; void TraverseNetworkAddresses(Logger& logger, const Function& func); bool TraverseRemoteAddresses(Logger& logger, const tchar* addr, u16 port, const Function& func); class NetworkBackend { public: virtual ~NetworkBackend() {} // Shutdown the connection (stops/finishes traffic) // External code should wait for disconnect callback before assuming that no more recv callbacks can happen virtual void Shutdown(void* connection) = 0; enum : u8 { SendFlags_Async = 1 << 0, // Data is sent async and call is returned before data has been transmitted. (can be used inside recv callbacks). Will make copy of data SendFlags_ExternalWait = 1 << 1, // Same as async but will not do any copies of context or data. Assumes something outside is handling the waiting }; struct SendContext; // Send data to connection. If sendContext is set it means that backend expects sendContext to stay around in memory until send is done (or rather, response is received) virtual bool Send(Logger& logger, void* connection, const void* data, u32 dataSize, SendContext& sendContext, const tchar* sendHint) = 0; using DataSentCallback = void(void* context, u32 bytes); virtual void SetDataSentCallback(void* connection, void* context, DataSentCallback* callback) = 0; // Recv data from connection. This is callback based so header callback is called first after headerSize bytes have been read // If header callback sets a value in outBodySize, body callback will be called once body size bytes are received. using RecvHeaderCallback = bool(void* context, const Guid& connectionUid, u8* headerData, void*& outBodyContext, u8*& outBodyData, u32& outBodySize); using RecvBodyCallback = bool(void* context, bool recvError, u8* headerData, void* bodyContext, u8* bodyData, u32 bodySize); virtual void SetRecvCallbacks(void* connection, void* context, u32 headerSize, RecvHeaderCallback* h, RecvBodyCallback* b, const tchar* recvHint) = 0; using RecvTimeoutCallback = bool(void* context, u32 timeoutMs, const tchar* recvHint, const tchar* hint); virtual void SetRecvTimeout(void* connection, u32 timeoutMs, void* context, RecvTimeoutCallback* callback) = 0; // Disconnect callback. This is called as soon as connection is interrupted from send, recv or shutdown. using DisconnectCallback = void(void* context, const Guid& connectionUid, void* connection); virtual void SetDisconnectCallback(void* connection, void* context, DisconnectCallback* callback) = 0; virtual void SetAllowLessThanBodySize(void* connection, bool allow) = 0; // Start listen on port/ip. using ListenConnectedFunc = Function; virtual bool StartListen(Logger& logger, u16 port, const tchar* ip, const ListenConnectedFunc& connectedFunc) = 0; virtual void StopListen() = 0; // Connect to remote ip/port using ConnectedFunc = Function; virtual bool Connect(Logger& logger, const tchar* ip, const ConnectedFunc& connectedFunc, u16 port = DefaultPort, bool* timedOut = nullptr) = 0; virtual bool Connect(Logger& logger, const sockaddr& remoteSocketAddr, const ConnectedFunc& connectedFunc, bool* timedOut = nullptr, const tchar* nameHint = nullptr) = 0; // Remove connection (user guarantee connection is not referenced anywhere) virtual void DeleteConnection(void* connection) = 0; virtual void GetTotalSendAndRecv(u64& outSend, u64& outRecv) = 0; virtual void Validate(Logger& logger, const Vector& connections, bool full) = 0; }; struct NetworkBackend::SendContext { u64 data[2]; u32 size = 0; u8 flags; bool isUsed = false; bool isFinished = false; SendContext(u8 sendFlags = 0) : flags(sendFlags) { *data = 0; } ~SendContext() { }//UBA_ASSERT(isFinished); } }; class HttpConnection { public: HttpConnection(); ~HttpConnection(); bool Query(Logger& logger, const char* type, StringBufferBase& outResponse, u32& outStatusCode, const char* host, const char* path, const char* header = "", u32 timeoutMs = 3000); void SetConnectTimeout(u32 timeOutMs); private: bool Connect(Logger& logger, const char* host); char m_host[256]; #if PLATFORM_WINDOWS u64 m_socket; bool m_wsaInitDone = false; #else int m_socket; #endif u32 m_connectTimeOutMs = 0; }; }