Merge pull request #15 from llyzs/cliprdr

New UI-independent cliprdr implementation using plugin event system.
This commit is contained in:
Otavio Salvador 2011-07-13 05:17:07 -07:00
commit e10a46ba65
22 changed files with 1109 additions and 25 deletions

View File

@ -17,5 +17,6 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
add_subdirectory(cliprdr)
add_subdirectory(rdpdbg) 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(CLIPRDR_SRCS
cliprdr_constants.h
cliprdr_format.c
cliprdr_format.h
cliprdr_main.c
cliprdr_main.h
)
add_library(cliprdr SHARED ${CLIPRDR_SRCS})
set_target_properties(cliprdr PROPERTIES PREFIX "")
target_link_libraries(cliprdr freerdp-utils)
install(TARGETS cliprdr DESTINATION ${FREERDP_PLUGIN_PATH})

View File

@ -0,0 +1,58 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* Clipboard Virtual Channel
*
* Copyright 2009-2011 Jay Sorg
* 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 __CLIPRDR_CONSTANTS
#define __CLIPRDR_CONSTANTS
/* CLIPRDR_HEADER.msgType */
#define CB_MONITOR_READY 1
#define CB_FORMAT_LIST 2
#define CB_FORMAT_LIST_RESPONSE 3
#define CB_FORMAT_DATA_REQUEST 4
#define CB_FORMAT_DATA_RESPONSE 5
#define CB_TEMP_DIRECTORY 6
#define CB_CLIP_CAPS 7
#define CB_FILECONTENTS_REQUEST 8
#define CB_FILECONTENTS_RESPONSE 9
#define CB_LOCK_CLIPDATA 10
#define CB_UNLOCK_CLIPDATA 11
/* CLIPRDR_HEADER.msgFlags */
#define CB_RESPONSE_OK 1
#define CB_RESPONSE_FAIL 2
#define CB_ASCII_NAMES 4
/* CLIPRDR_CAPS_SET.capabilitySetType */
#define CB_CAPSTYPE_GENERAL 1
/* CLIPRDR_GENERAL_CAPABILITY.lengthCapability */
#define CB_CAPSTYPE_GENERAL_LEN 12
/* CLIPRDR_GENERAL_CAPABILITY.version */
#define CB_CAPS_VERSION_1 1
#define CB_CAPS_VERSION_2 2
/* CLIPRDR_GENERAL_CAPABILITY.generalFlags */
#define CB_USE_LONG_FORMAT_NAMES 2
#define CB_STREAM_FILECLIP_ENABLED 4
#define CB_FILECLIP_NO_FILE_PATHS 8
#define CB_CAN_LOCK_CLIPDATA 16
#endif /* __CLIPRDR_CONSTANTS */

View File

@ -0,0 +1,172 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* Clipboard Virtual Channel
*
* Copyright 2009-2011 Jay Sorg
* 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/types.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/svc_plugin.h>
#include "cliprdr_constants.h"
#include "cliprdr_main.h"
#include "cliprdr_format.h"
#define CFSTR_HTML "H\0T\0M\0L\0 \0F\0o\0r\0m\0a\0t\0\0"
#define CFSTR_PNG "P\0N\0G\0\0"
#define CFSTR_JPEG "J\0F\0I\0F\0\0"
#define CFSTR_GIF "G\0I\0F\0\0"
void cliprdr_process_format_list_event(cliprdrPlugin* cliprdr, FRDP_CB_FORMAT_LIST_EVENT* cb_event)
{
STREAM* data_out;
int i;
data_out = cliprdr_packet_new(CB_FORMAT_LIST, 0, 36 * cb_event->num_formats);
for (i = 0; i < cb_event->num_formats; i++)
{
stream_write_uint32(data_out, cb_event->formats[i]);
switch (cb_event->formats[i])
{
case CB_FORMAT_HTML:
memcpy(stream_get_tail(data_out), CFSTR_HTML, sizeof(CFSTR_HTML));
break;
case CB_FORMAT_PNG:
memcpy(stream_get_tail(data_out), CFSTR_PNG, sizeof(CFSTR_PNG));
break;
case CB_FORMAT_JPEG:
memcpy(stream_get_tail(data_out), CFSTR_JPEG, sizeof(CFSTR_JPEG));
break;
case CB_FORMAT_GIF:
memcpy(stream_get_tail(data_out), CFSTR_GIF, sizeof(CFSTR_GIF));
break;
}
stream_seek(data_out, 32);
}
cliprdr_packet_send(cliprdr, data_out);
}
static void cliprdr_send_format_list_response(cliprdrPlugin* cliprdr)
{
STREAM* data_out;
data_out = cliprdr_packet_new(CB_FORMAT_LIST_RESPONSE, CB_RESPONSE_OK, 0);
cliprdr_packet_send(cliprdr, data_out);
}
void cliprdr_process_format_list(cliprdrPlugin* cliprdr, STREAM* data_in, uint32 dataLen)
{
FRDP_CB_FORMAT_LIST_EVENT* cb_event;
uint32 format;
int num_formats;
int supported;
int i;
cb_event = (FRDP_CB_FORMAT_LIST_EVENT*)freerdp_event_new(FRDP_EVENT_TYPE_CB_FORMAT_LIST, NULL, NULL);
num_formats = dataLen / 36;
cb_event->formats = (uint32*)xmalloc(sizeof(uint32) * num_formats);
cb_event->num_formats = 0;
if (num_formats * 36 != dataLen)
DEBUG_WARN("dataLen %d not devided by 36!");
for (i = 0; i < num_formats; i++)
{
stream_read_uint32(data_in, format);
supported = 1;
switch (format)
{
case CB_FORMAT_TEXT:
case CB_FORMAT_DIB:
case CB_FORMAT_UNICODETEXT:
break;
default:
if (memcmp(stream_get_tail(data_in), CFSTR_HTML, sizeof(CFSTR_HTML)) == 0)
{
format = CB_FORMAT_HTML;
break;
}
if (memcmp(stream_get_tail(data_in), CFSTR_PNG, sizeof(CFSTR_PNG)) == 0)
{
format = CB_FORMAT_PNG;
break;
}
if (memcmp(stream_get_tail(data_in), CFSTR_JPEG, sizeof(CFSTR_JPEG)) == 0)
{
format = CB_FORMAT_JPEG;
break;
}
if (memcmp(stream_get_tail(data_in), CFSTR_GIF, sizeof(CFSTR_GIF)) == 0)
{
format = CB_FORMAT_GIF;
break;
}
supported = 0;
break;
}
stream_seek(data_in, 32);
if (supported)
cb_event->formats[cb_event->num_formats++] = format;
}
svc_plugin_send_event((rdpSvcPlugin*)cliprdr, (FRDP_EVENT*)cb_event);
cliprdr_send_format_list_response(cliprdr);
}
void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, STREAM* data_in)
{
FRDP_CB_DATA_REQUEST_EVENT* cb_event;
cb_event = (FRDP_CB_DATA_REQUEST_EVENT*)freerdp_event_new(FRDP_EVENT_TYPE_CB_DATA_REQUEST, NULL, NULL);
stream_read_uint32(data_in, cb_event->format);
svc_plugin_send_event((rdpSvcPlugin*)cliprdr, (FRDP_EVENT*)cb_event);
}
void cliprdr_process_format_data_response_event(cliprdrPlugin* cliprdr, FRDP_CB_DATA_RESPONSE_EVENT* cb_event)
{
STREAM* data_out;
data_out = cliprdr_packet_new(CB_FORMAT_DATA_RESPONSE, CB_RESPONSE_OK, cb_event->size);
stream_write(data_out, cb_event->data, cb_event->size);
cliprdr_packet_send(cliprdr, data_out);
}
void cliprdr_process_format_data_request_event(cliprdrPlugin* cliprdr, FRDP_CB_DATA_REQUEST_EVENT* cb_event)
{
STREAM* data_out;
data_out = cliprdr_packet_new(CB_FORMAT_DATA_REQUEST, 0, 4);
stream_write_uint32(data_out, cb_event->format);
cliprdr_packet_send(cliprdr, data_out);
}
void cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, STREAM* data_in, uint32 dataLen)
{
FRDP_CB_DATA_RESPONSE_EVENT* cb_event;
cb_event = (FRDP_CB_DATA_RESPONSE_EVENT*)freerdp_event_new(FRDP_EVENT_TYPE_CB_DATA_RESPONSE, NULL, NULL);
cb_event->size = dataLen;
cb_event->data = (uint8*)xmalloc(dataLen);
memcpy(cb_event->data, stream_get_tail(data_in), dataLen);
svc_plugin_send_event((rdpSvcPlugin*)cliprdr, (FRDP_EVENT*)cb_event);
}

View File

@ -0,0 +1,33 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* Clipboard Virtual Channel
*
* Copyright 2009-2011 Jay Sorg
* 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 __CLIPRDR_FORMAT_H
#define __CLIPRDR_FORMAT_H
void cliprdr_process_format_list_event(cliprdrPlugin* cliprdr, FRDP_CB_FORMAT_LIST_EVENT* cb_event);
void cliprdr_process_format_list(cliprdrPlugin* cliprdr, STREAM* data_in, uint32 dataLen);
void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, STREAM* data_in);
void cliprdr_process_format_data_response_event(cliprdrPlugin* cliprdr, FRDP_CB_DATA_RESPONSE_EVENT* cb_event);
void cliprdr_process_format_data_request_event(cliprdrPlugin* cliprdr, FRDP_CB_DATA_REQUEST_EVENT* cb_event);
void cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, STREAM* data_in, uint32 dataLen);
#endif /* __CLIPRDR_FORMAT_H */

View File

@ -0,0 +1,193 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* Clipboard Virtual Channel
*
* Copyright 2009-2011 Jay Sorg
* 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/types.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/svc_plugin.h>
#include "cliprdr_constants.h"
#include "cliprdr_main.h"
#include "cliprdr_format.h"
STREAM* cliprdr_packet_new(uint16 msgType, uint16 msgFlags, uint32 dataLen)
{
STREAM* data_out;
data_out = stream_new(dataLen + 8);
stream_write_uint16(data_out, msgType);
stream_write_uint16(data_out, msgFlags);
/* Write actual length after the entire packet has been constructed. */
stream_seek(data_out, 4);
return data_out;
}
void cliprdr_packet_send(cliprdrPlugin* cliprdr, STREAM* data_out)
{
int pos;
uint32 dataLen;
pos = stream_get_pos(data_out);
dataLen = pos - 8;
stream_set_pos(data_out, 4);
stream_write_uint32(data_out, dataLen);
stream_set_pos(data_out, pos);
svc_plugin_send((rdpSvcPlugin*)cliprdr, data_out);
}
static void cliprdr_process_connect(rdpSvcPlugin* plugin)
{
DEBUG_SVC("connecting");
}
static void cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, STREAM* data_in)
{
uint16 cCapabilitiesSets;
stream_read_uint16(data_in, cCapabilitiesSets);
DEBUG_SVC("cCapabilitiesSets %d", cCapabilitiesSets);
}
static void cliprdr_send_clip_caps(cliprdrPlugin* cliprdr)
{
STREAM* data_out;
data_out = cliprdr_packet_new(CB_CLIP_CAPS, 0, 4 + CB_CAPSTYPE_GENERAL_LEN);
stream_write_uint16(data_out, 1); /* cCapabilitiesSets */
stream_write_uint16(data_out, 0); /* pad1 */
stream_write_uint16(data_out, CB_CAPSTYPE_GENERAL); /* capabilitySetType */
stream_write_uint16(data_out, CB_CAPSTYPE_GENERAL_LEN); /* lengthCapability */
stream_write_uint32(data_out, CB_CAPS_VERSION_2); /* version */
stream_write_uint32(data_out, 0); /* generalFlags */
cliprdr_packet_send(cliprdr, data_out);
}
static void cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr)
{
FRDP_EVENT* event;
cliprdr_send_clip_caps(cliprdr);
event = freerdp_event_new(FRDP_EVENT_TYPE_CB_SYNC, NULL, NULL);
svc_plugin_send_event((rdpSvcPlugin*)cliprdr, event);
}
static void cliprdr_process_receive(rdpSvcPlugin* plugin, STREAM* data_in)
{
cliprdrPlugin* cliprdr = (cliprdrPlugin*)plugin;
uint16 msgType;
uint16 msgFlags;
uint32 dataLen;
stream_read_uint16(data_in, msgType);
stream_read_uint16(data_in, msgFlags);
stream_read_uint32(data_in, dataLen);
DEBUG_SVC("msgType %d msgFlags %d dataLen %d", msgType, msgFlags, dataLen);
switch (msgType)
{
case CB_CLIP_CAPS:
cliprdr_process_clip_caps(cliprdr, data_in);
break;
case CB_MONITOR_READY:
cliprdr_process_monitor_ready(cliprdr);
break;
case CB_FORMAT_LIST:
cliprdr_process_format_list(cliprdr, data_in, dataLen);
break;
case CB_FORMAT_LIST_RESPONSE:
break;
case CB_FORMAT_DATA_REQUEST:
cliprdr_process_format_data_request(cliprdr, data_in);
break;
case CB_FORMAT_DATA_RESPONSE:
cliprdr_process_format_data_response(cliprdr, data_in, dataLen);
break;
default:
DEBUG_WARN("unknown msgType %d", msgType);
break;
}
stream_free(data_in);
}
static void cliprdr_process_event(rdpSvcPlugin* plugin, FRDP_EVENT* event)
{
switch (event->event_type)
{
case FRDP_EVENT_TYPE_CB_FORMAT_LIST:
cliprdr_process_format_list_event((cliprdrPlugin*)plugin, (FRDP_CB_FORMAT_LIST_EVENT*)event);
break;
case FRDP_EVENT_TYPE_CB_DATA_REQUEST:
cliprdr_process_format_data_request_event((cliprdrPlugin*)plugin, (FRDP_CB_DATA_REQUEST_EVENT*)event);
break;
case FRDP_EVENT_TYPE_CB_DATA_RESPONSE:
cliprdr_process_format_data_response_event((cliprdrPlugin*)plugin, (FRDP_CB_DATA_RESPONSE_EVENT*)event);
break;
default:
DEBUG_WARN("unknown event type %d", event->event_type);
break;
}
freerdp_event_free(event);
}
static void cliprdr_process_terminate(rdpSvcPlugin* plugin)
{
xfree(plugin);
}
int VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
{
cliprdrPlugin* cliprdr;
cliprdr = (cliprdrPlugin*)xmalloc(sizeof(cliprdrPlugin));
memset(cliprdr, 0, sizeof(cliprdrPlugin));
cliprdr->plugin.channel_def.options = CHANNEL_OPTION_INITIALIZED |
CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP |
CHANNEL_OPTION_SHOW_PROTOCOL;
strcpy(cliprdr->plugin.channel_def.name, "cliprdr");
cliprdr->plugin.connect_callback = cliprdr_process_connect;
cliprdr->plugin.receive_callback = cliprdr_process_receive;
cliprdr->plugin.event_callback = cliprdr_process_event;
cliprdr->plugin.terminate_callback = cliprdr_process_terminate;
svc_plugin_init((rdpSvcPlugin*)cliprdr, pEntryPoints);
return 1;
}

View File

@ -0,0 +1,35 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* Clipboard Virtual Channel
*
* Copyright 2009-2011 Jay Sorg
* 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 __CLIPRDR_MAIN_H
#define __CLIPRDR_MAIN_H
#include <freerdp/utils/stream.h>
typedef struct cliprdr_plugin cliprdrPlugin;
struct cliprdr_plugin
{
rdpSvcPlugin plugin;
};
STREAM* cliprdr_packet_new(uint16 msgType, uint16 msgFlags, uint32 dataLen);
void cliprdr_packet_send(cliprdrPlugin* cliprdr, STREAM* data_out);
#endif /* __CLIPRDR_MAIN_H */

View File

@ -34,14 +34,14 @@ struct rdpdbg_plugin
static void rdpdbg_process_connect(rdpSvcPlugin* plugin) static void rdpdbg_process_connect(rdpSvcPlugin* plugin)
{ {
printf("rdpdbg_process_connect\n"); DEBUG_WARN("connecting");
} }
static void rdpdbg_process_receive(rdpSvcPlugin* plugin, STREAM* data_in) static void rdpdbg_process_receive(rdpSvcPlugin* plugin, STREAM* data_in)
{ {
STREAM* data_out; STREAM* data_out;
printf("rdpdbg_process_receive: size %d\n", stream_get_size(data_in)); DEBUG_WARN("size %d", stream_get_size(data_in));
stream_free(data_in); stream_free(data_in);
data_out = stream_new(8); data_out = stream_new(8);
@ -51,7 +51,7 @@ static void rdpdbg_process_receive(rdpSvcPlugin* plugin, STREAM* data_in)
static void rdpdbg_process_event(rdpSvcPlugin* plugin, FRDP_EVENT* event) static void rdpdbg_process_event(rdpSvcPlugin* plugin, FRDP_EVENT* event)
{ {
printf("rdpdbg_process_event: event_type %d\n", event->event_type); DEBUG_WARN("event_type %d", event->event_type);
freerdp_event_free(event); freerdp_event_free(event);
event = freerdp_event_new(FRDP_EVENT_TYPE_DEBUG, NULL, NULL); event = freerdp_event_new(FRDP_EVENT_TYPE_DEBUG, NULL, NULL);
@ -60,7 +60,7 @@ static void rdpdbg_process_event(rdpSvcPlugin* plugin, FRDP_EVENT* event)
static void rdpdbg_process_terminate(rdpSvcPlugin* plugin) static void rdpdbg_process_terminate(rdpSvcPlugin* plugin)
{ {
printf("rdpdbg_process_terminate\n"); DEBUG_WARN("terminating");
xfree(plugin); xfree(plugin);
} }

View File

@ -1,3 +1,6 @@
#ifndef __CONFIG_H
#define __CONFIG_H
/* Include files */ /* Include files */
#cmakedefine HAVE_SYS_PARAM_H #cmakedefine HAVE_SYS_PARAM_H
#cmakedefine HAVE_SYS_SOCKET_H #cmakedefine HAVE_SYS_SOCKET_H
@ -12,3 +15,5 @@
#cmakedefine WITH_DEBUG_TRANSPORT #cmakedefine WITH_DEBUG_TRANSPORT
#cmakedefine WITH_DEBUG_CHANMAN #cmakedefine WITH_DEBUG_CHANMAN
#cmakedefine WITH_DEBUG_SVC #cmakedefine WITH_DEBUG_SVC
#endif

View File

@ -47,6 +47,8 @@ add_executable(test_freerdp
test_transport.h test_transport.h
test_chanman.c test_chanman.c
test_chanman.h test_chanman.h
test_cliprdr.c
test_cliprdr.h
test_freerdp.c test_freerdp.c
test_freerdp.h) test_freerdp.h)

View File

@ -71,16 +71,20 @@ void test_chanman(void)
freerdp_chanman_post_connect(chan_man, &inst); freerdp_chanman_post_connect(chan_man, &inst);
freerdp_chanman_data(&inst, 0, "testdata", 8, CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, 8); freerdp_chanman_data(&inst, 0, "testdata", 8, CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, 8);
freerdp_chanman_data(&inst, 0, "testdata1", 9, CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, 9);
freerdp_chanman_check_fds(chan_man, &inst); freerdp_chanman_data(&inst, 0, "testdata11", 10, CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, 10);
freerdp_chanman_data(&inst, 0, "testdata111", 11, CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, 11);
event = freerdp_event_new(FRDP_EVENT_TYPE_DEBUG, NULL, NULL); event = freerdp_event_new(FRDP_EVENT_TYPE_DEBUG, NULL, NULL);
freerdp_chanman_send_event(chan_man, "rdpdbg", event); freerdp_chanman_send_event(chan_man, "rdpdbg", event);
event = freerdp_chanman_pop_event(chan_man); while ((event = freerdp_chanman_pop_event(chan_man)) == NULL)
{
freerdp_chanman_check_fds(chan_man, &inst);
}
printf("responded event_type %d\n", event->event_type); printf("responded event_type %d\n", event->event_type);
freerdp_event_free(event); freerdp_event_free(event);
freerdp_chanman_close(chan_man, NULL); freerdp_chanman_close(chan_man, &inst);
freerdp_chanman_free(chan_man); freerdp_chanman_free(chan_man);
} }

246
cunit/test_cliprdr.c Normal file
View File

@ -0,0 +1,246 @@
/**
* FreeRDP: A Remote Desktop Protocol Client
* Clipboard 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_cliprdr.h"
int init_cliprdr_suite(void)
{
freerdp_chanman_global_init();
return 0;
}
int clean_cliprdr_suite(void)
{
freerdp_chanman_global_uninit();
return 0;
}
int add_cliprdr_suite(void)
{
add_test_suite(cliprdr);
add_test_function(cliprdr);
return 0;
}
static const uint8 test_clip_caps_data[] =
{
"\x07\x00\x00\x00\x10\x00\x00\x00\x01\x00\x00\x00\x01\x00\x0C\x00"
"\x02\x00\x00\x00\x0E\x00\x00\x00"
};
static const uint8 test_monitor_ready_data[] =
{
"\x01\x00\x00\x00\x00\x00\x00\x00"
};
static const uint8 test_format_list_data[] =
{
"\x02\x00\x00\x00\x48\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\xd0\x00\x00"
"\x48\x00\x54\x00\x4D\x00\x4C\x00\x20\x00\x46\x00\x6F\x00\x72\x00"
"\x6D\x00\x61\x00\x74\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
};
static const uint8 test_format_list_response_data[] =
{
"\x03\x00\x01\x00\x00\x00\x00\x00"
};
static const uint8 test_data_request_data[] =
{
"\x04\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00"
};
static const uint8 test_data_response_data[] =
{
"\x05\x00\x01\x00\x18\x00\x00\x00\x68\x00\x65\x00\x6C\x00\x6C\x00"
"\x6F\x00\x20\x00\x77\x00\x6F\x00\x72\x00\x6c\x00\x64\x00\x00\x00"
};
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);
}
static int event_processed;
static void event_process_callback(FRDP_EVENT* event)
{
printf("Event %d processed.\n", event->event_type);
event_processed = 1;
}
void test_cliprdr(void)
{
rdpChanMan* chan_man;
rdpSettings settings = { 0 };
rdpInst inst = { 0 };
FRDP_EVENT* event;
FRDP_CB_FORMAT_LIST_EVENT* format_list_event;
FRDP_CB_DATA_REQUEST_EVENT* data_request_event;
FRDP_CB_DATA_RESPONSE_EVENT* data_response_event;
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/cliprdr/cliprdr.so", NULL);
freerdp_chanman_pre_connect(chan_man, &inst);
freerdp_chanman_post_connect(chan_man, &inst);
/* server sends cliprdr capabilities and monitor ready PDU */
freerdp_chanman_data(&inst, 0, (char*)test_clip_caps_data, sizeof(test_clip_caps_data) - 1,
CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, sizeof(test_clip_caps_data) - 1);
freerdp_chanman_data(&inst, 0, (char*)test_monitor_ready_data, sizeof(test_monitor_ready_data) - 1,
CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, sizeof(test_monitor_ready_data) - 1);
/* cliprdr sends clipboard_sync event to UI */
while ((event = freerdp_chanman_pop_event(chan_man)) == NULL)
{
freerdp_chanman_check_fds(chan_man, &inst);
}
printf("Got event %d\n", event->event_type);
CU_ASSERT(event->event_type == FRDP_EVENT_TYPE_CB_SYNC);
freerdp_event_free(event);
/* UI sends format_list event to cliprdr */
event = freerdp_event_new(FRDP_EVENT_TYPE_CB_FORMAT_LIST, event_process_callback, NULL);
format_list_event = (FRDP_CB_FORMAT_LIST_EVENT*)event;
format_list_event->num_formats = 2;
format_list_event->formats = (uint32*)xmalloc(sizeof(uint32) * 2);
format_list_event->formats[0] = CB_FORMAT_TEXT;
format_list_event->formats[1] = CB_FORMAT_HTML;
event_processed = 0;
freerdp_chanman_send_event(chan_man, "cliprdr", event);
/* cliprdr sends format list PDU to server */
while (!event_processed)
{
freerdp_chanman_check_fds(chan_man, &inst);
}
/* server sends format list response PDU to cliprdr */
freerdp_chanman_data(&inst, 0, (char*)test_format_list_response_data, sizeof(test_format_list_response_data) - 1,
CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, sizeof(test_format_list_response_data) - 1);
/* server sends format list PDU to cliprdr */
freerdp_chanman_data(&inst, 0, (char*)test_format_list_data, sizeof(test_format_list_data) - 1,
CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, sizeof(test_format_list_data) - 1);
/* cliprdr sends format_list event to UI */
while ((event = freerdp_chanman_pop_event(chan_man)) == NULL)
{
freerdp_chanman_check_fds(chan_man, &inst);
}
printf("Got event %d\n", event->event_type);
CU_ASSERT(event->event_type == FRDP_EVENT_TYPE_CB_FORMAT_LIST);
if (event->event_type == FRDP_EVENT_TYPE_CB_FORMAT_LIST)
{
format_list_event = (FRDP_CB_FORMAT_LIST_EVENT*)event;
for (i = 0; i < format_list_event->num_formats; i++)
printf("Format: 0x%X\n", format_list_event->formats[i]);
}
freerdp_event_free(event);
/* server sends data request PDU to cliprdr */
freerdp_chanman_data(&inst, 0, (char*)test_data_request_data, sizeof(test_data_request_data) - 1,
CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, sizeof(test_data_request_data) - 1);
/* cliprdr sends data request event to UI */
while ((event = freerdp_chanman_pop_event(chan_man)) == NULL)
{
freerdp_chanman_check_fds(chan_man, &inst);
}
printf("Got event %d\n", event->event_type);
CU_ASSERT(event->event_type == FRDP_EVENT_TYPE_CB_DATA_REQUEST);
if (event->event_type == FRDP_EVENT_TYPE_CB_DATA_REQUEST)
{
data_request_event = (FRDP_CB_DATA_REQUEST_EVENT*)event;
printf("Requested format: 0x%X\n", data_request_event->format);
}
freerdp_event_free(event);
/* UI sends data response event to cliprdr */
event = freerdp_event_new(FRDP_EVENT_TYPE_CB_DATA_RESPONSE, event_process_callback, NULL);
data_response_event = (FRDP_CB_DATA_RESPONSE_EVENT*)event;
data_response_event->data = (uint8*)xmalloc(6);
strcpy(data_response_event->data, "hello");
data_response_event->size = 6;
event_processed = 0;
freerdp_chanman_send_event(chan_man, "cliprdr", event);
/* cliprdr sends data response PDU to server */
while (!event_processed)
{
freerdp_chanman_check_fds(chan_man, &inst);
}
/* UI sends data request event to cliprdr */
event = freerdp_event_new(FRDP_EVENT_TYPE_CB_DATA_REQUEST, event_process_callback, NULL);
data_request_event = (FRDP_CB_DATA_REQUEST_EVENT*)event;
data_request_event->format = CB_FORMAT_UNICODETEXT;
event_processed = 0;
freerdp_chanman_send_event(chan_man, "cliprdr", event);
/* cliprdr sends data request PDU to server */
while (!event_processed)
{
freerdp_chanman_check_fds(chan_man, &inst);
}
/* server sends data response PDU to cliprdr */
freerdp_chanman_data(&inst, 0, (char*)test_data_response_data, sizeof(test_data_response_data) - 1,
CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, sizeof(test_data_response_data) - 1);
/* cliprdr sends data response event to UI */
while ((event = freerdp_chanman_pop_event(chan_man)) == NULL)
{
freerdp_chanman_check_fds(chan_man, &inst);
}
printf("Got event %d\n", event->event_type);
CU_ASSERT(event->event_type == FRDP_EVENT_TYPE_CB_DATA_RESPONSE);
if (event->event_type == FRDP_EVENT_TYPE_CB_DATA_RESPONSE)
{
data_response_event = (FRDP_CB_DATA_RESPONSE_EVENT*)event;
printf("Data response size: %d\n", data_response_event->size);
freerdp_hexdump(data_response_event->data, data_response_event->size);
}
freerdp_event_free(event);
freerdp_chanman_close(chan_man, &inst);
freerdp_chanman_free(chan_man);
}

26
cunit/test_cliprdr.h Normal file
View File

@ -0,0 +1,26 @@
/**
* FreeRDP: A Remote Desktop Protocol Client
* Clipboard 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_cliprdr_suite(void);
int clean_cliprdr_suite(void);
int add_cliprdr_suite(void);
void test_cliprdr(void);

View File

@ -31,6 +31,7 @@
#include "test_utils.h" #include "test_utils.h"
#include "test_transport.h" #include "test_transport.h"
#include "test_chanman.h" #include "test_chanman.h"
#include "test_cliprdr.h"
#include "test_freerdp.h" #include "test_freerdp.h"
void dump_data(unsigned char * p, int len, int width, char* name) void dump_data(unsigned char * p, int len, int width, char* name)
@ -123,6 +124,7 @@ int main(int argc, char* argv[])
add_utils_suite(); add_utils_suite();
add_transport_suite(); add_transport_suite();
add_chanman_suite(); add_chanman_suite();
add_cliprdr_suite();
} }
else else
{ {
@ -160,6 +162,10 @@ int main(int argc, char* argv[])
{ {
add_chanman_suite(); add_chanman_suite();
} }
else if (strcmp("cliprdr", argv[*pindex]) == 0)
{
add_cliprdr_suite();
}
else if (strcmp("per", argv[*pindex]) == 0) else if (strcmp("per", argv[*pindex]) == 0)
{ {
add_per_suite(); add_per_suite();

View File

@ -99,7 +99,26 @@ enum FRDP_EVENT_TYPE
{ {
FRDP_EVENT_TYPE_DEBUG = 0, FRDP_EVENT_TYPE_DEBUG = 0,
FRDP_EVENT_TYPE_VIDEO_FRAME = 1, FRDP_EVENT_TYPE_VIDEO_FRAME = 1,
FRDP_EVENT_TYPE_REDRAW = 2 FRDP_EVENT_TYPE_REDRAW = 2,
FRDP_EVENT_TYPE_CB_SYNC = 3,
FRDP_EVENT_TYPE_CB_FORMAT_LIST = 4,
FRDP_EVENT_TYPE_CB_DATA_REQUEST = 5,
FRDP_EVENT_TYPE_CB_DATA_RESPONSE = 6
};
/**
* Clipboard Formats
*/
enum FRDP_CB_FORMAT
{
CB_FORMAT_RAW = 0,
CB_FORMAT_TEXT = 1,
CB_FORMAT_DIB = 8,
CB_FORMAT_UNICODETEXT = 13,
CB_FORMAT_HTML = 0xD010,
CB_FORMAT_PNG = 0xD011,
CB_FORMAT_JPEG = 0xD012,
CB_FORMAT_GIF = 0xD013
}; };
#endif #endif

View File

@ -164,6 +164,31 @@ struct _FRDP_REDRAW_EVENT
}; };
typedef struct _FRDP_REDRAW_EVENT FRDP_REDRAW_EVENT; typedef struct _FRDP_REDRAW_EVENT FRDP_REDRAW_EVENT;
typedef FRDP_EVENT FRDP_CB_SYNC_EVENT;
struct _FRDP_CB_FORMAT_LIST_EVENT
{
FRDP_EVENT event;
uint32* formats;
uint16 num_formats;
};
typedef struct _FRDP_CB_FORMAT_LIST_EVENT FRDP_CB_FORMAT_LIST_EVENT;
struct _FRDP_CB_DATA_REQUEST_EVENT
{
FRDP_EVENT event;
uint32 format;
};
typedef struct _FRDP_CB_DATA_REQUEST_EVENT FRDP_CB_DATA_REQUEST_EVENT;
struct _FRDP_CB_DATA_RESPONSE_EVENT
{
FRDP_EVENT event;
uint8* data;
uint32 size;
};
typedef struct _FRDP_CB_DATA_RESPONSE_EVENT FRDP_CB_DATA_RESPONSE_EVENT;
typedef struct rdp_inst rdpInst; typedef struct rdp_inst rdpInst;
#endif /* __RDP_TYPES_H */ #endif /* __RDP_TYPES_H */

View File

@ -20,9 +20,7 @@
#ifndef __UTILS_DEBUG_H #ifndef __UTILS_DEBUG_H
#define __UTILS_DEBUG_H #define __UTILS_DEBUG_H
#ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif
#ifdef WITH_DEBUG_ASSERT #ifdef WITH_DEBUG_ASSERT
#include <assert.h> #include <assert.h>
@ -36,6 +34,7 @@
#define DEBUG_NULL(fmt, ...) do { } while (0) #define DEBUG_NULL(fmt, ...) do { } while (0)
#define DEBUG_PRINT(_dbg_str, fmt, ...) printf(_dbg_str fmt "\n" , __FUNCTION__, __LINE__, ## __VA_ARGS__) #define DEBUG_PRINT(_dbg_str, fmt, ...) printf(_dbg_str fmt "\n" , __FUNCTION__, __LINE__, ## __VA_ARGS__)
#define DEBUG_CLASS(_dbg_class, fmt, ...) DEBUG_PRINT("DBG_" #_dbg_class " %s (%d): ", fmt, ## __VA_ARGS__) #define DEBUG_CLASS(_dbg_class, fmt, ...) DEBUG_PRINT("DBG_" #_dbg_class " %s (%d): ", fmt, ## __VA_ARGS__)
#define DEBUG_WARN(fmt, ...) DEBUG_PRINT("Warning %s (%d): ", fmt, ## __VA_ARGS__)
#ifdef WITH_DEBUG #ifdef WITH_DEBUG
#define DEBUG(fmt, ...) DEBUG_PRINT("DBG %s (%d): ", fmt, ## __VA_ARGS__) #define DEBUG(fmt, ...) DEBUG_PRINT("DBG %s (%d): ", fmt, ## __VA_ARGS__)

View File

@ -20,6 +20,8 @@
#ifndef __LIST_UTILS_H #ifndef __LIST_UTILS_H
#define __LIST_UTILS_H #define __LIST_UTILS_H
#include <freerdp/utils/memory.h>
#define DEFINE_LIST_TYPE(_list_type, _item_type) \ #define DEFINE_LIST_TYPE(_list_type, _item_type) \
\ \
struct _item_type##_full \ struct _item_type##_full \
@ -32,7 +34,7 @@ struct _item_type##_full \
static struct _item_type* _item_type##_new(void) \ static struct _item_type* _item_type##_new(void) \
{ \ { \
struct _item_type* item; \ struct _item_type* item; \
item = (struct _item_type*)malloc(sizeof(struct _item_type##_full));\ item = (struct _item_type*)xmalloc(sizeof(struct _item_type##_full));\
memset(item, 0, sizeof(struct _item_type##_full)); \ memset(item, 0, sizeof(struct _item_type##_full)); \
return item; \ return item; \
} \ } \
@ -58,7 +60,7 @@ struct _list_type \
static struct _list_type* _list_type##_new(void) \ static struct _list_type* _list_type##_new(void) \
{ \ { \
struct _list_type* list; \ struct _list_type* list; \
list = (struct _list_type*)malloc(sizeof(struct _list_type)); \ list = (struct _list_type*)xmalloc(sizeof(struct _list_type)); \
memset(list, 0, sizeof(struct _list_type)); \ memset(list, 0, sizeof(struct _list_type)); \
return list; \ return list; \
} \ } \
@ -101,9 +103,9 @@ void _list_type##_free(struct _list_type* list) \
{ \ { \
item = _list_type##_dequeue(list); \ item = _list_type##_dequeue(list); \
_item_type##_free(item); \ _item_type##_free(item); \
free(item); \ xfree(item); \
} \ } \
free(list); \ xfree(list); \
} }
#endif #endif

View File

@ -26,6 +26,7 @@
#include <freerdp/svc.h> #include <freerdp/svc.h>
#include <freerdp/utils/stream.h> #include <freerdp/utils/stream.h>
#include <freerdp/utils/event.h> #include <freerdp/utils/event.h>
#include <freerdp/utils/debug.h>
typedef struct rdp_svc_plugin_private rdpSvcPluginPrivate; typedef struct rdp_svc_plugin_private rdpSvcPluginPrivate;
typedef struct rdp_svc_plugin rdpSvcPlugin; typedef struct rdp_svc_plugin rdpSvcPlugin;
@ -46,4 +47,10 @@ void svc_plugin_init(rdpSvcPlugin* plugin, CHANNEL_ENTRY_POINTS* pEntryPoints);
int svc_plugin_send(rdpSvcPlugin* plugin, STREAM* data_out); int svc_plugin_send(rdpSvcPlugin* plugin, STREAM* data_out);
int svc_plugin_send_event(rdpSvcPlugin* plugin, FRDP_EVENT* event); int svc_plugin_send_event(rdpSvcPlugin* plugin, FRDP_EVENT* event);
#ifdef WITH_DEBUG_SVC
#define DEBUG_SVC(fmt, ...) DEBUG_CLASS(SVC, fmt, ## __VA_ARGS__)
#else
#define DEBUG_SVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
#endif
#endif /* __SVC_PLUGIN_UTILS_H */ #endif /* __SVC_PLUGIN_UTILS_H */

View File

@ -0,0 +1,41 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* Thread Utils
*
* 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.
*/
#ifndef __THREAD_UTILS_H
#define __THREAD_UTILS_H
#ifdef _WIN32
#define freerdp_thread_create(_proc, _arg) do { \
DWORD thread; \
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_proc, _arg, 0, &thread); \
while (0)
#else
#include <pthread.h>
#define freerdp_thread_create(_proc, _arg) do { \
pthread_t thread; \
pthread_create(&thread, 0, _proc, _arg); \
pthread_detach(thread); \
} while (0)
#endif
#endif /* __THREAD_UTILS_H */

View File

@ -40,6 +40,22 @@ FRDP_EVENT* freerdp_event_new(uint32 event_type, FRDP_EVENT_CALLBACK on_event_fr
event = (FRDP_EVENT*)xmalloc(sizeof(FRDP_REDRAW_EVENT)); event = (FRDP_EVENT*)xmalloc(sizeof(FRDP_REDRAW_EVENT));
memset(event, 0, sizeof(FRDP_REDRAW_EVENT)); memset(event, 0, sizeof(FRDP_REDRAW_EVENT));
break; break;
case FRDP_EVENT_TYPE_CB_SYNC:
event = (FRDP_EVENT*)xmalloc(sizeof(FRDP_CB_SYNC_EVENT));
memset(event, 0, sizeof(FRDP_CB_SYNC_EVENT));
break;
case FRDP_EVENT_TYPE_CB_FORMAT_LIST:
event = (FRDP_EVENT*)xmalloc(sizeof(FRDP_CB_FORMAT_LIST_EVENT));
memset(event, 0, sizeof(FRDP_CB_FORMAT_LIST_EVENT));
break;
case FRDP_EVENT_TYPE_CB_DATA_REQUEST:
event = (FRDP_EVENT*)xmalloc(sizeof(FRDP_CB_DATA_REQUEST_EVENT));
memset(event, 0, sizeof(FRDP_CB_DATA_REQUEST_EVENT));
break;
case FRDP_EVENT_TYPE_CB_DATA_RESPONSE:
event = (FRDP_EVENT*)xmalloc(sizeof(FRDP_CB_DATA_RESPONSE_EVENT));
memset(event, 0, sizeof(FRDP_CB_DATA_RESPONSE_EVENT));
break;
} }
if (event != NULL) if (event != NULL)
{ {
@ -68,6 +84,20 @@ void freerdp_event_free(FRDP_EVENT* event)
xfree(vevent->visible_rects); xfree(vevent->visible_rects);
} }
break; break;
case FRDP_EVENT_TYPE_CB_FORMAT_LIST:
{
FRDP_CB_FORMAT_LIST_EVENT* cb_event = (FRDP_CB_FORMAT_LIST_EVENT*)event;
xfree(cb_event->formats);
}
break;
case FRDP_EVENT_TYPE_CB_DATA_RESPONSE:
{
FRDP_CB_DATA_RESPONSE_EVENT* cb_event = (FRDP_CB_DATA_RESPONSE_EVENT*)event;
xfree(cb_event->data);
}
break;
} }
xfree(event); xfree(event);
} }

View File

@ -22,19 +22,18 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h>
#include <freerdp/constants.h> #include <freerdp/constants.h>
#include <freerdp/utils/memory.h> #include <freerdp/utils/memory.h>
#include <freerdp/utils/mutex.h> #include <freerdp/utils/mutex.h>
#include <freerdp/utils/debug.h> #include <freerdp/utils/debug.h>
#include <freerdp/utils/stream.h> #include <freerdp/utils/stream.h>
#include <freerdp/utils/list.h>
#include <freerdp/utils/thread.h>
#include <freerdp/utils/wait_obj.h>
#include <freerdp/utils/event.h>
#include <freerdp/utils/svc_plugin.h> #include <freerdp/utils/svc_plugin.h>
#ifdef WITH_DEBUG_SVC
#define DEBUG_SVC(fmt, ...) DEBUG_CLASS(SVC, fmt, ## __VA_ARGS__)
#else
#define DEBUG_SVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
#endif
/* The list of all plugin instances. */ /* The list of all plugin instances. */
typedef struct rdp_svc_plugin_list rdpSvcPluginList; typedef struct rdp_svc_plugin_list rdpSvcPluginList;
struct rdp_svc_plugin_list struct rdp_svc_plugin_list
@ -48,11 +47,42 @@ static rdpSvcPluginList* g_svc_plugin_list = NULL;
/* For locking the global resources */ /* For locking the global resources */
static freerdp_mutex g_mutex = NULL; static freerdp_mutex g_mutex = NULL;
/* Queue for receiving packets */
struct svc_data_in_item
{
STREAM* data_in;
FRDP_EVENT* event_in;
};
DEFINE_LIST_TYPE(svc_data_in_list, svc_data_in_item);
void svc_data_in_item_free(struct svc_data_in_item* item)
{
if (item->data_in)
{
stream_free(item->data_in);
item->data_in = NULL;
}
if (item->event_in)
{
freerdp_event_free(item->event_in);
item->event_in = NULL;
}
}
struct rdp_svc_plugin_private struct rdp_svc_plugin_private
{ {
void* init_handle; void* init_handle;
uint32 open_handle; uint32 open_handle;
STREAM* data_in; STREAM* data_in;
struct svc_data_in_list* data_in_list;
freerdp_mutex* data_in_mutex;
struct wait_obj* signals[5];
int num_signals;
int thread_status;
}; };
static rdpSvcPlugin* svc_plugin_find_by_init_handle(void* init_handle) static rdpSvcPlugin* svc_plugin_find_by_init_handle(void* init_handle)
@ -120,6 +150,7 @@ static void svc_plugin_process_received(rdpSvcPlugin* plugin, void* pData, uint3
uint32 totalLength, uint32 dataFlags) uint32 totalLength, uint32 dataFlags)
{ {
STREAM* data_in; STREAM* data_in;
struct svc_data_in_item* item;
if (dataFlags & CHANNEL_FLAG_FIRST) if (dataFlags & CHANNEL_FLAG_FIRST)
{ {
@ -138,13 +169,35 @@ static void svc_plugin_process_received(rdpSvcPlugin* plugin, void* pData, uint3
{ {
printf("svc_plugin_process_received: read error\n"); printf("svc_plugin_process_received: read error\n");
} }
/* the stream ownership is passed to the callback who is responsible for freeing it. */
plugin->priv->data_in = NULL; plugin->priv->data_in = NULL;
stream_set_pos(data_in, 0); stream_set_pos(data_in, 0);
plugin->receive_callback(plugin, data_in);
item = svc_data_in_item_new();
item->data_in = data_in;
freerdp_mutex_lock(plugin->priv->data_in_mutex);
svc_data_in_list_enqueue(plugin->priv->data_in_list, item);
freerdp_mutex_unlock(plugin->priv->data_in_mutex);
wait_obj_set(plugin->priv->signals[1]);
} }
} }
static void svc_plugin_process_event(rdpSvcPlugin* plugin, FRDP_EVENT* event_in)
{
struct svc_data_in_item* item;
item = svc_data_in_item_new();
item->event_in = event_in;
freerdp_mutex_lock(plugin->priv->data_in_mutex);
svc_data_in_list_enqueue(plugin->priv->data_in_list, item);
freerdp_mutex_unlock(plugin->priv->data_in_mutex);
wait_obj_set(plugin->priv->signals[1]);
}
static void svc_plugin_open_event(uint32 openHandle, uint32 event, void* pData, uint32 dataLength, static void svc_plugin_open_event(uint32 openHandle, uint32 event, void* pData, uint32 dataLength,
uint32 totalLength, uint32 dataFlags) uint32 totalLength, uint32 dataFlags)
{ {
@ -168,11 +221,71 @@ static void svc_plugin_open_event(uint32 openHandle, uint32 event, void* pData,
stream_free((STREAM*)pData); stream_free((STREAM*)pData);
break; break;
case CHANNEL_EVENT_USER: case CHANNEL_EVENT_USER:
plugin->event_callback(plugin, (FRDP_EVENT*)pData); svc_plugin_process_event(plugin, (FRDP_EVENT*)pData);
break; break;
} }
} }
static void svc_plugin_process_data_in(rdpSvcPlugin* plugin)
{
struct svc_data_in_item* item;
while (1)
{
/* terminate signal */
if (wait_obj_is_set(plugin->priv->signals[0]))
break;
freerdp_mutex_lock(plugin->priv->data_in_mutex);
item = svc_data_in_list_dequeue(plugin->priv->data_in_list);
freerdp_mutex_unlock(plugin->priv->data_in_mutex);
if (item != NULL)
{
/* the ownership of the data is passed to the callback */
if (item->data_in)
plugin->receive_callback(plugin, item->data_in);
if (item->event_in)
plugin->event_callback(plugin, item->event_in);
xfree(item);
}
else
break;
}
}
static void* svc_plugin_thread_func(void* arg)
{
rdpSvcPlugin* plugin = (rdpSvcPlugin*)arg;
DEBUG_SVC("in");
plugin->connect_callback(plugin);
while (1)
{
wait_obj_select(plugin->priv->signals, plugin->priv->num_signals, -1);
/* terminate signal */
if (wait_obj_is_set(plugin->priv->signals[0]))
break;
/* data_in signal */
if (wait_obj_is_set(plugin->priv->signals[1]))
{
wait_obj_clear(plugin->priv->signals[1]);
/* process data in */
svc_plugin_process_data_in(plugin);
}
}
plugin->priv->thread_status = -1;
DEBUG_SVC("out");
return 0;
}
static void svc_plugin_process_connected(rdpSvcPlugin* plugin, void* pData, uint32 dataLength) static void svc_plugin_process_connected(rdpSvcPlugin* plugin, void* pData, uint32 dataLength)
{ {
uint32 error; uint32 error;
@ -184,15 +297,46 @@ static void svc_plugin_process_connected(rdpSvcPlugin* plugin, void* pData, uint
printf("svc_plugin_process_connected: open failed\n"); printf("svc_plugin_process_connected: open failed\n");
return; return;
} }
plugin->connect_callback(plugin);
plugin->priv->data_in_list = svc_data_in_list_new();
plugin->priv->data_in_mutex = freerdp_mutex_new();
/* terminate signal */
plugin->priv->signals[plugin->priv->num_signals++] = wait_obj_new();
/* data_in signal */
plugin->priv->signals[plugin->priv->num_signals++] = wait_obj_new();
plugin->priv->thread_status = 1;
freerdp_thread_create(svc_plugin_thread_func, plugin);
} }
static void svc_plugin_process_terminated(rdpSvcPlugin* plugin) static void svc_plugin_process_terminated(rdpSvcPlugin* plugin)
{ {
struct timespec ts;
int i;
wait_obj_set(plugin->priv->signals[0]);
i = 0;
ts.tv_sec = 0;
ts.tv_nsec = 10000000;
while (plugin->priv->thread_status > 0 && i < 1000)
{
i++;
nanosleep(&ts, NULL);
}
plugin->channel_entry_points.pVirtualChannelClose(plugin->priv->open_handle); plugin->channel_entry_points.pVirtualChannelClose(plugin->priv->open_handle);
svc_plugin_remove(plugin); svc_plugin_remove(plugin);
for (i = 0; i < plugin->priv->num_signals; i++)
wait_obj_free(plugin->priv->signals[i]);
plugin->priv->num_signals = 0;
freerdp_mutex_free(plugin->priv->data_in_mutex);
svc_data_in_list_free(plugin->priv->data_in_list);
if (plugin->priv->data_in != NULL) if (plugin->priv->data_in != NULL)
{ {
stream_free(plugin->priv->data_in); stream_free(plugin->priv->data_in);
@ -267,7 +411,10 @@ int svc_plugin_send(rdpSvcPlugin* plugin, STREAM* data_out)
error = plugin->channel_entry_points.pVirtualChannelWrite(plugin->priv->open_handle, error = plugin->channel_entry_points.pVirtualChannelWrite(plugin->priv->open_handle,
stream_get_data(data_out), stream_get_length(data_out), data_out); stream_get_data(data_out), stream_get_length(data_out), data_out);
if (error != CHANNEL_RC_OK) if (error != CHANNEL_RC_OK)
{
stream_free(data_out);
printf("svc_plugin_send: VirtualChannelWrite failed %d\n", error); printf("svc_plugin_send: VirtualChannelWrite failed %d\n", error);
}
return error; return error;
} }