From bea03d667a57ca256a727046643b81290a963bc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sat, 3 Aug 2019 20:20:10 +0200 Subject: [PATCH] Detect Remote Disconnect --- gui/include/streamsession.h | 2 +- gui/include/streamwindow.h | 2 +- gui/src/main.cpp | 2 +- gui/src/streamsession.cpp | 2 +- gui/src/streamwindow.cpp | 7 ++- lib/include/chiaki/common.h | 1 + lib/include/chiaki/session.h | 5 +- lib/include/chiaki/streamconnection.h | 2 + lib/src/common.c | 2 + lib/src/session.c | 12 ++++- lib/src/streamconnection.c | 66 +++++++++++++++++++++++++-- 11 files changed, 91 insertions(+), 12 deletions(-) diff --git a/gui/include/streamsession.h b/gui/include/streamsession.h index 79afb13..7b9041c 100644 --- a/gui/include/streamsession.h +++ b/gui/include/streamsession.h @@ -94,7 +94,7 @@ class StreamSession : public QObject signals: void CurrentImageUpdated(); - void SessionQuit(ChiakiQuitReason reason); + void SessionQuit(ChiakiQuitReason reason, const QString &reason_str); private slots: #if CHIAKI_GUI_ENABLE_QT_GAMEPAD diff --git a/gui/include/streamwindow.h b/gui/include/streamwindow.h index fc8996d..dc68394 100644 --- a/gui/include/streamwindow.h +++ b/gui/include/streamwindow.h @@ -46,7 +46,7 @@ class StreamWindow: public QMainWindow private slots: void FramesAvailable(); - void SessionQuit(ChiakiQuitReason reason); + void SessionQuit(ChiakiQuitReason reason, const QString &reason_str); }; #endif // CHIAKI_GUI_STREAMWINDOW_H diff --git a/gui/src/main.cpp b/gui/src/main.cpp index d1074cc..686820c 100644 --- a/gui/src/main.cpp +++ b/gui/src/main.cpp @@ -71,7 +71,7 @@ int main(int argc, char *argv[]) connect_info.did = parser.value(did_option); chiaki_connect_video_profile_preset(&connect_info.video_profile, - CHIAKI_VIDEO_RESOLUTION_PRESET_540p, + CHIAKI_VIDEO_RESOLUTION_PRESET_360p, CHIAKI_VIDEO_FPS_PRESET_30); if(connect_info.registkey.isEmpty() || connect_info.ostype.isEmpty() || connect_info.auth.isEmpty() || connect_info.morning.isEmpty() || connect_info.did.isEmpty()) diff --git a/gui/src/streamsession.cpp b/gui/src/streamsession.cpp index 627c12a..3ac90bd 100644 --- a/gui/src/streamsession.cpp +++ b/gui/src/streamsession.cpp @@ -257,7 +257,7 @@ void StreamSession::Event(ChiakiEvent *event) switch(event->type) { case CHIAKI_EVENT_QUIT: - emit SessionQuit(event->quit.reason); + emit SessionQuit(event->quit.reason, event->quit.reason_str ? QString::fromUtf8(event->quit.reason_str) : QString()); break; } } diff --git a/gui/src/streamwindow.cpp b/gui/src/streamwindow.cpp index 2aee360..65cc568 100644 --- a/gui/src/streamwindow.cpp +++ b/gui/src/streamwindow.cpp @@ -83,10 +83,13 @@ void StreamWindow::FramesAvailable() } } -void StreamWindow::SessionQuit(ChiakiQuitReason reason) +void StreamWindow::SessionQuit(ChiakiQuitReason reason, const QString &reason_str) { if(reason == CHIAKI_QUIT_REASON_STOPPED) return; - QMessageBox::critical(this, tr("Session has quit"), tr("Chiaki Session has quit:") + "\n" + chiaki_quit_reason_string(reason)); + QString m = tr("Chiaki Session has quit") + ":\n" + chiaki_quit_reason_string(reason); + if(!reason_str.isEmpty()) + m += "\n" + tr("Reason") + ": \"" + reason_str + "\""; + QMessageBox::critical(this, tr("Session has quit"), m); close(); } diff --git a/lib/include/chiaki/common.h b/lib/include/chiaki/common.h index 5a8f8e6..29c21ff 100644 --- a/lib/include/chiaki/common.h +++ b/lib/include/chiaki/common.h @@ -35,6 +35,7 @@ typedef enum CHIAKI_ERR_MEMORY, CHIAKI_ERR_OVERFLOW, CHIAKI_ERR_NETWORK, + CHIAKI_ERR_DISCONNECTED, CHIAKI_ERR_INVALID_DATA, CHIAKI_ERR_BUF_TOO_SMALL, CHIAKI_ERR_MUTEX_LOCKED, diff --git a/lib/include/chiaki/session.h b/lib/include/chiaki/session.h index c3766f4..d2783b3 100644 --- a/lib/include/chiaki/session.h +++ b/lib/include/chiaki/session.h @@ -86,7 +86,8 @@ typedef enum { CHIAKI_QUIT_REASON_SESSION_REQUEST_RP_CRASH, CHIAKI_QUIT_REASON_CTRL_UNKNOWN, CHIAKI_QUIT_REASON_CTRL_CONNECTION_REFUSED, - CHIAKI_QUIT_REASON_STREAM_CONNECTION_UNKNOWN + CHIAKI_QUIT_REASON_STREAM_CONNECTION_UNKNOWN, + CHIAKI_QUIT_REASON_STREAM_CONNECTION_REMOTE_DISCONNECTED } ChiakiQuitReason; CHIAKI_EXPORT const char *chiaki_quit_reason_string(ChiakiQuitReason reason); @@ -94,6 +95,7 @@ CHIAKI_EXPORT const char *chiaki_quit_reason_string(ChiakiQuitReason reason); typedef struct chiaki_quit_event_t { ChiakiQuitReason reason; + const char *reason_str; } ChiakiQuitEvent; typedef struct chiaki_audio_stream_info_event_t @@ -145,6 +147,7 @@ typedef struct chiaki_session_t ChiakiECDH ecdh; ChiakiQuitReason quit_reason; + char *quit_reason_str; // additional reason string from remote ChiakiEventCallback event_cb; void *event_cb_user; diff --git a/lib/include/chiaki/streamconnection.h b/lib/include/chiaki/streamconnection.h index b1e3fb7..c8f2bea 100644 --- a/lib/include/chiaki/streamconnection.h +++ b/lib/include/chiaki/streamconnection.h @@ -66,6 +66,8 @@ typedef struct chiaki_stream_connection_t bool state_finished; bool state_failed; bool should_stop; + bool remote_disconnected; + char *remote_disconnect_reason; } ChiakiStreamConnection; CHIAKI_EXPORT ChiakiErrorCode chiaki_stream_connection_init(ChiakiStreamConnection *stream_connection, ChiakiSession *session); diff --git a/lib/src/common.c b/lib/src/common.c index a418211..40d8c7f 100644 --- a/lib/src/common.c +++ b/lib/src/common.c @@ -32,6 +32,8 @@ CHIAKI_EXPORT const char *chiaki_error_string(ChiakiErrorCode code) return "Memory error"; case CHIAKI_ERR_NETWORK: return "Network error"; + case CHIAKI_ERR_DISCONNECTED: + return "Disconnected"; case CHIAKI_ERR_INVALID_DATA: return "Invalid data"; case CHIAKI_ERR_BUF_TOO_SMALL: diff --git a/lib/src/session.c b/lib/src/session.c index 008f67b..bdbc18a 100644 --- a/lib/src/session.c +++ b/lib/src/session.c @@ -103,6 +103,8 @@ CHIAKI_EXPORT const char *chiaki_quit_reason_string(ChiakiQuitReason reason) return "Connection Refused in Ctrl"; case CHIAKI_QUIT_REASON_STREAM_CONNECTION_UNKNOWN: return "Unknown Error in Stream Connection"; + case CHIAKI_QUIT_REASON_STREAM_CONNECTION_REMOTE_DISCONNECTED: + return "Remote has disconnected from Stream Connection"; case CHIAKI_QUIT_REASON_NONE: default: return "Unknown"; @@ -186,6 +188,7 @@ CHIAKI_EXPORT void chiaki_session_fini(ChiakiSession *session) { if(!session) return; + free(session->quit_reason_str); chiaki_stream_connection_fini(&session->stream_connection); chiaki_stop_pipe_fini(&session->stop_pipe); chiaki_cond_fini(&session->state_cond); @@ -357,7 +360,13 @@ static void *session_thread_func(void *arg) chiaki_mutex_unlock(&session->state_mutex); err = chiaki_stream_connection_run(&session->stream_connection); chiaki_mutex_lock(&session->state_mutex); - if(err != CHIAKI_ERR_SUCCESS && err != CHIAKI_ERR_CANCELED) + if(err == CHIAKI_ERR_DISCONNECTED) + { + CHIAKI_LOGE(&session->log, "Remote disconnected from StreamConnection"); + session->quit_reason = CHIAKI_QUIT_REASON_STREAM_CONNECTION_REMOTE_DISCONNECTED; + session->quit_reason_str = strdup(session->stream_connection.remote_disconnect_reason); + } + else if(err != CHIAKI_ERR_SUCCESS && err != CHIAKI_ERR_CANCELED) { CHIAKI_LOGE(&session->log, "StreamConnection run failed"); session->quit_reason = CHIAKI_QUIT_REASON_STREAM_CONNECTION_UNKNOWN; @@ -388,6 +397,7 @@ quit: CHIAKI_LOGI(&session->log, "Session has quit"); quit_event.type = CHIAKI_EVENT_QUIT; quit_event.quit.reason = session->quit_reason; + quit_event.quit.reason_str = session->quit_reason_str; session_send_event(session, &quit_event); return NULL; diff --git a/lib/src/streamconnection.c b/lib/src/streamconnection.c index 45a427e..72d8cd6 100644 --- a/lib/src/streamconnection.c +++ b/lib/src/streamconnection.c @@ -88,6 +88,8 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_stream_connection_init(ChiakiStreamConnecti stream_connection->state_finished = false; stream_connection->state_failed = false; stream_connection->should_stop = false; + stream_connection->remote_disconnected = false; + stream_connection->remote_disconnect_reason = NULL; return CHIAKI_ERR_SUCCESS; @@ -101,6 +103,8 @@ error: CHIAKI_EXPORT void chiaki_stream_connection_fini(ChiakiStreamConnection *stream_connection) { + free(stream_connection->remote_disconnect_reason); + chiaki_gkcrypt_free(stream_connection->gkcrypt_remote); chiaki_gkcrypt_free(stream_connection->gkcrypt_local); @@ -116,7 +120,7 @@ CHIAKI_EXPORT void chiaki_stream_connection_fini(ChiakiStreamConnection *stream_ static bool state_finished_cond_check(void *user) { ChiakiStreamConnection *stream_connection = user; - return stream_connection->state_finished || stream_connection->should_stop; + return stream_connection->state_finished || stream_connection->should_stop || stream_connection->remote_disconnected; } CHIAKI_EXPORT ChiakiErrorCode chiaki_stream_connection_run(ChiakiStreamConnection *stream_connection) @@ -145,7 +149,6 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_stream_connection_run(ChiakiStreamConnectio #define CHECK_STOP(quit_label) do { \ if(stream_connection->should_stop) \ { \ - session->quit_reason = CHIAKI_QUIT_REASON_STOPPED; \ goto quit_label; \ } } while(0) @@ -259,7 +262,15 @@ disconnect: stream_connection_send_disconnect(stream_connection); if(stream_connection->should_stop) + { CHIAKI_LOGI(stream_connection->log, "StreamConnection was requested to stop"); + err = CHIAKI_ERR_CANCELED; + } + else if(stream_connection->remote_disconnected) + { + CHIAKI_LOGI(stream_connection->log, "StreamConnection closing after Remote disconnected"); + err = CHIAKI_ERR_DISCONNECTED; + } close_takion: chiaki_mutex_unlock(&stream_connection->state_mutex); @@ -329,6 +340,36 @@ static void stream_connection_takion_data(ChiakiStreamConnection *stream_connect chiaki_mutex_unlock(&stream_connection->state_mutex); } +static void stream_connection_takion_data_handle_disconnect(ChiakiStreamConnection *stream_connection, uint8_t *buf, size_t buf_size) +{ + tkproto_TakionMessage msg; + memset(&msg, 0, sizeof(msg)); + + char reason[256]; + ChiakiPBDecodeBuf decode_buf; + decode_buf.size = 0; + decode_buf.max_size = sizeof(reason) - 1; + decode_buf.buf = (uint8_t *)reason; + msg.disconnect_payload.reason.arg = &decode_buf; + msg.disconnect_payload.reason.funcs.decode = chiaki_pb_decode_buf; + + pb_istream_t stream = pb_istream_from_buffer(buf, buf_size); + bool r = pb_decode(&stream, tkproto_TakionMessage_fields, &msg); + if(!r) + { + CHIAKI_LOGE(stream_connection->log, "StreamConnection failed to decode data protobuf"); + chiaki_log_hexdump(stream_connection->log, CHIAKI_LOG_ERROR, buf, buf_size); + return; + } + + reason[decode_buf.size] = '\0'; + CHIAKI_LOGI(stream_connection->log, "Remote disconnected from StreamConnection with reason \"%s\"", reason); + + stream_connection->remote_disconnected = true; + free(stream_connection->remote_disconnect_reason); + stream_connection->remote_disconnect_reason = strdup(reason); + chiaki_cond_signal(&stream_connection->state_cond); +} static void stream_connection_takion_data_idle(ChiakiStreamConnection *stream_connection, uint8_t *buf, size_t buf_size) { @@ -344,8 +385,11 @@ static void stream_connection_takion_data_idle(ChiakiStreamConnection *stream_co return; } - //CHIAKI_LOGD(stream_connection->log, "StreamConnection received data"); - //chiaki_log_hexdump(stream_connection->log, CHIAKI_LOG_DEBUG, buf, buf_size); + CHIAKI_LOGV(stream_connection->log, "StreamConnection received data"); + chiaki_log_hexdump(stream_connection->log, CHIAKI_LOG_VERBOSE, buf, buf_size); + + if(msg.type == tkproto_TakionMessage_PayloadType_DISCONNECT) + stream_connection_takion_data_handle_disconnect(stream_connection, buf, buf_size); } static ChiakiErrorCode stream_connection_init_crypt(ChiakiStreamConnection *stream_connection) @@ -397,6 +441,12 @@ static void stream_connection_takion_data_expect_bang(ChiakiStreamConnection *st if(msg.type != tkproto_TakionMessage_PayloadType_BANG || !msg.has_bang_payload) { + if(msg.type == tkproto_TakionMessage_PayloadType_DISCONNECT) + { + stream_connection_takion_data_handle_disconnect(stream_connection, buf, buf_size); + return; + } + CHIAKI_LOGE(stream_connection->log, "StreamConnection expected bang payload but received something else"); return; } @@ -531,6 +581,12 @@ static void stream_connection_takion_data_expect_streaminfo(ChiakiStreamConnecti if(msg.type != tkproto_TakionMessage_PayloadType_STREAMINFO || !msg.has_stream_info_payload) { + if(msg.type == tkproto_TakionMessage_PayloadType_DISCONNECT) + { + stream_connection_takion_data_handle_disconnect(stream_connection, buf, buf_size); + return; + } + CHIAKI_LOGE(stream_connection->log, "StreamConnection expected streaminfo payload but received something else"); chiaki_log_hexdump(stream_connection->log, CHIAKI_LOG_VERBOSE, buf, buf_size); return; @@ -710,6 +766,8 @@ static ChiakiErrorCode stream_connection_send_disconnect(ChiakiStreamConnection return CHIAKI_ERR_UNKNOWN; } + CHIAKI_LOGI(stream_connection->log, "StreamConnection sending Disconnect"); + buf_size = stream.bytes_written; ChiakiErrorCode err = chiaki_takion_send_message_data(&stream_connection->takion, 1, 1, buf, buf_size);