Refactor using new uSockets API

This commit is contained in:
Alex Hultman
2019-01-25 14:15:40 +01:00
parent e14461e253
commit d331ec3e45
10 changed files with 107 additions and 198 deletions
+2 -2
View File
@@ -28,7 +28,7 @@ int main(int argc, char **argv) {
};
int port = 3000;
struct us_ssl_socket_context_options ssl_options = {};
struct us_new_socket_context_options_t ssl_options = {};
while ((option = optparse_long(&options, longopts, nullptr)) != -1) {
switch (option) {
@@ -63,7 +63,7 @@ int main(int argc, char **argv) {
AsyncFileStreamer asyncFileStreamer(root);
/* Either serve over HTTP or HTTPS */
struct us_ssl_socket_context_options empty_ssl_options = {};
struct us_new_socket_context_options_t empty_ssl_options = {};
if (memcmp(&ssl_options, &empty_ssl_options, sizeof(empty_ssl_options))) {
/* HTTPS */
uWS::SSLApp(ssl_options).get("/*", [&asyncFileStreamer](auto *res, auto *req) {
-1
View File
@@ -21,7 +21,6 @@ HEADERS += \
../src/HttpContextData.h \
../src/HttpResponseData.h \
../src/HttpResponse.h \
../src/StaticDispatch.h \
../src/LoopData.h \
../src/AsyncSocket.h \
../src/AsyncSocketData.h \
+8 -10
View File
@@ -42,14 +42,12 @@ enum CompressOptions {
};
template <bool SSL>
struct TemplatedApp : StaticDispatch<SSL> {
struct TemplatedApp {
private:
/* The app always owns at least one http context, but creates websocket contexts on demand */
HttpContext<SSL> *httpContext;
std::vector<WebSocketContext<SSL, true> *> webSocketContexts;
using SOCKET_TYPE = typename StaticDispatch<SSL>::SOCKET_TYPE;
using StaticDispatch<SSL>::static_dispatch;
public:
/* Attaches a "filter" function to track socket connections/disconnections */
@@ -84,8 +82,8 @@ public:
webSocketContexts = std::move(other.webSocketContexts);
}
TemplatedApp(us_ssl_socket_context_options sslOptions = {}) {
httpContext = uWS::HttpContext<SSL>::create(uWS::Loop::defaultLoop(), &sslOptions);
TemplatedApp(us_new_socket_context_options_t options = {}) {
httpContext = uWS::HttpContext<SSL>::create(uWS::Loop::defaultLoop(), options);
}
struct WebSocketBehavior {
@@ -103,7 +101,7 @@ public:
template <class UserData>
TemplatedApp &&ws(std::string pattern, WebSocketBehavior &&behavior) {
/* Every route has its own websocket context with its own behavior and user data type */
auto *webSocketContext = WebSocketContext<SSL, true>::create(Loop::defaultLoop(), (typename StaticDispatch<SSL>::SOCKET_CONTEXT_TYPE *) httpContext);
auto *webSocketContext = WebSocketContext<SSL, true>::create(Loop::defaultLoop(), (us_new_socket_context_t *) httpContext);
/* We need to clear this later on */
webSocketContexts.push_back(webSocketContext);
@@ -115,7 +113,7 @@ public:
/* If we are the first one to use compression, initialize it */
if (behavior.compression) {
LoopData *loopData = (LoopData *) us_loop_ext(static_dispatch(us_ssl_socket_context_loop, us_socket_context_loop)(webSocketContext->getSocketContext()));
LoopData *loopData = (LoopData *) us_loop_ext(us_new_socket_context_loop(SSL, webSocketContext->getSocketContext()));
/* Initialize loop's deflate inflate streams */
if (!loopData->zlibContext) {
@@ -191,8 +189,8 @@ public:
res->getHttpResponseData()->~HttpResponseData();
/* Adopting a socket invalidates it, do not rely on it directly to carry any data */
WebSocket<SSL, true> *webSocket = (WebSocket<SSL, true> *) StaticDispatch<SSL>::static_dispatch(us_ssl_socket_context_adopt_socket, us_socket_context_adopt_socket)(
(typename StaticDispatch<SSL>::SOCKET_CONTEXT_TYPE *) webSocketContext, (typename StaticDispatch<SSL>::SOCKET_TYPE *) res, sizeof(WebSocketData) + sizeof(UserData));
WebSocket<SSL, true> *webSocket = (WebSocket<SSL, true> *) us_new_socket_context_adopt_socket(SSL,
(us_new_socket_context_t *) webSocketContext, (us_new_socket_t *) res, sizeof(WebSocketData) + sizeof(UserData));
/* Update corked socket in case we got a new one (assuming we always are corked in handlers). */
webSocket->cork();
@@ -204,7 +202,7 @@ public:
/* Emit open event and start the timeout */
if (behavior.open) {
static_dispatch(us_ssl_socket_timeout, us_socket_timeout)((SOCKET_TYPE *) webSocket, behavior.idleTimeout);
us_new_socket_timeout(SSL, (us_new_socket_t *) webSocket, behavior.idleTimeout);
behavior.open(webSocket, req);
}
+12 -14
View File
@@ -20,46 +20,44 @@
/* This class implements async socket memory management strategies */
#include "StaticDispatch.h"
#include "LoopData.h"
#include "AsyncSocketData.h"
namespace uWS {
template <bool SSL>
struct AsyncSocket : StaticDispatch<SSL> {
struct AsyncSocket {
template <bool> friend struct HttpContext;
template <bool, bool> friend struct WebSocketContext;
protected:
using SOCKET_TYPE = typename StaticDispatch<SSL>::SOCKET_TYPE;
using StaticDispatch<SSL>::static_dispatch;
/* Get loop data for socket */
LoopData *getLoopData() {
return (LoopData *) us_loop_ext(
static_dispatch(us_ssl_socket_context_loop, us_socket_context_loop)(
static_dispatch(us_ssl_socket_get_context, us_socket_get_context)((SOCKET_TYPE *) this))
us_new_socket_context_loop(SSL,
us_new_socket_context(SSL, (us_new_socket_t *) this))
);
}
/* Get socket extension */
void *getExt() {
return static_dispatch(us_ssl_socket_ext, us_socket_ext)((SOCKET_TYPE *) this);
return us_new_socket_ext(SSL, (us_new_socket_t *) this);
}
/* Socket timeout */
void timeout(unsigned int seconds) {
static_dispatch(us_ssl_socket_timeout, us_socket_timeout)((SOCKET_TYPE *) this, seconds);
us_new_socket_timeout(SSL, (us_new_socket_t *) this, seconds);
}
/* Shutdown socket without any automatic drainage */
void shutdown() {
static_dispatch(us_ssl_socket_shutdown, us_socket_shutdown)((SOCKET_TYPE *) this);
us_new_socket_shutdown(SSL, (us_new_socket_t *) this);
}
/* Immediately close socket */
SOCKET_TYPE *close() {
return static_dispatch(us_ssl_socket_close, us_socket_close)((SOCKET_TYPE *) this);
us_new_socket_t *close() {
return us_new_socket_close(SSL, (us_new_socket_t *) this);
}
/* Cork this socket. Only one socket may ever be corked per-loop at any given time */
@@ -103,7 +101,7 @@ protected:
* writable (or we are in a state that implies polling for writable). */
std::pair<int, bool> write(const char *src, int length, bool optionally = false, int nextLength = 0) {
/* Fake success if closed, simpel fix to allow uncork of closed socket to succeed */
if (us_socket_is_closed((us_socket *) this)) {
if (us_new_socket_is_closed(SSL, (us_new_socket_t *) this)) {
std::cout << "Faking successful send due to closed socket!" << std::endl;
return {length, false};
}
@@ -114,7 +112,7 @@ protected:
/* We are limited if we have a per-socket buffer */
if (asyncSocketData->buffer.length()) {
/* Write off as much as we can */
int written = static_dispatch(us_ssl_socket_write, us_socket_write)((SOCKET_TYPE *) this, asyncSocketData->buffer.data(), asyncSocketData->buffer.length(), /*nextLength != 0 | */length);
int written = us_new_socket_write(SSL, (us_new_socket_t *) this, asyncSocketData->buffer.data(), asyncSocketData->buffer.length(), /*nextLength != 0 | */length);
/* On failure return, otherwise continue down the function */
if (written < asyncSocketData->buffer.length()) {
@@ -165,7 +163,7 @@ protected:
}
} else {
/* We are not corked */
int written = static_dispatch(us_ssl_socket_write, us_socket_write)((SOCKET_TYPE *) this, src, length, nextLength != 0);
int written = us_new_socket_write(SSL, (us_new_socket_t *) this, src, length, nextLength != 0);
/* Did we fail? */
if (written < length) {
+35 -43
View File
@@ -25,7 +25,6 @@
#include "HttpResponseData.h"
#include "AsyncSocket.h"
#include "StaticDispatch.h"
#include <string_view>
#include <functional>
@@ -36,41 +35,38 @@ namespace uWS {
template<bool> struct HttpResponse;
template <bool SSL>
struct HttpContext : StaticDispatch<SSL> {
struct HttpContext {
private:
using SOCKET_CONTEXT_TYPE = typename StaticDispatch<SSL>::SOCKET_CONTEXT_TYPE;
using SOCKET_TYPE = typename StaticDispatch<SSL>::SOCKET_TYPE;
using StaticDispatch<SSL>::static_dispatch;
HttpContext() = delete;
/* Maximum delay allowed until an HTTP connection is terminated due to outstanding request or rejected data (slow loris protection) */
static const int HTTP_IDLE_TIMEOUT_S = 10;
SOCKET_CONTEXT_TYPE *getSocketContext() {
return (SOCKET_CONTEXT_TYPE *) this;
us_new_socket_context_t *getSocketContext() {
return (us_new_socket_context_t *) this;
}
static SOCKET_CONTEXT_TYPE *getSocketContext(SOCKET_TYPE *s) {
return (SOCKET_CONTEXT_TYPE *) static_dispatch(us_ssl_socket_get_context, us_socket_get_context)(s);
static us_new_socket_context_t *getSocketContext(us_new_socket_t *s) {
return (us_new_socket_context_t *) us_new_socket_context(SSL, s);
}
HttpContextData<SSL> *getSocketContextData() {
return (HttpContextData<SSL> *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(getSocketContext());
return (HttpContextData<SSL> *) us_new_socket_context_ext(SSL, getSocketContext());
}
static HttpContextData<SSL> *getSocketContextDataS(SOCKET_TYPE *s) {
return (HttpContextData<SSL> *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(getSocketContext(s));
static HttpContextData<SSL> *getSocketContextDataS(us_new_socket_t *s) {
return (HttpContextData<SSL> *) us_new_socket_context_ext(SSL, getSocketContext(s));
}
/* Init the HttpContext by registering libusockets event handlers */
HttpContext<SSL> *init() {
/* Handle socket connections */
static_dispatch(us_ssl_socket_context_on_open, us_socket_context_on_open)(getSocketContext(), [](auto *s, int is_client) {
us_new_socket_context_on_open(SSL, getSocketContext(), [](auto *s, int is_client) {
/* Any connected socket should timeout until it has a request */
static_dispatch(us_ssl_socket_timeout, us_socket_timeout)(s, HTTP_IDLE_TIMEOUT_S);
us_new_socket_timeout(SSL, s, HTTP_IDLE_TIMEOUT_S);
/* Init socket ext */
new (static_dispatch(us_ssl_socket_ext, us_socket_ext)(s)) HttpResponseData<SSL>;
new (us_new_socket_ext(SSL, s)) HttpResponseData<SSL>;
/* Call filter */
HttpContextData<SSL> *httpContextData = getSocketContextDataS(s);
@@ -82,9 +78,9 @@ private:
});
/* Handle socket disconnections */
static_dispatch(us_ssl_socket_context_on_close, us_socket_context_on_close)(getSocketContext(), [](auto *s) {
us_new_socket_context_on_close(SSL, getSocketContext(), [](auto *s) {
/* Get socket ext */
HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) static_dispatch(us_ssl_socket_ext, us_socket_ext)(s);
HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) us_new_socket_ext(SSL, s);
/* Call filter */
HttpContextData<SSL> *httpContextData = getSocketContextDataS(s);
@@ -104,7 +100,7 @@ private:
});
/* Handle HTTP data streams */
static_dispatch(us_ssl_socket_context_on_data, us_socket_context_on_data)(getSocketContext(), [](auto *s, char *data, int length) {
us_new_socket_context_on_data(SSL, getSocketContext(), [](auto *s, char *data, int length) {
// total overhead is about 210k down to 180k
// ~210k req/sec is the original perf with write in data
@@ -115,11 +111,11 @@ private:
HttpContextData<SSL> *httpContextData = getSocketContextDataS(s);
/* Do not accept any data while in shutdown state */
if (static_dispatch(us_ssl_socket_is_shut_down, us_socket_is_shut_down)((SOCKET_TYPE *) s)) {
if (us_new_socket_is_shut_down(SSL, (us_new_socket_t *) s)) {
return s;
}
HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) static_dispatch(us_ssl_socket_ext, us_socket_ext)(s);
HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) us_new_socket_ext(SSL, s);
/* Cork this socket */
((AsyncSocket<SSL> *) s)->cork();
@@ -129,16 +125,16 @@ private:
void *returnedSocket = httpResponseData->consumePostPadded(data, length, s, [httpContextData](void *s, uWS::HttpRequest *httpRequest) -> void * {
/* For every request we reset the timeout and hang until user makes action */
/* Warning: if we are in shutdown state, resetting the timer is a security issue! */
static_dispatch(us_ssl_socket_timeout, us_socket_timeout)((SOCKET_TYPE *) s, 0);
us_new_socket_timeout(SSL, (us_new_socket_t *) s, 0);
/* Reset httpResponse */
HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) static_dispatch(us_ssl_socket_ext, us_socket_ext)((SOCKET_TYPE *) s);
HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) us_new_socket_ext(SSL, (us_new_socket_t *) s);
httpResponseData->offset = 0;
httpResponseData->state = 0;
/* Are we not ready for another request yet? Terminate the connection. */
if (httpResponseData->state & HttpResponseData<SSL>::HTTP_RESPONSE_PENDING) {
static_dispatch(us_ssl_socket_close, us_socket_close)((SOCKET_TYPE *) s);
us_new_socket_close(SSL, (us_new_socket_t *) s);
return nullptr;
}
@@ -151,7 +147,7 @@ private:
/* If first pass failed, we try and match by "any" method */
if (!httpContextData->router.route("*", httpRequest->getUrl(), routerData)) {
/* If second pass fail, we have to force close this socket as we have no handler for it */
static_dispatch(us_ssl_socket_close, us_socket_close)((SOCKET_TYPE *) s);
us_new_socket_close(SSL, (us_new_socket_t *) s);
return nullptr;
}
}
@@ -165,12 +161,12 @@ private:
}
/* Was the socket closed? */
if (us_socket_is_closed((struct us_socket *) s)) {
if (us_new_socket_is_closed(SSL, (struct us_new_socket_t *) s)) {
return nullptr;
}
/* We absolutely have to terminate parsing if shutdown */
if (static_dispatch(us_ssl_socket_is_shut_down, us_socket_is_shut_down)((SOCKET_TYPE *) s)) {
if (us_new_socket_is_shut_down(SSL, (us_new_socket_t *) s)) {
return nullptr;
}
@@ -189,19 +185,19 @@ private:
httpResponseData->inStream(data, fin);
/* Was the socket closed? */
if (us_socket_is_closed((struct us_socket *) user)) {
if (us_new_socket_is_closed(SSL, (struct us_new_socket_t *) user)) {
return nullptr;
}
/* We absolutely have to terminate parsing if shutdown */
if (static_dispatch(us_ssl_socket_is_shut_down, us_socket_is_shut_down)((SOCKET_TYPE *) user)) {
if (us_new_socket_is_shut_down(SSL, (us_new_socket_t *) user)) {
return nullptr;
}
}
return user;
}, [](void *user) {
/* Close any socket on HTTP errors */
static_dispatch(us_ssl_socket_close, us_socket_close)((SOCKET_TYPE *) user);
us_new_socket_close(SSL, (us_new_socket_t *) user);
return nullptr;
});
@@ -214,7 +210,7 @@ private:
((AsyncSocket<SSL> *) s)->timeout(HTTP_IDLE_TIMEOUT_S);
}
return (SOCKET_TYPE *) returnedSocket;
return (us_new_socket_t *) returnedSocket;
}
/* We cannot return nullptr to the underlying stack in any case */
@@ -222,10 +218,10 @@ private:
});
/* Handle HTTP write out (note: SSL_read may trigger this spuriously, the app need to handle spurious calls) */
static_dispatch(us_ssl_socket_context_on_writable, us_socket_context_on_writable)(getSocketContext(), [](auto *s) {
us_new_socket_context_on_writable(SSL, getSocketContext(), [](auto *s) {
/* We are now writable, so hang timeout again */
static_dispatch(us_ssl_socket_timeout, us_socket_timeout)(s, 0);
us_new_socket_timeout(SSL, s, 0);
AsyncSocket<SSL> *asyncSocket = (AsyncSocket<SSL> *) s;
HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) asyncSocket->getExt();
@@ -253,7 +249,7 @@ 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) {
us_new_socket_context_on_end(SSL, getSocketContext(), [](auto *s) {
/* We do not care for half closed sockets */
AsyncSocket<SSL> *asyncSocket = (AsyncSocket<SSL> *) s;
@@ -262,7 +258,7 @@ 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) {
us_new_socket_context_on_timeout(SSL, getSocketContext(), [](auto *s) {
/* Force close rather than gracefully shutdown and risk confusing the client with a complete download */
AsyncSocket<SSL> *asyncSocket = (AsyncSocket<SSL> *) s;
@@ -275,21 +271,17 @@ private:
public:
/* Construct a new HttpContext using specified loop */
static HttpContext *create(Loop *loop, us_ssl_socket_context_options *ssl_options = nullptr) {
static HttpContext *create(Loop *loop, us_new_socket_context_options_t options = {}) {
HttpContext *httpContext;
if constexpr(SSL) {
httpContext = (HttpContext *) us_create_ssl_socket_context((us_loop *) loop, sizeof(HttpContextData<SSL>), *ssl_options);
} else {
httpContext = (HttpContext *) us_create_socket_context((us_loop *) loop, sizeof(HttpContextData<SSL>));
}
httpContext = (HttpContext *) us_new_create_socket_context(SSL, (us_loop *) loop, sizeof(HttpContextData<SSL>), options);
if (!httpContext) {
return nullptr;
}
/* Init socket context data */
new ((HttpContextData<SSL> *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)((SOCKET_CONTEXT_TYPE *) httpContext)) HttpContextData<SSL>();
new ((HttpContextData<SSL> *) us_new_socket_context_ext(SSL, (us_new_socket_context_t *) httpContext)) HttpContextData<SSL>();
return httpContext->init();
}
@@ -300,7 +292,7 @@ public:
httpContextData->~HttpContextData<SSL>();
/* Free the socket context in whole */
static_dispatch(us_ssl_socket_context_free, us_socket_context_free)(getSocketContext());
us_new_socket_context_free(SSL, getSocketContext());
}
void filter(fu2::unique_function<void(HttpResponse<SSL> *, int)> &&filterHandler) {
@@ -333,7 +325,7 @@ public:
/* Listen to port using this HttpContext */
us_listen_socket *listen(const char *host, int port, int options) {
return static_dispatch(us_ssl_socket_context_listen, us_socket_context_listen)(getSocketContext(), host, port, options, sizeof(HttpResponseData<SSL>));
return us_new_socket_context_listen(SSL, getSocketContext(), host, port, options, sizeof(HttpResponseData<SSL>));
}
};
+1 -1
View File
@@ -22,7 +22,7 @@
#include "LoopData.h"
#include <libusockets.h>
#include <libusockets_new.h>
-71
View File
@@ -1,71 +0,0 @@
/*
* Authored by Alex Hultman, 2018-2019.
* Intellectual property of third-party.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef STATICDISPATCH_H
#define STATICDISPATCH_H
/* This headers is basically a statically dispatched libusockets wrapper base */
#include <type_traits>
#include <libusockets.h>
/* For now we just define all these as nonsense if using a non-SSL version of uSockets */
#ifdef LIBUS_NO_SSL
#define us_ssl_socket_context_options int
#define us_ssl_socket_context_ext us_socket_context_ext
#define us_ssl_socket_context_on_open us_socket_context_on_open
#define us_ssl_socket_timeout us_socket_timeout
#define us_ssl_socket_ext us_socket_ext
#define us_ssl_socket_context_on_close us_socket_context_on_close
#define us_ssl_socket_context_on_data us_socket_context_on_data
#define us_ssl_socket_context_on_writable us_socket_context_on_writable
#define us_ssl_socket_context_on_end us_socket_context_on_end
#define us_ssl_socket_context_on_timeout us_socket_context_on_timeout
#define us_ssl_socket_is_shut_down us_socket_is_shut_down
#define us_ssl_socket_close us_socket_close
#define us_ssl_socket_write us_socket_write
#define us_ssl_socket_context_loop us_socket_context_loop
#define us_ssl_socket_get_context us_socket_get_context
#define us_ssl_socket_context_listen us_socket_context_listen
#define us_ssl_socket_context_adopt_socket us_socket_context_adopt_socket
#define us_create_child_ssl_socket_context us_create_child_socket_context
#define us_ssl_socket_shutdown us_socket_shutdown
#define us_ssl_socket_context_free us_socket_context_free
/* This is the only differing function - time to fix! */
#define us_create_ssl_socket_context(l, e, o) us_create_socket_context(l, e)
#endif
namespace uWS {
template <bool SSL>
struct StaticDispatch {
template <class A, class B>
static constexpr typename std::conditional<SSL, A, B>::type *static_dispatch(A *a, B *b) {
if constexpr(SSL) {
return a;
} else {
return b;
}
}
typedef typename std::conditional<SSL, us_ssl_socket, us_socket>::type SOCKET_TYPE;
typedef typename std::conditional<SSL, us_ssl_socket_context, us_socket_context>::type SOCKET_CONTEXT_TYPE;
};
}
#endif // STATICDISPATCH_H
+5 -8
View File
@@ -31,19 +31,16 @@ struct WebSocket : AsyncSocket<SSL> {
template <bool> friend struct TemplatedApp;
private:
typedef AsyncSocket<SSL> Super;
using SOCKET_TYPE = typename StaticDispatch<SSL>::SOCKET_TYPE;
using SOCKET_CONTEXT_TYPE = typename StaticDispatch<SSL>::SOCKET_CONTEXT_TYPE;
using StaticDispatch<SSL>::static_dispatch;
void *init(bool perMessageDeflate, bool slidingCompression, std::string &&backpressure) {
new (static_dispatch(us_ssl_socket_ext, us_socket_ext)((SOCKET_TYPE *) this)) WebSocketData(perMessageDeflate, slidingCompression, std::move(backpressure));
new (us_new_socket_ext(SSL, (us_new_socket_t *) this)) WebSocketData(perMessageDeflate, slidingCompression, std::move(backpressure));
return this;
}
public:
/* Returns pointer to the per socket user data */
void *getUserData() {
WebSocketData *webSocketData = (WebSocketData *) static_dispatch(us_ssl_socket_ext, us_socket_ext)((SOCKET_TYPE *) this);
WebSocketData *webSocketData = (WebSocketData *) us_new_socket_ext(SSL, (us_new_socket_t *) this);
/* We just have it overallocated by sizeof type */
return (webSocketData + 1);
}
@@ -92,7 +89,7 @@ public:
/* Send websocket close frame, emit close event, send FIN if successful */
void close(int code, std::string_view message = {}) {
/* Check if we already called this one */
WebSocketData *webSocketData = (WebSocketData *) static_dispatch(us_ssl_socket_ext, us_socket_ext)((SOCKET_TYPE *) this);
WebSocketData *webSocketData = (WebSocketData *) us_new_socket_ext(SSL, (us_new_socket_t *) this);
if (webSocketData->isShuttingDown) {
return;
}
@@ -118,8 +115,8 @@ public:
}
/* Emit close event */
WebSocketContextData<SSL> *webSocketContextData = (WebSocketContextData<SSL> *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(
(SOCKET_CONTEXT_TYPE *) static_dispatch(us_ssl_socket_get_context, us_socket_get_context)((SOCKET_TYPE *) this)
WebSocketContextData<SSL> *webSocketContextData = (WebSocketContextData<SSL> *) us_new_socket_context_ext(SSL,
(us_new_socket_context_t *) us_new_socket_context(SSL, (us_new_socket_t *) this)
);
if (webSocketContextData->closeHandler) {
webSocketContextData->closeHandler(this, code, message);
+43 -47
View File
@@ -18,7 +18,6 @@
#ifndef WEBSOCKETCONTEXT_H
#define WEBSOCKETCONTEXT_H
#include "StaticDispatch.h"
#include "WebSocketContextData.h"
#include "WebSocketProtocol.h"
#include "WebSocketData.h"
@@ -27,26 +26,23 @@
namespace uWS {
template <bool SSL, bool isServer>
struct WebSocketContext : StaticDispatch<SSL> {
struct WebSocketContext {
template <bool> friend struct TemplatedApp;
template <bool, class> friend class WebSocketProtocol;
private:
using SOCKET_CONTEXT_TYPE = typename StaticDispatch<SSL>::SOCKET_CONTEXT_TYPE;
using SOCKET_TYPE = typename StaticDispatch<SSL>::SOCKET_TYPE;
using StaticDispatch<SSL>::static_dispatch;
WebSocketContext() = delete;
SOCKET_CONTEXT_TYPE *getSocketContext() {
return (SOCKET_CONTEXT_TYPE *) this;
us_new_socket_context_t *getSocketContext() {
return (us_new_socket_context_t *) this;
}
WebSocketContextData<SSL> *getExt() {
return (WebSocketContextData<SSL> *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)((SOCKET_CONTEXT_TYPE *) this);
return (WebSocketContextData<SSL> *) us_new_socket_context_ext(SSL, (us_new_socket_context_t *) this);
}
/* If we have negotiated compression, set this frame compressed */
static bool setCompressed(uWS::WebSocketState<isServer> *wState, void *s) {
WebSocketData *webSocketData = (WebSocketData *) static_dispatch(us_ssl_socket_ext, us_socket_ext)((SOCKET_TYPE *) s);
WebSocketData *webSocketData = (WebSocketData *) us_new_socket_ext(SSL, (us_new_socket_t *) s);
if (webSocketData->compressionStatus == WebSocketData::CompressionStatus::ENABLED) {
webSocketData->compressionStatus = WebSocketData::CompressionStatus::COMPRESSED_FRAME;
@@ -57,16 +53,16 @@ private:
}
static void forceClose(uWS::WebSocketState<isServer> *wState, void *s) {
us_socket_close((us_socket *) s);
us_new_socket_close(SSL, (us_new_socket_t *) s);
}
/* Returns true on breakage */
static bool handleFragment(char *data, size_t length, unsigned int remainingBytes, int opCode, bool fin, uWS::WebSocketState<isServer> *webSocketState, void *s) {
/* WebSocketData and WebSocketContextData */
WebSocketContextData<SSL> *webSocketContextData = (WebSocketContextData<SSL> *) 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)
WebSocketContextData<SSL> *webSocketContextData = (WebSocketContextData<SSL> *) us_new_socket_context_ext(SSL,
us_new_socket_context(SSL, (us_new_socket_t *) s)
);
WebSocketData *webSocketData = (WebSocketData *) static_dispatch(us_ssl_socket_ext, us_socket_ext)((SOCKET_TYPE *) s);
WebSocketData *webSocketData = (WebSocketData *) us_new_socket_ext(SSL, (us_new_socket_t *) s);
/* Is this a non-control frame? */
if (opCode < 3) {
@@ -78,8 +74,8 @@ private:
webSocketData->compressionStatus = WebSocketData::CompressionStatus::ENABLED;
LoopData *loopData = (LoopData *)us_loop_ext(
static_dispatch(us_ssl_socket_context_loop, us_socket_context_loop)(
static_dispatch(us_ssl_socket_get_context, us_socket_get_context)((SOCKET_TYPE *)s)
us_new_socket_context_loop(SSL,
us_new_socket_context(SSL, (us_new_socket_t *)s)
)
);
@@ -102,7 +98,7 @@ private:
/* Emit message event & break if we are closed or shut down when returning */
if (webSocketContextData->messageHandler) {
webSocketContextData->messageHandler((WebSocket<SSL, isServer> *) s, std::string_view(data, length), (uWS::OpCode) opCode);
if (us_socket_is_closed((us_socket *)s) || webSocketData->isShuttingDown) {
if (us_new_socket_is_closed(SSL, (us_new_socket_t *)s) || webSocketData->isShuttingDown) {
return true;
}
}
@@ -125,8 +121,8 @@ private:
webSocketData->fragmentBuffer.append("....");
LoopData *loopData = (LoopData *) us_loop_ext(
static_dispatch(us_ssl_socket_context_loop, us_socket_context_loop)(
static_dispatch(us_ssl_socket_get_context, us_socket_get_context)((SOCKET_TYPE *) s)
us_new_socket_context_loop(SSL,
us_new_socket_context(SSL, (us_new_socket_t *) s)
)
);
@@ -155,7 +151,7 @@ private:
/* Emit message and check for shutdown or close */
if (webSocketContextData->messageHandler) {
webSocketContextData->messageHandler((WebSocket<SSL, isServer> *) s, std::string_view(data, length), (uWS::OpCode) opCode);
if (us_socket_is_closed((us_socket *)s) || webSocketData->isShuttingDown) {
if (us_new_socket_is_closed(SSL, (us_new_socket_t *)s) || webSocketData->isShuttingDown) {
return true;
}
}
@@ -223,8 +219,8 @@ private:
}
static bool refusePayloadLength(uint64_t length, uWS::WebSocketState<isServer> *wState, void *s) {
WebSocketContextData<SSL> *webSocketContextData = (WebSocketContextData<SSL> *) 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)
WebSocketContextData<SSL> *webSocketContextData = (WebSocketContextData<SSL> *) us_new_socket_context_ext(SSL,
us_new_socket_context(SSL, (us_new_socket_t *)s)
);
/* Return true for refuse, false for accept */
@@ -237,14 +233,14 @@ private:
* any backpressure from HTTP state kept. */
/* Handle socket disconnections */
static_dispatch(us_ssl_socket_context_on_close, us_socket_context_on_close)(getSocketContext(), [](auto *s) {
us_new_socket_context_on_close(SSL, getSocketContext(), [](auto *s) {
/* For whatever reason, if we already have emitted close event, do not emit it again */
WebSocketData *webSocketData = (WebSocketData *) (static_dispatch(us_ssl_socket_ext, us_socket_ext)(s));
WebSocketData *webSocketData = (WebSocketData *) (us_new_socket_ext(SSL, s));
if (!webSocketData->isShuttingDown) {
/* Emit close event */
WebSocketContextData<SSL> *webSocketContextData = (WebSocketContextData<SSL> *) 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)
WebSocketContextData<SSL> *webSocketContextData = (WebSocketContextData<SSL> *) us_new_socket_context_ext(SSL,
us_new_socket_context(SSL, (us_new_socket_t *)s)
);
if (webSocketContextData->closeHandler) {
@@ -259,18 +255,18 @@ 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) {
us_new_socket_context_on_data(SSL, 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 */
// å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<SSL> *webSocketContextData = (WebSocketContextData<SSL> *) 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)
WebSocketContextData<SSL> *webSocketContextData = (WebSocketContextData<SSL> *) us_new_socket_context_ext(SSL,
us_new_socket_context(SSL, (us_new_socket_t *) s)
);
static_dispatch(us_ssl_socket_timeout, us_socket_timeout)((SOCKET_TYPE *) s, webSocketContextData->idleTimeout);
us_new_socket_timeout(SSL, (us_new_socket_t *) s, webSocketContextData->idleTimeout);
/* We always cork on data */
@@ -278,7 +274,7 @@ private:
webSocket->cork();
/* We need the websocket data */
WebSocketData *webSocketData = (WebSocketData *) (static_dispatch(us_ssl_socket_ext, us_socket_ext)(s));
WebSocketData *webSocketData = (WebSocketData *) (us_new_socket_ext(SSL, s));
/* This parser has virtually no overhead */
uWS::WebSocketProtocol<isServer, WebSocketContext<SSL, isServer>>::consume(data, length, (WebSocketState<isServer> *) webSocketData, s);
@@ -289,7 +285,7 @@ private:
webSocket->uncork();
// cannot do anything else if closed
if (us_socket_is_closed((us_socket *) s)) {
if (us_new_socket_is_closed(SSL, (us_new_socket_t *) s)) {
return s;
}
@@ -304,15 +300,15 @@ private:
});
/* Handle HTTP write out (note: SSL_read may trigger this spuriously, the app need to handle spurious calls) */
static_dispatch(us_ssl_socket_context_on_writable, us_socket_context_on_writable)(getSocketContext(), [](auto *s) {
us_new_socket_context_on_writable(SSL, getSocketContext(), [](auto *s) {
/* It makes sense to check for us_is_shut_down here and return if so, to avoid shutting down twice */
if (static_dispatch(us_ssl_socket_is_shut_down, us_socket_is_shut_down)((SOCKET_TYPE *) s)) {
if (us_new_socket_is_shut_down(SSL, (us_new_socket_t *) s)) {
return s;
}
AsyncSocket<SSL> *webSocket = (AsyncSocket<SSL> *) s;
WebSocketData *webSocketData = (WebSocketData *)(static_dispatch(us_ssl_socket_ext, us_socket_ext)(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();
@@ -322,8 +318,8 @@ private:
/* Behavior: if we actively drain backpressure, always reset timeout (even if we are in shutdown) */
if (backpressure < webSocket->getBufferedAmount()) {
WebSocketContextData<SSL> *webSocketContextData = (WebSocketContextData<SSL> *) 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)
WebSocketContextData<SSL> *webSocketContextData = (WebSocketContextData<SSL> *) us_new_socket_context_ext(SSL,
us_new_socket_context(SSL, (us_new_socket_t *)s)
);
webSocket->timeout(webSocketContextData->idleTimeout);
}
@@ -337,8 +333,8 @@ private:
}
} else if (backpressure > webSocket->getBufferedAmount()) {
/* Only call drain if we actually drained backpressure */
WebSocketContextData<SSL> *webSocketContextData = (WebSocketContextData<SSL> *) 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)
WebSocketContextData<SSL> *webSocketContextData = (WebSocketContextData<SSL> *) us_new_socket_context_ext(SSL,
us_new_socket_context(SSL, (us_new_socket_t *)s)
);
if (webSocketContextData->drainHandler) {
webSocketContextData->drainHandler((WebSocket<SSL, isServer> *) s);
@@ -350,19 +346,19 @@ 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) {
us_new_socket_context_on_end(SSL, getSocketContext(), [](auto *s) {
/* If we get a fin, we just close I guess */
static_dispatch(us_ssl_socket_close, us_socket_close)((SOCKET_TYPE *) s);
us_new_socket_close(SSL, (us_new_socket_t *) s);
return s;
});
/* 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) {
us_new_socket_context_on_timeout(SSL, getSocketContext(), [](auto *s) {
/* Timeout is very simple; we just close it */
static_dispatch(us_ssl_socket_close, us_socket_close)((SOCKET_TYPE *) s);
us_new_socket_close(SSL, (us_new_socket_t *) s);
return s;
});
@@ -371,22 +367,22 @@ private:
}
void free() {
WebSocketContextData<SSL> *webSocketContextData = (WebSocketContextData<SSL> *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)((SOCKET_CONTEXT_TYPE *) this);
WebSocketContextData<SSL> *webSocketContextData = (WebSocketContextData<SSL> *) us_new_socket_context_ext(SSL, (us_new_socket_context_t *) this);
webSocketContextData->~WebSocketContextData();
static_dispatch(us_ssl_socket_context_free, us_socket_context_free)((SOCKET_CONTEXT_TYPE *) this);
us_new_socket_context_free(SSL, (us_new_socket_context_t *) this);
}
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, SOCKET_CONTEXT_TYPE *parentSocketContext) {
WebSocketContext *webSocketContext = (WebSocketContext *)static_dispatch(us_create_child_ssl_socket_context, us_create_child_socket_context)(parentSocketContext, sizeof(WebSocketContextData<SSL>));
static WebSocketContext *create(Loop *loop, us_new_socket_context_t *parentSocketContext) {
WebSocketContext *webSocketContext = (WebSocketContext *) us_new_create_child_socket_context(SSL, parentSocketContext, sizeof(WebSocketContextData<SSL>));
if (!webSocketContext) {
return nullptr;
}
/* Init socket context data */
new ((WebSocketContextData<SSL> *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)((SOCKET_CONTEXT_TYPE *)webSocketContext)) WebSocketContextData<SSL>;
new ((WebSocketContextData<SSL> *) us_new_socket_context_ext(SSL, (us_new_socket_context_t *)webSocketContext)) WebSocketContextData<SSL>;
return webSocketContext->init();
}
};