From 4b92956db7cb479a1c3ee63f102f9866fbbc6fef Mon Sep 17 00:00:00 2001 From: Fabio Alessandrelli Date: Mon, 24 Sep 2018 00:58:28 +0200 Subject: [PATCH] Implement WebSocket clean close detection. --- modules/websocket/emws_client.cpp | 4 ++-- modules/websocket/emws_peer.cpp | 2 +- modules/websocket/lws_client.cpp | 4 +++- modules/websocket/lws_peer.cpp | 1 + modules/websocket/lws_peer.h | 1 + modules/websocket/lws_server.cpp | 5 ++++- modules/websocket/websocket_client.cpp | 6 +++--- modules/websocket/websocket_client.h | 2 +- modules/websocket/websocket_server.cpp | 6 +++--- modules/websocket/websocket_server.h | 2 +- 10 files changed, 20 insertions(+), 13 deletions(-) diff --git a/modules/websocket/emws_client.cpp b/modules/websocket/emws_client.cpp index 413ef661b17..8255ed71161 100644 --- a/modules/websocket/emws_client.cpp +++ b/modules/websocket/emws_client.cpp @@ -57,7 +57,7 @@ EMSCRIPTEN_KEEPALIVE void _esws_on_close(void *obj, int code, char *reason, int EMWSClient *client = static_cast(obj); client->_on_close_request(code, String(reason)); client->_is_connecting = false; - client->_on_disconnect(); + client->_on_disconnect(was_clean != 0); } } @@ -146,7 +146,7 @@ Error EMWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port, if (!Module.IDHandler.has($0)) return; // Godot Object is gone! var was_clean = 0; - if (event.was_clean) + if (event.wasClean) was_clean = 1; ccall("_esws_on_close", "void", diff --git a/modules/websocket/emws_peer.cpp b/modules/websocket/emws_peer.cpp index 61b2e3b01e4..68f41165eb2 100644 --- a/modules/websocket/emws_peer.cpp +++ b/modules/websocket/emws_peer.cpp @@ -140,7 +140,7 @@ void EMWSPeer::close(int p_code, String p_reason) { var reason = UTF8ToString($2); sock.close(code, reason); Module.IDHandler.remove($0); - }, peer_sock, p_code); + }, peer_sock, p_code, p_reason.utf8().get_data()); /* clang-format on */ } peer_sock = -1; diff --git a/modules/websocket/lws_client.cpp b/modules/websocket/lws_client.cpp index a568b97a1ae..cd814760e62 100644 --- a/modules/websocket/lws_client.cpp +++ b/modules/websocket/lws_client.cpp @@ -129,6 +129,7 @@ int LWSClient::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi peer->set_wsi(wsi); peer_data->peer_id = 0; peer_data->force_close = false; + peer_data->clean_close = false; _on_connect(lws_get_protocol(wsi)->name); break; @@ -140,6 +141,7 @@ int LWSClient::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: { int code; String reason = peer->get_close_reason(in, len, code); + peer_data->clean_close = true; _on_close_request(code, reason); return 0; } @@ -147,7 +149,7 @@ int LWSClient::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi case LWS_CALLBACK_CLIENT_CLOSED: peer->close(); destroy_context(); - _on_disconnect(); + _on_disconnect(peer_data->clean_close); return 0; // We can end here case LWS_CALLBACK_CLIENT_RECEIVE: diff --git a/modules/websocket/lws_peer.cpp b/modules/websocket/lws_peer.cpp index 43ffcfdea1b..245b28b608b 100644 --- a/modules/websocket/lws_peer.cpp +++ b/modules/websocket/lws_peer.cpp @@ -216,6 +216,7 @@ void LWSPeer::close(int p_code, String p_reason) { close_reason = p_reason; PeerData *data = ((PeerData *)lws_wsi_user(wsi)); data->force_close = true; + data->clean_close = true; lws_callback_on_writable(wsi); // Notify that we want to disconnect } else { close_code = -1; diff --git a/modules/websocket/lws_peer.h b/modules/websocket/lws_peer.h index 05a38805775..571445db01f 100644 --- a/modules/websocket/lws_peer.h +++ b/modules/websocket/lws_peer.h @@ -60,6 +60,7 @@ public: struct PeerData { uint32_t peer_id; bool force_close; + bool clean_close; }; RingBuffer rbw; diff --git a/modules/websocket/lws_server.cpp b/modules/websocket/lws_server.cpp index d13a8024fb3..58fa0433461 100644 --- a/modules/websocket/lws_server.cpp +++ b/modules/websocket/lws_server.cpp @@ -90,6 +90,7 @@ int LWSServer::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi peer_data->peer_id = id; peer_data->force_close = false; + peer_data->clean_close = false; _on_connect(id, lws_get_protocol(wsi)->name); break; } @@ -103,6 +104,7 @@ int LWSServer::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi int code; Ref peer = _peer_map[id]; String reason = peer->get_close_reason(in, len, code); + peer_data->clean_close = true; _on_close_request(id, code, reason); } return 0; @@ -112,11 +114,12 @@ int LWSServer::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi if (peer_data == NULL) return 0; int32_t id = peer_data->peer_id; + bool clean = peer_data->clean_close; if (_peer_map.has(id)) { _peer_map[id]->close(); _peer_map.erase(id); } - _on_disconnect(id); + _on_disconnect(id, clean); return 0; // we can end here } diff --git a/modules/websocket/websocket_client.cpp b/modules/websocket/websocket_client.cpp index 8211a7c3617..f9b94dc5193 100644 --- a/modules/websocket/websocket_client.cpp +++ b/modules/websocket/websocket_client.cpp @@ -112,12 +112,12 @@ void WebSocketClient::_on_close_request(int p_code, String p_reason) { emit_signal("server_close_request", p_code, p_reason); } -void WebSocketClient::_on_disconnect() { +void WebSocketClient::_on_disconnect(bool p_was_clean) { if (_is_multiplayer) { emit_signal("connection_failed"); } else { - emit_signal("connection_closed"); + emit_signal("connection_closed", p_was_clean); } } @@ -141,6 +141,6 @@ void WebSocketClient::_bind_methods() { ADD_SIGNAL(MethodInfo("data_received")); ADD_SIGNAL(MethodInfo("connection_established", PropertyInfo(Variant::STRING, "protocol"))); ADD_SIGNAL(MethodInfo("server_close_request", PropertyInfo(Variant::INT, "code"), PropertyInfo(Variant::STRING, "reason"))); - ADD_SIGNAL(MethodInfo("connection_closed")); + ADD_SIGNAL(MethodInfo("connection_closed", PropertyInfo(Variant::BOOL, "was_clean_close"))); ADD_SIGNAL(MethodInfo("connection_error")); } diff --git a/modules/websocket/websocket_client.h b/modules/websocket/websocket_client.h index 086e90318f5..948f128e9f1 100644 --- a/modules/websocket/websocket_client.h +++ b/modules/websocket/websocket_client.h @@ -63,7 +63,7 @@ public: void _on_peer_packet(); void _on_connect(String p_protocol); void _on_close_request(int p_code, String p_reason); - void _on_disconnect(); + void _on_disconnect(bool p_was_clean); void _on_error(); WebSocketClient(); diff --git a/modules/websocket/websocket_server.cpp b/modules/websocket/websocket_server.cpp index ac3a8ca87dd..c631ed70d57 100644 --- a/modules/websocket/websocket_server.cpp +++ b/modules/websocket/websocket_server.cpp @@ -49,7 +49,7 @@ void WebSocketServer::_bind_methods() { ClassDB::bind_method(D_METHOD("disconnect_peer", "id", "code", "reason"), &WebSocketServer::disconnect_peer, DEFVAL(1000), DEFVAL("")); ADD_SIGNAL(MethodInfo("client_close_request", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::INT, "code"), PropertyInfo(Variant::STRING, "reason"))); - ADD_SIGNAL(MethodInfo("client_disconnected", PropertyInfo(Variant::INT, "id"))); + ADD_SIGNAL(MethodInfo("client_disconnected", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::BOOL, "was_clean_close"))); ADD_SIGNAL(MethodInfo("client_connected", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::STRING, "protocol"))); ADD_SIGNAL(MethodInfo("data_received", PropertyInfo(Variant::INT, "id"))); } @@ -86,14 +86,14 @@ void WebSocketServer::_on_connect(int32_t p_peer_id, String p_protocol) { } } -void WebSocketServer::_on_disconnect(int32_t p_peer_id) { +void WebSocketServer::_on_disconnect(int32_t p_peer_id, bool p_was_clean) { if (_is_multiplayer) { // Send delete to clients _send_del(p_peer_id); emit_signal("peer_disconnected", p_peer_id); } else { - emit_signal("client_disconnected", p_peer_id); + emit_signal("client_disconnected", p_peer_id, p_was_clean); } } diff --git a/modules/websocket/websocket_server.h b/modules/websocket/websocket_server.h index 0f044c17ad5..156f25897c2 100644 --- a/modules/websocket/websocket_server.h +++ b/modules/websocket/websocket_server.h @@ -58,7 +58,7 @@ public: void _on_peer_packet(int32_t p_peer_id); void _on_connect(int32_t p_peer_id, String p_protocol); - void _on_disconnect(int32_t p_peer_id); + void _on_disconnect(int32_t p_peer_id, bool p_was_clean); void _on_close_request(int32_t p_peer_id, int p_code, String p_reason); WebSocketServer();