mirror of https://github.com/FreeRDP/FreeRDP
Merge pull request #1 from llyzs/network
Initial transport layer implementation
This commit is contained in:
commit
3a9e3e51aa
|
@ -21,6 +21,7 @@ include_directories(${CUNIT_INCLUDE_DIRS})
|
|||
|
||||
include_directories(.)
|
||||
include_directories(../include)
|
||||
include_directories(../libfreerdp-core)
|
||||
include_directories(../libfreerdp-gdi)
|
||||
|
||||
add_executable(test_freerdp
|
||||
|
@ -30,11 +31,14 @@ add_executable(test_freerdp
|
|||
test_libgdi.h
|
||||
test_stream.c
|
||||
test_stream.h
|
||||
test_transport.c
|
||||
test_transport.h
|
||||
test_freerdp.c
|
||||
test_freerdp.h)
|
||||
|
||||
target_link_libraries(test_freerdp ${CUNIT_LIBRARIES})
|
||||
|
||||
target_link_libraries(test_freerdp freerdp-core)
|
||||
target_link_libraries(test_freerdp freerdp-gdi)
|
||||
target_link_libraries(test_freerdp freerdp-asn1)
|
||||
target_link_libraries(test_freerdp freerdp-utils)
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "test_color.h"
|
||||
#include "test_libgdi.h"
|
||||
#include "test_stream.h"
|
||||
#include "test_transport.h"
|
||||
#include "test_freerdp.h"
|
||||
|
||||
void dump_data(unsigned char * p, int len, int width, char* name)
|
||||
|
@ -63,6 +64,7 @@ int main(int argc, char* argv[])
|
|||
add_color_suite();
|
||||
add_libgdi_suite();
|
||||
add_stream_suite();
|
||||
add_transport_suite();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -80,6 +82,10 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
add_stream_suite();
|
||||
}
|
||||
else if (strcmp("transport", argv[*pindex]) == 0)
|
||||
{
|
||||
add_transport_suite();
|
||||
}
|
||||
|
||||
*pindex = *pindex + 1;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Client
|
||||
* Transport Unit Tests
|
||||
*
|
||||
* Copyright 2011 Vic Lee
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/utils/hexdump.h>
|
||||
#include <freerdp/utils/stream.h>
|
||||
|
||||
#include "tpkt.h"
|
||||
#include "transport.h"
|
||||
#include "test_transport.h"
|
||||
|
||||
static const char test_server[] = "192.168.0.1";
|
||||
static const uint8 test_x224_req[] =
|
||||
{
|
||||
"\x03\x00\x00\x2C\x27\xE0\x00\x00\x00\x00\x00\x43\x6F\x6F\x6B\x69"
|
||||
"\x65\x3A\x20\x6D\x73\x74\x73\x68\x61\x73\x68\x3D\x65\x6C\x74\x6F"
|
||||
"\x6e\x73\x0D\x0A\x01\x00\x08\x00\x00\x00\x00\x00"
|
||||
};
|
||||
|
||||
int init_transport_suite(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clean_transport_suite(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int add_transport_suite(void)
|
||||
{
|
||||
add_test_suite(transport);
|
||||
|
||||
add_test_function(transport);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_finished = 0;
|
||||
|
||||
static int
|
||||
packet_received(STREAM * stream, void * callback_data)
|
||||
{
|
||||
uint16 len;
|
||||
|
||||
len = tpkt_read_header(stream);
|
||||
CU_ASSERT(len == 19);
|
||||
freerdp_hexdump(stream->buffer, len);
|
||||
test_finished = 1;
|
||||
}
|
||||
|
||||
void test_transport(void)
|
||||
{
|
||||
rdpTransport * transport;
|
||||
STREAM * stream;
|
||||
int r;
|
||||
|
||||
transport = transport_new();
|
||||
transport->recv_callback = packet_received;
|
||||
transport->recv_callback_data = NULL;
|
||||
|
||||
r = transport_connect(transport, test_server, 3389);
|
||||
CU_ASSERT(r == 0);
|
||||
|
||||
stream = stream_new(sizeof(test_x224_req));
|
||||
stream_write_buffer(stream, test_x224_req, sizeof(test_x224_req));
|
||||
r = transport_send(transport, stream);
|
||||
CU_ASSERT(r == 0);
|
||||
|
||||
while (!test_finished)
|
||||
{
|
||||
transport_check_fds(transport);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
r = transport_disconnect(transport);
|
||||
CU_ASSERT(r == 0);
|
||||
|
||||
transport_free(transport);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Client
|
||||
* Transport Unit Tests
|
||||
*
|
||||
* Copyright 2011 Vic Lee
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "test_freerdp.h"
|
||||
|
||||
int init_transport_suite(void);
|
||||
int clean_transport_suite(void);
|
||||
int add_transport_suite(void);
|
||||
|
||||
void test_transport(void);
|
|
@ -45,6 +45,8 @@ stream_extend(STREAM * stream);
|
|||
#define stream_get_pos(_s) (_s->ptr - _s->buffer)
|
||||
#define stream_set_pos(_s,_m) _s->ptr = _s->buffer + (_m)
|
||||
#define stream_seek(_s,_offset) _s->ptr += (_offset)
|
||||
#define stream_get_head(_s) _s->buffer
|
||||
#define stream_get_tail(_s) _s->ptr
|
||||
|
||||
#define stream_read_uint8(_s, _v) do { _v = *_s->ptr++; } while (0)
|
||||
#define stream_read_uint16(_s, _v) do { _v = \
|
||||
|
@ -87,6 +89,10 @@ stream_extend(STREAM * stream);
|
|||
*_s->ptr++ = ((_v) >> 40) & 0xFF; \
|
||||
*_s->ptr++ = ((_v) >> 48) & 0xFF; \
|
||||
*_s->ptr++ = ((_v) >> 56) & 0xFF; } while (0)
|
||||
#define stream_write_buffer(_s, _b, _n) do { \
|
||||
memcpy(_s->ptr, (_b), (_n)); \
|
||||
_s->ptr += (_n); \
|
||||
} while (0)
|
||||
|
||||
#define stream_peek_uint8(_s, _v) do { _v = *_s->ptr; } while (0)
|
||||
#define stream_peek_uint16(_s, _v) do { _v = \
|
||||
|
@ -110,5 +116,20 @@ stream_extend(STREAM * stream);
|
|||
(((uint64)(*(_s->ptr + 7))) << 56); \
|
||||
} while (0)
|
||||
|
||||
#define stream_read_uint16_be(_s, _v) do { _v = \
|
||||
(((uint16)(*_s->ptr)) << 8) + \
|
||||
(uint16)(*(_s->ptr + 1)); \
|
||||
_s->ptr += 2; } while (0)
|
||||
|
||||
#define stream_write_uint16_be(_s, _v) do { \
|
||||
*_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 */
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@ set(LIBFREERDP_CORE_SRCS
|
|||
tpdu.h
|
||||
tpkt.c
|
||||
tpkt.h
|
||||
transport.c
|
||||
transport.h
|
||||
)
|
||||
|
||||
add_library(freerdp-core SHARED ${LIBFREERDP_CORE_SRCS})
|
||||
|
|
|
@ -64,7 +64,7 @@ tpkt_read_header(STREAM* s)
|
|||
if (version == 3)
|
||||
{
|
||||
stream_seek(s, 2);
|
||||
stream_read_uint16(s, length);
|
||||
stream_read_uint16_be(s, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -80,5 +80,5 @@ tpkt_write_header(STREAM* s, int length)
|
|||
{
|
||||
stream_write_uint8(s, 3); /* version */
|
||||
stream_write_uint8(s, 8); /* reserved */
|
||||
stream_write_uint16(s, length); /* length */
|
||||
stream_write_uint16_be(s, length); /* length */
|
||||
}
|
||||
|
|
|
@ -0,0 +1,285 @@
|
|||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Client
|
||||
* Network Transport Layer
|
||||
*
|
||||
* Copyright 2011 Vic Lee
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <freerdp/utils/stream.h>
|
||||
#include <freerdp/utils/memory.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "tpkt.h"
|
||||
#include "transport.h"
|
||||
|
||||
#define BUFFER_SIZE 16384
|
||||
|
||||
rdpTransport *
|
||||
transport_new(void)
|
||||
{
|
||||
rdpTransport * transport;
|
||||
|
||||
transport = (rdpTransport *) xmalloc(sizeof(rdpTransport));
|
||||
memset(transport, 0, sizeof(rdpTransport));
|
||||
|
||||
transport->sockfd = -1;
|
||||
|
||||
/* a small 0.1ms delay when transport is blocking. */
|
||||
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);
|
||||
}
|
||||
|
||||
static int
|
||||
transport_connect_sockfd(rdpTransport * transport, const char * server, int port)
|
||||
{
|
||||
struct addrinfo hints = { 0 };
|
||||
struct addrinfo * res, * ai;
|
||||
int r;
|
||||
char servname[10];
|
||||
int sockfd = -1;
|
||||
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
snprintf(servname, sizeof(servname), "%d", port);
|
||||
r = getaddrinfo(server, servname, &hints, &res);
|
||||
if (r != 0)
|
||||
{
|
||||
printf("transport_connect: getaddrinfo (%s)\n", gai_strerror(r));
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (ai = res; ai; ai = ai->ai_next)
|
||||
{
|
||||
sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||
if (sockfd < 0)
|
||||
continue;
|
||||
|
||||
r = connect(sockfd, ai->ai_addr, ai->ai_addrlen);
|
||||
if (r == 0)
|
||||
{
|
||||
printf("connected to %s:%s\n", server, servname);
|
||||
break;
|
||||
}
|
||||
|
||||
sockfd = -1;
|
||||
}
|
||||
freeaddrinfo(res);
|
||||
|
||||
if (sockfd == -1)
|
||||
{
|
||||
printf("unable to connect to %s:%s\n", server, servname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
transport->sockfd = sockfd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
transport_configure_sockfd(rdpTransport * transport)
|
||||
{
|
||||
int flags;
|
||||
|
||||
flags = fcntl(transport->sockfd, F_GETFL);
|
||||
if (flags == -1)
|
||||
{
|
||||
printf("transport_configure_sockfd: fcntl failed.\n");
|
||||
return -1;
|
||||
}
|
||||
fcntl(transport->sockfd, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
transport_connect(rdpTransport * transport, const char * server, int port)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = transport_connect_sockfd(transport, server, port);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = transport_configure_sockfd(transport);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
transport_disconnect(rdpTransport * transport)
|
||||
{
|
||||
if (transport->sockfd != -1)
|
||||
{
|
||||
close(transport->sockfd);
|
||||
transport->sockfd = -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
transport_start_tls(rdpTransport * transport)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
transport_delay(rdpTransport * transport)
|
||||
{
|
||||
nanosleep(&transport->ts, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
transport_send_tls(rdpTransport * transport, STREAM * stream)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
transport_send_tcp(rdpTransport * transport, STREAM * stream)
|
||||
{
|
||||
uint8 * head;
|
||||
uint8 * tail;
|
||||
int r;
|
||||
|
||||
head = stream_get_head(stream);
|
||||
tail = stream_get_tail(stream);
|
||||
while (head < tail)
|
||||
{
|
||||
r = send(transport->sockfd, head, tail - head, MSG_NOSIGNAL);
|
||||
if (r < 0)
|
||||
{
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
{
|
||||
if (transport_delay(transport) != 0)
|
||||
return -1;
|
||||
continue;
|
||||
}
|
||||
printf("transport_send_tcp: send (%d)\n", errno);
|
||||
return -1;
|
||||
}
|
||||
head += r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
transport_send(rdpTransport * transport, STREAM * stream)
|
||||
{
|
||||
if (transport->tls)
|
||||
return transport_send_tls(transport, stream);
|
||||
else
|
||||
return transport_send_tcp(transport, stream);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Client
|
||||
* Network Transport Layer
|
||||
*
|
||||
* Copyright 2011 Vic Lee
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __TRANSPORT_H
|
||||
#define __TRANSPORT_H
|
||||
|
||||
#include <freerdp/utils/stream.h>
|
||||
|
||||
typedef int (* PacketReceivedCallback) (STREAM * stream, void * callback_data);
|
||||
|
||||
struct rdp_transport
|
||||
{
|
||||
int sockfd;
|
||||
struct crypto_tls * tls;
|
||||
struct timespec ts;
|
||||
STREAM * recv_buffer;
|
||||
|
||||
PacketReceivedCallback recv_callback;
|
||||
void * recv_callback_data;
|
||||
};
|
||||
typedef struct rdp_transport rdpTransport;
|
||||
|
||||
rdpTransport *
|
||||
transport_new(void);
|
||||
void
|
||||
transport_free(rdpTransport * transport);
|
||||
int
|
||||
transport_connect(rdpTransport * transport, const char * server, int port);
|
||||
int
|
||||
transport_disconnect(rdpTransport * transport);
|
||||
int
|
||||
transport_start_tls(rdpTransport * transport);
|
||||
int
|
||||
transport_send(rdpTransport * transport, STREAM * stream);
|
||||
int
|
||||
transport_check_fds(rdpTransport * transport);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue