diff --git a/README.md b/README.md index 5bce24b..9824b8e 100644 --- a/README.md +++ b/README.md @@ -53,3 +53,7 @@ For command line debugging, there's This extension makes use of the C library WSlay by @tatsuhiro-t: * https://github.com/tatsuhiro-t/wslay + +The test server used by the example: + +* https://www.lob.com/blog/websocket-org-is-down-here-is-an-alternative diff --git a/examples/websocket.gui_script b/examples/websocket.gui_script index b24b7a5..8f905a7 100644 --- a/examples/websocket.gui_script +++ b/examples/websocket.gui_script @@ -1,4 +1,4 @@ -local URL = "echo.websocket.org" +local URL = "echo.websocket.events" local function click_button(node, action) return gui.is_enabled(node) and action.pressed and gui.pick_node(node, action.x, action.y) @@ -57,7 +57,7 @@ end local function websocket_callback(self, conn, data) if data.event == websocket.EVENT_DISCONNECTED then - log("Disconnected: " .. tostring(conn)) + log("Disconnected: " .. tostring(conn) .. " Code: " .. data.code .. " Message: " .. tostring(data.message)) self.connection = nil update_gui(self) elseif data.event == websocket.EVENT_CONNECTED then diff --git a/websocket/api/api.script_api b/websocket/api/api.script_api index c5f1337..5914199 100644 --- a/websocket/api/api.script_api +++ b/websocket/api/api.script_api @@ -61,6 +61,14 @@ type: string desc: The received data if event is `websocket.EVENT_MESSAGE`. Error message otherwise + - name: handshake_response + type: table + desc: Handshake response information (status, headers etc) + + - name: code + type: number + desc: Status code received from the server if the server closed the connection. Only present if event is `EVENT_DISCONNECTED`. + returns: - name: connection @@ -86,7 +94,7 @@ end function init(self) - self.url = "ws://echo.websocket.org" + self.url = "ws://echo.websocket.events" local params = { timeout = 3000, headers = "Sec-WebSocket-Protocol: chat\r\nOrigin: mydomain.com\r\n" diff --git a/websocket/src/emscripten_callbacks.cpp b/websocket/src/emscripten_callbacks.cpp index ddb3b98..80ddb4e 100644 --- a/websocket/src/emscripten_callbacks.cpp +++ b/websocket/src/emscripten_callbacks.cpp @@ -21,8 +21,8 @@ EM_BOOL Emscripten_WebSocketOnError(int eventType, const EmscriptenWebSocketErro EM_BOOL Emscripten_WebSocketOnClose(int eventType, const EmscriptenWebSocketCloseEvent *websocketEvent, void *userData) { DebugLog(1, "WebSocket OnClose"); WebsocketConnection* conn = (WebsocketConnection*)userData; - PushMessage(conn, MESSAGE_TYPE_CLOSE, 0, 0); - SetState(conn, STATE_DISCONNECTED); + int length = strlen(websocketEvent->reason); + PushMessage(conn, MESSAGE_TYPE_CLOSE, length, (uint8_t*)websocketEvent->reason, websocketEvent->code); return EM_TRUE; } EM_BOOL Emscripten_WebSocketOnMessage(int eventType, const EmscriptenWebSocketMessageEvent *websocketEvent, void *userData) { @@ -33,7 +33,7 @@ EM_BOOL Emscripten_WebSocketOnMessage(int eventType, const EmscriptenWebSocketMe { length--; } - PushMessage(conn, MESSAGE_TYPE_NORMAL, length, websocketEvent->data); + PushMessage(conn, MESSAGE_TYPE_NORMAL, length, websocketEvent->data, 0); return EM_TRUE; } diff --git a/websocket/src/websocket.cpp b/websocket/src/websocket.cpp index 1f4e1a1..1ecff5e 100644 --- a/websocket/src/websocket.cpp +++ b/websocket/src/websocket.cpp @@ -436,6 +436,12 @@ void HandleCallback(WebsocketConnection* conn, int event, int msg_offset, int ms conn->m_HandshakeResponse = 0; } + if (event == EVENT_DISCONNECTED) + { + lua_pushinteger(L, conn->m_CloseCode); + lua_setfield(L, -2, "code"); + } + dmScript::PCall(L, 3, 0); dmScript::TeardownCallback(conn->m_Callback); @@ -576,7 +582,7 @@ static dmExtension::Result Finalize(dmExtension::Params* params) return dmExtension::RESULT_OK; } -Result PushMessage(WebsocketConnection* conn, MessageType type, int length, const uint8_t* buffer) +Result PushMessage(WebsocketConnection* conn, MessageType type, int length, const uint8_t* buffer, uint16_t code) { if (conn->m_Messages.Full()) conn->m_Messages.OffsetCapacity(4); @@ -584,6 +590,7 @@ Result PushMessage(WebsocketConnection* conn, MessageType type, int length, cons Message msg; msg.m_Type = (uint32_t)type; msg.m_Length = length; + msg.m_Code = code; conn->m_Messages.Push(msg); if ((conn->m_BufferSize + length) >= conn->m_BufferCapacity) @@ -646,7 +653,7 @@ static dmExtension::Result OnUpdate(dmExtension::Params* params) --size; DestroyConnection(conn); } - else if (STATE_CONNECTED == conn->m_State) + else if ((STATE_CONNECTED == conn->m_State) || (STATE_DISCONNECTING == conn->m_State)) { #if defined(HAVE_WSLAY) int r = WSL_Poll(conn->m_Ctx); @@ -658,7 +665,6 @@ static dmExtension::Result OnUpdate(dmExtension::Params* params) #endif uint32_t offset = 0; - bool close_received = false; for (uint32_t i = 0; i < conn->m_Messages.Size(); ++i) { const Message& msg = conn->m_Messages[i]; @@ -666,24 +672,18 @@ static dmExtension::Result OnUpdate(dmExtension::Params* params) if (EVENT_DISCONNECTED == msg.m_Type) { conn->m_Status = RESULT_OK; - CloseConnection(conn); - - // Put the message at the front of the buffer - conn->m_Messages.SetSize(0); - conn->m_BufferSize = 0; - PushMessage(conn, MESSAGE_TYPE_CLOSE, msg.m_Length, (const uint8_t*)conn->m_Buffer+offset); - close_received = true; + // close the connection and immediately transition to the DISCONNECTED + // state + SetState(conn, STATE_DISCONNECTED); + conn->m_CloseCode = msg.m_Code; break; } HandleCallback(conn, EVENT_MESSAGE, offset, msg.m_Length); offset += msg.m_Length; } - if (!close_received) // saving the close message for next step - { - conn->m_Messages.SetSize(0); - conn->m_BufferSize = 0; - } + conn->m_Messages.SetSize(0); + conn->m_BufferSize = 0; } else if (STATE_HANDSHAKE_READ == conn->m_State) { diff --git a/websocket/src/websocket.h b/websocket/src/websocket.h index 265fed5..55517af 100644 --- a/websocket/src/websocket.h +++ b/websocket/src/websocket.h @@ -80,6 +80,7 @@ namespace dmWebsocket struct Message { + uint16_t m_Code; uint32_t m_Length:30; uint32_t m_Type:2; }; @@ -129,6 +130,7 @@ namespace dmWebsocket int m_BufferSize; uint32_t m_BufferCapacity; Result m_Status; + uint16_t m_CloseCode; uint8_t m_SSL:1; uint8_t m_HasHandshakeData:1; uint8_t :7; @@ -159,7 +161,7 @@ namespace dmWebsocket void HandleCallback(WebsocketConnection* conn, int event, int msg_offset, int msg_length); // Messages - Result PushMessage(WebsocketConnection* conn, MessageType type, int length, const uint8_t* msg); + Result PushMessage(WebsocketConnection* conn, MessageType type, int length, const uint8_t* msg, uint16_t code); #if defined(HAVE_WSLAY) // Wslay callbacks diff --git a/websocket/src/wslay_callbacks.cpp b/websocket/src/wslay_callbacks.cpp index 82c2ac7..b2ef359 100644 --- a/websocket/src/wslay_callbacks.cpp +++ b/websocket/src/wslay_callbacks.cpp @@ -124,7 +124,7 @@ void WSL_OnMsgRecvCallback(wslay_event_context_ptr ctx, const struct wslay_event WebsocketConnection* conn = (WebsocketConnection*)user_data; if (arg->opcode == WSLAY_TEXT_FRAME || arg->opcode == WSLAY_BINARY_FRAME) { - PushMessage(conn, MESSAGE_TYPE_NORMAL, arg->msg_length, arg->msg); + PushMessage(conn, MESSAGE_TYPE_NORMAL, arg->msg_length, arg->msg, 0); } else if (arg->opcode == WSLAY_CONNECTION_CLOSE) { // The first two bytes is the close code @@ -137,8 +137,9 @@ void WSL_OnMsgRecvCallback(wslay_event_context_ptr ctx, const struct wslay_event } char buffer[1024]; - len = dmSnPrintf(buffer, sizeof(buffer), "Server closing (%u). Reason: '%s'", wslay_event_get_status_code_received(ctx), reason); - PushMessage(conn, MESSAGE_TYPE_CLOSE, len, (const uint8_t*)buffer); + uint16_t status_code = wslay_event_get_status_code_received(ctx); + len = dmSnPrintf(buffer, sizeof(buffer), "Server closing (%u). Reason: '%s'", status_code, reason); + PushMessage(conn, MESSAGE_TYPE_CLOSE, len, (const uint8_t*)buffer, status_code); if (!wslay_event_get_close_sent(ctx)) {