Add option sendPingsAutomatically
This commit is contained in:
@@ -21,8 +21,11 @@ int main() {
|
||||
/* Settings */
|
||||
.compression = uWS::SHARED_COMPRESSOR,
|
||||
.maxPayloadLength = 16 * 1024,
|
||||
.idleTimeout = 10,
|
||||
.idleTimeout = 16,
|
||||
.maxBackpressure = 1 * 1024 * 1024,
|
||||
.closeOnBackpressureLimit = false,
|
||||
.resetIdleTimeoutOnSend = false,
|
||||
.sendPingsAutomatically = true,
|
||||
/* Handlers */
|
||||
.upgrade = nullptr,
|
||||
.open = [](auto */*ws*/) {
|
||||
|
||||
@@ -139,8 +139,10 @@ public:
|
||||
unsigned int maxPayloadLength = 16 * 1024;
|
||||
unsigned int idleTimeout = 120;
|
||||
unsigned int maxBackpressure = 1 * 1024 * 1024;
|
||||
// change these before release
|
||||
bool closeOnBackpressureLimit = false;
|
||||
bool resetIdleTimeoutOnSend = true;
|
||||
bool sendPingsAutomatically = false;
|
||||
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> *, std::string_view, uWS::OpCode)> message = nullptr;
|
||||
@@ -204,8 +206,12 @@ public:
|
||||
webSocketContext->getExt()->maxBackpressure = behavior.maxBackpressure;
|
||||
webSocketContext->getExt()->closeOnBackpressureLimit = behavior.closeOnBackpressureLimit;
|
||||
webSocketContext->getExt()->resetIdleTimeoutOnSend = behavior.resetIdleTimeoutOnSend;
|
||||
webSocketContext->getExt()->sendPingsAutomatically = behavior.sendPingsAutomatically;
|
||||
webSocketContext->getExt()->compression = behavior.compression;
|
||||
|
||||
/* Calculate idleTimeoutCompnents */
|
||||
webSocketContext->getExt()->calculateIdleTimeoutCompnents();
|
||||
|
||||
httpContext->onHttp("get", pattern, [webSocketContext, behavior = std::move(behavior)](auto *res, auto *req) mutable {
|
||||
|
||||
/* If we have this header set, it's a websocket */
|
||||
|
||||
+3
-1
@@ -123,7 +123,9 @@ public:
|
||||
|
||||
/* Every successful send resets the timeout */
|
||||
if (webSocketContextData->resetIdleTimeoutOnSend) {
|
||||
Super::timeout(webSocketContextData->idleTimeout);
|
||||
Super::timeout(webSocketContextData->idleTimeoutComponents.first);
|
||||
WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData();
|
||||
webSocketData->hasTimedOut = false;
|
||||
}
|
||||
|
||||
/* Return success */
|
||||
|
||||
+15
-2
@@ -276,7 +276,8 @@ private:
|
||||
auto *asyncSocket = (AsyncSocket<SSL> *) s;
|
||||
|
||||
/* 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 */
|
||||
asyncSocket->cork();
|
||||
@@ -325,7 +326,8 @@ private:
|
||||
/* Also reset timeout if we came here with 0 backpressure */
|
||||
if (!backpressure || backpressure > asyncSocket->getBufferedAmount()) {
|
||||
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? */
|
||||
@@ -359,6 +361,17 @@ private:
|
||||
/* Handle socket timeouts, simply close them so to not confuse client with FIN */
|
||||
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 */
|
||||
/* Warning: we happen to know forceClose will not use first parameter so pass nullptr here */
|
||||
forceClose(nullptr, s, ERR_WEBSOCKET_TIMEOUT);
|
||||
|
||||
@@ -66,10 +66,31 @@ public:
|
||||
size_t maxBackpressure = 0;
|
||||
bool closeOnBackpressureLimit;
|
||||
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 */
|
||||
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() {
|
||||
/* We must unregister any loop post handler here */
|
||||
Loop::get()->removePostHandler(this);
|
||||
@@ -157,7 +178,9 @@ public:
|
||||
* ENTIRE SUCCESS - we need minor API changes to support correct checks */
|
||||
if (!failed) {
|
||||
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 */
|
||||
if (!failed) {
|
||||
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;
|
||||
unsigned int controlTipLength = 0;
|
||||
bool isShuttingDown = 0;
|
||||
bool hasTimedOut = false;
|
||||
enum CompressionStatus : char {
|
||||
DISABLED,
|
||||
ENABLED,
|
||||
|
||||
Reference in New Issue
Block a user