wtsvc: add server dvc creation and closure.
This commit is contained in:
parent
f9e5709e64
commit
3fae14f2ef
@ -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,
|
||||
|
@ -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,14 +563,36 @@ boolean WTSVirtualChannelWrite(
|
||||
boolean WTSVirtualChannelClose(
|
||||
/* __in */ void* hChannelHandle)
|
||||
{
|
||||
STREAM* s;
|
||||
wts_data_item* item;
|
||||
WTSVirtualChannelManager* vcm;
|
||||
rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle;
|
||||
|
||||
if (channel != NULL)
|
||||
if (channel)
|
||||
{
|
||||
if (channel->index < channel->client->settings->num_channels)
|
||||
channel->client->settings->channels[channel->index].handle = NULL;
|
||||
stream_free(channel->receive_data);
|
||||
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);
|
||||
if (channel->receive_queue)
|
||||
@ -431,6 +607,5 @@ boolean WTSVirtualChannelClose(
|
||||
freerdp_mutex_free(channel->mutex);
|
||||
xfree(channel);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user