From 3d7524cac91b4b33d07a5664923af8987ecdfdd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Tue, 3 Jun 2014 13:00:03 -0400 Subject: [PATCH] channels/drdynvc: add state machine, add workaround for missing capabilities pdu --- channels/drdynvc/client/drdynvc_main.c | 57 +++++++++++++++++++------- channels/drdynvc/client/drdynvc_main.h | 12 ++++++ 2 files changed, 55 insertions(+), 14 deletions(-) diff --git a/channels/drdynvc/client/drdynvc_main.c b/channels/drdynvc/client/drdynvc_main.c index b1a6ed588..0b83753b0 100644 --- a/channels/drdynvc/client/drdynvc_main.c +++ b/channels/drdynvc/client/drdynvc_main.c @@ -153,12 +153,32 @@ int drdynvc_push_event(drdynvcPlugin* drdynvc, wMessage* event) return 0; } +static int drdynvc_send_capability_response(drdynvcPlugin* drdynvc) +{ + int status; + wStream* data_out; + + data_out = Stream_New(NULL, 4); + Stream_Write_UINT16(data_out, 0x0050); /* Cmd+Sp+cbChId+Pad. Note: MSTSC sends 0x005c */ + Stream_Write_UINT16(data_out, drdynvc->version); + + status = svc_plugin_send((rdpSvcPlugin*) drdynvc, data_out); + + if (status != CHANNEL_RC_OK) + { + DEBUG_WARN("VirtualChannelWrite failed %d", status); + return 1; + } + + return status; +} + static int drdynvc_process_capability_request(drdynvcPlugin* drdynvc, int Sp, int cbChId, wStream* s) { - wStream* data_out; - int error; + int status; DEBUG_DVC("Sp=%d cbChId=%d", Sp, cbChId); + Stream_Seek(s, 1); /* pad */ Stream_Read_UINT16(s, drdynvc->version); @@ -173,18 +193,11 @@ static int drdynvc_process_capability_request(drdynvcPlugin* drdynvc, int Sp, in Stream_Read_UINT16(s, drdynvc->PriorityCharge3); } - data_out = Stream_New(NULL, 4); - Stream_Write_UINT16(data_out, 0x0050); /* Cmd+Sp+cbChId+Pad. Note: MSTSC sends 0x005c */ - Stream_Write_UINT16(data_out, drdynvc->version); - error = svc_plugin_send((rdpSvcPlugin*) drdynvc, data_out); + status = drdynvc_send_capability_response(drdynvc); - if (error != CHANNEL_RC_OK) - { - DEBUG_WARN("VirtualChannelWrite failed %d", error); - return 1; - } + drdynvc->channel_error = status; - drdynvc->channel_error = error; + drdynvc->state = DRDYNVC_STATE_READY; return 0; } @@ -219,6 +232,19 @@ static int drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, int cb wStream* data_out; int channel_status; + if (drdynvc->state == DRDYNVC_STATE_CAPABILITIES) + { + /** + * For some reason the server does not always send the + * capabilities pdu as it should. When this happens, + * send a capabilities response. + */ + + drdynvc->version = 3; + drdynvc_send_capability_response(drdynvc); + drdynvc->state = DRDYNVC_STATE_READY; + } + ChannelId = drdynvc_read_variable_uint(s, cbChId); pos = Stream_GetPosition(s); DEBUG_DVC("ChannelId=%d ChannelName=%s", ChannelId, Stream_Pointer(s)); @@ -381,6 +407,8 @@ static void drdynvc_process_connect(rdpSvcPlugin* plugin) } dvcman_init(drdynvc->channel_mgr); + + drdynvc->state = DRDYNVC_STATE_CAPABILITIES; } static void drdynvc_process_event(rdpSvcPlugin* plugin, wMessage* event) @@ -419,8 +447,7 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) DrdynvcClientContext* context; CHANNEL_ENTRY_POINTS_FREERDP* pEntryPointsEx; - _p = (drdynvcPlugin*) malloc(sizeof(drdynvcPlugin)); - ZeroMemory(_p, sizeof(drdynvcPlugin)); + _p = (drdynvcPlugin*) calloc(1, sizeof(drdynvcPlugin)); _p->plugin.channel_def.options = CHANNEL_OPTION_INITIALIZED | @@ -429,6 +456,8 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) strcpy(_p->plugin.channel_def.name, "drdynvc"); + _p->state = DRDYNVC_STATE_INITIAL; + _p->plugin.connect_callback = drdynvc_process_connect; _p->plugin.receive_callback = drdynvc_process_receive; _p->plugin.event_callback = drdynvc_process_event; diff --git a/channels/drdynvc/client/drdynvc_main.h b/channels/drdynvc/client/drdynvc_main.h index 369084a19..4eda9d8f5 100644 --- a/channels/drdynvc/client/drdynvc_main.h +++ b/channels/drdynvc/client/drdynvc_main.h @@ -26,6 +26,17 @@ #include #include +enum _DRDYNVC_STATE +{ + DRDYNVC_STATE_INITIAL, + DRDYNVC_STATE_CAPABILITIES, + DRDYNVC_STATE_READY, + DRDYNVC_STATE_OPENING_CHANNEL, + DRDYNVC_STATE_SEND_RECEIVE, + DRDYNVC_STATE_FINAL +}; +typedef enum _DRDYNVC_STATE DRDYNVC_STATE; + #define CREATE_REQUEST_PDU 0x01 #define DATA_FIRST_PDU 0x02 #define DATA_PDU 0x03 @@ -38,6 +49,7 @@ struct drdynvc_plugin { rdpSvcPlugin plugin; + DRDYNVC_STATE state; DrdynvcClientContext* context; int version;