wtsvc: implement channel writing.

This commit is contained in:
Vic Lee 2011-12-12 16:42:42 +08:00
parent b1ee431a3e
commit 228ebb83cd
4 changed files with 154 additions and 8 deletions

View File

@ -25,9 +25,8 @@
* Difference between the MS API are documented in this header. All functions
* are implemented in and integrated with libfreerdp-channels.
*
* Thread-safety: the API is designed to be safe to use one thread per channel.
* To access a virtual channel from multiple threads, one must provide his own
* machanism to protect the virtual channel handle.
* Unlike MS API, all functions except WTSVirtualChannelOpenEx in this
* implementation are thread-safe.
*/
#ifndef __FREERDP_WTSVC_H
@ -36,6 +35,8 @@
#include <freerdp/types.h>
#include <freerdp/peer.h>
typedef struct WTSVirtualChannelManager WTSVirtualChannelManager;
#define WTS_CHANNEL_OPTION_DYNAMIC 0x00000001
typedef enum _WTS_VIRTUAL_CLASS
@ -44,15 +45,26 @@ typedef enum _WTS_VIRTUAL_CLASS
WTSVirtualFileHandle
} WTS_VIRTUAL_CLASS;
/**
* WTSVirtualChannelManager functions are FreeRDP extensions to the API.
*/
FREERDP_API WTSVirtualChannelManager* WTSCreateVirtualChannelManager(freerdp_peer* client);
FREERDP_API void WTSDestroyVirtualChannelManager(WTSVirtualChannelManager* vcm);
FREERDP_API void WTSVirtualChannelManagerGetFileDescriptor(WTSVirtualChannelManager* vcm,
void** fds, int* fds_count);
FREERDP_API boolean WTSVirtualChannelManagerCheckFileDescriptor(WTSVirtualChannelManager* vcm);
/**
* Opens a static or dynamic virtual channel and return the handle. If the
* operation fails, a NULL handle is returned.
*
* The original MS API has 'DWORD SessionId' as the first argument, while we
* just use the server peer instance (representing the session) instead.
* use our WTSVirtualChannelManager object instead.
*
* This functions should be called only from the main thread.
*/
FREERDP_API void* WTSVirtualChannelOpenEx(
/* __in */ freerdp_peer* client,
/* __in */ WTSVirtualChannelManager* vcm,
/* __in */ const char* pVirtualName,
/* __in */ uint32 flags);

View File

@ -25,8 +25,83 @@
#include "wtsvc.h"
struct send_item
{
uint16 channel_id;
uint8* buffer;
uint32 length;
};
static void send_item_free(struct send_item* item)
{
xfree(item->buffer);
xfree(item);
}
WTSVirtualChannelManager* WTSCreateVirtualChannelManager(freerdp_peer* client)
{
WTSVirtualChannelManager* vcm;
vcm = xnew(WTSVirtualChannelManager);
if (vcm != NULL)
{
vcm->client = client;
vcm->send_event = wait_obj_new();
vcm->send_queue = list_new();
vcm->mutex = freerdp_mutex_new();
}
return vcm;
}
void WTSDestroyVirtualChannelManager(WTSVirtualChannelManager* vcm)
{
struct send_item* item;
if (vcm != NULL)
{
wait_obj_free(vcm->send_event);
while ((item = (struct send_item*) list_dequeue(vcm->send_queue)) != NULL)
{
send_item_free(item);
}
list_free(vcm->send_queue);
freerdp_mutex_free(vcm->mutex);
xfree(vcm);
}
}
void WTSVirtualChannelManagerGetFileDescriptor(WTSVirtualChannelManager* vcm,
void** fds, int* fds_count)
{
wait_obj_get_fds(vcm->send_event, fds, fds_count);
}
boolean WTSVirtualChannelManagerCheckFileDescriptor(WTSVirtualChannelManager* vcm)
{
boolean result = true;
struct send_item* item;
wait_obj_clear(vcm->send_event);
freerdp_mutex_lock(vcm->mutex);
while ((item = (struct send_item*) list_dequeue(vcm->send_queue)) != NULL)
{
if (vcm->client->SendChannelData(vcm->client, item->channel_id, item->buffer, item->length) == false)
{
result = false;
}
send_item_free(item);
if (result == false)
break;
}
freerdp_mutex_unlock(vcm->mutex);
return result;
}
void* WTSVirtualChannelOpenEx(
/* __in */ freerdp_peer* client,
/* __in */ WTSVirtualChannelManager* vcm,
/* __in */ const char* pVirtualName,
/* __in */ uint32 flags)
{
@ -34,6 +109,7 @@ void* WTSVirtualChannelOpenEx(
int len;
rdpPeerChannel* channel;
const char* channel_name;
freerdp_peer* client = vcm->client;
channel_name = ((flags & WTS_CHANNEL_OPTION_DYNAMIC) != 0 ? "drdynvc" : pVirtualName);
@ -53,6 +129,7 @@ void* WTSVirtualChannelOpenEx(
return NULL;
channel = xnew(rdpPeerChannel);
channel->vcm = vcm;
channel->client = client;
channel->channel_id = client->settings->channels[i].channel_id;
if ((flags & WTS_CHANNEL_OPTION_DYNAMIC) != 0)
@ -99,7 +176,40 @@ boolean WTSVirtualChannelWrite(
/* __in */ uint32 Length,
/* __out */ uint32* pBytesWritten)
{
return false;
uint32 written = 0;
boolean result = false;
struct send_item* item;
rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle;
WTSVirtualChannelManager* vcm = channel->vcm;
if (channel == NULL)
return false;
if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC)
{
item = xnew(struct send_item);
item->channel_id = channel->channel_id;
item->buffer = xmalloc(Length);
item->length = Length;
memcpy(item->buffer, Buffer, Length);
freerdp_mutex_lock(vcm->mutex);
list_enqueue(vcm->send_queue, item);
freerdp_mutex_unlock(vcm->mutex);
wait_obj_set(vcm->send_event);
written = Length;
result = true;
}
else
{
/* TODO: Send to DVC channel */
}
if (pBytesWritten != NULL)
*pBytesWritten = written;
return result;
}
boolean WTSVirtualChannelClose(

View File

@ -23,6 +23,7 @@
#include <freerdp/freerdp.h>
#include <freerdp/utils/list.h>
#include <freerdp/utils/mutex.h>
#include <freerdp/utils/wait_obj.h>
#include <freerdp/channels/wtsvc.h>
enum
@ -33,9 +34,18 @@ enum
typedef struct rdp_peer_channel
{
WTSVirtualChannelManager* vcm;
freerdp_peer* client;
uint16 channel_id;
uint16 channel_type;
} rdpPeerChannel;
struct WTSVirtualChannelManager
{
freerdp_peer* client;
struct wait_obj* send_event;
LIST* send_queue;
freerdp_mutex mutex;
};
#endif /* __WTSVC_H */

View File

@ -55,6 +55,7 @@ struct test_peer_context
int icon_x;
int icon_y;
boolean activated;
WTSVirtualChannelManager* vcm;
void* debug_channel;
};
typedef struct test_peer_context testPeerContext;
@ -71,6 +72,8 @@ void test_peer_context_new(freerdp_peer* client, testPeerContext* context)
context->icon_x = -1;
context->icon_y = -1;
context->vcm = WTSCreateVirtualChannelManager(client);
}
void test_peer_context_free(freerdp_peer* client, testPeerContext* context)
@ -81,6 +84,11 @@ void test_peer_context_free(freerdp_peer* client, testPeerContext* context)
xfree(context->icon_data);
xfree(context->bg_data);
rfx_context_free(context->rfx_context);
if (context->debug_channel)
{
WTSVirtualChannelClose(context->debug_channel);
}
WTSDestroyVirtualChannelManager(context->vcm);
xfree(context);
}
}
@ -354,10 +362,11 @@ boolean tf_peer_post_connect(freerdp_peer* client)
{
if (strncmp(client->settings->channels[i].name, "rdpdbg", 6) == 0)
{
context->debug_channel = WTSVirtualChannelOpenEx(client, "rdpdbg", 0);
context->debug_channel = WTSVirtualChannelOpenEx(context->vcm, "rdpdbg", 0);
if (context->debug_channel != NULL)
{
printf("Open channel rdpdbg.\n");
WTSVirtualChannelWrite(context->debug_channel, (uint8*) "test1", 5, NULL);
}
}
}
@ -442,6 +451,7 @@ static void* test_peer_mainloop(void* arg)
int rcount;
void* rfds[32];
fd_set rfds_set;
testPeerContext* context;
freerdp_peer* client = (freerdp_peer*) arg;
memset(rfds, 0, sizeof(rfds));
@ -464,6 +474,7 @@ static void* test_peer_mainloop(void* arg)
client->input->ExtendedMouseEvent = tf_peer_extended_mouse_event;
client->Initialize(client);
context = (testPeerContext*) client->context;
printf("We've got a client %s\n", client->hostname);
@ -476,6 +487,7 @@ static void* test_peer_mainloop(void* arg)
printf("Failed to get FreeRDP file descriptor\n");
break;
}
WTSVirtualChannelManagerGetFileDescriptor(context->vcm, rfds, &rcount);
max_fds = 0;
FD_ZERO(&rfds_set);
@ -508,6 +520,8 @@ static void* test_peer_mainloop(void* arg)
if (client->CheckFileDescriptor(client) != true)
break;
if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != true)
break;
}
printf("Client %s disconnected.\n", client->hostname);