From f9e5709e6404197d418d58a670100eeedff4ea46 Mon Sep 17 00:00:00 2001 From: Vic Lee Date: Sun, 24 Jun 2012 23:35:32 +0800 Subject: [PATCH] wtsvc: add server drdynvc capabilities exchange. --- libfreerdp-channels/wtsvc.c | 137 ++++++++++++++++++++++++++---------- libfreerdp-channels/wtsvc.h | 11 ++- 2 files changed, 108 insertions(+), 40 deletions(-) diff --git a/libfreerdp-channels/wtsvc.c b/libfreerdp-channels/wtsvc.c index 45aaf6964..21dd1c8c0 100644 --- a/libfreerdp-channels/wtsvc.c +++ b/libfreerdp-channels/wtsvc.c @@ -26,6 +26,12 @@ #include "wtsvc.h" +#define CREATE_REQUEST_PDU 0x01 +#define DATA_FIRST_PDU 0x02 +#define DATA_PDU 0x03 +#define CLOSE_REQUEST_PDU 0x04 +#define CAPABILITY_REQUEST_PDU 0x05 + typedef struct wts_data_item { uint16 channel_id; @@ -39,6 +45,51 @@ static void wts_data_item_free(wts_data_item* item) xfree(item); } +static void wts_read_drdynvc_capabilities_response(rdpPeerChannel* channel, uint32 length) +{ + uint16 Version; + + if (length < 3) + return; + stream_seek_uint8(channel->receive_data); /* Pad (1 byte) */ + stream_read_uint16(channel->receive_data, Version); + + printf("version: %d\n", Version); + channel->vcm->drdynvc_state = DRDYNVC_STATE_READY; +} + +static void wts_read_drdynvc_pdu(rdpPeerChannel* channel) +{ + uint32 length; + int value; + int Cmd; + int Sp; + int cbChId; + + length = stream_get_pos(channel->receive_data); + if (length < 1) + return; + stream_set_pos(channel->receive_data, 0); + stream_read_uint8(channel->receive_data, value); + length--; + Cmd = (value & 0xf0) >> 4; + Sp = (value & 0x0c) >> 2; + cbChId = (value & 0x03) >> 0; + + if (Cmd == CAPABILITY_REQUEST_PDU) + { + wts_read_drdynvc_capabilities_response(channel, length); + } + else if (channel->vcm->drdynvc_state == DRDYNVC_STATE_READY) + { + /* TODO: process other drdynvc commands */ + } + else + { + printf("wts_read_drdynvc_pdu: received Cmd %d but channel is not ready.\n", Cmd); + } +} + static void WTSProcessChannelData(rdpPeerChannel* channel, int channelId, uint8* data, int size, int flags, int total_size) { wts_data_item* item; @@ -57,9 +108,9 @@ static void WTSProcessChannelData(rdpPeerChannel* channel, int channelId, uint8* { printf("WTSProcessChannelData: read error\n"); } - if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_DVC) + if (channel == channel->vcm->drdynvc_channel) { - /* TODO: Receive DVC channel data */ + wts_read_drdynvc_pdu(channel); } else { @@ -153,6 +204,22 @@ boolean WTSVirtualChannelManagerCheckFileDescriptor(WTSVirtualChannelManager* vc { boolean result = true; wts_data_item* item; + rdpPeerChannel* channel; + uint32 dynvc_caps; + + if (vcm->drdynvc_state == DRDYNVC_STATE_NONE && vcm->client->activated) + { + /* Initialize drdynvc channel once and only once. */ + vcm->drdynvc_state = DRDYNVC_STATE_INITIALIZED; + + channel = WTSVirtualChannelOpenEx(vcm, "drdynvc", 0); + if (channel) + { + vcm->drdynvc_channel = channel; + dynvc_caps = 0x00010050; /* DYNVC_CAPS_VERSION1 (4 bytes) */ + WTSVirtualChannelWrite(channel, (uint8*) &dynvc_caps, sizeof(dynvc_caps), NULL); + } + } wait_obj_clear(vcm->send_event); @@ -180,55 +247,49 @@ void* WTSVirtualChannelOpenEx( int i; int len; rdpPeerChannel* channel; - const char* channel_name; freerdp_peer* client = vcm->client; - channel_name = ((flags & WTS_CHANNEL_OPTION_DYNAMIC) != 0 ? "drdynvc" : pVirtualName); - - len = strlen(channel_name); - if (len > 8) - return NULL; - - for (i = 0; i < client->settings->num_channels; i++) + if ((flags & WTS_CHANNEL_OPTION_DYNAMIC) != 0) { - if (client->settings->channels[i].joined && - strncmp(client->settings->channels[i].name, channel_name, len) == 0) - { - break; - } + channel = vcm->drdynvc_channel; + + /* TODO: do DVC channel initialization here using pVirtualName */ + /* A sub-channel should be created and returned, instead of using the main drdynvc channel */ + /* Set channel->index to num_channels */ } - if (i >= client->settings->num_channels) - return NULL; - - channel = (rdpPeerChannel*) client->settings->channels[i].handle; - if (channel == NULL) + else { - channel = xnew(rdpPeerChannel); - channel->vcm = vcm; - channel->client = client; - channel->channel_id = client->settings->channels[i].channel_id; - channel->index = i; - channel->receive_data = stream_new(client->settings->vc_chunk_size); - if ((flags & WTS_CHANNEL_OPTION_DYNAMIC) != 0) + len = strlen(pVirtualName); + if (len > 8) + return NULL; + + for (i = 0; i < client->settings->num_channels; i++) { - channel->channel_type = RDP_PEER_CHANNEL_TYPE_DVC; - vcm->drdynvc_channel = channel; + if (client->settings->channels[i].joined && + strncmp(client->settings->channels[i].name, pVirtualName, len) == 0) + { + break; + } } - else + if (i >= client->settings->num_channels) + return NULL; + + channel = (rdpPeerChannel*) client->settings->channels[i].handle; + if (channel == NULL) { + channel = xnew(rdpPeerChannel); + channel->vcm = vcm; + channel->client = client; + channel->channel_id = client->settings->channels[i].channel_id; + channel->index = i; + channel->receive_data = stream_new(client->settings->vc_chunk_size); channel->channel_type = RDP_PEER_CHANNEL_TYPE_SVC; channel->receive_event = wait_obj_new(); channel->receive_queue = list_new(); channel->mutex = freerdp_mutex_new(); - } - client->settings->channels[i].handle = channel; - } - if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_DVC) - { - /* TODO: do DVC channel initialization here using pVirtualName */ - /* A sub-channel should be created and returned, instead of using the main drdynvc channel */ - /* Set channel->index to num_channels */ + client->settings->channels[i].handle = channel; + } } return channel; diff --git a/libfreerdp-channels/wtsvc.h b/libfreerdp-channels/wtsvc.h index 11110d490..ca241bbd6 100644 --- a/libfreerdp-channels/wtsvc.h +++ b/libfreerdp-channels/wtsvc.h @@ -30,8 +30,14 @@ enum { RDP_PEER_CHANNEL_TYPE_SVC = 0, - RDP_PEER_CHANNEL_TYPE_DVC = 1, - RDP_PEER_CHANNEL_TYPE_DVC_SUB = 2 + RDP_PEER_CHANNEL_TYPE_DVC = 1 +}; + +enum +{ + DRDYNVC_STATE_NONE = 0, + DRDYNVC_STATE_INITIALIZED = 1, + DRDYNVC_STATE_READY = 2 }; typedef struct rdp_peer_channel @@ -56,6 +62,7 @@ struct WTSVirtualChannelManager freerdp_mutex mutex; rdpPeerChannel* drdynvc_channel; + uint8 drdynvc_state; }; #endif /* __WTSVC_H */