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