diff --git a/src/App.h b/src/App.h index 8f3263d..911774e 100644 --- a/src/App.h +++ b/src/App.h @@ -73,7 +73,7 @@ public: ->writeHeader("Sec-WebSocket-Accept", secWebSocketAccept) ->end(); - std::cout << "Adopting" << std::endl; + //std::cout << "Adopting" << std::endl; // adopting will immediately delete the socket! we cannot rely on reading anything on it // rely on http context data @@ -84,7 +84,7 @@ public: webSocket->init(); - std::cout << "adopted" << std::endl; + //std::cout << "adopted" << std::endl; httpContext->upgradeToWebSocket( webSocket diff --git a/src/WebSocket.h b/src/WebSocket.h index 7fe3d49..b09ab49 100644 --- a/src/WebSocket.h +++ b/src/WebSocket.h @@ -11,10 +11,16 @@ namespace uWS { template struct WebSocket : AsyncSocket { + template friend struct TemplatedApp; private: typedef AsyncSocket Super; + + void init() { + new (us_socket_ext((us_socket *) this)) WebSocketData; + } public: + // this function need clean-ups and perf. fixes void send(std::string_view message, uWS::OpCode opCode) { // if corkAllocate(size) then corkFree(unused) @@ -54,13 +60,6 @@ public: // why should we fin here? //us_socket_shutdown((us_socket *) this); } - - // absolutely not public! - void init() { - // construct us - - new (us_socket_ext((us_socket *) this)) WebSocketData; - } }; } diff --git a/src/WebSocketContext.h b/src/WebSocketContext.h index de96123..ed8ad87 100644 --- a/src/WebSocketContext.h +++ b/src/WebSocketContext.h @@ -3,14 +3,13 @@ #include "StaticDispatch.h" #include "WebSocketContextData.h" - -// the context depend on the PARSER but not the formatter! #include "WebSocketProtocol.h" - #include "WebSocketData.h" - #include "AsyncSocket.h" +/* This is a hack for now on, update uSockets */ +extern "C" int us_internal_socket_is_closed(struct us_socket *s); + namespace uWS { template @@ -31,30 +30,23 @@ private: return (WebSocketContextData *) us_socket_context_ext((SOCKET_CONTEXT_TYPE *) this); } - // could still lie in its own struct! static bool setCompressed(uWS::WebSocketState *wState) { - std::cout << "set compressed" << std::endl; return false; // do not support it } - // todo: pass along user! static void forceClose(uWS::WebSocketState *wState, void *s) { - std::cout << "force close" << std::endl; - us_socket_close((us_socket *) s); - } + /* Returns true on breakage */ static bool handleFragment(char *data, size_t length, unsigned int remainingBytes, int opCode, bool fin, uWS::WebSocketState *webSocketState, void *s) { - - // this is maybe not the most elegant but who cares + /* WebSocketData and WebSocketContextData */ WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(us_socket_get_context((us_socket *) s)); - - // we need to get the WebSocket data also! WebSocketData *webSocketData = (WebSocketData *) us_socket_ext((us_socket *) s); + /* Is this a non-control frame? */ if (opCode < 3) { - + /* Did we get everything in one go? */ if (!remainingBytes && fin && !webSocketData->fragmentBuffer.length()) { /* Check text messages for Utf-8 validity */ @@ -63,57 +55,49 @@ private: return true; } - webSocketContextData->messageHandler((WebSocket *) s, std::string_view(data, length), (uWS::OpCode) opCode); - - // todo: check if shut down or shutting down (shut down from websocket perspective) - // if so, then return true - + /* Emit message event & break if we are closed or shut down when returning */ + webSocketContextData->messageHandler((WebSocket *) s, std::string_view(data, length), (uWS::OpCode) opCode); + if (us_internal_socket_is_closed((us_socket *) s) || webSocketData->isShuttingDown) { + return true; + } } else { /* Allocate fragment buffer up front first time */ if (!webSocketData->fragmentBuffer.length()) { - std::cout << "Resizing buffers to " << (length + remainingBytes) << " bytes" << std::endl; webSocketData->fragmentBuffer.reserve(length + remainingBytes); } - webSocketData->fragmentBuffer.append(data, length); - std::cout << "buffering incomplete fragment: " << webSocketData->fragmentBuffer.length() << " added " << length << std::endl; - /* Are we done now? */ // what if we don't have any remaining bytes yet we are not fin? forceclose! if (!remainingBytes && fin) { - std::cout << "GOT FINAL FRAGMENT!" << std::endl; - // reset length and data ptrs length = webSocketData->fragmentBuffer.length(); data = webSocketData->fragmentBuffer.data(); - /* Check text messages for Utf-8 validity */ if (opCode == 1 && !WebSocketProtocol>::isValidUtf8((unsigned char *) data, length)) { forceClose(webSocketState, s); return true; } + /* Emit message and check for shutdown or close */ webSocketContextData->messageHandler((WebSocket *) s, std::string_view(data, length), (uWS::OpCode) opCode); + if (us_internal_socket_is_closed((us_socket *) s) || webSocketData->isShuttingDown) { + return true; + } - // todo: check if shut down or shutting down (shut down from websocket perspective) - // if so, then return true - - + /* If we shutdown or closed, this will be taken care of elsewhere */ webSocketData->fragmentBuffer.clear(); } - } - - } else { + /* Control frames need the websocket to send pings, pongs and close */ WebSocket *webSocket = (WebSocket *) s; if (!remainingBytes && fin && !webSocketData->controlTipLength) { if (opCode == CLOSE) { - typename WebSocketProtocol>::CloseFrame closeFrame = WebSocketProtocol>::parseClosePayload(data, length); + auto closeFrame = WebSocketProtocol>::parseClosePayload(data, length); webSocket->close(closeFrame.code, std::string_view(closeFrame.message, closeFrame.length)); return true; } else { @@ -131,16 +115,10 @@ private: } } } else { - // todo, buffer control frames - - std::cout << "control frames! BUFFFERRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR" << std::endl; - - - // unsure how big this is? + /* Here we never mind any size optimizations as we are in the worst possible path */ webSocketData->fragmentBuffer.append(data, length); webSocketData->controlTipLength += length; - if (!remainingBytes && fin) { char *controlBuffer = (char *) webSocketData->fragmentBuffer.data() + webSocketData->fragmentBuffer.length() - webSocketData->controlTipLength; if (opCode == CLOSE) { @@ -162,35 +140,24 @@ private: } } - // not optimal but slow path + /* Same here, we do not care for any particular smart allocation scheme */ webSocketData->fragmentBuffer.resize(webSocketData->fragmentBuffer.length() - webSocketData->controlTipLength); webSocketData->controlTipLength = 0; } - - - - } - - } - - - - // the only thing here to check is probably closed - - // why does it not do anything immediately on true? return false; } + // bug: todo static bool refusePayloadLength(uint64_t length, uWS::WebSocketState *wState) { - //std::cout << "refusepayloadlength" << std::endl; + /* We check if we want to accept such a frame based on size */ + // for now, accept anything return false; } WebSocketContext *init() { - - /* I guess open is never called */ + /* Open is never called, we only adopt sockets */ /* Handle socket disconnections */ static_dispatch(us_ssl_socket_context_on_close, us_socket_context_on_close)(getSocketContext(), [](auto *s) { @@ -200,21 +167,20 @@ private: return s; }); - /* Handle HTTP data streams */ + /* Handle WebSocket data streams */ static_dispatch(us_ssl_socket_context_on_data, us_socket_context_on_data)(getSocketContext(), [](auto *s, char *data, int length) { - - + /* We always cork on data */ AsyncSocket *webSocket = (AsyncSocket *) s; - webSocket->cork(); - // get the data + /* We need the websocket data */ WebSocketData *wsState = (WebSocketData *) us_socket_ext(s); // this parser requires almost no time -> 215k req/sec of 215k possible uWS::WebSocketProtocol>::consume(data, length, wsState, s); + // todo: check for failures here just like for HTTP webSocket->uncork(); // are we shutdown? @@ -234,6 +200,7 @@ private: AsyncSocket *webSocket = (AsyncSocket *) s; + // check for failures and shutdown just like in data event webSocket->write(nullptr, 0); // drainage - also check for shutdown! return s; @@ -242,6 +209,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 */ diff --git a/src/WebSocketData.h b/src/WebSocketData.h index 985edde..75f4f7a 100644 --- a/src/WebSocketData.h +++ b/src/WebSocketData.h @@ -18,7 +18,7 @@ private: bool isShuttingDown = 0; public: WebSocketData() : WebSocketState() { - std::cout << "init websocket data!" << std::endl; + //std::cout << "init websocket data!" << std::endl; } }; diff --git a/src/WebSocketProtocol.h b/src/WebSocketProtocol.h index 3ce3e9b..b24a61f 100644 --- a/src/WebSocketProtocol.h +++ b/src/WebSocketProtocol.h @@ -17,6 +17,8 @@ #ifndef WEBSOCKETPROTOCOL_UWS_H #define WEBSOCKETPROTOCOL_UWS_H +/* This segment is not cross-platform! Fix! */ +/* PortableEndianConversion.h */ #ifdef __linux #include #include