Merge branch 'master' of github.com:FreeRDP/FreeRDP-1.0
This commit is contained in:
commit
10afbbbeee
@ -18,5 +18,6 @@
|
||||
# limitations under the License.
|
||||
|
||||
add_subdirectory(cliprdr)
|
||||
add_subdirectory(drdynvc)
|
||||
add_subdirectory(rdpdbg)
|
||||
|
||||
|
33
channels/drdynvc/CMakeLists.txt
Normal file
33
channels/drdynvc/CMakeLists.txt
Normal 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})
|
356
channels/drdynvc/drdynvc_main.c
Normal file
356
channels/drdynvc/drdynvc_main.c
Normal 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)
|
30
channels/drdynvc/drdynvc_main.h
Normal file
30
channels/drdynvc/drdynvc_main.h
Normal 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
|
32
channels/drdynvc/drdynvc_types.h
Normal file
32
channels/drdynvc/drdynvc_types.h
Normal 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
430
channels/drdynvc/dvcman.c
Normal 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
35
channels/drdynvc/dvcman.h
Normal 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
|
@ -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)
|
||||
|
@ -15,5 +15,6 @@
|
||||
#cmakedefine WITH_DEBUG_TRANSPORT
|
||||
#cmakedefine WITH_DEBUG_CHANMAN
|
||||
#cmakedefine WITH_DEBUG_SVC
|
||||
#cmakedefine WITH_DEBUG_DVC
|
||||
|
||||
#endif
|
||||
|
@ -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
97
cunit/test_drdynvc.c
Normal 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
26
cunit/test_drdynvc.h
Normal 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);
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
149
include/freerdp/dvc.h
Normal 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
|
@ -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; \
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user