diff --git a/freerdp-ui/test/freerdp-test b/freerdp-ui/test/freerdp-test index 15e10dac6..49e46d006 100755 Binary files a/freerdp-ui/test/freerdp-test and b/freerdp-ui/test/freerdp-test differ diff --git a/libfreerdp-core/CMakeLists.txt b/libfreerdp-core/CMakeLists.txt index 13ea4913b..0d86742b0 100644 --- a/libfreerdp-core/CMakeLists.txt +++ b/libfreerdp-core/CMakeLists.txt @@ -30,6 +30,8 @@ set(LIBFREERDP_CORE_SRCS # credssp.h # ntlmssp.c # ntlmssp.h + tcp.c + tcp.h tpdu.c tpdu.h tpkt.c diff --git a/libfreerdp-core/nego.c b/libfreerdp-core/nego.c index 968241d05..7e29ef2d3 100644 --- a/libfreerdp-core/nego.c +++ b/libfreerdp-core/nego.c @@ -47,23 +47,21 @@ int nego_connect(rdpNego *nego) nego->state = NEGO_STATE_FAIL; } - DEBUG_NEGO("Negotiating protocol security"); - while (nego->state != NEGO_STATE_FINAL) { - nego_send(nego); - DEBUG_NEGO("state: %s", NEGO_STATE_STRINGS[nego->state]); + nego_send(nego); + if (nego->state == NEGO_STATE_FAIL) { nego->state = NEGO_STATE_FINAL; return 0; } - - nego->state = NEGO_STATE_FINAL; } + DEBUG_NEGO("Negotiated %s security", PROTOCOL_SECURITY_STRINGS[nego->selected_protocol]); + return 1; } @@ -215,6 +213,10 @@ int nego_recv(rdpTransport * transport, STREAM* s, void * extra) break; } } + else + { + nego->state = NEGO_STATE_FINAL; + } return 0; } diff --git a/libfreerdp-core/nego.h b/libfreerdp-core/nego.h index 30483ada5..cf1627a46 100644 --- a/libfreerdp-core/nego.h +++ b/libfreerdp-core/nego.h @@ -38,12 +38,12 @@ typedef enum _NEGO_STATE NEGO_STATE; char NEGO_STATE_STRINGS[6][25] = { - "NEGO_STATE_INITIAL", - "NEGO_STATE_NLA", - "NEGO_STATE_TLS", - "NEGO_STATE_RDP", - "NEGO_STATE_FAIL", - "NEGO_STATE_FINAL" + "NEGO_STATE_INITIAL", + "NEGO_STATE_NLA", + "NEGO_STATE_TLS", + "NEGO_STATE_RDP", + "NEGO_STATE_FAIL", + "NEGO_STATE_FINAL" }; /* RDP Negotiation Messages */ @@ -56,6 +56,13 @@ enum RDP_NEG_MSG TYPE_RDP_NEG_FAILURE = 0x3 }; +char PROTOCOL_SECURITY_STRINGS[3][4] = +{ + "RDP", + "TLS", + "NLA" +}; + struct rdp_nego { int port; diff --git a/libfreerdp-core/tcp.c b/libfreerdp-core/tcp.c new file mode 100644 index 000000000..183464a30 --- /dev/null +++ b/libfreerdp-core/tcp.c @@ -0,0 +1,145 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * Transmission Control Protocol (TCP) + * + * Copyright 2011 Vic Lee + * Copyright 2011 Marc-Andre Moreau + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "tcp.h" + +FRDP_BOOL +tcp_connect(rdpTcp * tcp, const char * hostname, int port) +{ + int status; + int sockfd = -1; + char servname[10]; + struct addrinfo hints = { 0 }; + struct addrinfo * res, * ai; + + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + snprintf(servname, sizeof(servname), "%d", port); + status = getaddrinfo(hostname, servname, &hints, &res); + + if (status != 0) + { + printf("transport_connect: getaddrinfo (%s)\n", gai_strerror(status)); + return False; + } + + for (ai = res; ai; ai = ai->ai_next) + { + sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + + if (sockfd < 0) + continue; + + if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) == 0) + { + printf("connected to %s:%s\n", hostname, servname); + break; + } + + sockfd = -1; + } + freeaddrinfo(res); + + if (sockfd == -1) + { + printf("unable to connect to %s:%s\n", hostname, servname); + return False; + } + + tcp->sockfd = sockfd; + + return True; +} + +FRDP_BOOL +tcp_disconnect(rdpTcp * tcp) +{ + if (tcp->sockfd != -1) + { + close(tcp->sockfd); + tcp->sockfd = -1; + } + + return True; +} + +FRDP_BOOL +tcp_set_blocking_mode(rdpTcp * tcp, FRDP_BOOL blocking) +{ + int flags; + flags = fcntl(tcp->sockfd, F_GETFL); + + if (flags == -1) + { + printf("transport_configure_sockfd: fcntl failed.\n"); + return False; + } + + if (blocking == True) + { + /* blocking */ + fcntl(tcp->sockfd, F_SETFL, flags & ~(O_NONBLOCK)); + } + else + { + /* non-blocking */ + fcntl(tcp->sockfd, F_SETFL, flags | O_NONBLOCK); + } + + return True; +} + +rdpTcp* +tcp_new() +{ + rdpTcp *tcp = (rdpTcp*) xzalloc(sizeof(rdpTcp)); + + if (tcp != NULL) + { + tcp->sockfd = -1; + tcp->connect = tcp_connect; + tcp->disconnect = tcp_disconnect; + tcp->set_blocking_mode = tcp_set_blocking_mode; + } + + return tcp; +} + +void +tcp_free(rdpTcp* tcp) +{ + if (tcp != NULL) + { + xfree(tcp); + } +} diff --git a/libfreerdp-core/tcp.h b/libfreerdp-core/tcp.h new file mode 100644 index 000000000..9033b8b76 --- /dev/null +++ b/libfreerdp-core/tcp.h @@ -0,0 +1,52 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * Transmission Control Protocol (TCP) + * + * Copyright 2011 Vic Lee + * Copyright 2011 Marc-Andre Moreau + * + * 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 __TCP_H +#define __TCP_H + +#include +#include + +typedef struct rdp_tcp rdpTcp; +typedef FRDP_BOOL (*TcpConnect) (rdpTcp * tcp, const char * hostname, int port); +typedef FRDP_BOOL (*TcpDisconnect) (rdpTcp * tcp); +typedef FRDP_BOOL (*TcpSetBlockingMode) (rdpTcp * tcp, FRDP_BOOL blocking); + +struct rdp_tcp +{ + int sockfd; + TcpConnect connect; + TcpDisconnect disconnect; + TcpSetBlockingMode set_blocking_mode; +}; + +FRDP_BOOL +tcp_connect(rdpTcp * tcp, const char * hostname, int port); +FRDP_BOOL +tcp_disconnect(rdpTcp * tcp); +FRDP_BOOL +tcp_set_blocking_mode(rdpTcp * tcp, FRDP_BOOL blocking); + +rdpTcp* +tcp_new(); +void +tcp_free(rdpTcp* tcp); + +#endif /* __TCP_H */ diff --git a/libfreerdp-core/transport.c b/libfreerdp-core/transport.c index 817625b15..6f9f8d2dc 100644 --- a/libfreerdp-core/transport.c +++ b/libfreerdp-core/transport.c @@ -34,122 +34,16 @@ #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 FRDP_BOOL -transport_connect_sockfd(rdpTransport * transport, const char * server, int port) -{ - int status; - int sockfd = -1; - char servname[10]; - struct addrinfo hints = { 0 }; - struct addrinfo * res, * ai; - - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - - snprintf(servname, sizeof(servname), "%d", port); - status = getaddrinfo(server, servname, &hints, &res); - - if (status != 0) - { - printf("transport_connect: getaddrinfo (%s)\n", gai_strerror(status)); - return False; - } - - for (ai = res; ai; ai = ai->ai_next) - { - sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); - - if (sockfd < 0) - continue; - - if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) == 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 False; - } - - transport->sockfd = sockfd; - - return True; -} - -static FRDP_BOOL -transport_configure_sockfd(rdpTransport * transport) -{ - int flags; - - flags = fcntl(transport->sockfd, F_GETFL); - - if (flags == -1) - { - printf("transport_configure_sockfd: fcntl failed.\n"); - return False; - } - - fcntl(transport->sockfd, F_SETFL, flags | O_NONBLOCK); - - return True; -} - FRDP_BOOL transport_connect(rdpTransport * transport, const char * server, int port) { - if (transport_connect_sockfd(transport, server, port) != True) - return False; - - if (transport_configure_sockfd(transport) != True) - return False; - - return True; + return transport->tcp->connect(transport->tcp, server, port); } -int +FRDP_BOOL transport_disconnect(rdpTransport * transport) { - if (transport->sockfd != -1) - { - close(transport->sockfd); - transport->sockfd = -1; - } - - return True; + return transport->tcp->disconnect(transport->tcp); } int @@ -183,7 +77,7 @@ transport_send_tcp(rdpTransport * transport, STREAM * stream) while (head < tail) { - bytes = send(transport->sockfd, head, tail - head, MSG_NOSIGNAL); + bytes = send(transport->tcp->sockfd, head, tail - head, MSG_NOSIGNAL); if (bytes < 0) { @@ -226,7 +120,7 @@ transport_recv_tcp(rdpTransport * transport) stream_check_capacity(transport->recv_buffer, BUFFER_SIZE); - bytes = recv(transport->sockfd, transport->recv_buffer->ptr, BUFFER_SIZE, 0); + bytes = recv(transport->tcp->sockfd, transport->recv_buffer->ptr, BUFFER_SIZE, 0); if (bytes == -1) { @@ -296,3 +190,42 @@ transport_check_fds(rdpTransport * transport) return bytes; } + +void +transport_init(rdpTransport * transport) +{ + transport->state = TRANSPORT_STATE_NEGO; +} + +rdpTransport * +transport_new(void) +{ + rdpTransport * transport; + + transport = (rdpTransport *) xzalloc(sizeof(rdpTransport)); + + if (transport != NULL) + { + transport->tcp = tcp_new(); + + /* 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) +{ + if (transport != NULL) + { + stream_free(transport->recv_buffer); + tcp_free(transport->tcp); + xfree(transport); + } +} diff --git a/libfreerdp-core/transport.h b/libfreerdp-core/transport.h index 170a8fc15..76ef5e479 100644 --- a/libfreerdp-core/transport.h +++ b/libfreerdp-core/transport.h @@ -20,16 +20,29 @@ #ifndef __TRANSPORT_H #define __TRANSPORT_H +#include "tcp.h" + #include #include #include +enum _TRANSPORT_STATE +{ + TRANSPORT_STATE_INITIAL, + TRANSPORT_STATE_NEGO, + TRANSPORT_STATE_TLS, + TRANSPORT_STATE_NLA, + TRANSPORT_STATE_FINAL +}; +typedef enum _TRANSPORT_STATE TRANSPORT_STATE; + typedef struct rdp_transport rdpTransport; typedef int (* PacketReceivedCallback) (rdpTransport * transport, STREAM * stream, void* extra); struct rdp_transport { - int sockfd; + TRANSPORT_STATE state; + struct rdp_tcp * tcp; struct crypto_tls * tls; struct timespec ts; STREAM * recv_buffer;