From 0934965fa5484b986a231a301372416b7c77fb54 Mon Sep 17 00:00:00 2001 From: Alex Hultman Date: Tue, 22 Jan 2019 10:15:27 +0100 Subject: [PATCH] Implement idleTimeout --- misc/main.cpp | 8 ++++---- src/App.h | 10 ++++++++-- src/HttpContextData.h | 5 ----- src/WebSocketContext.h | 32 +++++++++++++++++++------------- src/WebSocketContextData.h | 3 +++ 5 files changed, 34 insertions(+), 24 deletions(-) diff --git a/misc/main.cpp b/misc/main.cpp index 731c9fd..2a9a70a 100644 --- a/misc/main.cpp +++ b/misc/main.cpp @@ -16,7 +16,7 @@ int main(int argc, char **argv) { .key_file_name = "/home/alexhultman/key.pem", .cert_file_name = "/home/alexhultman/cert.pem", .passphrase = "1234" - }).post("/exit", [](auto *res, auto *req) { + }).get("/exit", [](auto *res, auto *req) { if (!token) { res->end("Server already closed down!"); @@ -32,7 +32,7 @@ int main(int argc, char **argv) { /* Settings */ .compression = uWS::DEDICATED_COMPRESSOR, .maxPayloadLength = 16 * 1024 * 1024, - /* autoPingInterval */ + .idleTimeout = 10, /* Handlers */ .open = [](auto *ws, auto *req) { std::cout << "WebSocket connected" << std::endl; @@ -60,12 +60,12 @@ int main(int argc, char **argv) { PerSocketData *perSocketData = (PerSocketData *) ws->getUserData(); std::cout << "OK per socket data: " << (perSocketData->hello == 13) << std::endl; } - })/*.listen(9001, [](auto *token) { + }).listen(9001, [](auto *token) { ::token = token; if (token) { std::cout << "Listening on port " << 3000 << std::endl; } - })*/.run(); + }).run(); std::cout << "Everything fine, falling through" << std::endl; diff --git a/src/App.h b/src/App.h index 348d1fe..b7483d5 100644 --- a/src/App.h +++ b/src/App.h @@ -91,6 +91,7 @@ public: struct WebSocketBehavior { CompressOptions compression = DISABLED; int maxPayloadLength = 16 * 1024; + int idleTimeout = 120; std::function *, HttpRequest *)> open = nullptr; std::function *, std::string_view, uWS::OpCode)> message = nullptr; std::function *)> drain = nullptr; @@ -131,6 +132,7 @@ public: /* Copy settings */ webSocketContext->getExt()->maxPayloadLength = behavior.maxPayloadLength; + webSocketContext->getExt()->idleTimeout = behavior.idleTimeout; return std::move(get(pattern, [webSocketContext, this, behavior](auto *res, auto *req) { /* If we have this header set, it's a websocket */ @@ -182,7 +184,8 @@ public: /* Add mark, we don't want to end anything */ res->writeHeader("WebSocket-Server", "uWebSockets")->end(); - /* todo: What about HttpResponseData here? */ + /* bug: memory leak? What about HttpResponseData here? I'm thinking not delete it but destruct it? */ + /* Esp. if the functions hold dynamic memory like something big */ /* Adopting a socket invalidates it, do not rely on it directly to carry any data */ WebSocket *webSocket = (WebSocket *) StaticDispatch::static_dispatch(us_ssl_socket_context_adopt_socket, us_socket_context_adopt_socket)( @@ -195,11 +198,14 @@ public: webSocket->init(perMessageDeflate, slidingDeflateWindow) ); - /* Emit open event */ + /* Emit open event and start the timeout */ if (behavior.open) { + static_dispatch(us_ssl_socket_timeout, us_socket_timeout)((SOCKET_TYPE *) webSocket, behavior.idleTimeout); behavior.open(webSocket, req); } + /* bug: What happens with corking? */ + /* We do not need to check for any close or shutdown here as we immediately return from get handler */ } else { diff --git a/src/HttpContextData.h b/src/HttpContextData.h index bc20b2e..d09a816 100644 --- a/src/HttpContextData.h +++ b/src/HttpContextData.h @@ -36,11 +36,6 @@ struct alignas(16) HttpContextData { private: std::vector *, int)>> filterHandlers; - /*HttpContextData(const HttpContextData&) = delete; - HttpContextData() { - - }*/ - struct RouterData { HttpResponse *httpResponse; HttpRequest *httpRequest; diff --git a/src/WebSocketContext.h b/src/WebSocketContext.h index 5dc1b35..2b5199d 100644 --- a/src/WebSocketContext.h +++ b/src/WebSocketContext.h @@ -233,6 +233,8 @@ private: WebSocketContext *init() { /* Open is never called, we only adopt sockets */ + /* Always assume timeout is disabled when we are adopted. + * HTTP requests should disable timeout anyways */ /* Handle socket disconnections */ static_dispatch(us_ssl_socket_context_on_close, us_socket_context_on_close)(getSocketContext(), [](auto *s) { @@ -247,6 +249,19 @@ private: /* Handle WebSocket data streams */ static_dispatch(us_ssl_socket_context_on_data, us_socket_context_on_data)(getSocketContext(), [](auto *s, char *data, int length) { + + /* Everytime we get data, we reset the timeout to our idleTimeout, that's the only timer we have */ + + /* If not in websocket shutdown state, for every */ + + // hur mycket sabbar denna? + WebSocketContextData *webSocketContextData = (WebSocketContextData *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)( + static_dispatch(us_ssl_socket_get_context, us_socket_get_context)((SOCKET_TYPE *)s) + ); + + static_dispatch(us_ssl_socket_timeout, us_socket_timeout)((SOCKET_TYPE *) s, webSocketContextData->idleTimeout); + + /* We always cork on data */ AsyncSocket *webSocket = (AsyncSocket *) s; webSocket->cork(); @@ -315,13 +330,8 @@ private: /* Handle FIN, HTTP does not support half-closed sockets, so simply close */ static_dispatch(us_ssl_socket_context_on_end, us_socket_context_on_end)(getSocketContext(), [](auto *s) { - // just like http, websocket does not support half-open sockets so just close here - - std::cout << "websopcket fin" << std::endl; - - /* We do not care for half closed sockets */ - //AsyncSocket *asyncSocket = (AsyncSocket *) s; - //return asyncSocket->close(); + /* If we get a fin, we just close I guess */ + static_dispatch(us_ssl_socket_close, us_socket_close)((SOCKET_TYPE *) s); return s; }); @@ -329,12 +339,8 @@ private: /* Handle socket timeouts, simply close them so to not confuse client with FIN */ static_dispatch(us_ssl_socket_context_on_timeout, us_socket_context_on_timeout)(getSocketContext(), [](auto *s) { - std::cout << "websocket timeout" << std::endl; - - /* Force close rather than gracefully shutdown and risk confusing the client with a complete download */ - //AsyncSocket *asyncSocket = (AsyncSocket *) s; - //return asyncSocket->close(); - + /* Timeout is very simple; we just close it */ + static_dispatch(us_ssl_socket_close, us_socket_close)((SOCKET_TYPE *) s); return s; }); diff --git a/src/WebSocketContextData.h b/src/WebSocketContextData.h index 6a8ff8e..e437404 100644 --- a/src/WebSocketContextData.h +++ b/src/WebSocketContextData.h @@ -27,6 +27,8 @@ namespace uWS { template struct WebSocket; +/* todo: this looks identical to WebSocketBehavior, why not just std::move that entire thing in? */ + template struct WebSocketContextData { /* The callbacks for this context */ @@ -36,6 +38,7 @@ struct WebSocketContextData { /* Settings for this context */ size_t maxPayloadLength = 0; + int idleTimeout = 0; }; }