From 6a3db6363dbd5fa1297b87b7af48a212ebe0bf88 Mon Sep 17 00:00:00 2001 From: Vic Lee Date: Sun, 3 Jul 2011 18:30:43 +0800 Subject: [PATCH] libfreerdp-core: implement tcp receiving. --- include/freerdp/utils/stream.h | 6 +++ libfreerdp-core/transport.c | 81 +++++++++++++++++++++++++++++++++- libfreerdp-core/transport.h | 7 ++- 3 files changed, 90 insertions(+), 4 deletions(-) diff --git a/include/freerdp/utils/stream.h b/include/freerdp/utils/stream.h index ebcced2d3..3c8376661 100644 --- a/include/freerdp/utils/stream.h +++ b/include/freerdp/utils/stream.h @@ -125,5 +125,11 @@ stream_extend(STREAM * stream); *_s->ptr++ = ((_v) >> 8) & 0xFF; \ *_s->ptr++ = (_v) & 0xFF; } while (0) +#define stream_copy(_dst, _src, _n) do { \ + memcpy(_dst->ptr, _src->ptr, _n); \ + _dst->ptr += _n; \ + _src->ptr += _n; \ + } while (0) + #endif /* __STREAM_UTILS_H */ diff --git a/libfreerdp-core/transport.c b/libfreerdp-core/transport.c index a1e14c6fc..62d9900ad 100644 --- a/libfreerdp-core/transport.c +++ b/libfreerdp-core/transport.c @@ -29,8 +29,11 @@ #include #include +#include "tpkt.h" #include "transport.h" +#define BUFFER_SIZE 16384 + rdpTransport * transport_new(void) { @@ -45,12 +48,16 @@ transport_new(void) transport->ts.tv_sec = 0; transport->ts.tv_nsec = 100000; + /* receive buffer for non-blocking read. */ + transport->recv_buffer = stream_new(BUFFER_SIZE); + return transport; } void transport_free(rdpTransport * transport) { + stream_free(transport->recv_buffer); xfree(transport); } @@ -201,8 +208,78 @@ transport_send(rdpTransport * transport, STREAM * stream) return transport_send_tcp(transport, stream); } -int -transport_check_fds(rdpTransport * transport) +static int +transport_recv_tls(rdpTransport * transport) { return 0; } + +static int +transport_recv_tcp(rdpTransport * transport) +{ + int r; + + stream_check_capacity(transport->recv_buffer, BUFFER_SIZE); + + r = recv(transport->sockfd, transport->recv_buffer->ptr, BUFFER_SIZE, 0); + if (r == -1) + { + if (errno == EAGAIN || errno == EWOULDBLOCK) + return 0; + printf("transport_recv_tcp: recv failed (%d).\n", errno); + return -1; + } + stream_seek(transport->recv_buffer, r); + + return r; +} + +int +transport_check_fds(rdpTransport * transport) +{ + int r; + int pos; + uint16 len; + STREAM * received; + + if (transport->tls) + r = transport_recv_tls(transport); + else + r = transport_recv_tcp(transport); + + if (r <= 0) + return r; + + pos = stream_get_pos(transport->recv_buffer); + /* Ensure the TPKT header is available. */ + if (pos <= 4) + return 0; + + stream_set_pos(transport->recv_buffer, 0); + len = tpkt_read_header(transport->recv_buffer); + if (len == 0) + { + printf("transport_check_fds: protocol error, not a TPKT header.\n"); + return -1; + } + if (pos < len) + return 0; /* Packet is not yet completely received. */ + + /* A complete packet has been received. In case there are trailing data + * for the next packet, we copy it to the new receive buffer. + */ + received = transport->recv_buffer; + transport->recv_buffer = stream_new(BUFFER_SIZE); + if (pos > len) + { + stream_set_pos(received, len); + stream_check_capacity(transport->recv_buffer, pos - len); + stream_copy(transport->recv_buffer, received, pos - len); + } + + stream_set_pos(received, 0); + r = transport->recv_callback(received, transport->recv_callback_data); + stream_free(received); + + return r; +} diff --git a/libfreerdp-core/transport.h b/libfreerdp-core/transport.h index 8fe62aef1..316f6d912 100644 --- a/libfreerdp-core/transport.h +++ b/libfreerdp-core/transport.h @@ -22,14 +22,17 @@ #include -typedef int (* PacketReceivedCallback) (STREAM * stream); +typedef int (* PacketReceivedCallback) (STREAM * stream, void * callback_data); struct rdp_transport { int sockfd; struct crypto_tls * tls; - PacketReceivedCallback * recv_callback; struct timespec ts; + STREAM * recv_buffer; + + PacketReceivedCallback recv_callback; + void * recv_callback_data; }; typedef struct rdp_transport rdpTransport;