Add option sendPingsAutomatically

This commit is contained in:
Alex Hultman
2021-01-31 12:53:17 +00:00
parent 43e3c76edc
commit df7c4bb9f8
6 changed files with 56 additions and 6 deletions
+4 -1
View File
@@ -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*/) {
+6
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+27 -2
View File
@@ -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);
}
}
}
+1
View File
@@ -37,6 +37,7 @@ private:
std::string fragmentBuffer;
unsigned int controlTipLength = 0;
bool isShuttingDown = 0;
bool hasTimedOut = false;
enum CompressionStatus : char {
DISABLED,
ENABLED,