diff --git a/src/App.h b/src/App.h index bf38c7a..4120699 100644 --- a/src/App.h +++ b/src/App.h @@ -53,7 +53,7 @@ struct TemplatedApp { private: /* The app always owns at least one http context, but creates websocket contexts on demand */ HttpContext *httpContext; - std::vector *> webSocketContexts; + std::vector *> webSocketContexts; public: @@ -134,6 +134,7 @@ public: return !httpContext; } + template struct WebSocketBehavior { /* Disabled compression by default - probably a bad default */ CompressOptions compression = DISABLED; @@ -151,16 +152,16 @@ public: /* Maximum socket lifetime in seconds before forced closure (defaults to disabled) */ unsigned short maxLifetime = 0; MoveOnlyFunction *, HttpRequest *, struct us_socket_context_t *)> upgrade = nullptr; - MoveOnlyFunction *)> open = nullptr; - MoveOnlyFunction *, std::string_view, OpCode)> message = nullptr; - MoveOnlyFunction *)> drain = nullptr; - MoveOnlyFunction *)> ping = nullptr; - MoveOnlyFunction *)> pong = nullptr; - MoveOnlyFunction *, int, std::string_view)> close = nullptr; + MoveOnlyFunction *)> open = nullptr; + MoveOnlyFunction *, std::string_view, OpCode)> message = nullptr; + MoveOnlyFunction *)> drain = nullptr; + MoveOnlyFunction *)> ping = nullptr; + MoveOnlyFunction *)> pong = nullptr; + MoveOnlyFunction *, int, std::string_view)> close = nullptr; }; template - TemplatedApp &&ws(std::string pattern, WebSocketBehavior &&behavior) { + TemplatedApp &&ws(std::string pattern, WebSocketBehavior &&behavior) { /* Don't compile if alignment rules cannot be satisfied */ static_assert(alignof(UserData) <= LIBUS_EXT_ALIGNMENT, "µWebSockets cannot satisfy UserData alignment requirements. You need to recompile µSockets with LIBUS_EXT_ALIGNMENT adjusted accordingly."); @@ -180,10 +181,10 @@ public: } /* Every route has its own websocket context with its own behavior and user data type */ - auto *webSocketContext = WebSocketContext::create(Loop::get(), (us_socket_context_t *) httpContext); + auto *webSocketContext = WebSocketContext::create(Loop::get(), (us_socket_context_t *) httpContext); /* We need to clear this later on */ - webSocketContexts.push_back(webSocketContext); + webSocketContexts.push_back((WebSocketContext *) webSocketContext); /* Quick fix to disable any compression if set */ #ifdef UWS_NO_ZLIB @@ -206,7 +207,7 @@ public: webSocketContext->getExt()->openHandler = std::move(behavior.open); webSocketContext->getExt()->messageHandler = std::move(behavior.message); webSocketContext->getExt()->drainHandler = std::move(behavior.drain); - webSocketContext->getExt()->closeHandler = std::move([closeHandler = std::move(behavior.close)](WebSocket *ws, int code, std::string_view message) mutable { + webSocketContext->getExt()->closeHandler = std::move([closeHandler = std::move(behavior.close)](WebSocket *ws, int code, std::string_view message) mutable { if (closeHandler) { closeHandler(ws, code, message); } diff --git a/src/AsyncSocket.h b/src/AsyncSocket.h index 427dc51..743f406 100644 --- a/src/AsyncSocket.h +++ b/src/AsyncSocket.h @@ -29,13 +29,13 @@ namespace uWS { - template struct WebSocketContext; + template struct WebSocketContext; template struct AsyncSocket { template friend struct HttpContext; - template friend struct WebSocketContext; - template friend struct WebSocketContextData; + template friend struct WebSocketContext; + template friend struct WebSocketContextData; friend struct TopicTree; protected: diff --git a/src/HttpResponse.h b/src/HttpResponse.h index 88720a1..3638d85 100644 --- a/src/HttpResponse.h +++ b/src/HttpResponse.h @@ -214,7 +214,7 @@ public: struct us_socket_context_t *webSocketContext) { /* Extract needed parameters from WebSocketContextData */ - WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, webSocketContext); + WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, webSocketContext); /* Note: OpenSSL can be used here to speed this up somewhat */ char secWebSocketAccept[29] = {}; @@ -281,7 +281,7 @@ public: bool wasCorked = Super::isCorked(); /* Adopting a socket invalidates it, do not rely on it directly to carry any data */ - WebSocket *webSocket = (WebSocket *) us_socket_context_adopt_socket(SSL, + WebSocket *webSocket = (WebSocket *) us_socket_context_adopt_socket(SSL, (us_socket_context_t *) webSocketContext, (us_socket_t *) this, sizeof(WebSocketData) + sizeof(UserData)); /* For whatever reason we were corked, update cork to the new socket */ diff --git a/src/WebSocket.h b/src/WebSocket.h index 03c7dea..771e01c 100644 --- a/src/WebSocket.h +++ b/src/WebSocket.h @@ -27,7 +27,7 @@ namespace uWS { -template +template struct WebSocket : AsyncSocket { template friend struct TemplatedApp; template friend struct HttpResponse; @@ -41,10 +41,10 @@ private: public: /* Returns pointer to the per socket user data */ - void *getUserData() { + USERDATA *getUserData() { WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) this); /* We just have it overallocated by sizeof type */ - return (webSocketData + 1); + return (USERDATA *) (webSocketData + 1); } /* See AsyncSocket */ @@ -65,7 +65,7 @@ public: /* Send or buffer a WebSocket frame, compressed or not. Returns BACKPRESSURE on increased user space backpressure, * DROPPED on dropped message (due to backpressure) or SUCCCESS if you are free to send even more now. */ SendStatus send(std::string_view message, OpCode opCode = OpCode::BINARY, bool compress = false) { - WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, + WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this) ); @@ -159,17 +159,16 @@ public: bool ok = send(std::string_view(closePayload, closePayloadLength), OpCode::CLOSE); /* FIN if we are ok and not corked */ - WebSocket *webSocket = (WebSocket *) this; - if (!webSocket->isCorked()) { + if (!this->isCorked()) { if (ok) { /* If we are not corked, and we just sent off everything, we need to FIN right here. * In all other cases, we need to fin either if uncork was successful, or when drainage is complete. */ - webSocket->shutdown(); + this->shutdown(); } } /* Emit close event */ - WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, + WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this) ); if (webSocketContextData->closeHandler) { @@ -199,7 +198,7 @@ public: /* Subscribe to a topic according to MQTT rules and syntax. Returns [numSubscribers, success]. */ std::pair subscribe(std::string_view topic, bool nonStrict = false) { - WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, + WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this) ); @@ -214,7 +213,7 @@ public: /* Unsubscribe from a topic, returns true if we were subscribed. Returns [numSubscribers, success]. */ std::pair unsubscribe(std::string_view topic, bool nonStrict = false) { - WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, + WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this) ); @@ -225,7 +224,7 @@ public: /* Returns whether this socket is subscribed to the specified topic */ bool isSubscribed(std::string_view topic) { - WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, + WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this) ); @@ -239,7 +238,7 @@ public: /* Returns number of subscribers for this topic, or 0 for failure */ unsigned int numSubscribers(std::string_view topic) { - WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, + WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this) ); @@ -274,7 +273,7 @@ public: * We, the WebSocket, must be subscribed to the topic itself and if so - no message will be sent to ourselves. * Use App::publish for an unconditional publish that simply publishes to whomever might be subscribed. */ bool publish(std::string_view topic, std::string_view message, OpCode opCode = OpCode::TEXT, bool compress = false) { - WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, + WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this) ); diff --git a/src/WebSocketContext.h b/src/WebSocketContext.h index f77f978..cdd067b 100644 --- a/src/WebSocketContext.h +++ b/src/WebSocketContext.h @@ -25,7 +25,7 @@ namespace uWS { -template +template struct WebSocketContext { template friend struct TemplatedApp; template friend struct WebSocketProtocol; @@ -36,8 +36,8 @@ private: return (us_socket_context_t *) this; } - WebSocketContextData *getExt() { - return (WebSocketContextData *) us_socket_context_ext(SSL, (us_socket_context_t *) this); + WebSocketContextData *getExt() { + return (WebSocketContextData *) us_socket_context_ext(SSL, (us_socket_context_t *) this); } /* If we have negotiated compression, set this frame compressed */ @@ -59,7 +59,7 @@ private: /* Returns true on breakage */ static bool handleFragment(char *data, size_t length, unsigned int remainingBytes, int opCode, bool fin, WebSocketState *webSocketState, void *s) { /* WebSocketData and WebSocketContextData */ - WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); + WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) s); /* Is this a non-control frame? */ @@ -90,7 +90,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), (OpCode) opCode); + webSocketContextData->messageHandler((WebSocket *) s, std::string_view(data, length), (OpCode) opCode); if (us_socket_is_closed(SSL, (us_socket_t *) s) || webSocketData->isShuttingDown) { return true; } @@ -148,7 +148,7 @@ private: /* Emit message and check for shutdown or close */ if (webSocketContextData->messageHandler) { - webSocketContextData->messageHandler((WebSocket *) s, std::string_view(data, length), (OpCode) opCode); + webSocketContextData->messageHandler((WebSocket *) s, std::string_view(data, length), (OpCode) opCode); if (us_socket_is_closed(SSL, (us_socket_t *) s) || webSocketData->isShuttingDown) { return true; } @@ -160,7 +160,7 @@ private: } } else { /* Control frames need the websocket to send pings, pongs and close */ - WebSocket *webSocket = (WebSocket *) s; + WebSocket *webSocket = (WebSocket *) s; if (!remainingBytes && fin && !webSocketData->controlTipLength) { if (opCode == CLOSE) { @@ -225,13 +225,13 @@ private: } static bool refusePayloadLength(uint64_t length, WebSocketState */*wState*/, void *s) { - auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); + auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); /* Return true for refuse, false for accept */ return webSocketContextData->maxPayloadLength < length; } - WebSocketContext *init() { + WebSocketContext *init() { /* Adopting a socket does not trigger open event. * We arreive as WebSocket with timeout set and * any backpressure from HTTP state kept. */ @@ -242,10 +242,10 @@ private: WebSocketData *webSocketData = (WebSocketData *) (us_socket_ext(SSL, s)); if (!webSocketData->isShuttingDown) { /* Emit close event */ - auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); + auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); if (webSocketContextData->closeHandler) { - webSocketContextData->closeHandler((WebSocket *) s, 1006, {(char *) reason, (size_t) code}); + webSocketContextData->closeHandler((WebSocket *) s, 1006, {(char *) reason, (size_t) code}); } /* Make sure to unsubscribe from any pub/sub node at exit */ @@ -272,7 +272,7 @@ private: return s; } - auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); + auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); auto *asyncSocket = (AsyncSocket *) s; /* Every time we get data and not in shutdown state we simply reset the timeout */ @@ -283,7 +283,7 @@ private: asyncSocket->cork(); /* This parser has virtually no overhead */ - WebSocketProtocol>::consume(data, (unsigned int) length, (WebSocketState *) webSocketData, s); + WebSocketProtocol>::consume(data, (unsigned int) length, (WebSocketState *) webSocketData, s); /* Uncorking a closed socekt is fine, in fact it is needed */ asyncSocket->uncork(); @@ -325,7 +325,7 @@ private: /* Behavior: if we actively drain backpressure, always reset timeout (even if we are in shutdown) */ /* Also reset timeout if we came here with 0 backpressure */ if (!backpressure || backpressure > asyncSocket->getBufferedAmount()) { - auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); + auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); asyncSocket->timeout(webSocketContextData->idleTimeoutComponents.first); webSocketData->hasTimedOut = false; } @@ -339,9 +339,9 @@ private: } } else if (!backpressure || backpressure > asyncSocket->getBufferedAmount()) { /* Only call drain if we actually drained backpressure or if we came here with 0 backpressure */ - auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); + auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); if (webSocketContextData->drainHandler) { - webSocketContextData->drainHandler((WebSocket *) s); + webSocketContextData->drainHandler((WebSocket *) s); } /* No need to check for closed here as we leave the handler immediately*/ } @@ -362,7 +362,7 @@ private: us_socket_context_on_timeout(SSL, getSocketContext(), [](auto *s) { auto *webSocketData = (WebSocketData *)(us_socket_ext(SSL, s)); - auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); + auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); if (webSocketContextData->sendPingsAutomatically && !webSocketData->hasTimedOut) { webSocketData->hasTimedOut = true; @@ -383,7 +383,7 @@ private: } void free() { - WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, (us_socket_context_t *) this); + WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, (us_socket_context_t *) this); webSocketContextData->~WebSocketContextData(); us_socket_context_free(SSL, (us_socket_context_t *) this); @@ -392,13 +392,13 @@ private: public: /* WebSocket contexts are always child contexts to a HTTP context so no SSL options are needed as they are inherited */ static WebSocketContext *create(Loop */*loop*/, us_socket_context_t *parentSocketContext) { - WebSocketContext *webSocketContext = (WebSocketContext *) us_create_child_socket_context(SSL, parentSocketContext, sizeof(WebSocketContextData)); + WebSocketContext *webSocketContext = (WebSocketContext *) us_create_child_socket_context(SSL, parentSocketContext, sizeof(WebSocketContextData)); if (!webSocketContext) { return nullptr; } /* Init socket context data */ - new ((WebSocketContextData *) us_socket_context_ext(SSL, (us_socket_context_t *)webSocketContext)) WebSocketContextData; + new ((WebSocketContextData *) us_socket_context_ext(SSL, (us_socket_context_t *)webSocketContext)) WebSocketContextData; return webSocketContext->init(); } }; diff --git a/src/WebSocketContextData.h b/src/WebSocketContextData.h index 3f913df..1b3cf88 100644 --- a/src/WebSocketContextData.h +++ b/src/WebSocketContextData.h @@ -27,11 +27,11 @@ namespace uWS { -template struct WebSocket; +template struct WebSocket; /* todo: this looks identical to WebSocketBehavior, why not just std::move that entire thing in? */ -template +template struct WebSocketContextData { private: /* Used for prepending unframed messages when using dedicated compressors */ @@ -47,13 +47,13 @@ private: public: /* The callbacks for this context */ - MoveOnlyFunction *)> openHandler = nullptr; - MoveOnlyFunction *, std::string_view, OpCode)> messageHandler = nullptr; - MoveOnlyFunction *)> drainHandler = nullptr; - MoveOnlyFunction *, int, std::string_view)> closeHandler = nullptr; + MoveOnlyFunction *)> openHandler = nullptr; + MoveOnlyFunction *, std::string_view, OpCode)> messageHandler = nullptr; + MoveOnlyFunction *)> drainHandler = nullptr; + MoveOnlyFunction *, int, std::string_view)> closeHandler = nullptr; /* Todo: these should take message also; breaking change for v0.18 */ - MoveOnlyFunction *)> pingHandler = nullptr; - MoveOnlyFunction *)> pongHandler = nullptr; + MoveOnlyFunction *)> pingHandler = nullptr; + MoveOnlyFunction *)> pongHandler = nullptr; /* Settings for this context */ size_t maxPayloadLength = 0; @@ -135,7 +135,7 @@ public: /* However, dedicated compression has its own path */ if (compression != SHARED_COMPRESSOR) { - WebSocket *ws = (WebSocket *) asyncSocket; + WebSocket *ws = (WebSocket *) asyncSocket; /* For performance reasons we always cork when in dedicated mode. * Is this really the best? We already kind of cork things in Zlib? diff --git a/src/WebSocketData.h b/src/WebSocketData.h index feb94f8..d0cea6f 100644 --- a/src/WebSocketData.h +++ b/src/WebSocketData.h @@ -29,9 +29,9 @@ namespace uWS { struct WebSocketData : AsyncSocketData, WebSocketState { /* This guy has a lot of friends - why? */ - template friend struct WebSocketContext; - template friend struct WebSocketContextData; - template friend struct WebSocket; + template friend struct WebSocketContext; + template friend struct WebSocketContextData; + template friend struct WebSocket; template friend struct HttpContext; private: std::string fragmentBuffer;