rail: started integrating Roman's RAIL virtual channel plugin

This commit is contained in:
Marc-André Moreau 2011-08-09 17:42:10 -04:00
parent 510fb93b99
commit b782189569
12 changed files with 1864 additions and 2 deletions

View File

@ -21,4 +21,5 @@ add_subdirectory(cliprdr)
add_subdirectory(drdynvc)
add_subdirectory(rdpdbg)
add_subdirectory(rdpdr)
add_subdirectory(rail)

View File

@ -0,0 +1,35 @@
# 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(RAIL_SRCS
rail_main.c
rail_main.h
rail_core.c
rail_core.h
rail_channel_orders.c
rail_channel_orders.h
)
add_library(rail SHARED ${RAIL_SRCS})
set_target_properties(rail PROPERTIES PREFIX "")
target_link_libraries(rail freerdp-utils)
install(TARGETS rail DESTINATION ${FREERDP_PLUGIN_PATH})

View File

@ -0,0 +1,646 @@
/*
FreeRDP: A Remote Desktop Protocol client.
Remote Applications Integrated Locally (RAIL)
Copyright 2009 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Copyright 2011 Roman Barabanov <romanbarabanov@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.
*/
#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/stream.h>
#include <freerdp/utils/svc_plugin.h>
#include <freerdp/rail.h>
#include "rail_core.h"
#include "rail_main.h"
/*
* RAIL_PDU_HEADER
* begin
* orderType = 2 bytes
* orderLength = 2 bytes
end
*/
static size_t RAIL_PDU_HEADER_SIZE = 4;
void stream_init_by_allocated_data(STREAM* s, void* data, size_t size)
{
s->data = data;
s->size = size;
s->p = s->data;
}
void* rail_alloc_order_data(size_t length)
{
uint8 * order_start = xmalloc(length + RAIL_PDU_HEADER_SIZE);
return (order_start + RAIL_PDU_HEADER_SIZE);
}
void write_rail_unicode_string_content(STREAM* s, RAIL_UNICODE_STRING* string)
{
if (string->length > 0)
stream_write(s, string->buffer, string->length);
}
void write_rail_unicode_string(STREAM* s, RAIL_UNICODE_STRING* string)
{
stream_write_uint16(s, string->length);
if (string->length > 0)
stream_write(s, string->buffer, string->length);
}
void write_rail_rect_16(STREAM* s, RAIL_RECT_16* rect)
{
stream_write_uint16(s, rect->left); /*Left*/
stream_write_uint16(s, rect->top); /*Top*/
stream_write_uint16(s, rect->right); /*Right*/
stream_write_uint16(s, rect->bottom); /*Bottom*/
}
void read_rail_unicode_string(STREAM* s, RAIL_UNICODE_STRING * string)
{
stream_read_uint16(s, string->length);
string->buffer = NULL;
if (string->length > 0)
{
string->buffer = xmalloc(string->length);
stream_read(s, string->buffer, string->length);
}
}
void free_rail_unicode_string(RAIL_UNICODE_STRING * string)
{
if (string->buffer != NULL)
{
xfree(string->buffer);
string->buffer = NULL;
string->length = 0;
}
}
// Used by 'rail_vchannel_send_' routines for sending constructed RAIL PDU to
// the 'rail' channel
static void rail_vchannel_send_order_data(RAIL_SESSION* session, uint16 order_type, void* allocated_order_data, uint16 data_length)
{
STREAM st_stream = {0};
STREAM* s = &st_stream;
uint8* header_start = ((uint8*)allocated_order_data - RAIL_PDU_HEADER_SIZE);
data_length += RAIL_PDU_HEADER_SIZE;
stream_init_by_allocated_data(s, header_start, RAIL_PDU_HEADER_SIZE);
stream_write_uint16(s, order_type);
stream_write_uint16(s, data_length);
session->data_sender->send_rail_vchannel_data(
session->data_sender->data_sender_object,
header_start, data_length);
// In there we free memory which we allocated in rail_alloc_order_data(..)
xfree(header_start);
}
/*
* The Handshake PDU is exchanged between the server and the client to
* establish that both endpoints are ready to begin RAIL mode.
* The server sends the Handshake PDU and the client responds
* with the Handshake PDU.
*/
void rail_vchannel_send_handshake_order(RAIL_SESSION * session, uint32 build_number)
{
STREAM st_stream = {0};
STREAM* s = &st_stream;
uint16 data_length = 4;
void* data = rail_alloc_order_data(data_length);
stream_init_by_allocated_data(s, data, data_length);
stream_write_uint32(s, build_number);
rail_vchannel_send_order_data(session, RDP_RAIL_ORDER_HANDSHAKE, data, data_length);
}
/*
* The Client Activate PDU is sent from client to server
* when a local RAIL window on the client is activated or deactivated.
*/
void rail_vchannel_send_activate_order(RAIL_SESSION* session, uint32 window_id, uint8 enabled)
{
STREAM st_stream = {0};
STREAM* s = &st_stream;
uint16 data_length = 5;
void* data = rail_alloc_order_data(data_length);
stream_init_by_allocated_data(s, data, data_length);
stream_write_uint32(s, window_id);
stream_write_uint8(s, enabled);
rail_vchannel_send_order_data(session, RDP_RAIL_ORDER_ACTIVATE, data, data_length);
}
/*
* Indicates a Client Execute PDU from client to server to request that a
* remote application launch on the server.
* */
void rail_vchannel_send_exec_order(RAIL_SESSION* session, uint16 flags,
RAIL_UNICODE_STRING* exe_or_file, RAIL_UNICODE_STRING* working_directory, RAIL_UNICODE_STRING* arguments)
{
STREAM st_stream = {0};
STREAM* s = &st_stream;
uint16 exe_or_file_length = exe_or_file->length;
uint16 working_directory_length = working_directory->length;
uint16 arguments_length = arguments->length;
size_t data_length =
2 + /*Flags (2 bytes)*/
2 + /*ExeOrFileLength (2 bytes)*/
2 + /*WorkingDirLength (2 bytes)*/
2 + /*ArgumentsLen (2 bytes)*/
exe_or_file_length + /*ExeOrFile (variable)*/
working_directory_length + /*WorkingDir (variable)*/
arguments_length; /*Arguments (variable):*/
void* data = rail_alloc_order_data(data_length);
stream_init_by_allocated_data(s, data, data_length);
stream_write_uint16(s, flags);
stream_write_uint16(s, exe_or_file_length);
stream_write_uint16(s, working_directory_length);
stream_write_uint16(s, arguments_length);
write_rail_unicode_string_content(s, exe_or_file);
write_rail_unicode_string_content(s, working_directory);
write_rail_unicode_string_content(s, arguments);
rail_vchannel_send_order_data(session, RDP_RAIL_ORDER_EXEC, data, data_length);
}
size_t get_sysparam_size_in_rdp_stream(RAIL_CLIENT_SYSPARAM * sysparam)
{
switch (sysparam->type)
{
case SPI_SETDRAGFULLWINDOWS: {return 1;}
case SPI_SETKEYBOARDCUES: {return 1;}
case SPI_SETKEYBOARDPREF: {return 1;}
case SPI_SETMOUSEBUTTONSWAP: {return 1;}
case SPI_SETWORKAREA: {return 8;}
case RAIL_SPI_DISPLAYCHANGE: {return 8;}
case RAIL_SPI_TASKBARPOS: {return 8;}
case SPI_SETHIGHCONTRAST:
{
return (4 + /*Flags (4 bytes)*/
4 + /*ColorSchemeLength (4 bytes)*/
2 + /*UNICODE_STRING.cbString (2 bytes)*/
sysparam->value.high_contrast_system_info.color_scheme.length);
}
};
assert(!"Unknown sysparam type");
return 0;
}
/*
* Indicates a Client System Parameters Update PDU from client to server to
* synchronize system parameters on the server with those on the client.
*/
void rail_vchannel_send_client_sysparam_update_order(RAIL_SESSION* session, RAIL_CLIENT_SYSPARAM* sysparam)
{
STREAM st_stream = {0};
STREAM* s = &st_stream;
size_t data_length = 4; /*SystemParam (4 bytes)*/
void* data = 0;
data_length += get_sysparam_size_in_rdp_stream(sysparam);
data = rail_alloc_order_data(data_length);
stream_init_by_allocated_data(s, data, data_length);
stream_write_uint32(s, sysparam->type);
switch (sysparam->type)
{
case SPI_SETDRAGFULLWINDOWS:
stream_write_uint8(s, sysparam->value.full_window_drag_enabled);
break;
case SPI_SETKEYBOARDCUES:
stream_write_uint8(s, sysparam->value.menu_access_key_always_underlined);
break;
case SPI_SETKEYBOARDPREF:
stream_write_uint8(s, sysparam->value.keyboard_for_user_prefered);
break;
case SPI_SETMOUSEBUTTONSWAP:
stream_write_uint8(s, sysparam->value.left_right_mouse_buttons_swapped);
break;
case SPI_SETWORKAREA:
write_rail_rect_16(s, &sysparam->value.work_area);
break;
case RAIL_SPI_DISPLAYCHANGE:
write_rail_rect_16(s, &sysparam->value.display_resolution);
break;
case RAIL_SPI_TASKBARPOS:
write_rail_rect_16(s, &sysparam->value.taskbar_size);
break;
case SPI_SETHIGHCONTRAST:
{
uint32 color_scheme_length = 2 +
sysparam->value.high_contrast_system_info.color_scheme.length;
stream_write_uint32(s, sysparam->value.high_contrast_system_info.flags);
stream_write_uint32(s, color_scheme_length);
write_rail_unicode_string(s, &sysparam->value.high_contrast_system_info.color_scheme);
break;
}
default:
assert(!"Unknown sysparam type");
break;
}
rail_vchannel_send_order_data(session, RDP_RAIL_ORDER_SYSPARAM, data, data_length);
}
/*
* Indicates a Client System Command PDU from client to server when a local
* RAIL window on the client receives a command to perform an action on the
* window, such as minimize or maximize.
*/
void rail_vchannel_send_syscommand_order(RAIL_SESSION* session, uint32 window_id, uint16 command)
{
STREAM st_stream = {0};
STREAM* s = &st_stream;
uint16 data_length = 4 + 2;
void* data = rail_alloc_order_data(data_length);
stream_init_by_allocated_data(s, data, data_length);
stream_write_uint32(s, window_id);
stream_write_uint16(s, command);
rail_vchannel_send_order_data(session, RDP_RAIL_ORDER_SYSCOMMAND, data, data_length);
}
/*
* The Client Notify Event PDU packet is sent from a client to a server when
* a local RAIL Notification Icon on the client receives a keyboard or mouse
* message from the user. This notification is forwarded to the server via
* the Notify Event PDU.
* */
void rail_vchannel_send_notify_event_order(RAIL_SESSION * session, uint32 window_id, uint32 notify_icon_id, uint32 message)
{
STREAM st_stream = {0};
STREAM* s = &st_stream;
uint16 data_length = 4 * 3;
void* data = rail_alloc_order_data(data_length);
stream_init_by_allocated_data(s, data, data_length);
stream_write_uint32(s, window_id);
stream_write_uint32(s, notify_icon_id);
stream_write_uint32(s, message);
rail_vchannel_send_order_data(session, RDP_RAIL_ORDER_NOTIFY_EVENT, data, data_length);
}
/*
* The Client Window Move PDU packet is sent from the client to the server
* when a local window is ending a move or resize. The client communicates the
* locally moved or resized window's position to the server by using this packet.
* The server uses this information to reposition its window.*/
void rail_vchannel_send_client_windowmove_order(RAIL_SESSION* session, uint32 window_id, RAIL_RECT_16* new_position)
{
STREAM st_stream = {0};
STREAM* s = &st_stream;
uint16 data_length = 4 + 2 * 4;
void* data = rail_alloc_order_data(data_length);
stream_init_by_allocated_data(s, data, data_length);
stream_write_uint32(s, window_id);
stream_write_uint16(s, new_position->left);
stream_write_uint16(s, new_position->top);
stream_write_uint16(s, new_position->right);
stream_write_uint16(s, new_position->bottom);
rail_vchannel_send_order_data(session, RDP_RAIL_ORDER_WINDOWMOVE, data, data_length);
}
/*
* The Client Information PDU is sent from client to server and contains
* information about RAIL client state and features supported by the client.
* */
void rail_vchannel_send_client_information_order(RAIL_SESSION* session, uint32 flags)
{
STREAM st_stream = {0};
STREAM* s = &st_stream;
uint16 data_length = 4;
void* data = rail_alloc_order_data(data_length);
stream_init_by_allocated_data(s, data, data_length);
stream_write_uint32(s, flags);
rail_vchannel_send_order_data(session, RDP_RAIL_ORDER_CLIENTSTATUS, data, data_length);
}
/*
* The Client System Menu PDU packet is sent from the client to the server
* when a local RAIL window on the client receives a command to display its
* System menu. This command is forwarded to the server via
* the System menu PDU.
*/
void rail_vchannel_send_client_system_menu_order(RAIL_SESSION* session, uint32 window_id, uint16 left, uint16 top)
{
STREAM st_stream = {0};
STREAM* s = &st_stream;
uint16 data_length = 4 + 2 * 2;
void* data = rail_alloc_order_data(data_length);
stream_init_by_allocated_data(s, data, data_length);
stream_write_uint32(s, window_id);
stream_write_uint16(s, left);
stream_write_uint16(s, top);
rail_vchannel_send_order_data(session, RDP_RAIL_ORDER_SYSMENU, data,
data_length);
}
/*
* The Language Bar Information PDU is used to set the language bar status.
* It is sent from a client to a server or a server to a client, but only when
* both support the Language Bar docking capability
* (TS_RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED).
* This PDU contains information about the language bar status.
* */
void rail_vchannel_send_client_langbar_information_order(RAIL_SESSION* session, uint32 langbar_status)
{
STREAM st_stream = {0};
STREAM* s = &st_stream;
uint16 data_length = 4;
void* data = rail_alloc_order_data(data_length);
stream_init_by_allocated_data(s, data, data_length);
stream_write_uint32(s, langbar_status);
rail_vchannel_send_order_data(session, RDP_RAIL_ORDER_LANGBARINFO, data, data_length);
}
/*
* The Client Get Application ID PDU is sent from a client to a server.
* This PDU requests information from the server about the Application ID
* that the window SHOULD <15> have on the client.
* */
void rail_vchannel_send_get_appid_req_order(RAIL_SESSION* session, uint32 window_id)
{
STREAM st_stream = {0};
STREAM* s = &st_stream;
uint16 data_length = 4;
void* data = rail_alloc_order_data(data_length);
stream_init_by_allocated_data(s, data, data_length);
stream_write_uint32(s, window_id);
rail_vchannel_send_order_data(session, RDP_RAIL_ORDER_GET_APPID_REQ, data, data_length);
}
/*
* Look at rail_vchannel_send_handshake_order(...)
*/
void rail_vchannel_process_handshake_order(RAIL_SESSION* session, STREAM* s)
{
uint32 build_number = 0;
stream_read_uint32(s, build_number);
rail_core_handle_server_handshake(session, build_number);
}
/*
* The Server Execute Result PDU is sent from server to client in response to
* a Client Execute PDU request, and contains the result of the server's
* attempt to launch the requested executable.
*/
void rail_vchannel_process_exec_result_order(RAIL_SESSION* session, STREAM* s)
{
uint16 flags = 0;
uint16 exec_result = 0;
uint32 raw_result = 0;
RAIL_UNICODE_STRING exe_or_file = {0};
stream_read_uint16(s, flags); /*Flags (2 bytes)*/
stream_read_uint16(s, exec_result); /*ExecResult (2 bytes)*/
stream_read_uint32(s, raw_result); /*RawResult (4 bytes)*/
stream_seek(s, 2); /*Padding (2 bytes)*/
read_rail_unicode_string(s, &exe_or_file); /*ExeOrFileLength with ExeOrFile (variable)*/
rail_core_handle_exec_result(session, flags, exec_result, raw_result, &exe_or_file);
free_rail_unicode_string(&exe_or_file);
}
/*
* The Server System Parameters Update PDU is sent from the server to client to
* synchronize system parameters on the client with those on the server.
*/
void rail_vchannel_process_server_sysparam_update_order(RAIL_SESSION* session, STREAM* s)
{
RAIL_SERVER_SYSPARAM sysparam = {0};
stream_read_uint32(s, sysparam.type);
switch (sysparam.type)
{
case SPI_SETSCREENSAVEACTIVE:
stream_read_uint8(s, sysparam.value.screen_saver_enabled);
break;
case SPI_SETSCREENSAVESECURE:
stream_read_uint8(s, sysparam.value.screen_saver_lock_enabled);
break;
default:
assert(!"Undocumented RAIL server sysparam type");
break;
};
rail_core_handle_server_sysparam(session, &sysparam);
}
/*
* The Server Move/Size Start PDU packet is sent by the server when a window on
* the server is beginning a move or resize.
* The client uses this information to initiate a local move or resize of the
* corresponding local window.
*
* The Server Move/Size End PDU is sent by the server when a window on the
* server is completing a move or resize.
* The client uses this information to end a local move/resize of the
* corresponding local window.
*
*/
void rail_vchannel_process_server_movesize_order(RAIL_SESSION* session, STREAM* s)
{
uint32 window_id = 0;
uint16 move_size_started = 0;
uint16 move_size_type = 0;
uint16 pos_x = 0;
uint16 pos_y = 0;
stream_read_uint32(s, window_id);
stream_read_uint16(s, move_size_started);
stream_read_uint16(s, move_size_type);
stream_read_uint16(s, pos_x);
stream_read_uint16(s, pos_y);
rail_core_handle_server_movesize(session, window_id, move_size_started, move_size_type, pos_x, pos_y);
}
/*
* The Server Min Max Info PDU is sent from a server to a client when a window
* move or resize on the server is being initiated.
* This PDU contains information about the minimum and maximum extents to
* which the window can be moved or sized.
*/
void rail_vchannel_process_server_minmax_info_order(RAIL_SESSION* session, STREAM* s)
{
uint32 window_id = 0;
uint16 max_width = 0;
uint16 max_height = 0;
uint16 max_pos_x = 0;
uint16 max_pos_y = 0;
uint16 min_track_width = 0;
uint16 min_track_height = 0;
uint16 max_track_width = 0;
uint16 max_track_height = 0;
stream_read_uint32(s, window_id);
stream_read_uint16(s, max_width);
stream_read_uint16(s, max_height);
stream_read_uint16(s, max_pos_x);
stream_read_uint16(s, max_pos_y);
stream_read_uint16(s, min_track_width);
stream_read_uint16(s, min_track_height);
stream_read_uint16(s, max_track_width);
stream_read_uint16(s, max_track_height);
rail_core_handle_server_minmax_info(session, window_id, max_width,
max_height, max_pos_x, max_pos_y, min_track_width, min_track_height,
max_track_width, max_track_height);
}
/*
*The Language Bar Information PDU is used to set the language bar status.
*/
void rail_vchannel_process_server_langbar_info_order(RAIL_SESSION* session, STREAM* s)
{
uint32 langbar_status = 0;
stream_read_uint32(s, langbar_status);
rail_core_handle_server_langbar_info(session, langbar_status);
}
/*
* The Server Get Application ID Response PDU is sent from a server to a client.
* This PDU MAY be sent to the client as a response to a Client Get Application
* ID PDU. This PDU specifies the Application ID that the specified window
* SHOULD have on the client. The client MAY ignore this PDU.
*/
static void rail_vchannel_process_server_get_appid_resp_order(RAIL_SESSION* session, STREAM* s)
{
uint32 window_id = 0;
RAIL_UNICODE_STRING app_id = {0};
app_id.length = 256;
app_id.buffer = xmalloc(app_id.length);
stream_read_uint32(s, window_id);
stream_read(s, app_id.buffer, app_id.length);
rail_core_handle_server_get_app_resp(session, window_id, &app_id);
free_rail_unicode_string(&app_id);
}
void rail_vchannel_process_received_vchannel_data(RAIL_SESSION * session, STREAM* s)
{
size_t length = 0;
uint16 order_type = 0;
uint16 order_length = 0;
length = ((s->data + s->size) - s->p);
stream_read_uint16(s, order_type); /* orderType */
stream_read_uint16(s, order_length); /* orderLength */
DEBUG_RAIL("rail_on_channel_data_received: session=0x%p data_size=%d "
"orderType=0x%X orderLength=%d", session, (int) length, order_type, order_length);
switch (order_type)
{
case RDP_RAIL_ORDER_HANDSHAKE:
rail_vchannel_process_handshake_order(session, s);
break;
case RDP_RAIL_ORDER_EXEC_RESULT:
rail_vchannel_process_exec_result_order(session, s);
break;
case RDP_RAIL_ORDER_SYSPARAM:
rail_vchannel_process_server_sysparam_update_order(session, s);
break;
case RDP_RAIL_ORDER_LOCALMOVESIZE:
rail_vchannel_process_server_movesize_order(session, s);
break;
case RDP_RAIL_ORDER_MINMAXINFO:
rail_vchannel_process_server_minmax_info_order(session, s);
break;
case RDP_RAIL_ORDER_LANGBARINFO:
rail_vchannel_process_server_langbar_info_order(session, s);
break;
case RDP_RAIL_ORDER_GET_APPID_RESP:
rail_vchannel_process_server_get_appid_resp_order(session, s);
break;
default:
DEBUG_RAIL("rail_on_channel_data_received: "
"Undocumented RAIL server PDU: order_type=0x%X",order_type);
break;
}
}

View File

@ -0,0 +1,40 @@
/*
FreeRDP: A Remote Desktop Protocol client.
Remote Applications Integrated Locally (RAIL)
Copyright 2009 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Copyright 2011 Roman Barabanov <romanbarabanov@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.
*/
#ifndef __RAIL_CHANNEL_ORDERS_H
#define __RAIL_CHANNEL_ORDERS_H
#include "rail_core.h"
void rail_vchannel_send_handshake_order(RAIL_SESSION* session, uint32 build_number);
void rail_vchannel_send_client_information_order(RAIL_SESSION* session, uint32 flags);
void rail_vchannel_send_activate_order(RAIL_SESSION* session, uint32 window_id, uint8 enabled);
void rail_vchannel_send_exec_order(RAIL_SESSION* session, uint16 flags, RAIL_UNICODE_STRING* exe_or_file,
RAIL_UNICODE_STRING* working_directory, RAIL_UNICODE_STRING* arguments);
void rail_vchannel_send_client_sysparam_update_order(RAIL_SESSION* session, RAIL_CLIENT_SYSPARAM* sysparam);
void rail_vchannel_send_syscommand_order(RAIL_SESSION* session, uint32 window_id, uint16 command);
void rail_vchannel_send_notify_event_order(RAIL_SESSION* session, uint32 window_id, uint32 notify_icon_id, uint32 message);
void rail_vchannel_send_client_windowmove_order(RAIL_SESSION* session, uint32 window_id, RAIL_RECT_16* new_position);
void rail_vchannel_send_client_system_menu_order(RAIL_SESSION* session, uint32 window_id, uint16 left, uint16 top);
void rail_vchannel_send_client_langbar_information_order(RAIL_SESSION* session, uint32 langbar_status);
void rail_vchannel_send_get_appid_req_order(RAIL_SESSION* session, uint32 window_id);
void rail_vchannel_process_received_vchannel_data(RAIL_SESSION* session, STREAM* s);
#endif /* __RAIL_CHANNEL_ORDERS_H */

471
channels/rail/rail_core.c Normal file
View File

@ -0,0 +1,471 @@
/**
* FreeRDP: A Remote Desktop Protocol Client
* Remote Applications Integrated Locally (RAIL)
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2011 Roman Barabanov <romanbarabanov@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.
*/
#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 <freerdp/rail.h>
#include "rail_core.h"
#include "rail_channel_orders.h"
/*
// Initialization stage in UI for RAIL:
// 1) create a sequence of rail_notify_client_sysparam_update()
// calls with all current client system parameters
//
// 2) if Language Bar capability enabled - call updating Language Bar PDU
//
// 3) prepare and call rail_client_execute(exe_or_file, working_dir, args)
//
*/
/*
Flow of init stage over channel;
Client notify UI about session start
and go to RAIL_ESTABLISHING state.
Client wait for Server Handshake PDU
Server send Handshake request
Client check Handshake response.
If NOT OK - exit with specified reason
Client send Handshake response
Server send Server System
Parameters Update (in parallel)
Client send Client Information
Client send Client System Parameters Update
Client send Client Execute
Server send Server Execute Result
Client check Server Execute Result. If NOT OK - exit with specified reason
Client notify UI about success session establishing and go to
RAIL_ESTABLISHED state.
*/
void init_vchannel_event(RAIL_VCHANNEL_EVENT* event, uint32 event_id)
{
memset(event, 0, sizeof(RAIL_VCHANNEL_EVENT));
event->event_id = event_id;
}
void init_rail_string(RAIL_STRING * rail_string, const char * string)
{
rail_string->buffer = (uint8*)string;
rail_string->length = strlen(string) + 1;
}
void rail_string2unicode_string(RAIL_SESSION* session, RAIL_STRING* string, RAIL_UNICODE_STRING* unicode_string)
{
size_t result_length = 0;
char* result_buffer = NULL;
unicode_string->buffer = NULL;
unicode_string->length = 0;
if (string->length == 0) return;
result_buffer = freerdp_uniconv_out(session->uniconv, (char*) string->buffer, &result_length);
unicode_string->buffer = (uint8*)result_buffer;
unicode_string->length = (uint16)result_length;
}
void rail_unicode_string2string(RAIL_SESSION* session, RAIL_UNICODE_STRING* unicode_string, RAIL_STRING* string)
{
char* result_buffer = NULL;
string->buffer = NULL;
string->length = 0;
if (unicode_string->length == 0) return;
result_buffer = freerdp_uniconv_in(session->uniconv, unicode_string->buffer, unicode_string->length);
string->buffer = (uint8*)result_buffer;
string->length = strlen(result_buffer) + 1;
}
RAIL_SESSION* rail_core_session_new(RAIL_VCHANNEL_DATA_SENDER* data_sender, RAIL_VCHANNEL_EVENT_SENDER* event_sender)
{
RAIL_SESSION* self;
self = (RAIL_SESSION*) xzalloc(sizeof(RAIL_SESSION));
if (self != NULL)
{
self->data_sender = data_sender;
self->event_sender = event_sender;
self->uniconv = freerdp_uniconv_new();
}
return self;
}
void rail_core_session_free(RAIL_SESSION* rail_session)
{
if (rail_session != NULL)
{
freerdp_uniconv_free(rail_session->uniconv);
xfree(rail_session);
}
}
void rail_core_on_channel_connected(RAIL_SESSION* session)
{
DEBUG_RAIL("RAIL channel connected.");
}
void rail_core_on_channel_terminated(RAIL_SESSION* session)
{
DEBUG_RAIL("RAIL channel terminated.");
}
void rail_core_handle_server_handshake(RAIL_SESSION* session, uint32 build_number)
{
uint32 client_build_number = 0x00001db0;
RAIL_VCHANNEL_EVENT event = {0};
DEBUG_RAIL("rail_core_handle_server_hadshake: session=0x%p buildNumber=0x%X.", session, build_number);
// Step 1. Send Handshake PDU (2.2.2.2.1)
// Fixed: MS-RDPERP 1.3.2.1 is not correct!
rail_vchannel_send_handshake_order(session, client_build_number);
// Step 2. Send Client Information PDU (2.2.2.2.1)
rail_vchannel_send_client_information_order(session, RAIL_CLIENTSTATUS_ALLOWLOCALMOVESIZE);
// Step 3. Notify UI about session establishing and about requirements to
// start UI initialization stage.
init_vchannel_event(&event, RAIL_VCHANNEL_EVENT_SESSION_ESTABLISHED);
session->event_sender->send_rail_vchannel_event(session->event_sender->event_sender_object, &event);
}
void rail_core_handle_exec_result(RAIL_SESSION* session, uint16 flags, uint16 exec_result, uint32 raw_result, RAIL_UNICODE_STRING* exe_or_file)
{
RAIL_VCHANNEL_EVENT event = {0};
RAIL_STRING exe_or_file_;
DEBUG_RAIL("rail_core_handle_exec_result: session=0x%p flags=0x%X "
"exec_result=0x%X raw_result=0x%X exe_or_file=(length=%d dump>)",
session, flags, exec_result, raw_result, exe_or_file->length);
#ifdef WITH_DEBUG_RAIL
freerdp_hexdump(exe_or_file->buffer, exe_or_file->length);
#endif
rail_unicode_string2string(session, exe_or_file, &exe_or_file_);
init_vchannel_event(&event, RAIL_VCHANNEL_EVENT_EXEC_RESULT_RETURNED);
event.param.exec_result_info.flags = flags;
event.param.exec_result_info.exec_result = exec_result;
event.param.exec_result_info.raw_result = raw_result;
event.param.exec_result_info.exe_or_file = exe_or_file_.buffer;
session->event_sender->send_rail_vchannel_event(session->event_sender->event_sender_object, &event);
}
void rail_core_handle_server_sysparam(RAIL_SESSION* session, RAIL_SERVER_SYSPARAM* sysparam)
{
RAIL_VCHANNEL_EVENT event = {0};
DEBUG_RAIL("rail_core_handle_server_sysparam: session=0x%p "
"type=0x%X scr_enabled=%d scr_lock_enabled=%d",
session, sysparam->type, sysparam->value.screen_saver_enabled,
sysparam->value.screen_saver_lock_enabled);
init_vchannel_event(&event, RAIL_VCHANNEL_EVENT_SERVER_SYSPARAM_RECEIVED);
event.param.server_param_info.param_type = sysparam->type;
event.param.server_param_info.screen_saver_enabled =
((sysparam->value.screen_saver_enabled != 0) ? True: False);
event.param.server_param_info.screen_saver_lock_enabled =
((sysparam->value.screen_saver_lock_enabled != 0) ? True: False);
session->event_sender->send_rail_vchannel_event(session->event_sender->event_sender_object, &event);
}
void rail_core_handle_server_movesize(RAIL_SESSION* session, uint32 window_id,
uint16 move_size_started, uint16 move_size_type, uint16 pos_x, uint16 pos_y)
{
RAIL_VCHANNEL_EVENT event = {0};
DEBUG_RAIL("rail_core_handle_server_movesize: session=0x%p "
"window_id=0x%X started=%d move_size_type=%d pos_x=%d pos_y=%d",
session, window_id, move_size_started, move_size_type, pos_x, pos_y);
init_vchannel_event(&event, ((move_size_started != 0) ?
RAIL_VCHANNEL_EVENT_MOVESIZE_STARTED:
RAIL_VCHANNEL_EVENT_MOVESIZE_FINISHED));
event.param.movesize_info.window_id = window_id;
event.param.movesize_info.move_size_type = move_size_type;
event.param.movesize_info.pos_x = pos_x;
event.param.movesize_info.pos_y = pos_y;
session->event_sender->send_rail_vchannel_event(session->event_sender->event_sender_object, &event);
}
void rail_core_handle_server_minmax_info(RAIL_SESSION* session,
uint32 window_id, uint16 max_width, uint16 max_height, uint16 max_pos_x, uint16 max_pos_y,
uint16 min_track_width, uint16 min_track_height, uint16 max_track_width, uint16 max_track_height)
{
RAIL_VCHANNEL_EVENT event = {0};
DEBUG_RAIL("rail_core_handle_server_minmax_info: session=0x%p "
"window_id=0x%X max_width=%d max_height=%d max_pos_x=%d max_pos_y=%d "
"min_track_width=%d min_track_height=%d max_track_width=%d max_track_height=%d",
session, window_id, max_width, max_height, max_pos_x, max_pos_y,
min_track_width, min_track_height, max_track_width, max_track_height);
init_vchannel_event(&event, RAIL_VCHANNEL_EVENT_MINMAX_INFO_UPDATED);
event.param.minmax_info.window_id = window_id;
event.param.minmax_info.max_width = max_width;
event.param.minmax_info.max_height = max_height;
event.param.minmax_info.max_pos_x = max_pos_x;
event.param.minmax_info.max_pos_y = max_pos_y;
event.param.minmax_info.min_track_width = min_track_width;
event.param.minmax_info.min_track_height = min_track_height;
event.param.minmax_info.max_track_width = max_track_width;
event.param.minmax_info.max_track_height = max_track_height;
session->event_sender->send_rail_vchannel_event(session->event_sender->event_sender_object, &event);
}
void rail_core_handle_server_langbar_info(RAIL_SESSION* session, uint32 langbar_status)
{
RAIL_VCHANNEL_EVENT event = {0};
DEBUG_RAIL("rail_core_handle_server_langbar_info: session=0x%p "
"langbar_status=0x%X", session, langbar_status);
init_vchannel_event(&event, RAIL_VCHANNEL_EVENT_LANGBAR_STATUS_UPDATED);
event.param.langbar_info.status = langbar_status;
session->event_sender->send_rail_vchannel_event(session->event_sender->event_sender_object, &event);
}
void rail_core_handle_server_get_app_resp(RAIL_SESSION* session, uint32 window_id, RAIL_UNICODE_STRING * app_id)
{
RAIL_VCHANNEL_EVENT event = { 0 };
RAIL_STRING app_id_;
DEBUG_RAIL("rail_core_handle_server_get_app_resp: session=0x%p "
"window_id=0x%X app_id=(length=%d dump>)", session, window_id, app_id->length);
#ifdef WITH_DEBUG_RAIL
freerdp_hexdump(app_id->buffer, app_id->length);
#endif
rail_unicode_string2string(session, app_id, &app_id_);
init_vchannel_event(&event, RAIL_VCHANNEL_EVENT_LANGBAR_STATUS_UPDATED);
event.param.app_response_info.window_id= window_id;
event.param.app_response_info.application_id = app_id_.buffer;
session->event_sender->send_rail_vchannel_event(session->event_sender->event_sender_object, &event);
}
void rail_core_send_client_execute(RAIL_SESSION* session,
boolean exec_or_file_is_file_path, const char* rail_exe_or_file,
const char* rail_working_directory, const char* rail_arguments)
{
RAIL_STRING exe_or_file_;
RAIL_STRING working_directory_;
RAIL_STRING arguments_;
RAIL_UNICODE_STRING exe_or_file;
RAIL_UNICODE_STRING working_directory;
RAIL_UNICODE_STRING arguments;
uint16 flags;
init_rail_string(&exe_or_file_, rail_exe_or_file);
init_rail_string(&working_directory_, rail_working_directory);
init_rail_string(&arguments_, rail_arguments);
rail_string2unicode_string(session, &exe_or_file_, &exe_or_file);
rail_string2unicode_string(session, &working_directory_, &working_directory);
rail_string2unicode_string(session, &arguments_, &arguments);
flags = (RAIL_EXEC_FLAG_EXPAND_WORKINGDIRECTORY | RAIL_EXEC_FLAG_EXPAND_ARGUMENTS);
if (exec_or_file_is_file_path)
{
flags |= (RAIL_EXEC_FLAG_TRANSLATE_FILES | RAIL_EXEC_FLAG_FILE);
}
rail_vchannel_send_exec_order(session, flags, &exe_or_file,
&working_directory, &arguments);
free_rail_unicode_string(&exe_or_file);
free_rail_unicode_string(&working_directory);
free_rail_unicode_string(&arguments);
}
uint8 boolean2uint8(boolean value)
{
return ((value == True) ? 1 : 0);
}
uint8 copy_rail_rect_16(RAIL_RECT_16* src, RAIL_RECT_16* dst)
{
memcpy(dst, src, sizeof(RAIL_RECT_16));
return 0;
}
static void rail_core_handle_ui_update_client_sysparam(RAIL_SESSION* session, RAIL_UI_EVENT* event)
{
RAIL_CLIENT_SYSPARAM sys_param;
memset(&sys_param, 0, sizeof(sys_param));
sys_param.type = event->param.sysparam_info.param;
sys_param.value.full_window_drag_enabled =
boolean2uint8(event->param.sysparam_info.value.full_window_drag_enabled);
sys_param.value.menu_access_key_always_underlined =
boolean2uint8(event->param.sysparam_info.value.menu_access_key_always_underlined);
sys_param.value.keyboard_for_user_prefered =
boolean2uint8(event->param.sysparam_info.value.keyboard_for_user_prefered);
sys_param.value.left_right_mouse_buttons_swapped =
boolean2uint8(event->param.sysparam_info.value.left_right_mouse_buttons_swapped);
copy_rail_rect_16(&event->param.sysparam_info.value.work_area,
&sys_param.value.work_area);
copy_rail_rect_16(&event->param.sysparam_info.value.display_resolution,
&sys_param.value.display_resolution);
copy_rail_rect_16(&event->param.sysparam_info.value.taskbar_size,
&sys_param.value.taskbar_size);
sys_param.value.high_contrast_system_info.flags =
event->param.sysparam_info.value.high_contrast_system_info.flags;
if (sys_param.type == SPI_SETHIGHCONTRAST)
{
RAIL_STRING color_scheme;
init_rail_string(&color_scheme,
event->param.sysparam_info.value.high_contrast_system_info.color_scheme);
rail_string2unicode_string(session, &color_scheme, &sys_param.value.high_contrast_system_info.color_scheme);
}
rail_vchannel_send_client_sysparam_update_order(session, &sys_param);
free_rail_unicode_string(&sys_param.value.high_contrast_system_info.color_scheme);
}
static void rail_core_handle_ui_execute_remote_app(RAIL_SESSION* session, RAIL_UI_EVENT* event)
{
rail_core_send_client_execute(session,
event->param.execute_info.exec_or_file_is_file_path,
event->param.execute_info.exe_or_file,
event->param.execute_info.working_directory,
event->param.execute_info.arguments);
}
static void rail_core_handle_ui_activate(RAIL_SESSION* session, RAIL_UI_EVENT* event)
{
rail_vchannel_send_activate_order(
session, event->param.activate_info.window_id,
((event->param.activate_info.enabled == True) ? 1 : 0));
}
static void rail_core_handle_ui_sys_command(RAIL_SESSION* session, RAIL_UI_EVENT* event)
{
rail_vchannel_send_syscommand_order(session,
event->param.syscommand_info.window_id,
event->param.syscommand_info.syscommand);
}
static void rail_core_handle_ui_notify(RAIL_SESSION* session, RAIL_UI_EVENT* event)
{
rail_vchannel_send_notify_event_order(session,
event->param.notify_info.window_id,
event->param.notify_info.notify_icon_id,
event->param.notify_info.message);
}
static void rail_core_handle_ui_window_move(RAIL_SESSION* session, RAIL_UI_EVENT* event)
{
rail_vchannel_send_client_windowmove_order(session,
event->param.window_move_info.window_id,
&event->param.window_move_info.new_position);
}
static void rail_core_handle_ui_system_menu(RAIL_SESSION* session, RAIL_UI_EVENT* event)
{
rail_vchannel_send_client_system_menu_order(session,
event->param.system_menu_info.window_id,
event->param.system_menu_info.left,
event->param.system_menu_info.top);
}
static void rail_core_handle_ui_get_app_id(RAIL_SESSION* session, RAIL_UI_EVENT* event)
{
rail_vchannel_send_get_appid_req_order(session, event->param.get_app_id_info.window_id);
}
void rail_core_handle_ui_event(RAIL_SESSION* session, RAIL_UI_EVENT* event)
{
struct
{
uint32 event_id;
void (*event_handler)(RAIL_SESSION* session, RAIL_UI_EVENT* event);
} handlers_table[] =
{
{RAIL_UI_EVENT_UPDATE_CLIENT_SYSPARAM, rail_core_handle_ui_update_client_sysparam},
{RAIL_UI_EVENT_EXECUTE_REMOTE_APP, rail_core_handle_ui_execute_remote_app},
{RAIL_UI_EVENT_ACTIVATE, rail_core_handle_ui_activate},
{RAIL_UI_EVENT_SYS_COMMAND, rail_core_handle_ui_sys_command},
{RAIL_UI_EVENT_NOTIFY, rail_core_handle_ui_notify},
{RAIL_UI_EVENT_WINDOW_MOVE, rail_core_handle_ui_window_move},
{RAIL_UI_EVENT_SYSTEM_MENU, rail_core_handle_ui_system_menu},
{RAIL_UI_EVENT_LANGBAR_INFO, rail_core_handle_ui_system_menu},
{RAIL_UI_EVENT_GET_APP_ID, rail_core_handle_ui_get_app_id}
};
int i = 0;
for (i = 0; i < RAIL_ARRAY_SIZE(handlers_table); i++)
{
if ((event->event_id == handlers_table[i].event_id) &&
(handlers_table[i].event_handler != NULL))
{
(handlers_table[i].event_handler)(session, event);
}
}
}

137
channels/rail/rail_core.h Normal file
View File

@ -0,0 +1,137 @@
/**
* FreeRDP: A Remote Desktop Protocol Client
* Remote Applications Integrated Locally (RAIL)
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2011 Roman Barabanov <romanbarabanov@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.
*/
#ifndef __RAIL_CORE_H
#define __RAIL_CORE_H
#include <freerdp/types.h>
#include <freerdp/utils/stream.h>
#include <freerdp/utils/unicode.h>
#include <freerdp/rail.h>
#include <assert.h>
#include <freerdp/utils/debug.h>
#define WITH_DEBUG_RAIL 1
#ifdef WITH_DEBUG_RAIL
#define DEBUG_RAIL(fmt, ...) DEBUG_CLASS(RAIL, fmt, ## __VA_ARGS__)
#else
#define DEBUG_RAIL(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
#endif
#define RAIL_ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
typedef struct _RAIL_STRING
{
uint16 length;
uint8 *buffer;
} RAIL_STRING;
typedef struct _RAIL_HIGHCONTRAST
{
uint32 flags;
RAIL_UNICODE_STRING color_scheme;
} RAIL_HIGHCONTRAST;
typedef struct _RAIL_CLIENT_SYSPARAM
{
uint32 type;
union
{
uint8 full_window_drag_enabled;
uint8 menu_access_key_always_underlined;
uint8 keyboard_for_user_prefered;
uint8 left_right_mouse_buttons_swapped;
RAIL_RECT_16 work_area;
RAIL_RECT_16 display_resolution;
RAIL_RECT_16 taskbar_size;
RAIL_HIGHCONTRAST high_contrast_system_info;
} value;
} RAIL_CLIENT_SYSPARAM;
struct _RAIL_SERVER_SYSPARAM
{
uint32 type;
union
{
uint8 screen_saver_enabled;
uint8 screen_saver_lock_enabled;
} value;
};
typedef struct _RAIL_SERVER_SYSPARAM RAIL_SERVER_SYSPARAM;
struct _RAIL_VCHANNEL_DATA_SENDER
{
void* data_sender_object;
void (*send_rail_vchannel_data)(void* sender_object, void* data, size_t length);
};
typedef struct _RAIL_VCHANNEL_DATA_SENDER RAIL_VCHANNEL_DATA_SENDER;
struct _RAIL_VCHANNEL_EVENT_SENDER
{
void * event_sender_object;
void (*send_rail_vchannel_event)(void* ui_event_sender_object, RAIL_VCHANNEL_EVENT* event);
};
typedef struct _RAIL_VCHANNEL_EVENT_SENDER RAIL_VCHANNEL_EVENT_SENDER;
struct _RAIL_SESSION
{
UNICONV * uniconv;
RAIL_VCHANNEL_DATA_SENDER* data_sender;
RAIL_VCHANNEL_EVENT_SENDER* event_sender;
};
typedef struct _RAIL_SESSION RAIL_SESSION;
RAIL_SESSION* rail_core_session_new(RAIL_VCHANNEL_DATA_SENDER *data_sender, RAIL_VCHANNEL_EVENT_SENDER *event_sender);
void rail_core_session_free(RAIL_SESSION * rail_session);
// RAIL Core Handlers for events from channel plugin interface
void rail_core_on_channel_connected(RAIL_SESSION* rail_session);
void rail_core_on_channel_terminated(RAIL_SESSION* rail_session);
void rail_core_on_channel_data_received(RAIL_SESSION* rail_session, void* data, size_t length);
// RAIL Core Handlers for events from UI
void rail_core_handle_ui_event(RAIL_SESSION* session, RAIL_UI_EVENT* event);
// RAIL Core Handlers for events from channel orders reader
void rail_core_handle_server_handshake(RAIL_SESSION* session, uint32 build_number);
void rail_core_handle_exec_result(RAIL_SESSION* session, uint16 flags,
uint16 exec_result, uint32 raw_result, RAIL_UNICODE_STRING* exe_or_file);
void rail_core_handle_server_sysparam(RAIL_SESSION* session, RAIL_SERVER_SYSPARAM* sysparam);
void rail_core_handle_server_movesize(RAIL_SESSION* session, uint32 window_id,
uint16 move_size_started, uint16 move_size_type, uint16 pos_x, uint16 pos_y);
void rail_core_handle_server_minmax_info(RAIL_SESSION* session, uint32 window_id,
uint16 max_width, uint16 max_height, uint16 max_pos_x, uint16 max_pos_y,
uint16 min_track_width, uint16 min_track_height, uint16 max_track_width, uint16 max_track_height);
void rail_core_handle_server_langbar_info(RAIL_SESSION* session, uint32 langbar_status);
void rail_core_handle_server_get_app_resp(RAIL_SESSION* session, uint32 window_id, RAIL_UNICODE_STRING* app_id);
#endif /* __RAIL_CORE_H */

149
channels/rail/rail_main.c Normal file
View File

@ -0,0 +1,149 @@
/**
* FreeRDP: A Remote Desktop Protocol Client
* RAIL Virtual Channel Plugin
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2011 Roman Barabanov <romanbarabanov@gmail.com>
* 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 <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 <freerdp/rail.h>
#include "rail_core.h"
#include "rail_main.h"
static void rail_plugin_process_connect(rdpSvcPlugin* plugin)
{
railPlugin* rail_plugin = (railPlugin*)plugin;
DEBUG_RAIL("rail_plugin_process_connect() called.");
rail_core_on_channel_connected(rail_plugin->session);
}
static void rail_plugin_process_terminate(rdpSvcPlugin* plugin)
{
DEBUG_RAIL("rail_plugin_process_terminate\n");
xfree(plugin);
}
static void rail_plugin_send_vchannel_data(void* rail_plugin_object, void* data, size_t length)
{
STREAM* s = NULL;
railPlugin* plugin = (railPlugin*) rail_plugin_object;
s = stream_new(length);
stream_write(s, data, length);
svc_plugin_send((rdpSvcPlugin*) plugin, s);
}
static void rail_plugin_process_received_vchannel_data(rdpSvcPlugin* plugin, STREAM* data_in)
{
railPlugin* rail_plugin = (railPlugin*) plugin;
DEBUG_RAIL("rail_plugin_process_receive: size=%d", stream_get_size(data_in));
rail_vchannel_process_received_vchannel_data(rail_plugin->session, data_in);
stream_free(data_in);
}
static void on_free_rail_vchannel_event(FRDP_EVENT* event)
{
assert(event->event_type == FRDP_EVENT_TYPE_RAIL_VCHANNEL_2_UI);
RAIL_VCHANNEL_EVENT* rail_event = (RAIL_VCHANNEL_EVENT*)event->user_data;
if (rail_event->event_id == RAIL_VCHANNEL_EVENT_APP_RESPONSE_RECEIVED)
xfree((void*)rail_event->param.app_response_info.application_id);
if (rail_event->event_id == RAIL_VCHANNEL_EVENT_EXEC_RESULT_RETURNED)
xfree((void*)rail_event->param.exec_result_info.exe_or_file);
xfree(rail_event);
}
static void rail_plugin_send_vchannel_event(void* rail_plugin_object, RAIL_VCHANNEL_EVENT* event)
{
railPlugin* plugin = (railPlugin*) rail_plugin_object;
RAIL_VCHANNEL_EVENT* payload = NULL;
FRDP_EVENT* out_event = NULL;
payload = xnew(RAIL_VCHANNEL_EVENT);
memset(payload, 0, sizeof(RAIL_VCHANNEL_EVENT));
memcpy(payload, event, sizeof(RAIL_VCHANNEL_EVENT));
out_event = freerdp_event_new(FRDP_EVENT_TYPE_RAIL_VCHANNEL_2_UI, on_free_rail_vchannel_event, payload);
svc_plugin_send_event((rdpSvcPlugin*) plugin, out_event);
}
static void rail_plugin_process_event(rdpSvcPlugin* plugin, FRDP_EVENT* event)
{
RAIL_UI_EVENT* rail_ui_event = NULL;
railPlugin* rail_plugin = NULL;
DEBUG_RAIL("rail_plugin_process_event: event_type=%d\n", event->event_type);
rail_plugin = (railPlugin*)plugin;
rail_ui_event = (RAIL_UI_EVENT*)event->user_data;
if (event->event_type == FRDP_EVENT_TYPE_RAIL_UI_2_VCHANNEL)
rail_core_handle_ui_event(rail_plugin->session, rail_ui_event);
freerdp_event_free(event);
}
int VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
{
railPlugin* rail;
DEBUG_RAIL("RAIL plugin VirtualChannelEntry started.");
rail = (railPlugin*) xzalloc(sizeof(railPlugin));
rail->plugin.channel_def.options = CHANNEL_OPTION_INITIALIZED |
CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP |
CHANNEL_OPTION_SHOW_PROTOCOL;
strcpy(rail->plugin.channel_def.name, "rail");
rail->plugin.connect_callback = rail_plugin_process_connect;
rail->plugin.terminate_callback = rail_plugin_process_terminate;
rail->plugin.receive_callback = rail_plugin_process_received_vchannel_data;
rail->plugin.event_callback = rail_plugin_process_event;
rail->rail_event_sender.event_sender_object = rail;
rail->rail_event_sender.send_rail_vchannel_event = rail_plugin_send_vchannel_event;
rail->rail_data_sender.data_sender_object = rail;
rail->rail_data_sender.send_rail_vchannel_data =
rail_plugin_send_vchannel_data;
rail->session = rail_core_session_new(&rail->rail_data_sender, &rail->rail_event_sender);
svc_plugin_init((rdpSvcPlugin*) rail, pEntryPoints);
DEBUG_RAIL("RAIL plugin VirtualChannelEntry finished.");
return 1;
}

34
channels/rail/rail_main.h Normal file
View File

@ -0,0 +1,34 @@
/**
* FreeRDP: A Remote Desktop Protocol Client
* RAIL Virtual Channel Plugin
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2011 Roman Barabanov <romanbarabanov@gmail.com>
* 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 __RAIL_MAIN_H
#define __RAIL_MAIN_H
struct rail_plugin
{
rdpSvcPlugin plugin;
RAIL_VCHANNEL_DATA_SENDER rail_data_sender;
RAIL_VCHANNEL_EVENT_SENDER rail_event_sender;
RAIL_SESSION * session;
};
typedef struct rail_plugin railPlugin;
#endif /* __RAIL_MAIN_H */

View File

@ -407,7 +407,8 @@ boolean disk_file_set_information(DISK_FILE* file, uint32 FsInformationClass, ui
case FileAllocationInformation:
/* http://msdn.microsoft.com/en-us/library/cc232076.aspx */
stream_read_uint64(input, size);
ftruncate(file->fd, size);
if (ftruncate(file->fd, size) != 0)
return False;
break;
case FileDispositionInformation:

View File

@ -81,7 +81,10 @@ enum FRDP_EVENT_TYPE
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
FRDP_EVENT_TYPE_CB_DATA_RESPONSE = 6,
FRDP_EVENT_TYPE_RAIL_UI_2_VCHANNEL = 100,
FRDP_EVENT_TYPE_RAIL_VCHANNEL_2_UI = 101
};
/**

341
include/freerdp/rail.h Normal file
View File

@ -0,0 +1,341 @@
/**
* FreeRDP: A Remote Desktop Protocol Client
* Remote Applications Integrated Locally (RAIL)
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2011 Roman Barabanov <romanbarabanov@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.
*/
#ifndef __RAIL_H
#define __RAIL_H
/* RAIL Constants*/
enum RDP_RAIL_PDU_TYPE
{
RDP_RAIL_ORDER_EXEC = 0x0001,
RDP_RAIL_ORDER_ACTIVATE = 0x0002,
RDP_RAIL_ORDER_SYSPARAM = 0x0003,
RDP_RAIL_ORDER_SYSCOMMAND = 0x0004,
RDP_RAIL_ORDER_HANDSHAKE = 0x0005,
RDP_RAIL_ORDER_NOTIFY_EVENT = 0x0006,
RDP_RAIL_ORDER_WINDOWMOVE = 0x0008,
RDP_RAIL_ORDER_LOCALMOVESIZE = 0x0009,
RDP_RAIL_ORDER_MINMAXINFO = 0x000A,
RDP_RAIL_ORDER_CLIENTSTATUS = 0x000B,
RDP_RAIL_ORDER_SYSMENU = 0x000C,
RDP_RAIL_ORDER_LANGBARINFO = 0x000D,
RDP_RAIL_ORDER_EXEC_RESULT = 0x0080,
RDP_RAIL_ORDER_GET_APPID_REQ = 0x000E,
RDP_RAIL_ORDER_GET_APPID_RESP = 0x000F
};
/* RAIL PDU flags */
#define RAIL_EXEC_FLAG_EXPAND_WORKINGDIRECTORY 0x0001
#define RAIL_EXEC_FLAG_TRANSLATE_FILES 0x0002
#define RAIL_EXEC_FLAG_FILE 0x0004
#define RAIL_EXEC_FLAG_EXPAND_ARGUMENTS 0x0008
/* Notification Icon Balloon Tooltip */
#define NIIF_NONE 0x00000000
#define NIIF_INFO 0x00000001
#define NIIF_WARNING 0x00000002
#define NIIF_ERROR 0x00000003
#define NIIF_NOSOUND 0x00000010
#define NIIF_LARGE_ICON 0x00000020
/* Client Execute PDU Flags */
#define RAIL_EXEC_FLAG_EXPAND_WORKING_DIRECTORY 0x0001
#define RAIL_EXEC_FLAG_TRANSLATE_FILES 0x0002
#define RAIL_EXEC_FLAG_FILE 0x0004
#define RAIL_EXEC_FLAG_EXPAND_ARGUMENTS 0x0008
/* Server Execute Result PDU */
#define RAIL_EXEC_S_OK 0x0000
#define RAIL_EXEC_E_HOOK_NOT_LOADED 0x0001
#define RAIL_EXEC_E_DECODE_FAILED 0x0002
#define RAIL_EXEC_E_NOT_IN_ALLOWLIST 0x0003
#define RAIL_EXEC_E_FILE_NOT_FOUND 0x0005
#define RAIL_EXEC_E_FAIL 0x0006
#define RAIL_EXEC_E_SESSION_LOCKED 0x0007
/* Client System Parameters Update PDU */
#define SPI_SETDRAGFULLWINDOWS 0x00000025
#define SPI_SETKEYBOARDCUES 0x0000100B
#define SPI_SETKEYBOARDPREF 0x00000045
#define SPI_SETWORKAREA 0x0000002F
#define SPI_SETMOUSEBUTTONSWAP 0x00000021
#define SPI_SETHIGHCONTRAST 0x00000043
#define RAIL_SPI_DISPLAYCHANGE 0x0000F001
#define RAIL_SPI_TASKBARPOS 0x0000F000
/* Server System Parameters Update PDU */
#define SPI_SETSCREENSAVEACTIVE 0x00000011
#define SPI_SETSCREENSAVESECURE 0x00000077
/* Client System Command PDU */
#define SC_SIZE 0xF000
#define SC_MOVE 0xF010
#define SC_MINIMIZE 0xF020
#define SC_MAXIMIZE 0xF030
#define SC_CLOSE 0xF060
#define SC_KEYMENU 0xF100
#define SC_RESTORE 0xF120
#define SC_DEFAULT 0xF160
/* Client Notify Event PDU */
#define WM_LBUTTONDOWN 0x00000201
#define WM_LBUTTONUP 0x00000202
#define WM_RBUTTONDOWN 0x00000204
#define WM_RBUTTONUP 0x00000205
#define WM_CONTEXTMENU 0x0000007B
#define WM_LBUTTONDBLCLK 0x00000203
#define WM_RBUTTONDBLCLK 0x00000206
#define NIN_SELECT 0x00000400
#define NIN_KEYSELECT 0x00000401
#define NIN_BALLOONSHOW 0x00000402
#define NIN_BALLOONHIDE 0x00000403
#define NIN_BALLOONTIMEOUT 0x00000404
#define NIN_BALLOONUSERCLICK 0x00000405
/* Client Information PDU */
#define RAIL_CLIENTSTATUS_ALLOWLOCALMOVESIZE 0x00000001
#define RAIL_CLIENTSTATUS_AUTORECONNECT 0x00000002
/*HIGHCONTRAST flags values */
#define HCF_AVAILABLE 0x00000002
#define HCF_CONFIRMHOTKEY 0x00000008
#define HCF_HIGHCONTRASTON 0x00000001
#define HCF_HOTKEYACTIVE 0x00000004
#define HCF_HOTKEYAVAILABLE 0x00000040
#define HCF_HOTKEYSOUND 0x00000010
#define HCF_INDICATOR 0x00000020
/* Server Move/Size Start PDU */
#define RAIL_WMSZ_LEFT 0x0001
#define RAIL_WMSZ_RIGHT 0x0002
#define RAIL_WMSZ_TOP 0x0003
#define RAIL_WMSZ_TOPLEFT 0x0004
#define RAIL_WMSZ_TOPRIGHT 0x0005
#define RAIL_WMSZ_BOTTOM 0x0006
#define RAIL_WMSZ_BOTTOMLEFT 0x0007
#define RAIL_WMSZ_BOTTOMRIGHT 0x0008
#define RAIL_WMSZ_MOVE 0x0009
#define RAIL_WMSZ_KEYMOVE 0x000A
#define RAIL_WMSZ_KEYSIZE 0x000B
/* Language Bar Information PDU */
#define TF_SFT_SHOWNORMAL 0x00000001
#define TF_SFT_DOCK 0x00000002
#define TF_SFT_MINIMIZED 0x00000004
#define TF_SFT_HIDDEN 0x00000008
#define TF_SFT_NOTRANSPARENCY 0x00000010
#define TF_SFT_LOWTRANSPARENCY 0x00000020
#define TF_SFT_HIGHTRANSPARENCY 0x00000040
#define TF_SFT_LABELS 0x00000080
#define TF_SFT_NOLABELS 0x00000100
#define TF_SFT_EXTRAICONSONMINIMIZED 0x00000200
#define TF_SFT_NOEXTRAICONSONMINIMIZED 0x00000400
#define TF_SFT_DESKBAND 0x00000800
/* RAIL Common structures */
typedef struct _RAIL_RECT_16
{
uint16 left;
uint16 top;
uint16 right;
uint16 bottom;
}
RAIL_RECT_16;
typedef struct _RAIL_UNICODE_STRING
{
uint16 length;
uint8 *buffer;
}
RAIL_UNICODE_STRING;
// Events from 'rail' vchannel plugin to UI
enum RAIL_VCHANNEL_EVENT
{
RAIL_VCHANNEL_EVENT_SESSION_ESTABLISHED = 1,
RAIL_VCHANNEL_EVENT_EXEC_RESULT_RETURNED,
RAIL_VCHANNEL_EVENT_SERVER_SYSPARAM_RECEIVED,
RAIL_VCHANNEL_EVENT_MOVESIZE_STARTED,
RAIL_VCHANNEL_EVENT_MOVESIZE_FINISHED,
RAIL_VCHANNEL_EVENT_MINMAX_INFO_UPDATED,
RAIL_VCHANNEL_EVENT_LANGBAR_STATUS_UPDATED,
RAIL_VCHANNEL_EVENT_APP_RESPONSE_RECEIVED
};
typedef struct _RAIL_VCHANNEL_EVENT
{
uint32 event_id;
union
{
struct
{
uint16 flags;
uint16 exec_result;
uint32 raw_result;
const char* exe_or_file;
} exec_result_info;
struct
{
uint32 param_type;
boolean screen_saver_enabled;
boolean screen_saver_lock_enabled;
} server_param_info;
struct
{
uint32 window_id;
uint16 move_size_type;
uint16 pos_x;
uint16 pos_y;
} movesize_info;
struct
{
uint32 window_id;
uint16 max_width;
uint16 max_height;
uint16 max_pos_x;
uint16 max_pos_y;
uint16 min_track_width;
uint16 min_track_height;
uint16 max_track_width;
uint16 max_track_height;
} minmax_info;
struct
{
uint32 status;
} langbar_info;
struct
{
uint32 window_id;
const char* application_id;
} app_response_info;
}param;
}
RAIL_VCHANNEL_EVENT;
// Events from UI to 'rail' vchannel plugin
enum RAIL_UI_EVENT
{
RAIL_UI_EVENT_UPDATE_CLIENT_SYSPARAM = 1,
RAIL_UI_EVENT_EXECUTE_REMOTE_APP,
RAIL_UI_EVENT_ACTIVATE,
RAIL_UI_EVENT_SYS_COMMAND,
RAIL_UI_EVENT_NOTIFY,
RAIL_UI_EVENT_WINDOW_MOVE,
RAIL_UI_EVENT_SYSTEM_MENU,
RAIL_UI_EVENT_LANGBAR_INFO,
RAIL_UI_EVENT_GET_APP_ID
};
typedef struct _RAIL_UI_EVENT
{
uint32 event_id;
union
{
struct
{
uint32 param;
union
{
boolean full_window_drag_enabled;
boolean menu_access_key_always_underlined;
boolean keyboard_for_user_prefered;
boolean left_right_mouse_buttons_swapped;
RAIL_RECT_16 work_area;
RAIL_RECT_16 display_resolution;
RAIL_RECT_16 taskbar_size;
struct
{
uint32 flags;
const char* color_scheme;
} high_contrast_system_info;
} value;
} sysparam_info;
struct
{
boolean exec_or_file_is_file_path;
const char* exe_or_file;
const char* working_directory;
const char* arguments;
} execute_info;
struct
{
uint32 window_id;
boolean enabled;
} activate_info;
struct
{
uint32 window_id;
uint32 syscommand;
} syscommand_info;
struct
{
uint32 window_id;
uint32 notify_icon_id;
uint32 message;
} notify_info;
struct
{
uint32 window_id;
RAIL_RECT_16 new_position;
} window_move_info;
struct
{
uint32 window_id;
uint16 left;
uint16 top;
} system_menu_info;
struct
{
uint32 status;
} langbar_info;
struct
{
uint32 window_id;
} get_app_id_info;
} param;
}
RAIL_UI_EVENT;
#endif /* __RAIL_H */

View File

@ -50,6 +50,10 @@ FRDP_EVENT* freerdp_event_new(uint32 event_type, FRDP_EVENT_CALLBACK on_event_fr
case FRDP_EVENT_TYPE_CB_DATA_RESPONSE:
event = (FRDP_EVENT*)xnew(FRDP_CB_DATA_RESPONSE_EVENT);
break;
case FRDP_EVENT_TYPE_RAIL_UI_2_VCHANNEL:
case FRDP_EVENT_TYPE_RAIL_VCHANNEL_2_UI:
event = xnew(FRDP_EVENT);
break;
}
if (event != NULL)
{