From c4f6dcc24ff8daf127f5d397591c7cd919c168d1 Mon Sep 17 00:00:00 2001 From: Mike McDonald Date: Thu, 16 Jan 2014 17:38:56 -0500 Subject: [PATCH 01/10] Added auto reconnect to FreeRDP core and X11 client --- client/X11/xf_client.c | 55 ++++++++++++++++++++++++++++++++++++ include/freerdp/freerdp.h | 1 + libfreerdp/core/connection.c | 27 ++++++++++++++++++ libfreerdp/core/connection.h | 1 + libfreerdp/core/freerdp.c | 5 ++++ libfreerdp/core/tcp.c | 24 +++++++++++++++- 6 files changed, 112 insertions(+), 1 deletion(-) diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index a29499339..d5b54e193 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -51,6 +51,8 @@ #include #endif +#define WITH_AUTORECONNECT + #include #include #include @@ -1336,6 +1338,51 @@ void* xf_channels_thread(void* arg) return NULL; } +#ifdef WITH_AUTORECONNECT +BOOL xf_auto_reconnect(freerdp* instance) +{ + xfContext* xfc = (xfContext*)instance->context; + + UINT32 num_retries = 0; + UINT32 max_retries = instance->settings->AutoReconnectMaxRetries; + + /* Only auto reconnect on network disconnects. */ + if (freerdp_error_info(instance) != 0) return FALSE; + + /* A network disconnect was detected */ + fprintf(stderr, "Network disconnect!\n"); + if (!instance->settings->AutoReconnectionEnabled) + { + /* No auto-reconnect - just quit */ + return FALSE; + } + + /* Perform an auto-reconnect. */ + for (;;) + { + /* Quit retrying if max retries has been exceeded */ + if (num_retries++ >= max_retries) + { + return FALSE; + } + + /* Attempt the next reconnect */ + fprintf(stderr, "Attempting reconnect (%u of %u)\n", num_retries, max_retries); + if (freerdp_reconnect(instance)) + { + xfc->disconnect = FALSE; + return TRUE; + } + + sleep(5); + } + + fprintf(stderr, "Maximum reconnect retries exceeded\n"); + + return FALSE; +} +#endif + /** Main loop for the rdp connection. * It will be run from the thread's entry point (thread_func()). * It initiates the connection, and will continue to run until the session ends, @@ -1382,6 +1429,11 @@ void* xf_thread(void* param) ZeroMemory(wfds, sizeof(wfds)); ZeroMemory(&timeout, sizeof(struct timeval)); +#ifdef WITH_AUTORECONNECT + instance->settings->AutoReconnectionEnabled = TRUE; + instance->settings->AutoReconnectMaxRetries = 20; +#endif + status = freerdp_connect(instance); xfc = (xfContext*) instance->context; @@ -1526,6 +1578,9 @@ void* xf_thread(void* param) { if (freerdp_check_fds(instance) != TRUE) { +#ifdef WITH_AUTORECONNECT + if (xf_auto_reconnect(instance)) continue; +#endif fprintf(stderr, "Failed to check FreeRDP file descriptor\n"); break; } diff --git a/include/freerdp/freerdp.h b/include/freerdp/freerdp.h index a7a4182f0..b1a461986 100644 --- a/include/freerdp/freerdp.h +++ b/include/freerdp/freerdp.h @@ -221,6 +221,7 @@ FREERDP_API void freerdp_context_free(freerdp* instance); FREERDP_API BOOL freerdp_connect(freerdp* instance); FREERDP_API BOOL freerdp_shall_disconnect(freerdp* instance); FREERDP_API BOOL freerdp_disconnect(freerdp* instance); +FREERDP_API BOOL freerdp_reconnect(freerdp* instance); FREERDP_API BOOL freerdp_get_fds(freerdp* instance, void** rfds, int* rcount, void** wfds, int* wcount); FREERDP_API BOOL freerdp_check_fds(freerdp* instance); diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index e84bb8e29..d170a5479 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -336,6 +336,33 @@ BOOL rdp_client_redirect(rdpRdp* rdp) return status; } +BOOL rdp_client_reconnect(rdpRdp* rdp) +{ + int i; + + transport_disconnect(rdp->transport); + + mcs_free(rdp->mcs); + nego_free(rdp->nego); + license_free(rdp->license); + transport_free(rdp->transport); + + /* Reset virtual channel status */ + for (i = 0; i < rdp->settings->ChannelCount; i++) + { + rdp->settings->ChannelDefArray[i].joined = FALSE; + } + + rdp->transport = transport_new(rdp->settings); + rdp->license = license_new(rdp); + rdp->nego = nego_new(rdp->transport); + rdp->mcs = mcs_new(rdp->transport); + + rdp->transport->layer = TRANSPORT_LAYER_TCP; + + return rdp_client_connect(rdp); +} + static BYTE fips_ivec[8] = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF }; static BOOL rdp_client_establish_keys(rdpRdp* rdp) diff --git a/libfreerdp/core/connection.h b/libfreerdp/core/connection.h index 828e79227..65708ae75 100644 --- a/libfreerdp/core/connection.h +++ b/libfreerdp/core/connection.h @@ -49,6 +49,7 @@ enum CONNECTION_STATE BOOL rdp_client_connect(rdpRdp* rdp); BOOL rdp_client_redirect(rdpRdp* rdp); +BOOL rdp_client_reconnect(rdpRdp* rdp); BOOL rdp_client_connect_mcs_connect_response(rdpRdp* rdp, wStream* s); BOOL rdp_client_connect_mcs_attach_user_confirm(rdpRdp* rdp, wStream* s); BOOL rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, wStream* s); diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index 57ea44526..7f075f49d 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -322,6 +322,11 @@ BOOL freerdp_disconnect(freerdp* instance) return TRUE; } +BOOL freerdp_reconnect(freerdp* instance) +{ + return rdp_client_reconnect(instance->context->rdp); +} + BOOL freerdp_shall_disconnect(freerdp* instance) { return instance->context->rdp->disconnect; diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c index 34cf4cc35..0df0dbfe4 100644 --- a/libfreerdp/core/tcp.c +++ b/libfreerdp/core/tcp.c @@ -251,7 +251,29 @@ BOOL tcp_set_keep_alive_mode(rdpTcp* tcp) if (setsockopt(tcp->sockfd, IPPROTO_TCP, TCP_KEEPIDLE, (void*) &option_value, option_len) < 0) { - perror("setsockopt() IPPROTO_TCP, SO_KEEPIDLE:"); + perror("setsockopt() IPPROTO_TCP, TCP_KEEPIDLE:"); + return FALSE; + } +#endif + +#ifdef TCP_KEEPCNT + option_value = 3; + option_len = sizeof(option_value); + + if (setsockopt(tcp->sockfd, SOL_TCP, TCP_KEEPCNT, (void *) &option_value, option_len) < 0) + { + perror("setsockopt() SOL_TCP, TCP_KEEPCNT:"); + return FALSE; + } +#endif + +#ifdef TCP_KEEPINTVL + option_value = 2; + option_len = sizeof(option_value); + + if (setsockopt(tcp->sockfd, SOL_TCP, TCP_KEEPINTVL, (void *) &option_value, option_len) < 0) + { + perror("setsockopt() SOL_TCP, TCP_KEEPINTVL:"); return FALSE; } #endif From 2a4923835143b4196ca7cafdaece687e93e79beb Mon Sep 17 00:00:00 2001 From: Mike McDonald Date: Fri, 17 Jan 2014 10:24:13 -0500 Subject: [PATCH 02/10] Fixed tls_read and tls_write to prevent a subsequent crash in SSL_shutdown when read/write errors occur. --- libfreerdp/crypto/tls.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index a4d2c6f19..b6c11790c 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -423,6 +423,13 @@ int tls_read(rdpTls* tls, BYTE* data, int length) } } + /* No need to send "close notify" shutdown alert to peer. In + fact, some circumstances will cause SSL_shutdown to crash. */ + if (status == -1) + { + SSL_set_shutdown(tls->ssl, SSL_SENT_SHUTDOWN); + } + return status; } @@ -474,6 +481,13 @@ int tls_write(rdpTls* tls, BYTE* data, int length) } } + /* No need to send "close notify" shutdown alert to peer. In + fact, some circumstances will cause SSL_shutdown to crash. */ + if (status == -1) + { + SSL_set_shutdown(tls->ssl, SSL_SENT_SHUTDOWN); + } + return status; } From c273a4ac5e7cca51fc7dbdc10a683227bb164120 Mon Sep 17 00:00:00 2001 From: Mike McDonald Date: Fri, 17 Jan 2014 11:51:39 -0500 Subject: [PATCH 03/10] Modified TLS code to handle disconnects a little cleaner. --- include/freerdp/crypto/tls.h | 1 + libfreerdp/crypto/tls.c | 31 +++++++++++++++++-------------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/include/freerdp/crypto/tls.h b/include/freerdp/crypto/tls.h index 09ff7a3a0..2135c752f 100644 --- a/include/freerdp/crypto/tls.h +++ b/include/freerdp/crypto/tls.h @@ -43,6 +43,7 @@ struct rdp_tls void* tsg; int sockfd; SSL_CTX* ctx; + int disconnected; BYTE* PublicKey; BIO_METHOD* methods; DWORD PublicKeyLength; diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index b6c11790c..dd82618d8 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -364,7 +364,22 @@ BOOL tls_disconnect(rdpTls* tls) return FALSE; if (tls->ssl) + { + if (tls->disconnected) + { + /** + * In cases where the underlying socket has become disconnected, + * there is no need to send a "close notify" shutdown alert. In + * fact, attempting to do so can cause a crash in SSL_shutdown. + * + * The following code disables sending the "close notify". + */ + + SSL_set_quiet_shutdown(tls->ssl, 1); + } + SSL_shutdown(tls->ssl); + } return TRUE; } @@ -412,6 +427,7 @@ int tls_read(rdpTls* tls, BYTE* data, int length) else { tls_print_error("SSL_read", tls->ssl, status); + tls->disconnected = 1; status = -1; } break; @@ -423,13 +439,6 @@ int tls_read(rdpTls* tls, BYTE* data, int length) } } - /* No need to send "close notify" shutdown alert to peer. In - fact, some circumstances will cause SSL_shutdown to crash. */ - if (status == -1) - { - SSL_set_shutdown(tls->ssl, SSL_SENT_SHUTDOWN); - } - return status; } @@ -470,6 +479,7 @@ int tls_write(rdpTls* tls, BYTE* data, int length) else { tls_print_error("SSL_write", tls->ssl, status); + tls->disconnected = 1; status = -1; } break; @@ -481,13 +491,6 @@ int tls_write(rdpTls* tls, BYTE* data, int length) } } - /* No need to send "close notify" shutdown alert to peer. In - fact, some circumstances will cause SSL_shutdown to crash. */ - if (status == -1) - { - SSL_set_shutdown(tls->ssl, SSL_SENT_SHUTDOWN); - } - return status; } From 7f040406acca031d9e7f2e8c397a8348e13e9db9 Mon Sep 17 00:00:00 2001 From: Mike McDonald Date: Fri, 17 Jan 2014 11:54:35 -0500 Subject: [PATCH 04/10] Fixed comment in tls_disconnect. --- libfreerdp/crypto/tls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index dd82618d8..10a00ab56 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -369,7 +369,7 @@ BOOL tls_disconnect(rdpTls* tls) { /** * In cases where the underlying socket has become disconnected, - * there is no need to send a "close notify" shutdown alert. In + * there is no need to send a "close notify" shutdown alert. In * fact, attempting to do so can cause a crash in SSL_shutdown. * * The following code disables sending the "close notify". From 3ddf681febcf4e28a99ae6a34e4a4faa9e720dd4 Mon Sep 17 00:00:00 2001 From: Mike McDonald Date: Mon, 20 Jan 2014 11:06:08 -0500 Subject: [PATCH 05/10] Revert "Fixed comment in tls_disconnect." This reverts commit 7f040406acca031d9e7f2e8c397a8348e13e9db9. --- libfreerdp/crypto/tls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index 10a00ab56..dd82618d8 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -369,7 +369,7 @@ BOOL tls_disconnect(rdpTls* tls) { /** * In cases where the underlying socket has become disconnected, - * there is no need to send a "close notify" shutdown alert. In + * there is no need to send a "close notify" shutdown alert. In * fact, attempting to do so can cause a crash in SSL_shutdown. * * The following code disables sending the "close notify". From 4e31b9bbb943e4389549171be3b8079229f5ba7c Mon Sep 17 00:00:00 2001 From: Mike McDonald Date: Mon, 20 Jan 2014 11:08:33 -0500 Subject: [PATCH 06/10] Revert "Modified TLS code to handle disconnects a little cleaner." This reverts commit c273a4ac5e7cca51fc7dbdc10a683227bb164120. --- include/freerdp/crypto/tls.h | 1 - libfreerdp/crypto/tls.c | 31 ++++++++++++++----------------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/include/freerdp/crypto/tls.h b/include/freerdp/crypto/tls.h index 2135c752f..09ff7a3a0 100644 --- a/include/freerdp/crypto/tls.h +++ b/include/freerdp/crypto/tls.h @@ -43,7 +43,6 @@ struct rdp_tls void* tsg; int sockfd; SSL_CTX* ctx; - int disconnected; BYTE* PublicKey; BIO_METHOD* methods; DWORD PublicKeyLength; diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index dd82618d8..b6c11790c 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -364,22 +364,7 @@ BOOL tls_disconnect(rdpTls* tls) return FALSE; if (tls->ssl) - { - if (tls->disconnected) - { - /** - * In cases where the underlying socket has become disconnected, - * there is no need to send a "close notify" shutdown alert. In - * fact, attempting to do so can cause a crash in SSL_shutdown. - * - * The following code disables sending the "close notify". - */ - - SSL_set_quiet_shutdown(tls->ssl, 1); - } - SSL_shutdown(tls->ssl); - } return TRUE; } @@ -427,7 +412,6 @@ int tls_read(rdpTls* tls, BYTE* data, int length) else { tls_print_error("SSL_read", tls->ssl, status); - tls->disconnected = 1; status = -1; } break; @@ -439,6 +423,13 @@ int tls_read(rdpTls* tls, BYTE* data, int length) } } + /* No need to send "close notify" shutdown alert to peer. In + fact, some circumstances will cause SSL_shutdown to crash. */ + if (status == -1) + { + SSL_set_shutdown(tls->ssl, SSL_SENT_SHUTDOWN); + } + return status; } @@ -479,7 +470,6 @@ int tls_write(rdpTls* tls, BYTE* data, int length) else { tls_print_error("SSL_write", tls->ssl, status); - tls->disconnected = 1; status = -1; } break; @@ -491,6 +481,13 @@ int tls_write(rdpTls* tls, BYTE* data, int length) } } + /* No need to send "close notify" shutdown alert to peer. In + fact, some circumstances will cause SSL_shutdown to crash. */ + if (status == -1) + { + SSL_set_shutdown(tls->ssl, SSL_SENT_SHUTDOWN); + } + return status; } From 5ce6b787ec00e9e5695afc10f3e43417a17fc89e Mon Sep 17 00:00:00 2001 From: Mike McDonald Date: Mon, 20 Jan 2014 11:09:45 -0500 Subject: [PATCH 07/10] Revert "Fixed tls_read and tls_write to prevent a subsequent crash in SSL_shutdown when read/write errors occur." This reverts commit 2a4923835143b4196ca7cafdaece687e93e79beb. --- libfreerdp/crypto/tls.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index b6c11790c..a4d2c6f19 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -423,13 +423,6 @@ int tls_read(rdpTls* tls, BYTE* data, int length) } } - /* No need to send "close notify" shutdown alert to peer. In - fact, some circumstances will cause SSL_shutdown to crash. */ - if (status == -1) - { - SSL_set_shutdown(tls->ssl, SSL_SENT_SHUTDOWN); - } - return status; } @@ -481,13 +474,6 @@ int tls_write(rdpTls* tls, BYTE* data, int length) } } - /* No need to send "close notify" shutdown alert to peer. In - fact, some circumstances will cause SSL_shutdown to crash. */ - if (status == -1) - { - SSL_set_shutdown(tls->ssl, SSL_SENT_SHUTDOWN); - } - return status; } From 25f834043ead5ac03c6ac09ebf2961585d890f5d Mon Sep 17 00:00:00 2001 From: Mike McDonald Date: Mon, 20 Jan 2014 11:20:50 -0500 Subject: [PATCH 08/10] Modified FreeRDP core to ignore SIGPIPE signal. This signal was being generated during a call to SSL_shutdown when the socket is in a disconnected state. The proper way to handle this is to ignore SIGPIPE and allow the write system call to report an errno of EPIPE. --- libfreerdp/utils/signal.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libfreerdp/utils/signal.c b/libfreerdp/utils/signal.c index 82cdec9ad..1fd62a28e 100644 --- a/libfreerdp/utils/signal.c +++ b/libfreerdp/utils/signal.c @@ -49,6 +49,8 @@ static void fatal_handler(int signum) struct sigaction default_sigaction; sigset_t this_mask; + printf("fatal_handler: signum=%d\n", signum); + if (terminal_needs_reset) tcsetattr(terminal_fildes, TCSAFLUSH, &orig_flags); @@ -74,7 +76,6 @@ const int fatal_signals[] = SIGILL, SIGINT, SIGKILL, - SIGPIPE, SIGQUIT, SIGSEGV, SIGSTOP, @@ -128,6 +129,9 @@ int freerdp_handle_signals(void) pthread_sigmask(SIG_SETMASK, &orig_set, NULL); + /* Ignore SIGPIPE signal. */ + signal(SIGPIPE, SIG_IGN); + return 0; } From c0d26443ce4e6171a047478c16a0e52f3a9d5bdf Mon Sep 17 00:00:00 2001 From: Mike McDonald Date: Tue, 21 Jan 2014 08:27:21 -0500 Subject: [PATCH 09/10] Added #define for SOL_TCP to fix compilation error on iOS --- libfreerdp/core/tcp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c index 0df0dbfe4..f37653764 100644 --- a/libfreerdp/core/tcp.c +++ b/libfreerdp/core/tcp.c @@ -41,6 +41,9 @@ #include #ifdef __APPLE__ +#ifndef SOL_TCP +#define SOL_TCP 6 +#endif #ifndef TCP_KEEPIDLE #define TCP_KEEPIDLE TCP_KEEPALIVE #endif From a563362ea2cf110ef6114236c062d8d02427ed85 Mon Sep 17 00:00:00 2001 From: Mike McDonald Date: Tue, 21 Jan 2014 11:06:29 -0500 Subject: [PATCH 10/10] Changed #define for SOL_TCP to be IPPROTO_TCP instead of 6 --- libfreerdp/core/tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c index f37653764..e4902e6e6 100644 --- a/libfreerdp/core/tcp.c +++ b/libfreerdp/core/tcp.c @@ -42,7 +42,7 @@ #ifdef __APPLE__ #ifndef SOL_TCP -#define SOL_TCP 6 +#define SOL_TCP IPPROTO_TCP #endif #ifndef TCP_KEEPIDLE #define TCP_KEEPIDLE TCP_KEEPALIVE