From 709df9aecc01eee60a560362039362ec42fa82aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Fri, 30 May 2014 14:03:20 -0400 Subject: [PATCH] libfreerdp-core: add connection timeout, fix gateway bypass local --- include/freerdp/settings.h | 1 + libfreerdp/core/nego.c | 6 ++--- libfreerdp/core/tcp.c | 46 +++++++++++++++++++++++++++++++++---- libfreerdp/core/tcp.h | 2 +- libfreerdp/core/transport.c | 19 ++++++++++----- libfreerdp/core/transport.h | 2 +- 6 files changed, 60 insertions(+), 16 deletions(-) diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index d73ccf22b..cb9e25cb7 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -1382,6 +1382,7 @@ FREERDP_API void freerdp_performance_flags_make(rdpSettings* settings); FREERDP_API void freerdp_performance_flags_split(rdpSettings* settings); FREERDP_API void freerdp_set_gateway_usage_method(rdpSettings* settings, UINT32 GatewayUsageMethod); +FREERDP_API void freerdp_update_gateway_usage_method(rdpSettings* settings, UINT32 GatewayEnabled, UINT32 GatewayBypassLocal); FREERDP_API BOOL freerdp_get_param_bool(rdpSettings* settings, int id); FREERDP_API int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param); diff --git a/libfreerdp/core/nego.c b/libfreerdp/core/nego.c index ab2753a03..c250b4be9 100644 --- a/libfreerdp/core/nego.c +++ b/libfreerdp/core/nego.c @@ -220,18 +220,18 @@ BOOL nego_tcp_connect(rdpNego* nego) { /* Attempt a direct connection first, and then fallback to using the gateway */ transport_set_gateway_enabled(nego->transport, FALSE); - nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port); + nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port, 1); } if (!nego->tcp_connected) { transport_set_gateway_enabled(nego->transport, TRUE); - nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port); + nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port, 15); } } else { - nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port); + nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port, 15); } } diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c index 1f44289ca..f2b64b029 100644 --- a/libfreerdp/core/tcp.c +++ b/libfreerdp/core/tcp.c @@ -284,8 +284,9 @@ void tcp_get_mac_address(rdpTcp* tcp) mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); */ } -BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port) +BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeout) { + int status; UINT32 option_value; socklen_t option_len; @@ -295,26 +296,55 @@ BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port) if (hostname[0] == '/') { tcp->sockfd = freerdp_uds_connect(hostname); + if (tcp->sockfd < 0) return FALSE; tcp->socketBio = BIO_new_fd(tcp->sockfd, 1); + if (!tcp->socketBio) return FALSE; } else { + fd_set cfds; + struct timeval tv; + tcp->socketBio = BIO_new(BIO_s_connect()); + if (!tcp->socketBio) return FALSE; - if (BIO_set_conn_hostname(tcp->socketBio, hostname) < 0 || BIO_set_conn_int_port(tcp->socketBio, &port) < 0) + if (BIO_set_conn_hostname(tcp->socketBio, hostname) < 0 || BIO_set_conn_int_port(tcp->socketBio, &port) < 0) return FALSE; - if (BIO_do_connect(tcp->socketBio) <= 0) + BIO_set_nbio(tcp->socketBio, 1); + + status = BIO_do_connect(tcp->socketBio); + + if ((status <= 0) && !BIO_should_retry(tcp->socketBio)) return FALSE; tcp->sockfd = BIO_get_fd(tcp->socketBio, NULL); + + if (tcp->sockfd < 0) + return FALSE; + + if (status <= 0) + { + FD_ZERO(&cfds); + FD_SET(tcp->sockfd, &cfds); + + tv.tv_sec = timeout; + tv.tv_usec = 0; + + status = select(tcp->sockfd + 1, NULL, &cfds, NULL, &tv); + + if (status == 0) + { + return FALSE; /* timeout */ + } + } } SetEventFileDescriptor(tcp->event, tcp->sockfd); @@ -324,6 +354,7 @@ BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port) option_value = 1; option_len = sizeof(option_value); + if (setsockopt(tcp->sockfd, IPPROTO_TCP, TCP_NODELAY, (void*) &option_value, option_len) < 0) fprintf(stderr, "%s: unable to set TCP_NODELAY\n", __FUNCTION__); @@ -334,6 +365,7 @@ BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port) { option_value = 1024 * 32; option_len = sizeof(option_value); + if (setsockopt(tcp->sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &option_value, option_len) < 0) { fprintf(stderr, "%s: unable to set receive buffer len\n", __FUNCTION__); @@ -346,15 +378,17 @@ BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port) return FALSE; tcp->bufferedBio = BIO_new(BIO_s_buffered_socket()); + if (!tcp->bufferedBio) return FALSE; + tcp->bufferedBio->ptr = tcp; tcp->bufferedBio = BIO_push(tcp->bufferedBio, tcp->socketBio); + return TRUE; } - BOOL tcp_disconnect(rdpTcp* tcp) { freerdp_tcp_disconnect(tcp->sockfd); @@ -503,7 +537,8 @@ rdpTcp* tcp_new(rdpSettings* settings) { rdpTcp* tcp; - tcp = (rdpTcp *)calloc(1, sizeof(rdpTcp)); + tcp = (rdpTcp*) calloc(1, sizeof(rdpTcp)); + if (!tcp) return NULL; @@ -515,6 +550,7 @@ rdpTcp* tcp_new(rdpSettings* settings) #ifndef _WIN32 tcp->event = CreateFileDescriptorEvent(NULL, FALSE, FALSE, tcp->sockfd); + if (!tcp->event || tcp->event == INVALID_HANDLE_VALUE) goto out_ringbuffer; #endif diff --git a/libfreerdp/core/tcp.h b/libfreerdp/core/tcp.h index a8b3153b9..d147d01f3 100644 --- a/libfreerdp/core/tcp.h +++ b/libfreerdp/core/tcp.h @@ -60,7 +60,7 @@ struct rdp_tcp HANDLE event; }; -BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port); +BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeout); BOOL tcp_disconnect(rdpTcp* tcp); int tcp_read(rdpTcp* tcp, BYTE* data, int length); int tcp_write(rdpTcp* tcp, BYTE* data, int length); diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index bf58ceff4..f0ad69183 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -373,6 +373,7 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 context = instance->context; tsg = tsg_new(transport); + if (!tsg) return FALSE; @@ -383,12 +384,15 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 if (!transport->TlsIn) { transport->TlsIn = tls_new(settings); + if (!transport->TlsIn) return FALSE; } + if (!transport->TlsOut) { transport->TlsOut = tls_new(settings); + if (!transport->TlsOut) return FALSE; } @@ -400,8 +404,8 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 transport->TlsIn->hostname = transport->TlsOut->hostname = settings->GatewayHostname; transport->TlsIn->port = transport->TlsOut->port = settings->GatewayPort; - tls_status = tls_connect(transport->TlsIn, transport->TcpIn->bufferedBio); + if (tls_status < 1) { if (tls_status < 0) @@ -419,6 +423,7 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 } tls_status = tls_connect(transport->TlsOut, transport->TcpOut->bufferedBio); + if (tls_status < 1) { if (tls_status < 0) @@ -440,10 +445,11 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 transport->frontBio = BIO_new(BIO_s_tsg()); transport->frontBio->ptr = tsg; + return TRUE; } -BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 port) +BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 port, int timeout) { BOOL status = FALSE; rdpSettings* settings = transport->settings; @@ -456,21 +462,22 @@ BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 por transport->SplitInputOutput = TRUE; transport->TcpOut = tcp_new(settings); - if (!tcp_connect(transport->TcpIn, settings->GatewayHostname, settings->GatewayPort) || + if (!tcp_connect(transport->TcpIn, settings->GatewayHostname, settings->GatewayPort, timeout) || !tcp_set_blocking_mode(transport->TcpIn, FALSE)) return FALSE; - if (!tcp_connect(transport->TcpOut, settings->GatewayHostname, settings->GatewayPort) || + if (!tcp_connect(transport->TcpOut, settings->GatewayHostname, settings->GatewayPort, timeout) || !tcp_set_blocking_mode(transport->TcpOut, FALSE)) return FALSE; if (!transport_tsg_connect(transport, hostname, port)) return FALSE; + status = TRUE; } else { - status = tcp_connect(transport->TcpIn, hostname, port); + status = tcp_connect(transport->TcpIn, hostname, port, timeout); transport->SplitInputOutput = FALSE; transport->TcpOut = transport->TcpIn; @@ -635,6 +642,7 @@ static int transport_wait_for_read(rdpTransport* transport) rdpTcp *tcpIn; tcpIn = transport->TcpIn; + if (tcpIn->readBlocked) { rsetPtr = &rset; @@ -660,7 +668,6 @@ static int transport_wait_for_read(rdpTransport* transport) return select(tcpIn->sockfd + 1, rsetPtr, wsetPtr, NULL, &tv); } - static int transport_wait_for_write(rdpTransport* transport) { struct timeval tv; diff --git a/libfreerdp/core/transport.h b/libfreerdp/core/transport.h index 4e9f7e5a4..3a4a41753 100644 --- a/libfreerdp/core/transport.h +++ b/libfreerdp/core/transport.h @@ -86,7 +86,7 @@ struct rdp_transport }; wStream* transport_send_stream_init(rdpTransport* transport, int size); -BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 port); +BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 port, int timeout); void transport_attach(rdpTransport* transport, int sockfd); BOOL transport_disconnect(rdpTransport* transport); BOOL transport_connect_rdp(rdpTransport* transport);