From b7a619ff8a86411f66c12d3bc91afaee89dcb6e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Fri, 13 Feb 2015 14:26:02 -0500 Subject: [PATCH] libfreerdp-core: move some rdpTcp operations under BIO layer --- libfreerdp/core/gateway/rpc.c | 6 +- libfreerdp/core/gateway/tsg.c | 3 - libfreerdp/core/tcp.c | 185 +++++++++++++++++----------------- libfreerdp/core/tcp.h | 21 ++-- libfreerdp/core/transport.c | 86 ++++++++-------- libfreerdp/crypto/tls.c | 8 +- 6 files changed, 154 insertions(+), 155 deletions(-) diff --git a/libfreerdp/core/gateway/rpc.c b/libfreerdp/core/gateway/rpc.c index f303b8f5e..6683d556f 100644 --- a/libfreerdp/core/gateway/rpc.c +++ b/libfreerdp/core/gateway/rpc.c @@ -766,12 +766,12 @@ int rpc_channel_tls_connect(RpcChannel* channel, int timeout) rdpContext* context = rpc->context; rdpSettings* settings = context->settings; - tcp = channel->tcp = freerdp_tcp_new(settings); + tcp = channel->tcp = freerdp_tcp_new(); - if (!freerdp_tcp_connect(tcp, settings->GatewayHostname, settings->GatewayPort, timeout)) + if (!freerdp_tcp_connect(tcp, settings, settings->GatewayHostname, settings->GatewayPort, timeout)) return -1; - if (!BIO_set_nonblock(tcp->socketBio, TRUE)) + if (!BIO_set_nonblock(tcp->bufferedBio, TRUE)) return -1; tls = channel->tls = tls_new(settings); diff --git a/libfreerdp/core/gateway/tsg.c b/libfreerdp/core/gateway/tsg.c index cd38e9a40..337d03b76 100644 --- a/libfreerdp/core/gateway/tsg.c +++ b/libfreerdp/core/gateway/tsg.c @@ -1483,12 +1483,9 @@ BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port, int timeout) tsg->bio->ptr = (void*) tsg; - transport->frontBio = tsg->bio; transport->TcpIn = inChannel->tcp; transport->TcpOut = outChannel->tcp; transport->GatewayEvent = rpc->client->PipeEvent; - transport->SplitInputOutput = TRUE; - transport->layer = TRANSPORT_LAYER_TSG; return TRUE; } diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c index 578eb28aa..5d9141489 100644 --- a/libfreerdp/core/tcp.c +++ b/libfreerdp/core/tcp.c @@ -22,9 +22,6 @@ #include "config.h" #endif -#include -#include -#include #include #include #include @@ -435,7 +432,7 @@ static int transport_bio_buffered_write(BIO* bio, const char* buf, int num) */ if (buf && num && !ringbuffer_write(&tcp->xmitBuffer, (const BYTE*) buf, num)) { - WLog_ERR(TAG, "an error occured when writing(toWrite=%d)", num); + WLog_ERR(TAG, "an error occured when writing (num: %d)", num); return -1; } @@ -473,6 +470,7 @@ static int transport_bio_buffered_write(BIO* bio, const char* buf, int num) out: ringbuffer_commit_read_bytes(&tcp->xmitBuffer, committedBytes); + return ret; } @@ -520,24 +518,40 @@ static int transport_bio_buffered_gets(BIO* bio, char* str, int size) static long transport_bio_buffered_ctrl(BIO* bio, int cmd, long arg1, void* arg2) { + int status = -1; rdpTcp* tcp = (rdpTcp*) bio->ptr; switch (cmd) { case BIO_CTRL_FLUSH: - return 1; + if (!ringbuffer_used(&tcp->xmitBuffer)) + status = 1; + else + status = (transport_bio_buffered_write(bio, NULL, 0) >= 0) ? 1 : -1; + break; case BIO_CTRL_WPENDING: - return ringbuffer_used(&tcp->xmitBuffer); + status = ringbuffer_used(&tcp->xmitBuffer); + break; case BIO_CTRL_PENDING: - return 0; + status = 0; + break; + + case BIO_C_READ_BLOCKED: + status = (int) tcp->readBlocked; + break; + + case BIO_C_WRITE_BLOCKED: + status = (int) tcp->writeBlocked; + break; default: - return BIO_ctrl(bio->next_bio, cmd, arg1, arg2); + status = BIO_ctrl(bio->next_bio, cmd, arg1, arg2); + break; } - return 0; + return status; } static int transport_bio_buffered_new(BIO* bio) @@ -573,43 +587,27 @@ BIO_METHOD* BIO_s_buffered_socket(void) return &transport_bio_buffered_socket_methods; } -BOOL transport_bio_buffered_drain(BIO *bio) -{ - int status; - rdpTcp* tcp = (rdpTcp*) bio->ptr; - - if (!ringbuffer_used(&tcp->xmitBuffer)) - return 1; - - status = transport_bio_buffered_write(bio, NULL, 0); - - return status >= 0; -} - -void freerdp_tcp_get_ip_address(rdpTcp* tcp) +char* freerdp_tcp_get_ip_address(int sockfd) { BYTE* ip; socklen_t length; + char ipAddress[32]; struct sockaddr_in sockaddr; length = sizeof(sockaddr); ZeroMemory(&sockaddr, length); - if (getsockname(tcp->sockfd, (struct sockaddr*) &sockaddr, &length) == 0) + if (getsockname(sockfd, (struct sockaddr*) &sockaddr, &length) == 0) { ip = (BYTE*) (&sockaddr.sin_addr); - sprintf_s(tcp->ip_address, sizeof(tcp->ip_address), - "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); + sprintf_s(ipAddress, sizeof(ipAddress), "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); } else { - strcpy(tcp->ip_address, "127.0.0.1"); + strcpy(ipAddress, "127.0.0.1"); } - tcp->settings->IPv6Enabled = 0; - - free(tcp->settings->ClientAddress); - tcp->settings->ClientAddress = _strdup(tcp->ip_address); + return _strdup(ipAddress); } int freerdp_uds_connect(const char* path) @@ -913,12 +911,67 @@ int freerdp_tcp_connect_multi(char** hostnames, int count, int port, int timeout #endif -BOOL freerdp_tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeout) +BOOL freerdp_tcp_set_keep_alive_mode(int sockfd) +{ +#ifndef _WIN32 + UINT32 optval; + socklen_t optlen; + + optval = 1; + optlen = sizeof(optval); + + if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void*) &optval, optlen) < 0) + { + WLog_WARN(TAG, "setsockopt() SOL_SOCKET, SO_KEEPALIVE"); + } + +#ifdef TCP_KEEPIDLE + optval = 5; + optlen = sizeof(optval); + + if (setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, (void*) &optval, optlen) < 0) + { + WLog_WARN(TAG, "setsockopt() IPPROTO_TCP, TCP_KEEPIDLE"); + } +#endif + +#ifdef TCP_KEEPCNT + optval = 3; + optlen = sizeof(optval); + + if (setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, (void*) &optval, optlen) < 0) + { + WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_KEEPCNT"); + } +#endif + +#ifdef TCP_KEEPINTVL + optval = 2; + optlen = sizeof(optval); + + if (setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, (void*) &optval, optlen) < 0) + { + WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_KEEPINTVL"); + } +#endif +#endif + +#if defined(__MACOSX__) || defined(__IOS__) + optval = 1; + optlen = sizeof(optval); + if (setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void*) &optval, optlen) < 0) + { + WLog_WARN(TAG, "setsockopt() SOL_SOCKET, SO_NOSIGPIPE"); + } +#endif + return TRUE; +} + +BOOL freerdp_tcp_connect(rdpTcp* tcp, rdpSettings* settings, const char* hostname, int port, int timeout) { int status; UINT32 option_value; socklen_t option_len; - rdpSettings* settings = tcp->settings; if (!hostname) return FALSE; @@ -1046,7 +1099,10 @@ BOOL freerdp_tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeou BIO_get_event(tcp->socketBio, &tcp->event); - freerdp_tcp_get_ip_address(tcp); + settings->IPv6Enabled = FALSE; + + free(settings->ClientAddress); + settings->ClientAddress = freerdp_tcp_get_ip_address(tcp->sockfd); option_value = 1; option_len = sizeof(option_value); @@ -1075,7 +1131,7 @@ BOOL freerdp_tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeou if (!tcp->ipcSocket) { - if (!freerdp_tcp_set_keep_alive_mode(tcp)) + if (!freerdp_tcp_set_keep_alive_mode(tcp->sockfd)) return FALSE; } @@ -1091,62 +1147,6 @@ BOOL freerdp_tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeou return TRUE; } -BOOL freerdp_tcp_set_keep_alive_mode(rdpTcp* tcp) -{ -#ifndef _WIN32 - UINT32 option_value; - socklen_t option_len; - - option_value = 1; - option_len = sizeof(option_value); - - if (setsockopt(tcp->sockfd, SOL_SOCKET, SO_KEEPALIVE, (void*) &option_value, option_len) < 0) - { - WLog_WARN(TAG, "setsockopt() SOL_SOCKET, SO_KEEPALIVE"); - } - -#ifdef TCP_KEEPIDLE - option_value = 5; - option_len = sizeof(option_value); - - if (setsockopt(tcp->sockfd, IPPROTO_TCP, TCP_KEEPIDLE, (void*) &option_value, option_len) < 0) - { - WLog_WARN(TAG, "setsockopt() IPPROTO_TCP, TCP_KEEPIDLE"); - } -#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) - { - WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_KEEPCNT"); - } -#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) - { - WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_KEEPINTVL"); - } -#endif -#endif - -#if defined(__MACOSX__) || defined(__IOS__) - option_value = 1; - option_len = sizeof(option_value); - if (setsockopt(tcp->sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void*) &option_value, option_len) < 0) - { - WLog_WARN(TAG, "setsockopt() SOL_SOCKET, SO_NOSIGPIPE"); - } -#endif - return TRUE; -} - int freerdp_tcp_attach(rdpTcp* tcp, int sockfd) { tcp->sockfd = sockfd; @@ -1261,7 +1261,7 @@ int freerdp_tcp_wait_write(rdpTcp* tcp, DWORD dwMilliSeconds) return status; } -rdpTcp* freerdp_tcp_new(rdpSettings* settings) +rdpTcp* freerdp_tcp_new() { rdpTcp* tcp; @@ -1274,7 +1274,6 @@ rdpTcp* freerdp_tcp_new(rdpSettings* settings) goto out_free; tcp->sockfd = -1; - tcp->settings = settings; return tcp; diff --git a/libfreerdp/core/tcp.h b/libfreerdp/core/tcp.h index 533db8ae5..de60e07ec 100644 --- a/libfreerdp/core/tcp.h +++ b/libfreerdp/core/tcp.h @@ -46,36 +46,37 @@ #define BIO_C_GET_SOCKET 1102 #define BIO_C_GET_EVENT 1103 #define BIO_C_SET_NONBLOCK 1104 +#define BIO_C_READ_BLOCKED 1105 +#define BIO_C_WRITE_BLOCKED 1106 #define BIO_set_socket(b, s, c) BIO_ctrl(b, BIO_C_SET_SOCKET, c, s); #define BIO_get_socket(b, c) BIO_ctrl(b, BIO_C_GET_SOCKET, 0, (char*) c) #define BIO_get_event(b, c) BIO_ctrl(b, BIO_C_GET_EVENT, 0, (char*) c) #define BIO_set_nonblock(b, c) BIO_ctrl(b, BIO_C_SET_NONBLOCK, c, NULL) +#define BIO_read_blocked(b) BIO_ctrl(b, BIO_C_READ_BLOCKED, 0, NULL) +#define BIO_write_blocked(b) BIO_ctrl(b, BIO_C_WRITE_BLOCKED, 0, NULL) typedef struct rdp_tcp rdpTcp; struct rdp_tcp { int sockfd; + HANDLE event; BOOL ipcSocket; - char ip_address[32]; - BYTE mac_address[6]; - rdpSettings* settings; BIO* socketBio; BIO* bufferedBio; - RingBuffer xmitBuffer; - BOOL writeBlocked; BOOL readBlocked; - HANDLE event; + BOOL writeBlocked; + RingBuffer xmitBuffer; }; -BOOL freerdp_tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeout); +int freerdp_tcp_attach(rdpTcp* tcp, int sockfd); +BOOL freerdp_tcp_connect(rdpTcp* tcp, rdpSettings* settings, const char* hostname, int port, int timeout); + int freerdp_tcp_wait_read(rdpTcp* tcp, DWORD dwMilliSeconds); int freerdp_tcp_wait_write(rdpTcp* tcp, DWORD dwMilliSeconds); -BOOL freerdp_tcp_set_keep_alive_mode(rdpTcp* tcp); -int freerdp_tcp_attach(rdpTcp* tcp, int sockfd); -rdpTcp* freerdp_tcp_new(rdpSettings* settings); +rdpTcp* freerdp_tcp_new(); void freerdp_tcp_free(rdpTcp* tcp); #endif /* __TCP_H */ diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index ebf841bc1..64a238c20 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -70,7 +70,7 @@ wStream* transport_send_stream_init(rdpTransport* transport, int size) void transport_attach(rdpTransport* transport, int sockfd) { if (!transport->TcpIn) - transport->TcpIn = freerdp_tcp_new(transport->settings); + transport->TcpIn = freerdp_tcp_new(); freerdp_tcp_attach(transport->TcpIn, sockfd); @@ -207,23 +207,6 @@ BOOL transport_connect_nla(rdpTransport* transport) return TRUE; } -BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 port, int timeout) -{ - rdpTsg* tsg; - - tsg = tsg_new(transport); - - if (!tsg) - return FALSE; - - transport->tsg = tsg; - - if (!tsg_connect(tsg, hostname, port, timeout)) - return FALSE; - - return TRUE; -} - BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 port, int timeout) { BOOL status = FALSE; @@ -233,18 +216,34 @@ BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 por if (transport->GatewayEnabled) { - if (!transport_tsg_connect(transport, hostname, port, timeout)) + transport->tsg = tsg_new(transport); + + if (!transport->tsg) return FALSE; + if (!tsg_connect(transport->tsg, hostname, port, timeout)) + return FALSE; + + transport->frontBio = transport->tsg->bio; + transport->SplitInputOutput = TRUE; + transport->layer = TRANSPORT_LAYER_TSG; + status = TRUE; } else { - transport->TcpIn = freerdp_tcp_new(settings); + transport->TcpIn = freerdp_tcp_new(); + + if (!transport->TcpIn) + return FALSE; + + if (!freerdp_tcp_connect(transport->TcpIn, settings, hostname, port, timeout)) + return FALSE; - status = freerdp_tcp_connect(transport->TcpIn, hostname, port, timeout); - transport->SplitInputOutput = FALSE; transport->frontBio = transport->TcpIn->bufferedBio; + transport->SplitInputOutput = FALSE; + + status = TRUE; } if (status) @@ -326,13 +325,16 @@ BOOL transport_accept_nla(rdpTransport* transport) static int transport_wait_for_read(rdpTransport* transport) { + BIO* bio; rdpTcp* tcpIn = transport->TcpIn; - if (tcpIn->readBlocked) + bio = tcpIn->bufferedBio; + + if (BIO_read_blocked(bio)) { return freerdp_tcp_wait_read(tcpIn, 10); } - else if (tcpIn->writeBlocked) + else if (BIO_write_blocked(bio)) { return freerdp_tcp_wait_write(tcpIn, 10); } @@ -343,14 +345,17 @@ static int transport_wait_for_read(rdpTransport* transport) static int transport_wait_for_write(rdpTransport* transport) { + BIO* bio; rdpTcp* tcpOut; - tcpOut = transport->SplitInputOutput ? transport->TcpOut : transport->TcpIn; - if (tcpOut->writeBlocked) + tcpOut = transport->SplitInputOutput ? transport->TcpOut : transport->TcpIn; + bio = tcpOut->bufferedBio; + + if (BIO_write_blocked(bio)) { return freerdp_tcp_wait_write(tcpOut, 10); } - else if (tcpOut->readBlocked) + else if (BIO_read_blocked(bio)) { return freerdp_tcp_wait_read(tcpOut, 10); } @@ -584,8 +589,6 @@ int transport_read_pdu(rdpTransport* transport, wStream* s) return Stream_Length(s); } -BOOL transport_bio_buffered_drain(BIO* bio); - int transport_write(rdpTransport* transport, wStream* s) { int length; @@ -639,7 +642,7 @@ int transport_write(rdpTransport* transport, wStream* s) /* blocking transport, we must ensure the write buffer is really empty */ rdpTcp* out = transport->SplitInputOutput ? transport->TcpOut : transport->TcpIn; - while (out->writeBlocked) + while (BIO_write_blocked(out->bufferedBio)) { if (transport_wait_for_write(transport) < 0) { @@ -647,9 +650,9 @@ int transport_write(rdpTransport* transport, wStream* s) return -1; } - if (!transport_bio_buffered_drain(out->bufferedBio)) + if (BIO_flush(out->bufferedBio) < 1) { - WLog_ERR(TAG, "error when draining outputBuffer"); + WLog_ERR(TAG, "error when flushing outputBuffer"); return -1; } } @@ -731,12 +734,11 @@ DWORD transport_get_event_handles(rdpTransport* transport, HANDLE* events) BOOL tranport_is_write_blocked(rdpTransport* transport) { - if (transport->TcpIn->writeBlocked) + if (BIO_write_blocked(transport->TcpIn->bufferedBio)) return TRUE; return transport->SplitInputOutput && - transport->TcpOut && - transport->TcpOut->writeBlocked; + transport->TcpOut && BIO_write_blocked(transport->TcpOut->bufferedBio); } int tranport_drain_output_buffer(rdpTransport* transport) @@ -744,20 +746,20 @@ int tranport_drain_output_buffer(rdpTransport* transport) BOOL status = FALSE; /* First try to send some accumulated bytes in the send buffer */ - if (transport->TcpIn->writeBlocked) + if (BIO_write_blocked(transport->TcpIn->bufferedBio)) { - if (!transport_bio_buffered_drain(transport->TcpIn->bufferedBio)) + if (BIO_flush(transport->TcpIn->bufferedBio) < 1) return -1; - status |= transport->TcpIn->writeBlocked; + status |= BIO_write_blocked(transport->TcpIn->bufferedBio); } - if (transport->SplitInputOutput && transport->TcpOut && transport->TcpOut->writeBlocked) + if (transport->SplitInputOutput && transport->TcpOut && BIO_write_blocked(transport->TcpOut->bufferedBio)) { - if (!transport_bio_buffered_drain(transport->TcpOut->bufferedBio)) + if (BIO_flush(transport->TcpOut->bufferedBio) < 1) return -1; - status |= transport->TcpOut->writeBlocked; + status |= BIO_write_blocked(transport->TcpOut->bufferedBio); } return status; @@ -827,7 +829,7 @@ BOOL transport_set_blocking_mode(rdpTransport* transport, BOOL blocking) if (!transport->SplitInputOutput) { - if (!BIO_set_nonblock(transport->TcpIn->socketBio, blocking ? FALSE : TRUE)) + if (!BIO_set_nonblock(transport->TcpIn->bufferedBio, blocking ? FALSE : TRUE)) return FALSE; } diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index d3a23a56f..d7d4bed5f 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -919,11 +919,11 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length) pollfds.revents = 0; pollfds.events = 0; - if (tcp->writeBlocked) + if (BIO_write_blocked(bio)) { pollfds.events |= POLLOUT; } - else if (tcp->readBlocked) + else if (BIO_read_blocked(bio)) { pollfds.events |= POLLIN; } @@ -943,13 +943,13 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length) /* we try to handle SSL want_read and want_write nicely */ rsetPtr = wsetPtr = NULL; - if (tcp->writeBlocked) + if (BIO_write_blocked(bio)) { wsetPtr = &wset; FD_ZERO(&wset); FD_SET(tcp->sockfd, &wset); } - else if (tcp->readBlocked) + else if (BIO_read_blocked(bio)) { rsetPtr = &rset; FD_ZERO(&rset);