From a419221a28a794f721e1cfe3d43266ac312c6d63 Mon Sep 17 00:00:00 2001 From: Alex Hultman Date: Sun, 10 Feb 2019 01:08:10 +0100 Subject: [PATCH] Fix up WebSocketContext.h --- src/WebSocketContext.h | 89 ++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 59 deletions(-) diff --git a/src/WebSocketContext.h b/src/WebSocketContext.h index aed4f3a..7154eaf 100644 --- a/src/WebSocketContext.h +++ b/src/WebSocketContext.h @@ -23,8 +23,6 @@ #include "WebSocketData.h" #include "WebSocket.h" -// todo: this module needs fixing! see below! - namespace uWS { template @@ -61,9 +59,7 @@ private: /* Returns true on breakage */ static bool handleFragment(char *data, size_t length, unsigned int remainingBytes, int opCode, bool fin, uWS::WebSocketState *webSocketState, void *s) { /* WebSocketData and WebSocketContextData */ - WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_new_socket_context_ext(SSL, - us_new_socket_context(SSL, (us_new_socket_t *) s) - ); + WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_new_socket_context_ext(SSL, us_new_socket_context(SSL, (us_new_socket_t *) s)); WebSocketData *webSocketData = (WebSocketData *) us_new_socket_ext(SSL, (us_new_socket_t *) s); /* Is this a non-control frame? */ @@ -75,12 +71,7 @@ private: if (webSocketData->compressionStatus == WebSocketData::CompressionStatus::COMPRESSED_FRAME) { webSocketData->compressionStatus = WebSocketData::CompressionStatus::ENABLED; - LoopData *loopData = (LoopData *)us_loop_ext( - us_new_socket_context_loop(SSL, - us_new_socket_context(SSL, (us_new_socket_t *)s) - ) - ); - + LoopData *loopData = (LoopData *) us_loop_ext(us_new_socket_context_loop(SSL, us_new_socket_context(SSL, (us_new_socket_t *) s))); std::string_view inflatedFrame = loopData->inflationStream->inflate(loopData->zlibContext, {data, length}, webSocketContextData->maxPayloadLength); if (!inflatedFrame.length()) { forceClose(webSocketState, s); @@ -100,7 +91,7 @@ private: /* Emit message event & break if we are closed or shut down when returning */ if (webSocketContextData->messageHandler) { webSocketContextData->messageHandler((WebSocket *) s, std::string_view(data, length), (uWS::OpCode) opCode); - if (us_new_socket_is_closed(SSL, (us_new_socket_t *)s) || webSocketData->isShuttingDown) { + if (us_new_socket_is_closed(SSL, (us_new_socket_t *) s) || webSocketData->isShuttingDown) { return true; } } @@ -153,7 +144,7 @@ private: /* Emit message and check for shutdown or close */ if (webSocketContextData->messageHandler) { webSocketContextData->messageHandler((WebSocket *) s, std::string_view(data, length), (uWS::OpCode) opCode); - if (us_new_socket_is_closed(SSL, (us_new_socket_t *)s) || webSocketData->isShuttingDown) { + if (us_new_socket_is_closed(SSL, (us_new_socket_t *) s) || webSocketData->isShuttingDown) { return true; } } @@ -221,9 +212,7 @@ private: } static bool refusePayloadLength(uint64_t length, uWS::WebSocketState *wState, void *s) { - WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_new_socket_context_ext(SSL, - us_new_socket_context(SSL, (us_new_socket_t *)s) - ); + auto *webSocketContextData = (WebSocketContextData *) us_new_socket_context_ext(SSL, us_new_socket_context(SSL, (us_new_socket_t *) s)); /* Return true for refuse, false for accept */ return webSocketContextData->maxPayloadLength < length; @@ -241,9 +230,7 @@ private: WebSocketData *webSocketData = (WebSocketData *) (us_new_socket_ext(SSL, s)); if (!webSocketData->isShuttingDown) { /* Emit close event */ - WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_new_socket_context_ext(SSL, - us_new_socket_context(SSL, (us_new_socket_t *)s) - ); + auto *webSocketContextData = (WebSocketContextData *) us_new_socket_context_ext(SSL, us_new_socket_context(SSL, (us_new_socket_t *) s)); if (webSocketContextData->closeHandler) { webSocketContextData->closeHandler((WebSocket *) s, 1006, {}); @@ -271,40 +258,28 @@ private: return s; } - /* 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 */ - - // återställ inte om vi är i shutdown state, dvs, ge den inte massa tid på sig att skicka massa skit-frames mellan och upphålla oss! - WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_new_socket_context_ext(SSL, - us_new_socket_context(SSL, (us_new_socket_t *) s) - ); - - us_new_socket_timeout(SSL, (us_new_socket_t *) s, webSocketContextData->idleTimeout); + auto *webSocketContextData = (WebSocketContextData *) us_new_socket_context_ext(SSL, us_new_socket_context(SSL, (us_new_socket_t *) s)); + auto *asyncSocket = (AsyncSocket *) s; + /* Every time we get data and not in shutdown state we simply reset the timeout */ + asyncSocket->timeout(webSocketContextData->idleTimeout); /* We always cork on data */ - AsyncSocket *webSocket = (AsyncSocket *) s; - webSocket->cork(); + asyncSocket->cork(); /* This parser has virtually no overhead */ uWS::WebSocketProtocol>::consume(data, length, (WebSocketState *) webSocketData, s); - // todo: we need to check for close and shutdown here? as we just emitted a bunch of message/close events! + /* Uncorking a closed socekt is fine, in fact it is needed */ + asyncSocket->uncork(); - // todo: check for failures here just like for HTTP - webSocket->uncork(); - - // cannot do anything else if closed - if (us_new_socket_is_closed(SSL, (us_new_socket_t *) s)) { - return s; - } - - // I guess we need to check drain here - emit drain if we had to poll for writable - - // are we shutdown? can onnly call this if we did succeed uncork! - if (webSocketData->isShuttingDown) { - webSocket->shutdown(); + /* If uncorking was successful and we are in shutdown state then send TCP FIN */ + if (asyncSocket->getBufferedAmount() == 0) { + /* We can now be in shutdown state */ + if (webSocketData->isShuttingDown) { + /* Shutting down a closed socket is handled by uSockets and just fine */ + asyncSocket->shutdown(); + } } return s; @@ -318,35 +293,31 @@ private: return s; } - AsyncSocket *webSocket = (AsyncSocket *) s; + AsyncSocket *asyncSocket = (AsyncSocket *) s; WebSocketData *webSocketData = (WebSocketData *)(us_new_socket_ext(SSL, s)); /* We store old backpressure since it is unclear whether write drained anything */ - int backpressure = webSocket->getBufferedAmount(); + int backpressure = asyncSocket->getBufferedAmount(); /* Drain as much as possible */ - webSocket->write(nullptr, 0); + asyncSocket->write(nullptr, 0); /* Behavior: if we actively drain backpressure, always reset timeout (even if we are in shutdown) */ - if (backpressure < webSocket->getBufferedAmount()) { - WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_new_socket_context_ext(SSL, - us_new_socket_context(SSL, (us_new_socket_t *)s) - ); - webSocket->timeout(webSocketContextData->idleTimeout); + if (backpressure < asyncSocket->getBufferedAmount()) { + auto *webSocketContextData = (WebSocketContextData *) us_new_socket_context_ext(SSL, us_new_socket_context(SSL, (us_new_socket_t *) s)); + asyncSocket->timeout(webSocketContextData->idleTimeout); } /* Are we in (WebSocket) shutdown mode? */ if (webSocketData->isShuttingDown) { /* Check if we just now drained completely */ - if (webSocket->getBufferedAmount() == 0) { + if (asyncSocket->getBufferedAmount() == 0) { /* Now perform the actual TCP/TLS shutdown which was postponed due to backpressure */ - webSocket->shutdown(); + asyncSocket->shutdown(); } - } else if (backpressure > webSocket->getBufferedAmount()) { + } else if (backpressure > asyncSocket->getBufferedAmount()) { /* Only call drain if we actually drained backpressure */ - WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_new_socket_context_ext(SSL, - us_new_socket_context(SSL, (us_new_socket_t *)s) - ); + auto *webSocketContextData = (WebSocketContextData *) us_new_socket_context_ext(SSL, us_new_socket_context(SSL, (us_new_socket_t *) s)); if (webSocketContextData->drainHandler) { webSocketContextData->drainHandler((WebSocket *) s); }