wtsvc: add server dvc creation and closure.

This commit is contained in:
Vic Lee 2012-06-25 16:41:59 +08:00
parent f9e5709e64
commit 3fae14f2ef
4 changed files with 225 additions and 16 deletions

View File

@ -61,7 +61,8 @@ FREERDP_API boolean WTSVirtualChannelManagerCheckFileDescriptor(WTSVirtualChanne
* The original MS API has 'DWORD SessionId' as the first argument, while we
* use our WTSVirtualChannelManager object instead.
*
* This functions should be called only from the main thread.
* Static virtual channels must be opened from the main thread. Dynamic virtual channels
* can be opened from any thread.
*/
FREERDP_API void* WTSVirtualChannelOpenEx(
/* __in */ WTSVirtualChannelManager* vcm,

View File

@ -45,6 +45,21 @@ static void wts_data_item_free(wts_data_item* item)
xfree(item);
}
static rdpPeerChannel* wts_get_dvc_channel_by_id(WTSVirtualChannelManager* vcm, uint32 ChannelId)
{
LIST_ITEM* item;
rdpPeerChannel* channel = NULL;
for (item = vcm->dvc_channel_list->head; item; item = item->next)
{
channel = (rdpPeerChannel*) item->data;
if (channel->channel_id == ChannelId)
break;
}
return channel;
}
static void wts_read_drdynvc_capabilities_response(rdpPeerChannel* channel, uint32 length)
{
uint16 Version;
@ -54,10 +69,36 @@ static void wts_read_drdynvc_capabilities_response(rdpPeerChannel* channel, uint
stream_seek_uint8(channel->receive_data); /* Pad (1 byte) */
stream_read_uint16(channel->receive_data, Version);
printf("version: %d\n", Version);
DEBUG_DVC("Version: %d", Version);
channel->vcm->drdynvc_state = DRDYNVC_STATE_READY;
}
static void wts_read_drdynvc_create_response(rdpPeerChannel* channel, STREAM* s, uint32 length)
{
uint32 CreationStatus;
if (length < 4)
return;
stream_read_uint32(s, CreationStatus);
if ((sint32)CreationStatus < 0)
{
DEBUG_DVC("ChannelId %d creation failed (%d)", channel->channel_id, (sint32)CreationStatus);
channel->dvc_open_state = DVC_OPEN_STATE_FAILED;
}
else
{
DEBUG_DVC("ChannelId %d creation succeeded", channel->channel_id);
channel->dvc_open_state = DVC_OPEN_STATE_SUCCEEDED;
}
}
static void wts_read_drdynvc_close_response(rdpPeerChannel* channel)
{
DEBUG_DVC("ChannelId %d close response", channel->channel_id);
channel->dvc_open_state = DVC_OPEN_STATE_CLOSED;
}
static void wts_read_drdynvc_pdu(rdpPeerChannel* channel)
{
uint32 length;
@ -65,6 +106,8 @@ static void wts_read_drdynvc_pdu(rdpPeerChannel* channel)
int Cmd;
int Sp;
int cbChId;
uint32 ChannelId;
rdpPeerChannel* dvc;
length = stream_get_pos(channel->receive_data);
if (length < 1)
@ -82,7 +125,59 @@ static void wts_read_drdynvc_pdu(rdpPeerChannel* channel)
}
else if (channel->vcm->drdynvc_state == DRDYNVC_STATE_READY)
{
/* TODO: process other drdynvc commands */
switch (cbChId)
{
case 0:
if (length < 1)
return;
stream_read_uint8(channel->receive_data, ChannelId);
length--;
break;
case 1:
if (length < 2)
return;
stream_read_uint16(channel->receive_data, ChannelId);
length -= 2;
break;
default:
if (length < 4)
return;
stream_read_uint32(channel->receive_data, ChannelId);
length -= 4;
break;
}
DEBUG_DVC("wts_read_drdynvc_pdu: Cmd %d ChannelId %d length %d", Cmd, ChannelId, length);
dvc = wts_get_dvc_channel_by_id(channel->vcm, ChannelId);
if (dvc)
{
switch (Cmd)
{
case CREATE_REQUEST_PDU:
wts_read_drdynvc_create_response(dvc, channel->receive_data, length);
break;
case DATA_FIRST_PDU:
break;
case DATA_PDU:
break;
case CLOSE_REQUEST_PDU:
wts_read_drdynvc_close_response(dvc);
break;
default:
printf("wts_read_drdynvc_pdu: Cmd %d not recognized.\n", Cmd);
break;
}
}
else
{
DEBUG_DVC("ChannelId %d not exists.", ChannelId);
}
}
else
{
@ -90,6 +185,35 @@ static void wts_read_drdynvc_pdu(rdpPeerChannel* channel)
}
}
static void wts_write_drdynvc_header(STREAM *s, uint8 Cmd, uint32 ChannelId)
{
if (ChannelId <= 0xFF)
{
stream_write_uint8(s, ((Cmd & 0x0F) << 4) | 0);
stream_write_uint8(s, ChannelId);
}
else if (ChannelId <= 0xFFFF)
{
stream_write_uint8(s, ((Cmd & 0x0F) << 4) | 1);
stream_write_uint16(s, ChannelId);
}
else
{
stream_write_uint8(s, ((Cmd & 0x0F) << 4) | 2);
stream_write_uint32(s, ChannelId);
}
}
static void wts_write_drdynvc_create_request(STREAM *s, uint32 ChannelId, const char *ChannelName)
{
uint32 len;
wts_write_drdynvc_header(s, CREATE_REQUEST_PDU, ChannelId);
len = strlen(ChannelName) + 1;
stream_check_size(s, len);
stream_write(s, ChannelName, len);
}
static void WTSProcessChannelData(rdpPeerChannel* channel, int channelId, uint8* data, int size, int flags, int total_size)
{
wts_data_item* item;
@ -164,6 +288,8 @@ WTSVirtualChannelManager* WTSCreateVirtualChannelManager(freerdp_peer* client)
vcm->send_event = wait_obj_new();
vcm->send_queue = list_new();
vcm->mutex = freerdp_mutex_new();
vcm->dvc_channel_id_seq = 1;
vcm->dvc_channel_list = list_new();
client->ReceiveChannelData = WTSReceiveChannelData;
}
@ -174,9 +300,15 @@ WTSVirtualChannelManager* WTSCreateVirtualChannelManager(freerdp_peer* client)
void WTSDestroyVirtualChannelManager(WTSVirtualChannelManager* vcm)
{
wts_data_item* item;
rdpPeerChannel* channel;
if (vcm != NULL)
{
while ((channel = (rdpPeerChannel*) list_dequeue(vcm->dvc_channel_list)) != NULL)
{
WTSVirtualChannelClose(channel);
}
list_free(vcm->dvc_channel_list);
if (vcm->drdynvc_channel != NULL)
{
WTSVirtualChannelClose(vcm->drdynvc_channel);
@ -198,6 +330,10 @@ void WTSVirtualChannelManagerGetFileDescriptor(WTSVirtualChannelManager* vcm,
void** fds, int* fds_count)
{
wait_obj_get_fds(vcm->send_event, fds, fds_count);
if (vcm->drdynvc_channel)
{
wait_obj_get_fds(vcm->drdynvc_channel->receive_event, fds, fds_count);
}
}
boolean WTSVirtualChannelManagerCheckFileDescriptor(WTSVirtualChannelManager* vcm)
@ -248,14 +384,32 @@ void* WTSVirtualChannelOpenEx(
int len;
rdpPeerChannel* channel;
freerdp_peer* client = vcm->client;
STREAM* s;
if ((flags & WTS_CHANNEL_OPTION_DYNAMIC) != 0)
{
channel = vcm->drdynvc_channel;
if (vcm->drdynvc_channel == NULL || vcm->drdynvc_state != DRDYNVC_STATE_READY)
{
DEBUG_DVC("Dynamic virtual channel not ready.");
return NULL;
}
/* 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 */
channel = xnew(rdpPeerChannel);
channel->vcm = vcm;
channel->client = client;
channel->channel_type = RDP_PEER_CHANNEL_TYPE_DVC;
freerdp_mutex_lock(vcm->mutex);
channel->channel_id = vcm->dvc_channel_id_seq++;
list_enqueue(vcm->dvc_channel_list, channel);
freerdp_mutex_unlock(vcm->mutex);
s = stream_new(64);
wts_write_drdynvc_create_request(s, channel->channel_id, pVirtualName);
WTSVirtualChannelWrite(vcm->drdynvc_channel, stream_get_head(s), stream_get_length(s), NULL);
stream_free(s);
DEBUG_DVC("ChannelId %d.%s (total %d)", channel->channel_id, pVirtualName, list_size(vcm->dvc_channel_list));
}
else
{
@ -372,7 +526,7 @@ boolean WTSVirtualChannelWrite(
wts_data_item* item;
boolean result = false;
rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle;
WTSVirtualChannelManager* vcm ;
WTSVirtualChannelManager* vcm;
if (channel == NULL)
return false;
@ -409,13 +563,35 @@ boolean WTSVirtualChannelWrite(
boolean WTSVirtualChannelClose(
/* __in */ void* hChannelHandle)
{
STREAM* s;
wts_data_item* item;
WTSVirtualChannelManager* vcm;
rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle;
if (channel != NULL)
if (channel)
{
vcm = channel->vcm;
if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC)
{
if (channel->index < channel->client->settings->num_channels)
channel->client->settings->channels[channel->index].handle = NULL;
}
else
{
freerdp_mutex_lock(vcm->mutex);
list_remove(vcm->dvc_channel_list, channel);
freerdp_mutex_unlock(vcm->mutex);
if (channel->dvc_open_state == DVC_OPEN_STATE_SUCCEEDED)
{
s = stream_new(8);
wts_write_drdynvc_header(s, CLOSE_REQUEST_PDU, channel->channel_id);
WTSVirtualChannelWrite(vcm->drdynvc_channel, stream_get_head(s), stream_get_length(s), NULL);
stream_free(s);
}
}
if (channel->receive_data)
stream_free(channel->receive_data);
if (channel->receive_event)
wait_obj_free(channel->receive_event);
@ -431,6 +607,5 @@ boolean WTSVirtualChannelClose(
freerdp_mutex_free(channel->mutex);
xfree(channel);
}
return true;
}

View File

@ -24,9 +24,16 @@
#include <freerdp/utils/stream.h>
#include <freerdp/utils/list.h>
#include <freerdp/utils/mutex.h>
#include <freerdp/utils/debug.h>
#include <freerdp/utils/wait_obj.h>
#include <freerdp/channels/wtsvc.h>
#ifdef WITH_DEBUG_DVC
#define DEBUG_DVC(fmt, ...) DEBUG_CLASS(DVC, fmt, ## __VA_ARGS__)
#else
#define DEBUG_DVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
#endif
enum
{
RDP_PEER_CHANNEL_TYPE_SVC = 0,
@ -40,11 +47,20 @@ enum
DRDYNVC_STATE_READY = 2
};
typedef struct rdp_peer_channel
enum
{
DVC_OPEN_STATE_NONE = 0,
DVC_OPEN_STATE_SUCCEEDED = 1,
DVC_OPEN_STATE_FAILED = 2,
DVC_OPEN_STATE_CLOSED = 3
};
typedef struct rdp_peer_channel rdpPeerChannel;
struct rdp_peer_channel
{
WTSVirtualChannelManager* vcm;
freerdp_peer* client;
uint16 channel_id;
uint32 channel_id;
uint16 channel_type;
uint16 index;
@ -52,7 +68,9 @@ typedef struct rdp_peer_channel
struct wait_obj* receive_event;
LIST* receive_queue;
freerdp_mutex mutex;
} rdpPeerChannel;
uint8 dvc_open_state;
};
struct WTSVirtualChannelManager
{
@ -63,6 +81,8 @@ struct WTSVirtualChannelManager
rdpPeerChannel* drdynvc_channel;
uint8 drdynvc_state;
uint32 dvc_channel_id_seq;
LIST* dvc_channel_list;
};
#endif /* __WTSVC_H */

View File

@ -60,6 +60,7 @@ struct test_peer_context
WTSVirtualChannelManager* vcm;
void* debug_channel;
freerdp_thread* debug_channel_thread;
void* audin_channel;
uint32 frame_id;
};
typedef struct test_peer_context testPeerContext;
@ -561,6 +562,18 @@ void tf_peer_keyboard_event(rdpInput* input, uint16 flags, uint16 code)
{
client->Close(client);
}
else if ((flags & 0x4000) && code == 0x13) /* 'r' key */
{
if (context->audin_channel)
{
WTSVirtualChannelClose(context->audin_channel);
context->audin_channel = NULL;
}
else
{
context->audin_channel = WTSVirtualChannelOpenEx(context->vcm, "AUDIO_INPUT", WTS_CHANNEL_OPTION_DYNAMIC);
}
}
}
void tf_peer_unicode_keyboard_event(rdpInput* input, uint16 flags, uint16 code)