diff --git a/misc/main.cpp b/misc/main.cpp index 2a9a70a..a84bf4e 100644 --- a/misc/main.cpp +++ b/misc/main.cpp @@ -12,7 +12,7 @@ int main(int argc, char **argv) { int hello; }; - auto app = uWS::SSLApp({ + auto app = uWS::/*SSL*/App({ .key_file_name = "/home/alexhultman/key.pem", .cert_file_name = "/home/alexhultman/cert.pem", .passphrase = "1234" diff --git a/src/WebSocket.h b/src/WebSocket.h index 6170a9a..0d96680 100644 --- a/src/WebSocket.h +++ b/src/WebSocket.h @@ -89,29 +89,33 @@ public: return true; } - /* Emit close event, start passive timeout */ + /* Send websocket close frame, emit close event, send FIN if successful */ void close(int code, std::string_view message = {}) { - static const int MAX_CLOSE_PAYLOAD = 123; - int length = std::min(MAX_CLOSE_PAYLOAD, message.length()); - - // todo: here we start a timeout and handle it accordingly in the timeout handler - + /* Check if we already called this one */ WebSocketData *webSocketData = (WebSocketData *) static_dispatch(us_ssl_socket_ext, us_socket_ext)((SOCKET_TYPE *) this); + if (webSocketData->isShuttingDown) { + return; + } /* We postpone any FIN sending to either drainage or uncorking */ webSocketData->isShuttingDown = true; /* Format and send the close frame */ + static const int MAX_CLOSE_PAYLOAD = 123; + int length = std::min(MAX_CLOSE_PAYLOAD, message.length()); char closePayload[MAX_CLOSE_PAYLOAD + 2]; int closePayloadLength = protocol::formatClosePayload(closePayload, code, message.data(), length); + bool ok = send(std::string_view(closePayload, closePayloadLength), OpCode::CLOSE); - // but what if we are NOT corked, THEN we can FIN here if we succeeded - - // if we are corked and send returns true we cannot know for sure if we can fin - send(std::string_view(closePayload, closePayloadLength), OpCode::CLOSE); - - // why should we fin here? - //us_socket_shutdown((us_socket *) this); + /* FIN if we are ok and not corked */ + WebSocket *webSocket = (WebSocket *) this; + if (!webSocket->isCorked()) { + if (ok) { + /* If we are not corked, and we just sent off everything, we need to FIN right here. + * In all other cases, we need to fin either if uncork was successful, or when drainage is complete. */ + webSocket->shutdown(); + } + } /* Emit close event */ WebSocketContextData *webSocketContextData = (WebSocketContextData *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)( diff --git a/src/WebSocketContext.h b/src/WebSocketContext.h index 2b5199d..bcb669a 100644 --- a/src/WebSocketContext.h +++ b/src/WebSocketContext.h @@ -236,17 +236,38 @@ private: /* Always assume timeout is disabled when we are adopted. * HTTP requests should disable timeout anyways */ + // beroende på state, skall close emitta eller inte emitta vår event + // om den sakll emitta, då blir det 1006 och noll meddelande + // annars, har vi redan emittat från den funktion som vi anropade dvs websocket::Close + + // det tar 15 minuter för en ACK att tima ut + // så, vi ska endast nollställa timeout om vi skrivit och kernel har tagit emit den + // vi kan inte nollställa timeout vid send som inte lyckades + /* Handle socket disconnections */ static_dispatch(us_ssl_socket_context_on_close, us_socket_context_on_close)(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)); + if (!webSocketData->isShuttingDown) { + /* Emit close event */ + WebSocketContextData *webSocketContextData = (WebSocketContextData *) 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) + ); + + if (webSocketContextData->closeHandler) { + webSocketContextData->closeHandler((WebSocket *) s, 1006, {}); + } + } + + /* Destruct in-placed data struct */ webSocketData->~WebSocketData(); - - return s; }); + // writable, data samt send skall nollställa timeouten till idleTimeout? allitd + /* Handle WebSocket data streams */ static_dispatch(us_ssl_socket_context_on_data, us_socket_context_on_data)(getSocketContext(), [](auto *s, char *data, int length) { @@ -254,9 +275,9 @@ private: /* If not in websocket shutdown state, for every */ - // hur mycket sabbar denna? + // å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 *webSocketContextData = (WebSocketContextData *) 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) + static_dispatch(us_ssl_socket_get_context, us_socket_get_context)((SOCKET_TYPE *) s) ); static_dispatch(us_ssl_socket_timeout, us_socket_timeout)((SOCKET_TYPE *) s, webSocketContextData->idleTimeout); @@ -327,6 +348,8 @@ private: return s; }); + // dessa nedan är samma oavsett state, de closar alltid! + /* 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) { diff --git a/src/WebSocketContextData.h b/src/WebSocketContextData.h index e437404..85eff4b 100644 --- a/src/WebSocketContextData.h +++ b/src/WebSocketContextData.h @@ -33,8 +33,8 @@ template struct WebSocketContextData { /* The callbacks for this context */ std::function *, std::string_view, uWS::OpCode)> messageHandler = nullptr; - std::function *)> drainHandler = nullptr; - std::function *, int, std::string_view)> closeHandler = nullptr; + std::function *)> drainHandler = nullptr; + std::function *, int, std::string_view)> closeHandler = nullptr; /* Settings for this context */ size_t maxPayloadLength = 0;