Merge branch 'master' of github.com:FreeRDP/FreeRDP-1.0

This commit is contained in:
Marc-André Moreau 2011-07-20 22:05:21 -04:00
commit 10afbbbeee
18 changed files with 1245 additions and 0 deletions

View File

@ -18,5 +18,6 @@
# limitations under the License.
add_subdirectory(cliprdr)
add_subdirectory(drdynvc)
add_subdirectory(rdpdbg)

View File

@ -0,0 +1,33 @@
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP cmake build script
#
# Copyright 2011 O.S. Systems Software Ltda.
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set(DRDYNVC_SRCS
drdynvc_main.c
drdynvc_main.h
drdynvc_types.h
dvcman.c
dvcman.h
)
add_library(drdynvc SHARED ${DRDYNVC_SRCS})
set_target_properties(drdynvc PROPERTIES PREFIX "")
target_link_libraries(drdynvc freerdp-utils)
install(TARGETS drdynvc DESTINATION ${FREERDP_PLUGIN_PATH})

View File

@ -0,0 +1,356 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* Dynamic Virtual Channel
*
* Copyright 2010-2011 Vic Lee
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/constants.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/stream.h>
#include <freerdp/utils/thread.h>
#include <freerdp/utils/svc_plugin.h>
#include <freerdp/utils/wait_obj.h>
#include "dvcman.h"
#include "drdynvc_types.h"
#include "drdynvc_main.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
struct drdynvc_plugin
{
rdpSvcPlugin plugin;
int version;
int PriorityCharge0;
int PriorityCharge1;
int PriorityCharge2;
int PriorityCharge3;
IWTSVirtualChannelManager* channel_mgr;
};
static int drdynvc_write_variable_uint(STREAM* stream, uint32 val)
{
int cb;
if (val <= 0xFF)
{
cb = 0;
stream_write_uint8(stream, val);
}
else if (val <= 0xFFFF)
{
cb = 1;
stream_write_uint16(stream, val);
}
else
{
cb = 3;
stream_write_uint32(stream, val);
}
return cb;
}
int drdynvc_write_data(drdynvcPlugin* drdynvc, uint32 ChannelId, char* data, uint32 data_size)
{
STREAM* data_out;
uint32 pos;
uint32 t;
uint32 cbChId;
uint32 cbLen;
uint32 chunk_len;
int error;
DEBUG_DVC("ChannelId=%d size=%d", ChannelId, data_size);
data_out = stream_new(CHANNEL_CHUNK_LENGTH);
stream_set_pos(data_out, 1);
cbChId = drdynvc_write_variable_uint(data_out, ChannelId);
if (data_size <= CHANNEL_CHUNK_LENGTH - pos)
{
pos = stream_get_pos(data_out);
stream_set_pos(data_out, 0);
stream_write_uint8(data_out, 0x30 | cbChId);
stream_set_pos(data_out, pos);
stream_write(data_out, data, data_size);
error = svc_plugin_send((rdpSvcPlugin*)drdynvc, data_out);
}
else
{
/* Fragment the data */
cbLen = drdynvc_write_variable_uint(data_out, data_size);
pos = stream_get_pos(data_out);
stream_set_pos(data_out, 0);
stream_write_uint8(data_out, 0x20 | cbChId | (cbLen << 2));
stream_set_pos(data_out, pos);
chunk_len = CHANNEL_CHUNK_LENGTH - pos;
stream_write(data_out, data, chunk_len);
data += chunk_len;
data_size -= chunk_len;
error = svc_plugin_send((rdpSvcPlugin*)drdynvc, data_out);
while (error == CHANNEL_RC_OK && data_size > 0)
{
data_out = stream_new(CHANNEL_CHUNK_LENGTH);
stream_set_pos(data_out, 1);
cbChId = drdynvc_write_variable_uint(data_out, ChannelId);
pos = stream_get_pos(data_out);
stream_set_pos(data_out, 0);
stream_write_uint8(data_out, 0x30 | cbChId);
stream_set_pos(data_out, pos);
chunk_len = data_size;
if (chunk_len > CHANNEL_CHUNK_LENGTH - pos)
chunk_len = CHANNEL_CHUNK_LENGTH - pos;
stream_write(data_out, data, chunk_len);
data += chunk_len;
data_size -= chunk_len;
error = svc_plugin_send((rdpSvcPlugin*)drdynvc, data_out);
}
}
if (error != CHANNEL_RC_OK)
{
DEBUG_WARN("VirtualChannelWrite failed %d", error);
return 1;
}
return 0;
}
int drdynvc_push_event(drdynvcPlugin* drdynvc, FRDP_EVENT* event)
{
int error;
error = svc_plugin_send_event((rdpSvcPlugin*)drdynvc, event);
if (error != CHANNEL_RC_OK)
{
DEBUG_WARN("pVirtualChannelEventPush failed %d", error);
return 1;
}
return 0;
}
static int drdynvc_process_capability_request(drdynvcPlugin* drdynvc, int Sp, int cbChId, STREAM* data_in)
{
STREAM* data_out;
int error;
DEBUG_DVC("Sp=%d cbChId=%d", Sp, cbChId);
stream_seek(data_in, 1); /* pad */
stream_read_uint16(data_in, drdynvc->version);
if (drdynvc->version == 2)
{
stream_read_uint16(data_in, drdynvc->PriorityCharge0);
stream_read_uint16(data_in, drdynvc->PriorityCharge1);
stream_read_uint16(data_in, drdynvc->PriorityCharge2);
stream_read_uint16(data_in, drdynvc->PriorityCharge3);
}
data_out = stream_new(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);
if (error != CHANNEL_RC_OK)
{
DEBUG_WARN("VirtualChannelWrite failed %d", error);
return 1;
}
return 0;
}
static uint32 drdynvc_read_variable_uint(STREAM* stream, int cbLen)
{
uint32 val;
switch (cbLen)
{
case 0:
stream_read_uint8(stream, val);
break;
case 1:
stream_read_uint16(stream, val);
break;
default:
stream_read_uint32(stream, val);
break;
}
return val;
}
static int drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, int cbChId, STREAM* data_in)
{
STREAM* data_out;
int pos;
int error;
uint32 ChannelId;
ChannelId = drdynvc_read_variable_uint(data_in, cbChId);
pos = stream_get_pos(data_in);
DEBUG_DVC("ChannelId=%d ChannelName=%s", ChannelId, stream_get_tail(data_in));
error = dvcman_create_channel(drdynvc->channel_mgr, ChannelId, stream_get_tail(data_in));
data_out = stream_new(pos + 4);
stream_write_uint8(data_out, 0x10 | cbChId);
stream_set_pos(data_in, 1);
stream_copy(data_out, data_in, pos - 1);
if (error == 0)
{
DEBUG_DVC("channel created");
stream_write_uint32(data_out, 0);
}
else
{
DEBUG_DVC("no listener");
stream_write_uint32(data_out, (uint32)(-1));
}
error = svc_plugin_send((rdpSvcPlugin*)drdynvc, data_out);
if (error != CHANNEL_RC_OK)
{
DEBUG_WARN("VirtualChannelWrite failed %d", error);
return 1;
}
return 0;
}
static int drdynvc_process_data_first(drdynvcPlugin* drdynvc, int Sp, int cbChId, STREAM* data_in, int in_length)
{
int pos;
uint32 ChannelId;
uint32 Length;
int error;
ChannelId = drdynvc_read_variable_uint(data_in, cbChId);
Length = drdynvc_read_variable_uint(data_in, Sp);
pos = stream_get_pos(data_in);
DEBUG_DVC("ChannelId=%d Length=%d", ChannelId, Length);
error = dvcman_receive_channel_data_first(drdynvc->channel_mgr, ChannelId, Length);
if (error)
return error;
return dvcman_receive_channel_data(drdynvc->channel_mgr, ChannelId,
stream_get_tail(data_in), in_length - pos);
}
static int drdynvc_process_data(drdynvcPlugin* drdynvc, int Sp, int cbChId, STREAM* data_in, int in_length)
{
int pos;
uint32 ChannelId;
ChannelId = drdynvc_read_variable_uint(data_in, cbChId);
pos = stream_get_pos(data_in);
DEBUG_DVC("ChannelId=%d", ChannelId);
return dvcman_receive_channel_data(drdynvc->channel_mgr, ChannelId,
stream_get_tail(data_in), in_length - pos);
}
static int drdynvc_process_close_request(drdynvcPlugin* drdynvc, int Sp, int cbChId, STREAM* data_in)
{
int pos;
uint32 ChannelId;
ChannelId = drdynvc_read_variable_uint(data_in, cbChId);
DEBUG_DVC("ChannelId=%d", ChannelId);
dvcman_close_channel(drdynvc->channel_mgr, ChannelId);
return 0;
}
static void drdynvc_process_receive(rdpSvcPlugin* plugin, STREAM* data_in)
{
drdynvcPlugin* drdynvc = (drdynvcPlugin*)plugin;
int in_length;
int value;
int Cmd;
int Sp;
int cbChId;
in_length = stream_get_length(data_in);
stream_set_pos(data_in, 0);
stream_read_uint8(data_in, value);
Cmd = (value & 0xf0) >> 4;
Sp = (value & 0x0c) >> 2;
cbChId = (value & 0x03) >> 0;
DEBUG_DVC("in_length=%d Cmd=0x%x", in_length, Cmd);
switch (Cmd)
{
case CAPABILITY_REQUEST_PDU:
drdynvc_process_capability_request(drdynvc, Sp, cbChId, data_in);
break;
case CREATE_REQUEST_PDU:
drdynvc_process_create_request(drdynvc, Sp, cbChId, data_in);
break;
case DATA_FIRST_PDU:
drdynvc_process_data_first(drdynvc, Sp, cbChId, data_in, in_length);
break;
case DATA_PDU:
drdynvc_process_data(drdynvc, Sp, cbChId, data_in, in_length);
break;
case CLOSE_REQUEST_PDU:
drdynvc_process_close_request(drdynvc, Sp, cbChId, data_in);
break;
default:
DEBUG_WARN("unknown drdynvc cmd 0x%x", Cmd);
break;
}
stream_free(data_in);
}
static void drdynvc_process_connect(rdpSvcPlugin* plugin)
{
drdynvcPlugin* drdynvc = (drdynvcPlugin*)plugin;
DEBUG_DVC("connecting");
drdynvc->channel_mgr = dvcman_new(drdynvc);
dvcman_load_plugin(drdynvc->channel_mgr, svc_plugin_get_data(plugin));
dvcman_init(drdynvc->channel_mgr);
}
static void drdynvc_process_event(rdpSvcPlugin* plugin, FRDP_EVENT* event)
{
freerdp_event_free(event);
}
static void drdynvc_process_terminate(rdpSvcPlugin* plugin)
{
drdynvcPlugin* drdynvc = (drdynvcPlugin*)plugin;
DEBUG_DVC("terminating");
if (drdynvc->channel_mgr != NULL)
dvcman_free(drdynvc->channel_mgr);
xfree(drdynvc);
}
DEFINE_SVC_PLUGIN(drdynvc, "drdynvc",
CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
CHANNEL_OPTION_COMPRESS_RDP)

View File

@ -0,0 +1,30 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* Dynamic Virtual Channel
*
* Copyright 2010-2011 Vic Lee
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DRDYNVC_MAIN_H
#define __DRDYNVC_MAIN_H
#include <freerdp/types.h>
typedef struct drdynvc_plugin drdynvcPlugin;
int drdynvc_write_data(drdynvcPlugin* plugin, uint32 ChannelId, char* data, uint32 data_size);
int drdynvc_push_event(drdynvcPlugin* plugin, FRDP_EVENT* event);
#endif

View File

@ -0,0 +1,32 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* Dynamic Virtual Channel
*
* Copyright 2010-2011 Vic Lee
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DRDYNVC_TYPES_H
#define __DRDYNVC_TYPES_H
#include "config.h"
#include <freerdp/utils/debug.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
#endif

430
channels/drdynvc/dvcman.c Normal file
View File

@ -0,0 +1,430 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* Dynamic Virtual Channel Manager
*
* Copyright 2010-2011 Vic Lee
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/stream.h>
#include <freerdp/utils/list.h>
#include <freerdp/utils/load_plugin.h>
#include "drdynvc_types.h"
#include "dvcman.h"
#define MAX_PLUGINS 10
typedef struct _DVCMAN DVCMAN;
struct _DVCMAN
{
IWTSVirtualChannelManager iface;
drdynvcPlugin* drdynvc;
const char* plugin_names[MAX_PLUGINS];
IWTSPlugin* plugins[MAX_PLUGINS];
int num_plugins;
IWTSListener* listeners[MAX_PLUGINS];
int num_listeners;
struct dvcman_channel_list* channels;
};
typedef struct _DVCMAN_LISTENER DVCMAN_LISTENER;
struct _DVCMAN_LISTENER
{
IWTSListener iface;
DVCMAN* dvcman;
char* channel_name;
uint32 flags;
IWTSListenerCallback* listener_callback;
};
typedef struct _DVCMAN_ENTRY_POINTS DVCMAN_ENTRY_POINTS;
struct _DVCMAN_ENTRY_POINTS
{
IDRDYNVC_ENTRY_POINTS iface;
DVCMAN* dvcman;
FRDP_PLUGIN_DATA* plugin_data;
};
typedef struct _DVCMAN_CHANNEL DVCMAN_CHANNEL;
struct _DVCMAN_CHANNEL
{
IWTSVirtualChannel iface;
DVCMAN* dvcman;
DVCMAN_CHANNEL* next;
uint32 channel_id;
IWTSVirtualChannelCallback* channel_callback;
STREAM* dvc_data;
};
struct dvcman_channel_list_item
{
DVCMAN_CHANNEL channel;
};
DEFINE_LIST_TYPE(dvcman_channel_list, dvcman_channel_list_item)
static int dvcman_get_configuration(IWTSListener* pListener,
void** ppPropertyBag)
{
*ppPropertyBag = NULL;
return 1;
}
static int dvcman_create_listener(IWTSVirtualChannelManager* pChannelMgr,
const char* pszChannelName,
uint32 ulFlags,
IWTSListenerCallback* pListenerCallback,
IWTSListener** ppListener)
{
DVCMAN* dvcman = (DVCMAN*)pChannelMgr;
DVCMAN_LISTENER* listener;
if (dvcman->num_listeners < MAX_PLUGINS)
{
DEBUG_DVC("%d.%s.", dvcman->num_listeners, pszChannelName);
listener = xnew(DVCMAN_LISTENER);
listener->iface.GetConfiguration = dvcman_get_configuration;
listener->dvcman = dvcman;
listener->channel_name = xstrdup(pszChannelName);
listener->flags = ulFlags;
listener->listener_callback = pListenerCallback;
if (ppListener)
*ppListener = (IWTSListener*)listener;
dvcman->listeners[dvcman->num_listeners++] = (IWTSListener*)listener;
return 0;
}
else
{
DEBUG_WARN("Maximum DVC listener number reached.");
return 1;
}
}
static int dvcman_push_event(IWTSVirtualChannelManager* pChannelMgr,
FRDP_EVENT* pEvent)
{
DVCMAN* dvcman = (DVCMAN*)pChannelMgr;
int error;
error = drdynvc_push_event(dvcman->drdynvc, pEvent);
if (error == 0)
{
DEBUG_DVC("event_type %d pushed.", pEvent->event_type);
}
else
{
DEBUG_WARN("event_type %d push failed.", pEvent->event_type);
}
return error;
}
static int dvcman_register_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints,
const char* name, IWTSPlugin* pPlugin)
{
DVCMAN* dvcman = ((DVCMAN_ENTRY_POINTS*)pEntryPoints)->dvcman;
if (dvcman->num_plugins < MAX_PLUGINS)
{
DEBUG_DVC("num_plugins %d", dvcman->num_plugins);
dvcman->plugin_names[dvcman->num_plugins] = name;
dvcman->plugins[dvcman->num_plugins++] = pPlugin;
return 0;
}
else
{
DEBUG_WARN("Maximum DVC plugin number reached.");
return 1;
}
}
IWTSPlugin* dvcman_get_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints,
const char* name)
{
DVCMAN* dvcman = ((DVCMAN_ENTRY_POINTS*)pEntryPoints)->dvcman;
int i;
for (i = 0; i < dvcman->num_plugins; i++)
{
if (dvcman->plugin_names[i] == name ||
strcmp(dvcman->plugin_names[i], name) == 0)
{
return dvcman->plugins[i];
}
}
return NULL;
}
FRDP_PLUGIN_DATA* dvcman_get_plugin_data(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
{
return ((DVCMAN_ENTRY_POINTS*)pEntryPoints)->plugin_data;
}
IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin)
{
DVCMAN* dvcman;
dvcman = xnew(DVCMAN);
dvcman->iface.CreateListener = dvcman_create_listener;
dvcman->iface.PushEvent = dvcman_push_event;
dvcman->drdynvc = plugin;
dvcman->channels = dvcman_channel_list_new();
return (IWTSVirtualChannelManager*)dvcman;
}
int dvcman_load_plugin(IWTSVirtualChannelManager* pChannelMgr, FRDP_PLUGIN_DATA* data)
{
DVCMAN_ENTRY_POINTS entryPoints;
PDVC_PLUGIN_ENTRY pDVCPluginEntry = NULL;
if (data != NULL)
{
pDVCPluginEntry = freerdp_load_plugin((char*)data->data[0], "DVCPluginEntry");
if(pDVCPluginEntry != NULL)
{
entryPoints.iface.RegisterPlugin = dvcman_register_plugin;
entryPoints.iface.GetPlugin = dvcman_get_plugin;
entryPoints.iface.GetPluginData = dvcman_get_plugin_data;
entryPoints.dvcman = (DVCMAN*)pChannelMgr;
entryPoints.plugin_data = data;
pDVCPluginEntry((IDRDYNVC_ENTRY_POINTS*)&entryPoints);
}
}
return 0;
}
void dvcman_free(IWTSVirtualChannelManager* pChannelMgr)
{
DVCMAN* dvcman = (DVCMAN*)pChannelMgr;
int i;
IWTSPlugin* pPlugin;
DVCMAN_LISTENER* listener;
dvcman_channel_list_free(dvcman->channels);
for (i = 0; i < dvcman->num_listeners; i++)
{
listener = (DVCMAN_LISTENER*)dvcman->listeners[i];
xfree(listener->channel_name);
xfree(listener);
}
for (i = 0; i < dvcman->num_plugins; i++)
{
pPlugin = dvcman->plugins[i];
if (pPlugin->Terminated)
pPlugin->Terminated(pPlugin);
}
xfree(dvcman);
}
int dvcman_init(IWTSVirtualChannelManager* pChannelMgr)
{
DVCMAN* dvcman = (DVCMAN*)pChannelMgr;
int i;
IWTSPlugin* pPlugin;
for (i = 0; i < dvcman->num_plugins; i++)
{
pPlugin = dvcman->plugins[i];
if (pPlugin->Initialize)
pPlugin->Initialize(pPlugin, pChannelMgr);
}
return 0;
}
static int dvcman_write_channel(IWTSVirtualChannel* pChannel,
uint32 cbSize,
char* pBuffer,
void* pReserved)
{
DVCMAN_CHANNEL* channel = (DVCMAN_CHANNEL*)pChannel;
return drdynvc_write_data(channel->dvcman->drdynvc, channel->channel_id, pBuffer, cbSize);
}
static void dvcman_channel_list_item_free(struct dvcman_channel_list_item* item)
{
DVCMAN_CHANNEL* channel = (DVCMAN_CHANNEL*)item;
if (channel->channel_callback)
channel->channel_callback->OnClose(channel->channel_callback);
xfree(item);
}
static int dvcman_close_channel_iface(IWTSVirtualChannel* pChannel)
{
DVCMAN_CHANNEL* channel = (DVCMAN_CHANNEL*)pChannel;
DVCMAN* dvcman = channel->dvcman;
DEBUG_DVC("id=%d", channel->channel_id);
if (dvcman_channel_list_remove(dvcman->channels, (struct dvcman_channel_list_item*)channel) == NULL)
DEBUG_WARN("channel not found");
dvcman_channel_list_item_free((struct dvcman_channel_list_item*)channel);
return 1;
}
int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, uint32 ChannelId, const char* ChannelName)
{
DVCMAN* dvcman = (DVCMAN*)pChannelMgr;
int i;
DVCMAN_LISTENER* listener;
DVCMAN_CHANNEL* channel;
struct dvcman_channel_list_item* item;
int bAccept;
IWTSVirtualChannelCallback* pCallback;
for (i = 0; i < dvcman->num_listeners; i++)
{
listener = (DVCMAN_LISTENER*)dvcman->listeners[i];
if (strcmp(listener->channel_name, ChannelName) == 0)
{
item = dvcman_channel_list_item_new();
channel = (DVCMAN_CHANNEL*)item;
channel->iface.Write = dvcman_write_channel;
channel->iface.Close = dvcman_close_channel_iface;
channel->dvcman = dvcman;
channel->channel_id = ChannelId;
bAccept = 1;
pCallback = NULL;
if (listener->listener_callback->OnNewChannelConnection(listener->listener_callback,
(IWTSVirtualChannel*)channel, NULL, &bAccept, &pCallback) == 0 && bAccept == 1)
{
DEBUG_PRINT("DVC", "listener %s created new channel %d",
listener->channel_name, channel->channel_id);
channel->channel_callback = pCallback;
dvcman_channel_list_add(dvcman->channels, item);
return 0;
}
else
{
DEBUG_WARN("channel rejected by plugin");
dvcman_channel_list_item_free(item);
return 1;
}
}
}
return 1;
}
static DVCMAN_CHANNEL* dvcman_find_channel_by_id(IWTSVirtualChannelManager* pChannelMgr, uint32 ChannelId)
{
DVCMAN* dvcman = (DVCMAN*)pChannelMgr;
struct dvcman_channel_list_item* curr;
for (curr = dvcman->channels->head; curr; curr = dvcman_channel_list_item_next(curr))
{
if (((DVCMAN_CHANNEL*)curr)->channel_id == ChannelId)
{
return (DVCMAN_CHANNEL*)curr;
}
}
return NULL;
}
int dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, uint32 ChannelId)
{
DVCMAN_CHANNEL* channel;
IWTSVirtualChannel* ichannel;
channel = dvcman_find_channel_by_id(pChannelMgr, ChannelId);
if (channel == NULL)
{
DEBUG_WARN("ChannelId %d not found!", ChannelId);
return 1;
}
if (channel->dvc_data)
{
stream_free(channel->dvc_data);
channel->dvc_data = NULL;
}
DEBUG_PRINT("DVC", "dvcman_close_channel: channel %d closed", ChannelId);
ichannel = (IWTSVirtualChannel*)channel;
ichannel->Close(ichannel);
return 0;
}
int dvcman_receive_channel_data_first(IWTSVirtualChannelManager* pChannelMgr, uint32 ChannelId, uint32 length)
{
DVCMAN_CHANNEL* channel;
channel = dvcman_find_channel_by_id(pChannelMgr, ChannelId);
if (channel == NULL)
{
DEBUG_WARN("ChannelId %d not found!", ChannelId);
return 1;
}
if (channel->dvc_data)
stream_free(channel->dvc_data);
channel->dvc_data = stream_new(length);
return 0;
}
int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, uint32 ChannelId, uint8* data, uint32 data_size)
{
DVCMAN_CHANNEL* channel;
int error = 0;
channel = dvcman_find_channel_by_id(pChannelMgr, ChannelId);
if (channel == NULL)
{
DEBUG_WARN("ChannelId %d not found!", ChannelId);
return 1;
}
if (channel->dvc_data)
{
/* Fragmented data */
if (stream_get_length(channel->dvc_data) + data_size > stream_get_size(channel->dvc_data))
{
DEBUG_WARN("data exceeding declared length!");
stream_free(channel->dvc_data);
channel->dvc_data = NULL;
return 1;
}
stream_write(channel->dvc_data, data, data_size);
if (stream_get_length(channel->dvc_data) >= stream_get_size(channel->dvc_data))
{
error = channel->channel_callback->OnDataReceived(channel->channel_callback,
stream_get_size(channel->dvc_data), stream_get_data(channel->dvc_data));
stream_free(channel->dvc_data);
channel->dvc_data = NULL;
}
}
else
{
error = channel->channel_callback->OnDataReceived(channel->channel_callback,
data_size, data);
}
return error;
}

35
channels/drdynvc/dvcman.h Normal file
View File

@ -0,0 +1,35 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* Dynamic Virtual Channel Manager
*
* Copyright 2010-2011 Vic Lee
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DVCMAN_H
#define __DVCMAN_H
#include <freerdp/dvc.h>
#include "drdynvc_main.h"
IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin);
int dvcman_load_plugin(IWTSVirtualChannelManager* pChannelMgr, FRDP_PLUGIN_DATA* data);
void dvcman_free(IWTSVirtualChannelManager* pChannelMgr);
int dvcman_init(IWTSVirtualChannelManager* pChannelMgr);
int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, uint32 ChannelId, const char* ChannelName);
int dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, uint32 ChannelId);
int dvcman_receive_channel_data_first(IWTSVirtualChannelManager* pChannelMgr, uint32 ChannelId, uint32 length);
int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, uint32 ChannelId, uint8* data, uint32 data_size);
#endif

View File

@ -1,3 +1,4 @@
option(WITH_DEBUG_TRANSPORT "Print transport debug message." OFF)
option(WITH_DEBUG_CHANMAN "Print channel manager debug message." OFF)
option(WITH_DEBUG_SVC "Print static virtual channel debug message." OFF)
option(WITH_DEBUG_DVC "Print dynamic virtual channel debug message." OFF)

View File

@ -15,5 +15,6 @@
#cmakedefine WITH_DEBUG_TRANSPORT
#cmakedefine WITH_DEBUG_CHANMAN
#cmakedefine WITH_DEBUG_SVC
#cmakedefine WITH_DEBUG_DVC
#endif

View File

@ -51,6 +51,8 @@ add_executable(test_freerdp
test_chanman.h
test_cliprdr.c
test_cliprdr.h
test_drdynvc.c
test_drdynvc.h
test_freerdp.c
test_freerdp.h)

97
cunit/test_drdynvc.c Normal file
View File

@ -0,0 +1,97 @@
/**
* FreeRDP: A Remote Desktop Protocol Client
* Dynamic Virtual Channel Unit Tests
*
* Copyright 2011 Vic Lee
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <freerdp/freerdp.h>
#include <freerdp/constants.h>
#include <freerdp/chanman.h>
#include <freerdp/utils/event.h>
#include <freerdp/utils/hexdump.h>
#include <freerdp/utils/memory.h>
#include "test_drdynvc.h"
int init_drdynvc_suite(void)
{
freerdp_chanman_global_init();
return 0;
}
int clean_drdynvc_suite(void)
{
freerdp_chanman_global_uninit();
return 0;
}
int add_drdynvc_suite(void)
{
add_test_suite(drdynvc);
add_test_function(drdynvc);
return 0;
}
static const uint8 test_capability_request_data[] =
{
"\x58\x00\x02\x00\x33\x33\x11\x11\x3D\x0A\xA7\x04"
};
static int data_received = 0;
static int test_rdp_channel_data(rdpInst* inst, int chan_id, char* data, int data_size)
{
printf("chan_id %d data_size %d\n", chan_id, data_size);
freerdp_hexdump(data, data_size);
data_received = 1;
}
void test_drdynvc(void)
{
rdpChanMan* chan_man;
rdpSettings settings = { 0 };
rdpInst inst = { 0 };
int i;
settings.hostname = "testhost";
inst.settings = &settings;
inst.rdp_channel_data = test_rdp_channel_data;
chan_man = freerdp_chanman_new();
freerdp_chanman_load_plugin(chan_man, &settings, "../channels/drdynvc/drdynvc.so", NULL);
freerdp_chanman_pre_connect(chan_man, &inst);
freerdp_chanman_post_connect(chan_man, &inst);
/* server sends capability request PDU */
freerdp_chanman_data(&inst, 0, (char*)test_capability_request_data, sizeof(test_capability_request_data) - 1,
CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, sizeof(test_capability_request_data) - 1);
/* drdynvc sends capability response PDU to server */
data_received = 0;
while (!data_received)
{
freerdp_chanman_check_fds(chan_man, &inst);
}
freerdp_chanman_close(chan_man, &inst);
freerdp_chanman_free(chan_man);
}

26
cunit/test_drdynvc.h Normal file
View File

@ -0,0 +1,26 @@
/**
* FreeRDP: A Remote Desktop Protocol Client
* Dynamic Virtual Channel Unit Tests
*
* Copyright 2011 Vic Lee
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "test_freerdp.h"
int init_drdynvc_suite(void);
int clean_drdynvc_suite(void);
int add_drdynvc_suite(void);
void test_drdynvc(void);

View File

@ -33,6 +33,7 @@
#include "test_transport.h"
#include "test_chanman.h"
#include "test_cliprdr.h"
#include "test_drdynvc.h"
#include "test_freerdp.h"
void dump_data(unsigned char * p, int len, int width, char* name)
@ -127,6 +128,7 @@ int main(int argc, char* argv[])
add_transport_suite();
add_chanman_suite();
add_cliprdr_suite();
add_drdynvc_suite();
}
else
{
@ -172,6 +174,10 @@ int main(int argc, char* argv[])
{
add_cliprdr_suite();
}
else if (strcmp("drdynvc", argv[*pindex]) == 0)
{
add_drdynvc_suite();
}
else if (strcmp("per", argv[*pindex]) == 0)
{
add_per_suite();

View File

@ -62,6 +62,8 @@ void test_list(void)
{
struct my_list* list;
struct my_list_item* item;
struct my_list_item* item1;
struct my_list_item* item2;
int i;
list = my_list_new();
@ -81,5 +83,16 @@ void test_list(void)
/*printf("%d %d\n", item->a, item->b);*/
}
item1 = my_list_item_new();
my_list_add(list, item1);
item2 = my_list_item_new();
my_list_add(list, item2);
CU_ASSERT(my_list_remove(list, item1) == item1);
my_list_item_free(item1);
CU_ASSERT(my_list_remove(list, item2) == item2);
CU_ASSERT(my_list_remove(list, item2) == NULL);
my_list_item_free(item2);
my_list_free(list);
}

View File

@ -99,4 +99,9 @@ enum FRDP_CB_FORMAT
CB_FORMAT_GIF = 0xD013
};
/**
* Virtual Channel Constants
*/
#define CHANNEL_CHUNK_LENGTH 1600
#endif

149
include/freerdp/dvc.h Normal file
View File

@ -0,0 +1,149 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* Dynamic Virtual Channel Interface
*
* Copyright 2010-2011 Vic Lee
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* DVC Plugin API: See the original MS DVC Client API:
* http://msdn.microsoft.com/en-us/library/bb540880%28v=VS.85%29.aspx
*
* The FreeRDP DVC Plugin API is a simulation of the MS DVC Client API in C.
* The main difference is that every interface method must take an instance
* pointer as the first parameter.
*/
/**
* Implemented by DRDYNVC:
* o IWTSVirtualChannelManager
* o IWTSListener
* o IWTSVirtualChannel
*
* Implemented by DVC plugin:
* o IWTSPlugin
* o IWTSListenerCallback
* o IWTSVirtualChannelCallback
*
* A basic DVC plugin implementation:
* 1. DVCPluginEntry:
* The plugin entry point, which creates and initializes a new IWTSPlugin
* instance
* 2. IWTSPlugin.Initialize:
* Call IWTSVirtualChannelManager.CreateListener with a newly created
* IWTSListenerCallback instance
* 3. IWTSListenerCallback.OnNewChannelConnection:
* Create IWTSVirtualChannelCallback instance if the new channel is accepted
*/
#ifndef __FREERDP_DVC_H
#define __FREERDP_DVC_H
#include <freerdp/types.h>
typedef struct _IWTSVirtualChannelManager IWTSVirtualChannelManager;
typedef struct _IWTSListener IWTSListener;
typedef struct _IWTSVirtualChannel IWTSVirtualChannel;
typedef struct _IWTSPlugin IWTSPlugin;
typedef struct _IWTSListenerCallback IWTSListenerCallback;
typedef struct _IWTSVirtualChannelCallback IWTSVirtualChannelCallback;
struct _IWTSListener
{
/* Retrieves the listener-specific configuration. */
int (*GetConfiguration) (IWTSListener* pListener,
void** ppPropertyBag);
};
struct _IWTSVirtualChannel
{
/* Starts a write request on the channel. */
int (*Write) (IWTSVirtualChannel* pChannel,
uint32 cbSize,
char* pBuffer,
void* pReserved);
/* Closes the channel. */
int (*Close) (IWTSVirtualChannel* pChannel);
};
struct _IWTSVirtualChannelManager
{
/* Returns an instance of a listener object that listens on a specific
endpoint, or creates a static channel. */
int (*CreateListener) (IWTSVirtualChannelManager* pChannelMgr,
const char* pszChannelName,
uint32 ulFlags,
IWTSListenerCallback* pListenerCallback,
IWTSListener** ppListener);
/* Push a virtual channel event.
This is a FreeRDP extension to standard MS API. */
int (*PushEvent) (IWTSVirtualChannelManager* pChannelMgr,
FRDP_EVENT* pEvent);
};
struct _IWTSPlugin
{
/* Used for the first call that is made from the client to the plug-in. */
int (*Initialize) (IWTSPlugin* pPlugin,
IWTSVirtualChannelManager* pChannelMgr);
/* Notifies the plug-in that the Remote Desktop Connection (RDC) client
has successfully connected to the Remote Desktop Session Host (RD
Session Host) server. */
int (*Connected) (IWTSPlugin* pPlugin);
/* Notifies the plug-in that the Remote Desktop Connection (RDC) client
has disconnected from the RD Session Host server. */
int (*Disconnected) (IWTSPlugin* pPlugin,
uint32 dwDisconnectCode);
/* Notifies the plug-in that the Remote Desktop Connection (RDC) client
has terminated. */
int (*Terminated) (IWTSPlugin* pPlugin);
};
struct _IWTSListenerCallback
{
/* Accepts or denies a connection request for an incoming connection to
the associated listener. */
int (*OnNewChannelConnection) (IWTSListenerCallback* pListenerCallback,
IWTSVirtualChannel* pChannel,
char* Data,
int* pbAccept,
IWTSVirtualChannelCallback** ppCallback);
};
struct _IWTSVirtualChannelCallback
{
/* Notifies the user about data that is being received. */
int (*OnDataReceived) (IWTSVirtualChannelCallback* pChannelCallback,
uint32 cbSize,
char* pBuffer);
/* Notifies the user that the channel has been closed. */
int (*OnClose) (IWTSVirtualChannelCallback* pChannelCallback);
};
/* The DVC Plugin entry points */
typedef struct _IDRDYNVC_ENTRY_POINTS IDRDYNVC_ENTRY_POINTS;
struct _IDRDYNVC_ENTRY_POINTS
{
int (*RegisterPlugin) (IDRDYNVC_ENTRY_POINTS* pEntryPoints,
const char* name, IWTSPlugin* pPlugin);
IWTSPlugin* (*GetPlugin) (IDRDYNVC_ENTRY_POINTS* pEntryPoints,
const char* name);
FRDP_PLUGIN_DATA* (*GetPluginData) (IDRDYNVC_ENTRY_POINTS* pEntryPoints);
};
typedef int (*PDVC_PLUGIN_ENTRY) (IDRDYNVC_ENTRY_POINTS*);
#endif

View File

@ -94,6 +94,32 @@ static struct _item_type* _list_type##_dequeue(struct _list_type* list) \
return item; \
} \
\
static void _list_type##_add(struct _list_type* list, struct _item_type* item) \
{ \
_list_type##_enqueue(list, item); \
} \
\
static struct _item_type* _list_type##_remove(struct _list_type* list, struct _item_type* item) \
{ \
struct _item_type* prev; \
struct _item_type* curr; \
\
for (prev = NULL, curr = (struct _item_type*)list->head; curr; prev = curr, curr = ((struct _item_type##_full*)curr)->next) \
{ \
if (curr == item) \
{ \
if (prev) \
((struct _item_type##_full*)prev)->next = ((struct _item_type##_full*)curr)->next; \
if (list->head == item) \
list->head = ((struct _item_type##_full*)curr)->next; \
if (list->tail == item) \
list->tail = prev; \
return item; \
} \
} \
return NULL; \
} \
\
void _list_type##_free(struct _list_type* list) \
{ \
struct _item_type* item; \

View File

@ -47,6 +47,8 @@ void svc_plugin_init(rdpSvcPlugin* plugin, CHANNEL_ENTRY_POINTS* pEntryPoints);
int svc_plugin_send(rdpSvcPlugin* plugin, STREAM* data_out);
int svc_plugin_send_event(rdpSvcPlugin* plugin, FRDP_EVENT* event);
#define svc_plugin_get_data(_p) (FRDP_PLUGIN_DATA*)(((rdpSvcPlugin*)_p)->channel_entry_points.pExtendedData)
#ifdef WITH_DEBUG_SVC
#define DEBUG_SVC(fmt, ...) DEBUG_CLASS(SVC, fmt, ## __VA_ARGS__)
#else