libfreerdp-core: move some rdpTcp operations under BIO layer

This commit is contained in:
Marc-André Moreau 2015-02-13 14:26:02 -05:00
parent 69b93c322d
commit b7a619ff8a
6 changed files with 154 additions and 155 deletions

View File

@ -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);

View File

@ -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;
}

View File

@ -22,9 +22,6 @@
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
@ -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;

View File

@ -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 */

View File

@ -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;
}

View File

@ -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);