Add option sendPingsAutomatically
This commit is contained in:
@@ -21,8 +21,11 @@ int main() {
|
|||||||
/* Settings */
|
/* Settings */
|
||||||
.compression = uWS::SHARED_COMPRESSOR,
|
.compression = uWS::SHARED_COMPRESSOR,
|
||||||
.maxPayloadLength = 16 * 1024,
|
.maxPayloadLength = 16 * 1024,
|
||||||
.idleTimeout = 10,
|
.idleTimeout = 16,
|
||||||
.maxBackpressure = 1 * 1024 * 1024,
|
.maxBackpressure = 1 * 1024 * 1024,
|
||||||
|
.closeOnBackpressureLimit = false,
|
||||||
|
.resetIdleTimeoutOnSend = false,
|
||||||
|
.sendPingsAutomatically = true,
|
||||||
/* Handlers */
|
/* Handlers */
|
||||||
.upgrade = nullptr,
|
.upgrade = nullptr,
|
||||||
.open = [](auto */*ws*/) {
|
.open = [](auto */*ws*/) {
|
||||||
|
|||||||
@@ -139,8 +139,10 @@ public:
|
|||||||
unsigned int maxPayloadLength = 16 * 1024;
|
unsigned int maxPayloadLength = 16 * 1024;
|
||||||
unsigned int idleTimeout = 120;
|
unsigned int idleTimeout = 120;
|
||||||
unsigned int maxBackpressure = 1 * 1024 * 1024;
|
unsigned int maxBackpressure = 1 * 1024 * 1024;
|
||||||
|
// change these before release
|
||||||
bool closeOnBackpressureLimit = false;
|
bool closeOnBackpressureLimit = false;
|
||||||
bool resetIdleTimeoutOnSend = true;
|
bool resetIdleTimeoutOnSend = true;
|
||||||
|
bool sendPingsAutomatically = false;
|
||||||
fu2::unique_function<void(HttpResponse<SSL> *, HttpRequest *, struct us_socket_context_t *)> upgrade = nullptr;
|
fu2::unique_function<void(HttpResponse<SSL> *, HttpRequest *, struct us_socket_context_t *)> upgrade = nullptr;
|
||||||
fu2::unique_function<void(uWS::WebSocket<SSL, true> *)> open = nullptr;
|
fu2::unique_function<void(uWS::WebSocket<SSL, true> *)> open = nullptr;
|
||||||
fu2::unique_function<void(uWS::WebSocket<SSL, true> *, std::string_view, uWS::OpCode)> message = nullptr;
|
fu2::unique_function<void(uWS::WebSocket<SSL, true> *, std::string_view, uWS::OpCode)> message = nullptr;
|
||||||
@@ -204,8 +206,12 @@ public:
|
|||||||
webSocketContext->getExt()->maxBackpressure = behavior.maxBackpressure;
|
webSocketContext->getExt()->maxBackpressure = behavior.maxBackpressure;
|
||||||
webSocketContext->getExt()->closeOnBackpressureLimit = behavior.closeOnBackpressureLimit;
|
webSocketContext->getExt()->closeOnBackpressureLimit = behavior.closeOnBackpressureLimit;
|
||||||
webSocketContext->getExt()->resetIdleTimeoutOnSend = behavior.resetIdleTimeoutOnSend;
|
webSocketContext->getExt()->resetIdleTimeoutOnSend = behavior.resetIdleTimeoutOnSend;
|
||||||
|
webSocketContext->getExt()->sendPingsAutomatically = behavior.sendPingsAutomatically;
|
||||||
webSocketContext->getExt()->compression = behavior.compression;
|
webSocketContext->getExt()->compression = behavior.compression;
|
||||||
|
|
||||||
|
/* Calculate idleTimeoutCompnents */
|
||||||
|
webSocketContext->getExt()->calculateIdleTimeoutCompnents();
|
||||||
|
|
||||||
httpContext->onHttp("get", pattern, [webSocketContext, behavior = std::move(behavior)](auto *res, auto *req) mutable {
|
httpContext->onHttp("get", pattern, [webSocketContext, behavior = std::move(behavior)](auto *res, auto *req) mutable {
|
||||||
|
|
||||||
/* If we have this header set, it's a websocket */
|
/* If we have this header set, it's a websocket */
|
||||||
|
|||||||
+3
-1
@@ -123,7 +123,9 @@ public:
|
|||||||
|
|
||||||
/* Every successful send resets the timeout */
|
/* Every successful send resets the timeout */
|
||||||
if (webSocketContextData->resetIdleTimeoutOnSend) {
|
if (webSocketContextData->resetIdleTimeoutOnSend) {
|
||||||
Super::timeout(webSocketContextData->idleTimeout);
|
Super::timeout(webSocketContextData->idleTimeoutComponents.first);
|
||||||
|
WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData();
|
||||||
|
webSocketData->hasTimedOut = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return success */
|
/* Return success */
|
||||||
|
|||||||
+15
-2
@@ -276,7 +276,8 @@ private:
|
|||||||
auto *asyncSocket = (AsyncSocket<SSL> *) s;
|
auto *asyncSocket = (AsyncSocket<SSL> *) s;
|
||||||
|
|
||||||
/* Every time we get data and not in shutdown state we simply reset the timeout */
|
/* Every time we get data and not in shutdown state we simply reset the timeout */
|
||||||
asyncSocket->timeout(webSocketContextData->idleTimeout);
|
asyncSocket->timeout(webSocketContextData->idleTimeoutComponents.first);
|
||||||
|
webSocketData->hasTimedOut = false;
|
||||||
|
|
||||||
/* We always cork on data */
|
/* We always cork on data */
|
||||||
asyncSocket->cork();
|
asyncSocket->cork();
|
||||||
@@ -325,7 +326,8 @@ private:
|
|||||||
/* Also reset timeout if we came here with 0 backpressure */
|
/* Also reset timeout if we came here with 0 backpressure */
|
||||||
if (!backpressure || backpressure > asyncSocket->getBufferedAmount()) {
|
if (!backpressure || backpressure > asyncSocket->getBufferedAmount()) {
|
||||||
auto *webSocketContextData = (WebSocketContextData<SSL> *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s));
|
auto *webSocketContextData = (WebSocketContextData<SSL> *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s));
|
||||||
asyncSocket->timeout(webSocketContextData->idleTimeout);
|
asyncSocket->timeout(webSocketContextData->idleTimeoutComponents.first);
|
||||||
|
webSocketData->hasTimedOut = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Are we in (WebSocket) shutdown mode? */
|
/* Are we in (WebSocket) shutdown mode? */
|
||||||
@@ -359,6 +361,17 @@ private:
|
|||||||
/* Handle socket timeouts, simply close them so to not confuse client with FIN */
|
/* Handle socket timeouts, simply close them so to not confuse client with FIN */
|
||||||
us_socket_context_on_timeout(SSL, getSocketContext(), [](auto *s) {
|
us_socket_context_on_timeout(SSL, getSocketContext(), [](auto *s) {
|
||||||
|
|
||||||
|
auto *webSocketData = (WebSocketData *)(us_socket_ext(SSL, s));
|
||||||
|
auto *webSocketContextData = (WebSocketContextData<SSL> *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s));
|
||||||
|
|
||||||
|
if (webSocketContextData->sendPingsAutomatically && !webSocketData->hasTimedOut) {
|
||||||
|
webSocketData->hasTimedOut = true;
|
||||||
|
us_socket_timeout(SSL, s, webSocketContextData->idleTimeoutComponents.second);
|
||||||
|
/* Send ping without being corked */
|
||||||
|
((AsyncSocket<SSL> *) s)->write("\x89\x00", 2);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
/* Timeout is very simple; we just close it */
|
/* Timeout is very simple; we just close it */
|
||||||
/* Warning: we happen to know forceClose will not use first parameter so pass nullptr here */
|
/* Warning: we happen to know forceClose will not use first parameter so pass nullptr here */
|
||||||
forceClose(nullptr, s, ERR_WEBSOCKET_TIMEOUT);
|
forceClose(nullptr, s, ERR_WEBSOCKET_TIMEOUT);
|
||||||
|
|||||||
@@ -66,10 +66,31 @@ public:
|
|||||||
size_t maxBackpressure = 0;
|
size_t maxBackpressure = 0;
|
||||||
bool closeOnBackpressureLimit;
|
bool closeOnBackpressureLimit;
|
||||||
bool resetIdleTimeoutOnSend;
|
bool resetIdleTimeoutOnSend;
|
||||||
|
bool sendPingsAutomatically;
|
||||||
|
|
||||||
|
/* These are calculated on creation */
|
||||||
|
std::pair<unsigned short, unsigned short> idleTimeoutComponents;
|
||||||
|
|
||||||
/* Each websocket context has a topic tree for pub/sub */
|
/* Each websocket context has a topic tree for pub/sub */
|
||||||
TopicTree topicTree;
|
TopicTree topicTree;
|
||||||
|
|
||||||
|
/* This is run once on start-up */
|
||||||
|
void calculateIdleTimeoutCompnents() {
|
||||||
|
unsigned short margin = 4;
|
||||||
|
/* 4, 8 or 16 seconds margin based on idleTimeout */
|
||||||
|
while ((int) idleTimeout - margin * 2 >= margin * 2 && margin < 16) {
|
||||||
|
margin *= 2;
|
||||||
|
}
|
||||||
|
/* We should have no margin if not using sendPingsAutomatically */
|
||||||
|
if (!sendPingsAutomatically) {
|
||||||
|
margin = 0;
|
||||||
|
}
|
||||||
|
idleTimeoutComponents = {
|
||||||
|
idleTimeout - margin,
|
||||||
|
margin
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
~WebSocketContextData() {
|
~WebSocketContextData() {
|
||||||
/* We must unregister any loop post handler here */
|
/* We must unregister any loop post handler here */
|
||||||
Loop::get()->removePostHandler(this);
|
Loop::get()->removePostHandler(this);
|
||||||
@@ -157,7 +178,9 @@ public:
|
|||||||
* ENTIRE SUCCESS - we need minor API changes to support correct checks */
|
* ENTIRE SUCCESS - we need minor API changes to support correct checks */
|
||||||
if (!failed) {
|
if (!failed) {
|
||||||
if (this->resetIdleTimeoutOnSend) {
|
if (this->resetIdleTimeoutOnSend) {
|
||||||
asyncSocket->timeout(this->idleTimeout);
|
auto *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) asyncSocket);
|
||||||
|
webSocketData->hasTimedOut = false;
|
||||||
|
asyncSocket->timeout(this->idleTimeoutComponents.first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -171,7 +194,9 @@ public:
|
|||||||
/* Again, this check should be more like DID WE PROGRESS rather than DID WE SUCCEED ENTIRELY */
|
/* Again, this check should be more like DID WE PROGRESS rather than DID WE SUCCEED ENTIRELY */
|
||||||
if (!failed) {
|
if (!failed) {
|
||||||
if (this->resetIdleTimeoutOnSend) {
|
if (this->resetIdleTimeoutOnSend) {
|
||||||
asyncSocket->timeout(this->idleTimeout);
|
auto *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) asyncSocket);
|
||||||
|
webSocketData->hasTimedOut = false;
|
||||||
|
asyncSocket->timeout(this->idleTimeoutComponents.first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ private:
|
|||||||
std::string fragmentBuffer;
|
std::string fragmentBuffer;
|
||||||
unsigned int controlTipLength = 0;
|
unsigned int controlTipLength = 0;
|
||||||
bool isShuttingDown = 0;
|
bool isShuttingDown = 0;
|
||||||
|
bool hasTimedOut = false;
|
||||||
enum CompressionStatus : char {
|
enum CompressionStatus : char {
|
||||||
DISABLED,
|
DISABLED,
|
||||||
ENABLED,
|
ENABLED,
|
||||||
|
|||||||
Reference in New Issue
Block a user