diff --git a/libfreerdp/core/gateway/rpc_client.c b/libfreerdp/core/gateway/rpc_client.c index d88cff81b..173cb125d 100644 --- a/libfreerdp/core/gateway/rpc_client.c +++ b/libfreerdp/core/gateway/rpc_client.c @@ -470,32 +470,23 @@ RPC_PDU* rpc_recv_peek_pdu(rdpRpc* rpc) static void* rpc_client_thread(void* arg) { - int fd; DWORD status; DWORD nCount; HANDLE events[3]; HANDLE ReadEvent; rdpRpc* rpc = (rdpRpc*) arg; - fd = BIO_get_fd(rpc->TlsOut->bio, NULL); - ReadEvent = CreateFileDescriptorEvent(NULL, TRUE, FALSE, fd); + if (!BIO_get_event(rpc->TlsOut->bio, &ReadEvent)) + { + WLog_ERR(TAG, "rpc_client_thread: failed to obtain read event from underlying BIO"); + goto out; + } nCount = 0; events[nCount++] = rpc->client->StopEvent; events[nCount++] = Queue_Event(rpc->client->SendQueue); events[nCount++] = ReadEvent; - /* Do a first free run in case some bytes were set from the HTTP headers. - * We also have to do it because most of the time the underlying socket has notified, - * and the ssl layer has eaten all bytes, so we won't be notified any more even if the - * bytes are buffered locally - */ - if (rpc_client_on_read_event(rpc) < 0) - { - WLog_ERR(TAG, "an error occurred when treating first packet"); - goto out; - } - while (rpc->transport->layer != TRANSPORT_LAYER_CLOSED) { status = WaitForMultipleObjects(nCount, events, FALSE, 100); @@ -522,7 +513,6 @@ static void* rpc_client_thread(void* arg) } out: - CloseHandle(ReadEvent); return NULL; } diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c index 83d04edf5..7563d37c9 100644 --- a/libfreerdp/core/tcp.c +++ b/libfreerdp/core/tcp.c @@ -174,6 +174,56 @@ static long transport_bio_simple_ctrl(BIO* bio, int cmd, long arg1, void* arg2) { int status = -1; + if (cmd == BIO_C_GET_EVENT) + { + if (!bio->init || !arg2) + return 0; + +#ifndef _WIN32 + if (!bio->ptr) + bio->ptr = CreateFileDescriptorEvent(NULL, FALSE, FALSE, bio->num); +#else + if (!bio->ptr) + bio->ptr = (void*) WSACreateEvent(); + + WSAEventSelect(bio->num, (HANDLE) bio->ptr, FD_READ); +#endif + + *((ULONG_PTR*) arg2) = (ULONG_PTR) bio->ptr; + + return 1; + } + else if (cmd == BIO_C_SET_NONBLOCK) + { +#ifndef _WIN32 + int flags; + + flags = fcntl(bio->num, F_GETFL); + + if (flags == -1) + return 0; + + if (arg1) + fcntl(bio->num, F_SETFL, flags | O_NONBLOCK); + else + fcntl(bio->num, F_SETFL, flags & ~(O_NONBLOCK)); +#else + if (arg1) + { + if (!bio->ptr) + bio->ptr = (void*) WSACreateEvent(); + + WSAEventSelect(bio->num, (HANDLE) bio->ptr, FD_READ); + } + else + { + if (bio->ptr) + WSAEventSelect(bio->num, (HANDLE) bio->ptr, 0); + } +#endif + return 1; + } + switch (cmd) { case BIO_C_SET_FD: @@ -228,6 +278,7 @@ static int transport_bio_simple_new(BIO* bio) bio->num = 0; bio->ptr = NULL; bio->flags = BIO_FLAGS_SHOULD_RETRY; + return 1; } @@ -239,7 +290,15 @@ static int transport_bio_simple_free(BIO* bio) if (bio->shutdown) { if (bio->init) + { + if (bio->ptr) + { + CloseHandle((HANDLE) bio->ptr); + bio->ptr = NULL; + } + closesocket((SOCKET) bio->num); + } bio->init = 0; bio->flags = 0; @@ -931,7 +990,7 @@ BOOL freerdp_tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeou BIO_set_fd(tcp->socketBio, tcp->sockfd, BIO_CLOSE); } - SetEventFileDescriptor(tcp->event, tcp->sockfd); + BIO_get_event(tcp->socketBio, &tcp->event); freerdp_tcp_get_ip_address(tcp); freerdp_tcp_get_mac_address(tcp); @@ -994,49 +1053,7 @@ BOOL freerdp_tcp_disconnect(rdpTcp* tcp) BOOL freerdp_tcp_set_blocking_mode(rdpTcp* tcp, BOOL blocking) { -#ifndef _WIN32 - int flags; - flags = fcntl(tcp->sockfd, F_GETFL); - - if (flags == -1) - { - WLog_ERR(TAG, "fcntl failed, %s.", strerror(errno)); - return FALSE; - } - - if (blocking == TRUE) - fcntl(tcp->sockfd, F_SETFL, flags & ~(O_NONBLOCK)); - else - fcntl(tcp->sockfd, F_SETFL, flags | O_NONBLOCK); -#else - /** - * ioctlsocket function: - * msdn.microsoft.com/en-ca/library/windows/desktop/ms738573/ - * - * The WSAAsyncSelect and WSAEventSelect functions automatically set a socket to nonblocking mode. - * If WSAAsyncSelect or WSAEventSelect has been issued on a socket, then any attempt to use - * ioctlsocket to set the socket back to blocking mode will fail with WSAEINVAL. - * - * To set the socket back to blocking mode, an application must first disable WSAAsyncSelect - * by calling WSAAsyncSelect with the lEvent parameter equal to zero, or disable WSAEventSelect - * by calling WSAEventSelect with the lNetworkEvents parameter equal to zero. - */ - - if (blocking == TRUE) - { - if (tcp->event) - WSAEventSelect(tcp->sockfd, tcp->event, 0); - } - else - { - if (!tcp->event) - tcp->event = WSACreateEvent(); - - WSAEventSelect(tcp->sockfd, tcp->event, FD_READ); - } -#endif - - return TRUE; + return BIO_set_nonblock(tcp->socketBio, blocking ? 0 : 1) ? TRUE : FALSE; } BOOL freerdp_tcp_set_keep_alive_mode(rdpTcp* tcp) @@ -1102,7 +1119,6 @@ BOOL freerdp_tcp_set_keep_alive_mode(rdpTcp* tcp) int freerdp_tcp_attach(rdpTcp* tcp, int sockfd) { tcp->sockfd = sockfd; - SetEventFileDescriptor(tcp->event, tcp->sockfd); ringbuffer_commit_read_bytes(&tcp->xmitBuffer, ringbuffer_used(&tcp->xmitBuffer)); @@ -1133,7 +1149,9 @@ int freerdp_tcp_attach(rdpTcp* tcp, int sockfd) tcp->bufferedBio = BIO_push(tcp->bufferedBio, tcp->socketBio); } - return 0; + BIO_get_event(tcp->socketBio, &tcp->event); + + return 1; } HANDLE freerdp_tcp_get_event_handle(rdpTcp* tcp) @@ -1235,19 +1253,8 @@ rdpTcp* freerdp_tcp_new(rdpSettings* settings) tcp->sockfd = -1; tcp->settings = settings; - if (0) - goto out_ringbuffer; /* avoid unreferenced label warning on Windows */ - -#ifndef _WIN32 - tcp->event = CreateFileDescriptorEvent(NULL, FALSE, FALSE, tcp->sockfd); - - if (!tcp->event || tcp->event == INVALID_HANDLE_VALUE) - goto out_ringbuffer; -#endif - return tcp; -out_ringbuffer: - ringbuffer_destroy(&tcp->xmitBuffer); + out_free: free(tcp); return NULL; @@ -1259,6 +1266,18 @@ void freerdp_tcp_free(rdpTcp* tcp) return; ringbuffer_destroy(&tcp->xmitBuffer); - CloseHandle(tcp->event); + + if (tcp->socketBio) + { + BIO_free(tcp->socketBio); + tcp->socketBio = NULL; + } + + if (tcp->bufferedBio) + { + BIO_free(tcp->bufferedBio); + tcp->bufferedBio = NULL; + } + free(tcp); } diff --git a/libfreerdp/core/tcp.h b/libfreerdp/core/tcp.h index d2dd6340c..b34f82b73 100644 --- a/libfreerdp/core/tcp.h +++ b/libfreerdp/core/tcp.h @@ -41,6 +41,11 @@ #define BIO_TYPE_SIMPLE 66 #define BIO_TYPE_BUFFERED 67 +#define BIO_C_GET_EVENT 1101 +#define BIO_C_SET_NONBLOCK 1102 +#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) + typedef struct rdp_tcp rdpTcp; struct rdp_tcp diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index c5e411b04..fac237a0e 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -391,8 +391,10 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 freerdp* instance; rdpContext* context; rdpSettings* settings = transport->settings; + instance = (freerdp*) transport->settings->instance; context = instance->context; + tsg = tsg_new(transport); if (!tsg) @@ -424,6 +426,7 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 transport->TlsIn->hostname = transport->TlsOut->hostname = settings->GatewayHostname; transport->TlsIn->port = transport->TlsOut->port = settings->GatewayPort; + transport->TlsIn->isGatewayTransport = TRUE; tls_status = tls_connect(transport->TlsIn, transport->TcpIn->bufferedBio); @@ -467,6 +470,7 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 transport->frontBio = BIO_new(BIO_s_tsg()); transport->frontBio->ptr = tsg; + return TRUE; }