/*********************************************************************** THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY DEVELOPER: Zihan Chen(vczh) ***********************************************************************/ #include "VlppOS.h" #include "Vlpp.h" /*********************************************************************** .\NETWORKPROTOCOL.WINDOWS.H ***********************************************************************/ /*********************************************************************** Vczh Library++ 3.0 Developer: Zihan Chen(vczh) Interfaces: ***********************************************************************/ #ifndef VCZH_INTERPROCESS_WINDOWS_NETWORKPROTOCOL #define VCZH_INTERPROCESS_WINDOWS_NETWORKPROTOCOL #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #define _WINSOCKAPI_ #include #include #define RPC_USE_NATIVE_WCHAR #include #include namespace vl::inter_process { /* * GET: /Request * To connect and initialize the server. * Returns available URLs. * * It can only be called once, all subsequence calls will be rejected. */ constexpr const wchar_t* HttpServerUrl_Connect = L"/VlppInterProcess/Connect"; /* * POST: /Request/GUID * Client should always maintain a living request on the server. * * Returns only when a request is issued. * It will be pending or timeout if no request is issued. * If a request is issued but no living request available, it waits. */ constexpr const wchar_t* HttpServerUrl_Request = L"/VlppInterProcess/Request"; /* * POST: /Response/GUID * To send responses or events to the server. * Returns nothing. */ constexpr const wchar_t* HttpServerUrl_Response = L"/VlppInterProcess/Response"; } #endif /*********************************************************************** .\HTTPCLIENTAPI.WINDOWS.H ***********************************************************************/ /*********************************************************************** Vczh Library++ 3.0 Developer: Zihan Chen(vczh) Interfaces: HttpClientApi ***********************************************************************/ #ifndef VCZH_INTERPROCESS_WINDOWS_HTTPCLIENTAPI #define VCZH_INTERPROCESS_WINDOWS_HTTPCLIENTAPI namespace vl::inter_process { /// An http request. class HttpRequest { typedef collections::Array BodyBuffer; typedef collections::List StringList; typedef collections::Dictionary HeaderMap; public: /// Query of the request, like "/index.html". WString query; /// Set to true if the request uses SSL, or https. bool secure = false; /// User name to authorize. Set to empty if authorization is not needed. WString username; /// Password to authorize. Set to empty if authorization is not needed. WString password; /// HTTP method, like "GET", "POST", "PUT", "DELETE", etc. WString method; /// Cookie. Set to empty if cookie is not needed. WString cookie; /// Request body. This is a byte array. BodyBuffer body; /// Content type, like "text/xml". WString contentType; /// Accept type list, elements like "text/xml". StringList acceptTypes; /// A dictionary to contain extra headers. HeaderMap extraHeaders; /// Set to true to let this request finish when is called. bool keepAliveOnStop = false; /// Timeout for resolving the host name. 0 or -1 means infinite. vint resolveTimeout = 0; /// Timeout for connecting to the server. 0 or -1 means infinite. vint connectTimeout = 60000; /// Timeout for sending the request. 0 or -1 means infinite. vint sendTimeout = 30000; /// Timeout for receiving the response. 0 or -1 means infinite. vint receiveTimeout = 30000; HttpRequest() = default; void SetBodyUtf8(const WString& bodyString); }; /// A type representing an http response. class HttpResponse { typedef collections::Array BodyBuffer; public: /// Status code, like 200. vint statusCode = 0; /// Response body. This is a byte array. BodyBuffer body; /// Returned cookie from the server. WString cookie; /// Returned content type from the server. WString contentType; HttpResponse() = default; WString GetBodyUtf8() const; }; /// A transport error reported by the underlying Windows HTTP API. class HttpError { public: DWORD errorCode = 0; WString operation; WString message; }; /// A Windows-only async HTTP client for a single host and port. class HttpClientApi : public Object { static constexpr vint32_t HttpRespondBodyStep = 65536; class HttpRequestContext : public Object { public: HttpClientApi* api = nullptr; HINTERNET httpRequest = NULL; Func)> callback; collections::Array requestBody; HttpResponse response; DWORD bodyBufferWriting = 0; DWORD bodyBufferWritingAvailable = 0; bool keepAliveOnStop = false; bool completed = false; bool closing = false; SpinLock lockContext; }; WString server; vint port = 0; HINTERNET httpSession = NULL; HINTERNET httpConnection = NULL; SpinLock lockActiveRequests; collections::List> activeRequests; bool stopping = false; atomic_vint pendingCallbacks = 0; EventObject eventPendingCallbacks; static void CALLBACK HttpStatusCallback(HINTERNET httpRequest, DWORD_PTR context, DWORD status, LPVOID statusInformation, DWORD statusInformationLength); static HttpError MakeError(const WString& operation, DWORD errorCode); static vint HexValue(wchar_t c); bool IsStopping(); void BeginPendingCallback(); void EndPendingCallback(); void AttachRequestUnsafe(Ptr context); void RemoveRequestUnsafe(Ptr context); void CloseRequest(Ptr context); void OnRequestHandleClosing(Ptr context); void CompleteRequest(Ptr context, HttpResponse&& response); void CompleteRequest(Ptr context, HttpError&& error); void CompleteRequestWithLastError(Ptr context, const WString& operation, DWORD errorCode); public: HttpClientApi(const WString& _server, vint _port); ~HttpClientApi(); HttpClientApi(const HttpClientApi&) = delete; HttpClientApi(HttpClientApi&&) = delete; HttpClientApi& operator=(const HttpClientApi&) = delete; HttpClientApi& operator=(HttpClientApi&&) = delete; void HttpQuery(const HttpRequest& request, Func)> callback); void Stop(); static WString UrlEncodeQuery(const WString& query); static WString UrlDecodeQuery(const WString& query); }; } #endif /*********************************************************************** .\HTTPCLIENT.WINDOWS.H ***********************************************************************/ /*********************************************************************** Vczh Library++ 3.0 Developer: Zihan Chen(vczh) Interfaces: HttpClient ***********************************************************************/ #ifndef VCZH_INTERPROCESS_WINDOWS_HTTPCLIENT #define VCZH_INTERPROCESS_WINDOWS_HTTPCLIENT namespace vl::inter_process { class HttpClient : public Object, public virtual INetworkProtocolConnection, public virtual INetworkProtocolClient { protected: static constexpr vint HttpRequestMaxAttempts = 3; enum class State { Ready, WaitForServerConnection, Running, Stopping, }; State state = State::Ready; INetworkProtocolCallback* callback = nullptr; WString baseUrl; Ptr httpClientApi; WString urlConnect; WString urlRequest; WString urlResponse; SpinLock lockState; /*********************************************************************** HttpClient (Reading) ***********************************************************************/ protected: static constexpr const wchar_t* JsonContentType = L"application/json; charset=utf8"; void RaiseLocalError(WString errorMessage, bool fatal); bool IsStopping(); public: void BeginReadingLoopUnsafe() override; /*********************************************************************** HttpClient (WaitForServer) ***********************************************************************/ protected: EventObject eventWaitForServer; SpinLock lockConnectResult; bool connectCompleted = false; WString connectResponse; WString connectError; void CompleteConnectRequest(const WString& response, const WString& error); public: INetworkProtocolConnection* GetConnection() override; void WaitForServer() override; ClientStatus GetStatus() override; /*********************************************************************** HttpClient (Writing) ***********************************************************************/ protected: enum class HttpRequestType { Connect, Request, Response, }; bool SendHttpRequest(HttpRequestType requestType, const wchar_t* method, const WString& url, const WString& body, vint attempt = 1); void OnHttpRequestCompleted(HttpRequestType requestType, WString body, vint attempt, Variant result); void OnHttpRequestFailed(HttpRequestType requestType, const WString& body, vint attempt, const WString& errorMessage); public: void SendString(const WString& str) override; /*********************************************************************** HttpClient ***********************************************************************/ public: HttpClient(const WString _baseUrl, vint port); ~HttpClient(); void InstallCallback(INetworkProtocolCallback* _callback) override; void Stop() override; }; } #endif /*********************************************************************** .\HTTPSERVERAPI.WINDOWS.H ***********************************************************************/ /*********************************************************************** Vczh Library++ 3.0 Developer: Zihan Chen(vczh) Interfaces: HttpServerApi ***********************************************************************/ #ifndef VCZH_INTERPROCESS_WINDOWS_HTTPSERVERAPI #define VCZH_INTERPROCESS_WINDOWS_HTTPSERVERAPI namespace vl::inter_process { /// A response to be sent by . struct HttpServerResponse { vint statusCode = 200; WString reason; WString body; WString contentType; }; /// A Windows-only async HTTP server for a single URL prefix. class HttpServerApi : public Object { static constexpr vint32_t HttpRequestBufferInitSize = 1024; protected: enum class State { Ready, Running, Stopping, }; WString urlPrefix; bool respondToOptions = false; HANDLE httpRequestQueue = INVALID_HANDLE_VALUE; HTTP_SERVER_SESSION_ID httpSessionId = HTTP_NULL_ID; HTTP_URL_GROUP_ID httpUrlGroupId = HTTP_NULL_ID; State state = State::Ready; collections::Array bufferRequest; HANDLE hWaitHandleRequest = INVALID_HANDLE_VALUE; OVERLAPPED overlappedRequest; HANDLE hEventRequest = INVALID_HANDLE_VALUE; EventObject eventPendingCallbacks; atomic_vint pendingCallbacks = 0; void OnHttpConnectionBrokenUnsafe(); void OnHttpRequestReceivedUnsafe(PHTTP_REQUEST pRequest); ULONG ListenToHttpRequest_Init(OVERLAPPED* overlapped); ULONG ListenToHttpRequest_InitMoreData(ULONG* bytesReturned); ULONG ListenToHttpRequest_OverlappedMoreData(vint expectedBufferSize); void ListenToHttpRequest(); void BeginPendingCallback(); void EndPendingCallback(); virtual void OnHttpRequestReceived(PHTTP_REQUEST pRequest) = 0; virtual void OnHttpServerStopping(); static void SendOptionsResponse(HANDLE httpRequestQueue, HTTP_REQUEST_ID requestId); public: HttpServerApi(const WString& _urlPrefix, bool _respondToOptions); ~HttpServerApi(); HttpServerApi(const HttpServerApi&) = delete; HttpServerApi(HttpServerApi&&) = delete; HttpServerApi& operator=(const HttpServerApi&) = delete; HttpServerApi& operator=(HttpServerApi&&) = delete; void Start(); void Stop(); bool IsStopped(); HANDLE GetHttpRequestQueue() const; Nullable GetUtf8Body(PHTTP_REQUEST pRequest); static ULONG SendResponse(HANDLE httpRequestQueue, HTTP_REQUEST_ID requestId, const HttpServerResponse& response); static void SendResponseUtf8(HANDLE httpRequestQueue, HTTP_REQUEST_ID requestId, WString body); }; } #endif /*********************************************************************** .\HTTPSERVER.WINDOWS.H ***********************************************************************/ /*********************************************************************** Vczh Library++ 3.0 Developer: Zihan Chen(vczh) Interfaces: HttpServer ***********************************************************************/ #ifndef VCZH_INTERPROCESS_WINDOWS_HTTPSERVER #define VCZH_INTERPROCESS_WINDOWS_HTTPSERVER namespace vl::inter_process { class HttpServer; class HttpServerConnection : public Object, public virtual INetworkProtocolConnection { friend class HttpServer; protected: HttpServer* server = nullptr; WString guid; INetworkProtocolCallback* callback = nullptr; SpinLock lockQueuedStrings; collections::List queuedStrings; SpinLock pendingRequestLock; HTTP_REQUEST_ID httpPendingRequestId = HTTP_NULL_ID; collections::List pendingRequestsToSend; bool submittingResponse = false; collections::List responsesToSubmit; // All following functions must be called inside SPIN_LOCK(pendingRequestLock) void OnCancelCurrentHttpRequestForPendingRequest(); void OnNewHttpRequestForPendingRequest(HTTP_REQUEST_ID httpRequestId); WString SubmitResponse(PHTTP_REQUEST pRequest); public: void InstallCallback(INetworkProtocolCallback* _callback) override; void BeginReadingLoopUnsafe() override; void SendString(const WString& str) override; void Stop() override; static WString GenerateNewGuid(); }; class HttpServer : public HttpServerApi, public virtual INetworkProtocolServer { friend class HttpServerConnection; using ConnectionMap = collections::Dictionary>; protected: WString baseUrl; WString urlConnect; WString urlRequestPrefix; WString urlResponsePrefix; // covers connections SpinLock lockConnections; ConnectionMap connections; /*********************************************************************** HttpServer (BeginReadingLoopUnsafe) ***********************************************************************/ protected: /*********************************************************************** HttpServer (HttpServerApi) ***********************************************************************/ protected: void OnHttpRequestReceived(PHTTP_REQUEST pRequest) override; void OnHttpServerStopping() override; /*********************************************************************** HttpServer ***********************************************************************/ public: HttpServer(const WString _baseUrl, vint port); ~HttpServer(); WaitForClientResult OnClientConnected(INetworkProtocolConnection* connection) override; void Start() override; void Stop() override; bool IsStopped() override; }; } #endif /*********************************************************************** .\NAMEDPIPE.WINDOWS.H ***********************************************************************/ /*********************************************************************** Vczh Library++ 3.0 Developer: Zihan Chen(vczh) Interfaces: NamedPipeServer NamedPipeClient ***********************************************************************/ #ifndef VCZH_INTERPROCESS_WINDOWS_NAMEDPIPE #define VCZH_INTERPROCESS_WINDOWS_NAMEDPIPE namespace vl::inter_process { class NamedPipeServer; class NamedPipeConnection : public Object, public virtual INetworkProtocolConnection { friend class NamedPipeServer; // ----------------------------------------------------------------------- // Reading // ----------------------------------------------------------------------- private: class ReadWaitContext; bool firstRead = true; atomic_vint stopped = 0; collections::Array bufferReadFile; stream::MemoryStream streamReadFile; std::atomic readWaitContext = nullptr; OVERLAPPED overlappedReadFile; HANDLE hEventReadFile = INVALID_HANDLE_VALUE; atomic_vint pendingCallbacks = 0; EventObject eventPendingCallbacks; void BeginReadingUnsafe(); void SubmitReadBufferUnsafe(vint bytes); void EndReadingUnsafe(); void BeginPendingCallback(); void EndPendingCallback(); public: void BeginReadingLoopUnsafe() override; // ----------------------------------------------------------------------- // Writing // ----------------------------------------------------------------------- private: SpinLock lockWrite; stream::MemoryStream streamWriteFile; OVERLAPPED overlappedWriteFile; HANDLE hEventWriteFile = INVALID_HANDLE_VALUE; vint32_t WriteInt32ToStream(vint32_t number); vint32_t WriteStringToStream(const WString& str); void BeginSendStream(); void EndSendStream(vint32_t bytes); protected: void SendString(const WString& str) override; // ----------------------------------------------------------------------- // Connection // ----------------------------------------------------------------------- protected: // NamedPipe doesn't support a single message that is larger than 64K static constexpr vint32_t MaxMessageSize = 65536; NamedPipeServer* server = nullptr; INetworkProtocolCallback* callback = nullptr; HANDLE hPipe = INVALID_HANDLE_VALUE; void OnLocalError(const WString& errorMessage); void OnDisconnected(); NamedPipeConnection(HANDLE _hPipe); public: ~NamedPipeConnection(); void InstallCallback(INetworkProtocolCallback* _callback) override; void Stop() override; }; class NamedPipeServer : public Object, public virtual INetworkProtocolServer { friend class NamedPipeConnection; protected: class PendingConnection : public Object { public: class ConnectWaitContext; NamedPipeServer* server = nullptr; Ptr connection; std::atomic connectWaitContext = nullptr; OVERLAPPED overlappedConnect; HANDLE hEventConnect = INVALID_HANDLE_VALUE; atomic_vint pendingCallbacks = 0; EventObject eventPendingCallbacks; PendingConnection(NamedPipeServer* _server, Ptr _connection); ~PendingConnection(); void Stop(); void BeginPendingCallback(); void EndPendingCallback(); }; static HANDLE ServerCreatePipe(const WString& pipeName); WString pipeName; // covers started, stopped, connections and pendingConnections SpinLock lockConnections; bool started = false; bool stopped = false; collections::List> connections; collections::List> pendingConnections; void BeginListening(); void CompletePendingConnection(Ptr pendingConnection, bool connected); void CompletePendingConnection(PendingConnection* pendingConnection, bool connected); public: NamedPipeServer(const WString& _pipeName); ~NamedPipeServer(); WaitForClientResult OnClientConnected(INetworkProtocolConnection* connection) override; void Start() override; void Stop() override; bool IsStopped() override; }; class NamedPipeClient : public NamedPipeConnection, public virtual INetworkProtocolClient { protected: static HANDLE ClientCreatePipe(const WString& pipeName); ClientStatus status = ClientStatus::Ready; public: NamedPipeClient(const WString& _pipeName); ~NamedPipeClient(); INetworkProtocolConnection* GetConnection() override; void WaitForServer() override; ClientStatus GetStatus() override; void Stop() override; }; } #endif