diff --git a/channels/rdpei/client/rdpei_main.c b/channels/rdpei/client/rdpei_main.c index 6f174ee68..d0b17377d 100644 --- a/channels/rdpei/client/rdpei_main.c +++ b/channels/rdpei/client/rdpei_main.c @@ -379,11 +379,21 @@ int rdpei_recv_sc_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) int rdpei_recv_suspend_touch_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) { + RdpeiClientContext* rdpei = (RdpeiClientContext*) callback->plugin->pInterface; + + if (rdpei->SuspendTouch) + rdpei->SuspendTouch(rdpei); + return 0; } int rdpei_recv_resume_touch_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) { + RdpeiClientContext* rdpei = (RdpeiClientContext*) callback->plugin->pInterface; + + if (rdpei->ResumeTouch) + rdpei->ResumeTouch(rdpei); + return 0; } @@ -490,7 +500,7 @@ static int rdpei_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManage (IWTSListenerCallback*) rdpei->listener_callback, &(rdpei->listener)); rdpei->listener->pInterface = rdpei->iface.pInterface; - + InitializeCriticalSection(&rdpei->lock); rdpei->event = CreateEvent(NULL, TRUE, FALSE, NULL); rdpei->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); @@ -675,7 +685,7 @@ int rdpei_touch_end(RdpeiClientContext* context, int externalId, int x, int y) int i; int contactId = -1; RDPINPUT_CONTACT_DATA contact; - RDPINPUT_CONTACT_POINT* contactPoint; + RDPINPUT_CONTACT_POINT* contactPoint = NULL; RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) context->handle; for (i = 0; i < rdpei->maxTouchContacts; i++) diff --git a/client/Mac/cli/AppDelegate.m b/client/Mac/cli/AppDelegate.m index 218f28178..e990c5374 100644 --- a/client/Mac/cli/AppDelegate.m +++ b/client/Mac/cli/AppDelegate.m @@ -59,8 +59,13 @@ void mac_set_view_size(rdpContext* context, MRDPView* view); - (void) applicationWillTerminate:(NSNotification*)notification { + NSLog(@"Stopping...\n"); + freerdp_client_stop(context); + [mrdpView releaseResources]; _singleDelegate = nil; + + NSLog(@"Stopped.\n"); } - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender diff --git a/client/Windows/cli/CMakeLists.txt b/client/Windows/cli/CMakeLists.txt index 7a0437279..2a5c32e1b 100644 --- a/client/Windows/cli/CMakeLists.txt +++ b/client/Windows/cli/CMakeLists.txt @@ -31,6 +31,8 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} wfreerdp-client) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) -install(TARGETS ${MODULE_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT client) +if(VENDOR MATCHES "FreeRDP") + install(TARGETS ${MODULE_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT client) +endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/Windows") diff --git a/client/Windows/wf_event.c b/client/Windows/wf_event.c index 1b8194794..dfd17411f 100644 --- a/client/Windows/wf_event.c +++ b/client/Windows/wf_event.c @@ -31,6 +31,7 @@ #include "wf_gdi.h" #include "wf_event.h" +#include "freerdp/event.h" static HWND g_focus_hWnd; @@ -575,6 +576,8 @@ BOOL wf_scale_blt(wfContext* wfc, HDC hdc, int x, int y, int w, int h, HDC hdcSr void wf_scale_mouse_event(wfContext* wfc, rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) { int ww, wh, dw, dh; + rdpContext* context; + MouseEventEventArgs eventArgs; if (!wfc->client_width) wfc->client_width = wfc->width; @@ -591,4 +594,10 @@ void wf_scale_mouse_event(wfContext* wfc, rdpInput* input, UINT16 flags, UINT16 input->MouseEvent(input, flags, x + wfc->xCurrentScroll, y + wfc->yCurrentScroll); else input->MouseEvent(input, flags, x * dw / ww + wfc->xCurrentScroll, y * dh / wh + wfc->yCurrentScroll); + + eventArgs.flags = flags; + eventArgs.x = x; + eventArgs.y = y; + context = (rdpContext*) wfc; + PubSub_OnMouseEvent(context->pubSub, context, &eventArgs); } diff --git a/client/common/CMakeLists.txt b/client/common/CMakeLists.txt index 07f162386..4b002e2d5 100644 --- a/client/common/CMakeLists.txt +++ b/client/common/CMakeLists.txt @@ -18,6 +18,13 @@ set(MODULE_NAME "freerdp-client") set(MODULE_PREFIX "FREERDP_CLIENT") +# Policy CMP0022: INTERFACE_LINK_LIBRARIES defines the link +# interface. Run "cmake --help-policy CMP0022" for policy details. Use the +# cmake_policy command to set the policy and suppress this warning. +if(POLICY CMP0022) + cmake_policy(SET CMP0022 NEW) +endif() + set(${MODULE_PREFIX}_SRCS client.c cmdline.c @@ -53,10 +60,7 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHI MODULE winpr MODULES winpr-crt winpr-utils) -if(NOT WIN32) - set_target_properties(${MODULE_NAME} PROPERTIES LINK_INTERFACE_LIBRARIES "") - set_target_properties(${MODULE_NAME} PROPERTIES INTERFACE_LINK_LIBRARIES "") -endif() + target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/include/freerdp/client/rdpei.h b/include/freerdp/client/rdpei.h index d7881b11c..76b889829 100644 --- a/include/freerdp/client/rdpei.h +++ b/include/freerdp/client/rdpei.h @@ -70,6 +70,9 @@ typedef int (*pcRdpeiTouchBegin)(RdpeiClientContext* context, int externalId, in typedef int (*pcRdpeiTouchUpdate)(RdpeiClientContext* context, int externalId, int x, int y); typedef int (*pcRdpeiTouchEnd)(RdpeiClientContext* context, int externalId, int x, int y); +typedef int (*pcRdpeiSuspendTouch)(RdpeiClientContext* context); +typedef int (*pcRdpeiResumeTouch)(RdpeiClientContext* context); + struct _rdpei_client_context { void* handle; @@ -82,6 +85,9 @@ struct _rdpei_client_context pcRdpeiTouchBegin TouchBegin; pcRdpeiTouchUpdate TouchUpdate; pcRdpeiTouchEnd TouchEnd; + + pcRdpeiSuspendTouch SuspendTouch; + pcRdpeiResumeTouch ResumeTouch; }; #endif /* FREERDP_CHANNEL_CLIENT_RDPEI_H */ diff --git a/include/freerdp/error.h b/include/freerdp/error.h index a5733bb8a..2f284b4f7 100755 --- a/include/freerdp/error.h +++ b/include/freerdp/error.h @@ -146,6 +146,7 @@ extern "C" { #define ERRINFO_ENCRYPT_FAILED 0x00001193 #define ERRINFO_ENCRYPTION_PACKAGE_MISMATCH 0x00001194 #define ERRINFO_DECRYPT_FAILED2 0x00001195 +#define ERRINFO_PEER_DISCONNECTED 0x00001196 #define ERRINFO_SUCCESS 0x00000000 #define ERRINFO_NONE 0xFFFFFFFF diff --git a/include/freerdp/event.h b/include/freerdp/event.h index 633ea79d5..0100d6988 100644 --- a/include/freerdp/event.h +++ b/include/freerdp/event.h @@ -83,6 +83,12 @@ DEFINE_EVENT_BEGIN(ChannelDisconnected) void* pInterface; DEFINE_EVENT_END(ChannelDisconnected) +DEFINE_EVENT_BEGIN(MouseEvent) + UINT16 flags; + UINT16 x; + UINT16 y; +DEFINE_EVENT_END(MouseEvent) + #ifdef __cplusplus } #endif diff --git a/libfreerdp/core/errinfo.c b/libfreerdp/core/errinfo.c index 44e3d301e..739dc18e4 100644 --- a/libfreerdp/core/errinfo.c +++ b/libfreerdp/core/errinfo.c @@ -385,6 +385,9 @@ int connectErrorCode; #define ERRINFO_DECRYPT_FAILED2_STRING \ "Unencrypted data was encountered in a protocol stream which is meant to be encrypted with Standard RDP Security mechanisms (section 5.3.6)." +#define ERRINFO_PEER_DISCONNECTED_STRING \ + "The peer connection was lost." + /* Special codes */ #define ERRINFO_SUCCESS_STRING "Success." #define ERRINFO_NONE_STRING "" @@ -507,6 +510,7 @@ static const ERRINFO ERRINFO_CODES[] = ERRINFO_DEFINE(ENCRYPT_FAILED), ERRINFO_DEFINE(ENCRYPTION_PACKAGE_MISMATCH), ERRINFO_DEFINE(DECRYPT_FAILED2), + ERRINFO_DEFINE(PEER_DISCONNECTED), ERRINFO_DEFINE(NONE) }; diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index 31222771b..8cb606953 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -375,6 +375,7 @@ static wEventType FreeRDP_Events[] = DEFINE_EVENT_ENTRY(ConnectionResult) DEFINE_EVENT_ENTRY(ChannelConnected) DEFINE_EVENT_ENTRY(ChannelDisconnected) + DEFINE_EVENT_ENTRY(MouseEvent) }; /** Allocator function for a rdp context. diff --git a/libfreerdp/core/gateway/rpc.c b/libfreerdp/core/gateway/rpc.c index 4df8c0da8..920548937 100644 --- a/libfreerdp/core/gateway/rpc.c +++ b/libfreerdp/core/gateway/rpc.c @@ -447,7 +447,9 @@ int rpc_write(rdpRpc* rpc, BYTE* data, int length, UINT16 opnum) offset += Buffers[1].cbBuffer; free(Buffers[1].pvBuffer); - rpc_send_enqueue_pdu(rpc, buffer, request_pdu->frag_length); + if (rpc_send_enqueue_pdu(rpc, buffer, request_pdu->frag_length) != 0) + length = -1; + free(request_pdu); return length; diff --git a/libfreerdp/core/gateway/rpc_bind.c b/libfreerdp/core/gateway/rpc_bind.c index 72a254381..4057263fc 100644 --- a/libfreerdp/core/gateway/rpc_bind.c +++ b/libfreerdp/core/gateway/rpc_bind.c @@ -215,7 +215,8 @@ int rpc_send_bind_pdu(rdpRpc* rpc) clientCall = rpc_client_call_new(bind_pdu->call_id, 0); ArrayList_Add(rpc->client->ClientCallList, clientCall); - rpc_send_enqueue_pdu(rpc, buffer, length); + if (rpc_send_enqueue_pdu(rpc, buffer, length) != 0) + length = -1; free(bind_pdu->p_context_elem.p_cont_elem[0].transfer_syntaxes); free(bind_pdu->p_context_elem.p_cont_elem[1].transfer_syntaxes); @@ -330,7 +331,8 @@ int rpc_send_rpc_auth_3_pdu(rdpRpc* rpc) clientCall = rpc_client_call_new(auth_3_pdu->call_id, 0); ArrayList_Add(rpc->client->ClientCallList, clientCall); - rpc_send_enqueue_pdu(rpc, buffer, length); + if (rpc_send_enqueue_pdu(rpc, buffer, length) != 0) + length = -1; free(auth_3_pdu); diff --git a/libfreerdp/core/gateway/rpc_client.c b/libfreerdp/core/gateway/rpc_client.c index 42843faab..827c5283e 100644 --- a/libfreerdp/core/gateway/rpc_client.c +++ b/libfreerdp/core/gateway/rpc_client.c @@ -25,6 +25,8 @@ #include #include +#include + #include #include #include @@ -37,6 +39,8 @@ #include "../rdp.h" +#define SYNCHRONOUS_TIMEOUT 5000 + wStream* rpc_client_fragment_pool_take(rdpRpc* rpc) { wStream* fragment = NULL; @@ -364,6 +368,7 @@ void rpc_client_call_free(RpcClientCall* clientCall) int rpc_send_enqueue_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length) { RPC_PDU* pdu; + int status; pdu = (RPC_PDU*) malloc(sizeof(RPC_PDU)); pdu->s = Stream_New(buffer, length); @@ -372,7 +377,13 @@ int rpc_send_enqueue_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length) if (rpc->client->SynchronousSend) { - WaitForSingleObject(rpc->client->PduSentEvent, INFINITE); + status = WaitForSingleObject(rpc->client->PduSentEvent, SYNCHRONOUS_TIMEOUT); + if (status == WAIT_TIMEOUT) + { + fprintf(stderr, "rpc_send_enqueue_pdu: timed out waiting for pdu sent event\n"); + return -1; + } + ResetEvent(rpc->client->PduSentEvent); } @@ -427,11 +438,19 @@ RPC_PDU* rpc_recv_dequeue_pdu(rdpRpc* rpc) { RPC_PDU* pdu; DWORD dwMilliseconds; + DWORD result; pdu = NULL; - dwMilliseconds = rpc->client->SynchronousReceive ? INFINITE : 0; + dwMilliseconds = rpc->client->SynchronousReceive ? SYNCHRONOUS_TIMEOUT : 0; - if (WaitForSingleObject(Queue_Event(rpc->client->ReceiveQueue), dwMilliseconds) == WAIT_OBJECT_0) + result = WaitForSingleObject(Queue_Event(rpc->client->ReceiveQueue), dwMilliseconds); + if (result == WAIT_TIMEOUT) + { + fprintf(stderr, "rpc_recv_dequeue_pdu: timed out waiting for receive event\n"); + return NULL; + } + + if (result == WAIT_OBJECT_0) { pdu = (RPC_PDU*) Queue_Dequeue(rpc->client->ReceiveQueue); @@ -454,11 +473,18 @@ RPC_PDU* rpc_recv_peek_pdu(rdpRpc* rpc) { RPC_PDU* pdu; DWORD dwMilliseconds; + DWORD result; pdu = NULL; - dwMilliseconds = rpc->client->SynchronousReceive ? INFINITE : 0; + dwMilliseconds = rpc->client->SynchronousReceive ? SYNCHRONOUS_TIMEOUT : 0; - if (WaitForSingleObject(Queue_Event(rpc->client->ReceiveQueue), dwMilliseconds) == WAIT_OBJECT_0) + result = WaitForSingleObject(Queue_Event(rpc->client->ReceiveQueue), dwMilliseconds); + if (result == WAIT_TIMEOUT) + { + return NULL; + } + + if (result == WAIT_OBJECT_0) { pdu = (RPC_PDU*) Queue_Peek(rpc->client->ReceiveQueue); return pdu; @@ -484,24 +510,27 @@ static void* rpc_client_thread(void* arg) events[nCount++] = Queue_Event(rpc->client->SendQueue); events[nCount++] = ReadEvent; - while (1) + while (rpc->transport->layer != TRANSPORT_LAYER_CLOSED) { - status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + status = WaitForMultipleObjects(nCount, events, FALSE, 100); - if (WaitForSingleObject(rpc->client->StopEvent, 0) == WAIT_OBJECT_0) + if (status != WAIT_TIMEOUT) { - break; - } - - if (WaitForSingleObject(ReadEvent, 0) == WAIT_OBJECT_0) - { - if (rpc_client_on_read_event(rpc) < 0) + if (WaitForSingleObject(rpc->client->StopEvent, 0) == WAIT_OBJECT_0) + { break; - } + } - if (WaitForSingleObject(Queue_Event(rpc->client->SendQueue), 0) == WAIT_OBJECT_0) - { - rpc_send_dequeue_pdu(rpc); + if (WaitForSingleObject(ReadEvent, 0) == WAIT_OBJECT_0) + { + if (rpc_client_on_read_event(rpc) < 0) + break; + } + + if (WaitForSingleObject(Queue_Event(rpc->client->SendQueue), 0) == WAIT_OBJECT_0) + { + rpc_send_dequeue_pdu(rpc); + } } } diff --git a/libfreerdp/core/gateway/tsg.c b/libfreerdp/core/gateway/tsg.c index be891abfa..a4cbd9a2a 100644 --- a/libfreerdp/core/gateway/tsg.c +++ b/libfreerdp/core/gateway/tsg.c @@ -1494,6 +1494,12 @@ int tsg_read(rdpTsg* tsg, BYTE* data, UINT32 length) rpc = tsg->rpc; + if (rpc->transport->layer == TRANSPORT_LAYER_CLOSED) + { + fprintf(stderr, "tsg_read error: connection lost\n"); + return -1; + } + if (tsg->PendingPdu) { CopyLength = (length < tsg->BytesAvailable) ? length : tsg->BytesAvailable; @@ -1546,6 +1552,12 @@ int tsg_read(rdpTsg* tsg, BYTE* data, UINT32 length) int tsg_write(rdpTsg* tsg, BYTE* data, UINT32 length) { + if (tsg->rpc->transport->layer == TRANSPORT_LAYER_CLOSED) + { + fprintf(stderr, "tsg_write error: connection lost\n"); + return -1; + } + return TsProxySendToServer((handle_t) tsg, data, 1, &length); } diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c index af13403eb..5bd5171e0 100644 --- a/libfreerdp/core/rdp.c +++ b/libfreerdp/core/rdp.c @@ -1220,6 +1220,7 @@ rdpRdp* rdp_new(rdpContext* context) rdp->extension = extension_new(context->instance); rdp->transport = transport_new(rdp->settings); + rdp->transport->rdp = rdp; rdp->license = license_new(rdp); rdp->input = input_new(rdp); rdp->update = update_new(rdp); @@ -1268,6 +1269,7 @@ void rdp_reset(rdpRdp* rdp) settings->ClientAddress = NULL; rdp->transport = transport_new(rdp->settings); + rdp->transport->rdp = rdp; rdp->license = license_new(rdp); rdp->nego = nego_new(rdp->transport); rdp->mcs = mcs_new(rdp->transport); diff --git a/libfreerdp/core/rdp.h b/libfreerdp/core/rdp.h index 1f7722252..75f85708e 100644 --- a/libfreerdp/core/rdp.h +++ b/libfreerdp/core/rdp.h @@ -223,4 +223,6 @@ void rdp_free(rdpRdp* rdp); BOOL rdp_decrypt(rdpRdp* rdp, wStream* s, int length, UINT16 securityFlags); +BOOL rdp_set_error_info(rdpRdp* rdp, UINT32 errorInfo); + #endif /* __RDP_H */ diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index f0fe28d50..c609afe27 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -46,6 +46,7 @@ #include "tpkt.h" #include "fastpath.h" #include "transport.h" +#include "rdp.h" #define BUFFER_SIZE 16384 @@ -82,7 +83,7 @@ BOOL transport_disconnect(rdpTransport* transport) if ((transport->layer == TRANSPORT_LAYER_TSG) || (transport->layer == TRANSPORT_LAYER_TSG_TLS)) { - tsg_disconnect(transport->tsg); + status &= tsg_disconnect(transport->tsg); } else { @@ -129,12 +130,12 @@ static int transport_bio_tsg_write(BIO* bio, const char* buf, int num) BIO_clear_retry_flags(bio); - if (status <= 0) + if (status == 0) { BIO_set_retry_write(bio); } - return num; + return status < 0 ? 0 : num; } static int transport_bio_tsg_read(BIO* bio, char* buf, int size) @@ -147,12 +148,17 @@ static int transport_bio_tsg_read(BIO* bio, char* buf, int size) BIO_clear_retry_flags(bio); - if (status <= 0) + if (status == 0) { BIO_set_retry_read(bio); + status = -1; + } + else if (status == -1) + { + status = 0; } - return status > 0 ? status : -1; + return status >= 0 ? status : -1; } static int transport_bio_tsg_puts(BIO* bio, const char* str) @@ -556,7 +562,11 @@ int transport_read_layer(rdpTransport* transport, BYTE* data, int bytes) return status; if (status < 0) + { + /* A read error indicates that the peer has dropped the connection */ + transport->layer = TRANSPORT_LAYER_CLOSED; return status; + } read += status; @@ -853,115 +863,125 @@ int transport_check_fds(rdpTransport* transport) #endif ResetEvent(transport->ReceiveEvent); - status = transport_read_nonblocking(transport); - - if (status < 0) - return status; - - while ((pos = Stream_GetPosition(transport->ReceiveBuffer)) > 0) + /** + * Loop through and read all available PDUs. Since multiple + * PDUs can exist, it's important to deliver them all before + * returning. Otherwise we run the risk of having a thread + * wait for a socket to get signalled that data is available + * (which may never happen). + */ + for (;;) { - Stream_SetPosition(transport->ReceiveBuffer, 0); + status = transport_read_nonblocking(transport); - if (tpkt_verify_header(transport->ReceiveBuffer)) /* TPKT */ - { - /* Ensure the TPKT header is available. */ - if (pos <= 4) - { - Stream_SetPosition(transport->ReceiveBuffer, pos); - return 0; - } - - length = tpkt_read_header(transport->ReceiveBuffer); - } - else if (nla_verify_header(transport->ReceiveBuffer)) - { - /* TSRequest */ - - /* Ensure the TSRequest header is available. */ - if (pos <= 4) - { - Stream_SetPosition(transport->ReceiveBuffer, pos); - return 0; - } - - /* TSRequest header can be 2, 3 or 4 bytes long */ - length = nla_header_length(transport->ReceiveBuffer); - - if (pos < length) - { - Stream_SetPosition(transport->ReceiveBuffer, pos); - return 0; - } - - length = nla_read_header(transport->ReceiveBuffer); - } - else /* Fast Path */ - { - /* Ensure the Fast Path header is available. */ - if (pos <= 2) - { - Stream_SetPosition(transport->ReceiveBuffer, pos); - return 0; - } - - /* Fastpath header can be two or three bytes long. */ - length = fastpath_header_length(transport->ReceiveBuffer); - - if (pos < length) - { - Stream_SetPosition(transport->ReceiveBuffer, pos); - return 0; - } - - length = fastpath_read_header(NULL, transport->ReceiveBuffer); - } - - if (length == 0) - { - fprintf(stderr, "transport_check_fds: protocol error, not a TPKT or Fast Path header.\n"); - winpr_HexDump(Stream_Buffer(transport->ReceiveBuffer), pos); - return -1; - } - - if (pos < length) - { - Stream_SetPosition(transport->ReceiveBuffer, pos); - return 0; /* Packet is not yet completely received. */ - } - - received = transport->ReceiveBuffer; - transport->ReceiveBuffer = StreamPool_Take(transport->ReceivePool, 0); - - Stream_SetPosition(received, length); - Stream_SealLength(received); - Stream_SetPosition(received, 0); - - /** - * status: - * -1: error - * 0: success - * 1: redirection - */ - - recv_status = transport->ReceiveCallback(transport, received, transport->ReceiveExtra); - - if (recv_status == 1) - { - /** - * Last call to ReceiveCallback resulted in a session redirection, - * which means the current rdpTransport* transport pointer has been freed. - * Return 0 for success, the rest of this function is meant for non-redirected cases. - */ - return 0; - } - - Stream_Release(received); - - if (recv_status < 0) - status = -1; - - if (status < 0) + if (status <= 0) return status; + + while ((pos = Stream_GetPosition(transport->ReceiveBuffer)) > 0) + { + Stream_SetPosition(transport->ReceiveBuffer, 0); + + if (tpkt_verify_header(transport->ReceiveBuffer)) /* TPKT */ + { + /* Ensure the TPKT header is available. */ + if (pos <= 4) + { + Stream_SetPosition(transport->ReceiveBuffer, pos); + return 0; + } + + length = tpkt_read_header(transport->ReceiveBuffer); + } + else if (nla_verify_header(transport->ReceiveBuffer)) + { + /* TSRequest */ + + /* Ensure the TSRequest header is available. */ + if (pos <= 4) + { + Stream_SetPosition(transport->ReceiveBuffer, pos); + return 0; + } + + /* TSRequest header can be 2, 3 or 4 bytes long */ + length = nla_header_length(transport->ReceiveBuffer); + + if (pos < length) + { + Stream_SetPosition(transport->ReceiveBuffer, pos); + return 0; + } + + length = nla_read_header(transport->ReceiveBuffer); + } + else /* Fast Path */ + { + /* Ensure the Fast Path header is available. */ + if (pos <= 2) + { + Stream_SetPosition(transport->ReceiveBuffer, pos); + return 0; + } + + /* Fastpath header can be two or three bytes long. */ + length = fastpath_header_length(transport->ReceiveBuffer); + + if (pos < length) + { + Stream_SetPosition(transport->ReceiveBuffer, pos); + return 0; + } + + length = fastpath_read_header(NULL, transport->ReceiveBuffer); + } + + if (length == 0) + { + fprintf(stderr, "transport_check_fds: protocol error, not a TPKT or Fast Path header.\n"); + winpr_HexDump(Stream_Buffer(transport->ReceiveBuffer), pos); + return -1; + } + + if (pos < length) + { + Stream_SetPosition(transport->ReceiveBuffer, pos); + return 0; /* Packet is not yet completely received. */ + } + + received = transport->ReceiveBuffer; + transport->ReceiveBuffer = StreamPool_Take(transport->ReceivePool, 0); + + Stream_SetPosition(received, length); + Stream_SealLength(received); + Stream_SetPosition(received, 0); + + /** + * status: + * -1: error + * 0: success + * 1: redirection + */ + + recv_status = transport->ReceiveCallback(transport, received, transport->ReceiveExtra); + + if (recv_status == 1) + { + /** + * Last call to ReceiveCallback resulted in a session redirection, + * which means the current rdpTransport* transport pointer has been freed. + * Return 0 for success, the rest of this function is meant for non-redirected cases. + */ + return 0; + } + + Stream_Release(received); + + if (recv_status < 0) + status = -1; + + if (status < 0) + return status; + } } return 0; @@ -1035,13 +1055,21 @@ static void* transport_client_thread(void* arg) transport_get_read_handles(transport, (HANDLE*) &handles, &nCount); - status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE); - - if (WaitForSingleObject(transport->stopEvent, 0) == WAIT_OBJECT_0) + status = WaitForMultipleObjects(nCount, handles, FALSE, 100); + if (transport->layer == TRANSPORT_LAYER_CLOSED) + { + rdpRdp* rdp = (rdpRdp*) transport->rdp; + rdp_set_error_info(rdp, ERRINFO_PEER_DISCONNECTED); break; + } + else if (status != WAIT_TIMEOUT) + { + if (WaitForSingleObject(transport->stopEvent, 0) == WAIT_OBJECT_0) + break; - if (!freerdp_check_fds(instance)) - break; + if (!freerdp_check_fds(instance)) + break; + } } WLog_Print(transport->log, WLOG_DEBUG, "Terminating transport thread"); diff --git a/libfreerdp/core/transport.h b/libfreerdp/core/transport.h index 1525b19ee..1ba273f7a 100644 --- a/libfreerdp/core/transport.h +++ b/libfreerdp/core/transport.h @@ -78,6 +78,7 @@ struct rdp_transport CRITICAL_SECTION ReadLock; CRITICAL_SECTION WriteLock; wLog* log; + void* rdp; }; wStream* transport_send_stream_init(rdpTransport* transport, int size); diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index d2168b39e..8313a0f72 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -464,7 +464,12 @@ int tls_write(rdpTls* tls, BYTE* data, int length) status = SSL_write(tls->ssl, data, length); - if (status <= 0) + if (status == 0) + { + return -1; /* peer disconnected */ + } + + if (status < 0) { error = SSL_get_error(tls->ssl, status); diff --git a/winpr/libwinpr/file/file.c b/winpr/libwinpr/file/file.c index 7d8fb3ab0..95a71887f 100644 --- a/winpr/libwinpr/file/file.c +++ b/winpr/libwinpr/file/file.c @@ -311,6 +311,10 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, PVOID Object; BOOL status = TRUE; + if (hFile == INVALID_HANDLE_VALUE) { + return FALSE; + } + /* * from http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=vs.85%29.aspx * lpNumberOfBytesRead can be NULL only when the lpOverlapped parameter is not NULL. @@ -464,6 +468,10 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, PVOID Object; BOOL status = TRUE; + if (hFile == INVALID_HANDLE_VALUE) { + return FALSE; + } + if (!winpr_Handle_GetInfo(hFile, &Type, &Object)) return FALSE; diff --git a/winpr/libwinpr/synch/wait.c b/winpr/libwinpr/synch/wait.c index 304b6e9fd..f3a6a9510 100644 --- a/winpr/libwinpr/synch/wait.c +++ b/winpr/libwinpr/synch/wait.c @@ -155,11 +155,8 @@ static void ts_add_ms(struct timespec *ts, DWORD dwMilliseconds) ts->tv_sec += dwMilliseconds / 1000L; ts->tv_nsec += (dwMilliseconds % 1000L) * 1000000L; - while(ts->tv_nsec >= 1000000000L) - { - ts->tv_sec ++; - ts->tv_nsec -= 1000000000L; - } + ts->tv_sec += ts->tv_nsec / 1000000000L; + ts->tv_nsec = ts->tv_nsec % 1000000000L; } DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)