diff --git a/channels/encomsp/client/CMakeLists.txt b/channels/encomsp/client/CMakeLists.txt index 7e96cbd0c..89b2e1ed0 100644 --- a/channels/encomsp/client/CMakeLists.txt +++ b/channels/encomsp/client/CMakeLists.txt @@ -17,9 +17,13 @@ define_channel_client("encomsp") +include_directories(..) + set(${MODULE_PREFIX}_SRCS encomsp_main.c - encomsp_main.h) + encomsp_main.h + ../encomsp_common.c + ../encomsp_common.h) add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry") diff --git a/channels/encomsp/client/encomsp_main.c b/channels/encomsp/client/encomsp_main.c index 1ed31296f..3e2be2182 100644 --- a/channels/encomsp/client/encomsp_main.c +++ b/channels/encomsp/client/encomsp_main.c @@ -26,6 +26,8 @@ #include +#include "encomsp_common.h" + #include "encomsp_main.h" EncomspClientContext* encomsp_get_client_interface(encomspPlugin* encomsp) @@ -59,45 +61,6 @@ int encomsp_virtual_channel_write(encomspPlugin* encomsp, wStream* s) return 1; } -int encomsp_read_header(wStream* s, ENCOMSP_ORDER_HEADER* header) -{ - if (Stream_GetRemainingLength(s) < ENCOMSP_ORDER_HEADER_SIZE) - return -1; - - Stream_Read_UINT16(s, header->Type); /* Type (2 bytes) */ - Stream_Read_UINT16(s, header->Length); /* Length (2 bytes) */ - - return 1; -} - -int encomsp_write_header(wStream* s, ENCOMSP_ORDER_HEADER* header) -{ - Stream_Write_UINT16(s, header->Type); /* Type (2 bytes) */ - Stream_Write_UINT16(s, header->Length); /* Length (2 bytes) */ - - return 1; -} - -int encomsp_read_unicode_string(wStream* s, ENCOMSP_UNICODE_STRING* str) -{ - ZeroMemory(str, sizeof(ENCOMSP_UNICODE_STRING)); - - if (Stream_GetRemainingLength(s) < 2) - return -1; - - Stream_Read_UINT16(s, str->cchString); /* cchString (2 bytes) */ - - if (str->cchString > 1024) - return -1; - - if (Stream_GetRemainingLength(s) < (str->cchString * 2)) - return -1; - - Stream_Read(s, &(str->wString), (str->cchString * 2)); /* String (variable) */ - - return 1; -} - int encomsp_recv_filter_updated_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) { int beg, end; diff --git a/channels/encomsp/encomsp_common.c b/channels/encomsp/encomsp_common.c new file mode 100644 index 000000000..6f3d61cad --- /dev/null +++ b/channels/encomsp/encomsp_common.c @@ -0,0 +1,66 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Multiparty Virtual Channel + * + * Copyright 2014 Marc-Andre Moreau + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "encomsp_common.h" + +int encomsp_read_header(wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + if (Stream_GetRemainingLength(s) < ENCOMSP_ORDER_HEADER_SIZE) + return -1; + + Stream_Read_UINT16(s, header->Type); /* Type (2 bytes) */ + Stream_Read_UINT16(s, header->Length); /* Length (2 bytes) */ + + return 1; +} + +int encomsp_write_header(wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + Stream_Write_UINT16(s, header->Type); /* Type (2 bytes) */ + Stream_Write_UINT16(s, header->Length); /* Length (2 bytes) */ + + return 1; +} + +int encomsp_read_unicode_string(wStream* s, ENCOMSP_UNICODE_STRING* str) +{ + ZeroMemory(str, sizeof(ENCOMSP_UNICODE_STRING)); + + if (Stream_GetRemainingLength(s) < 2) + return -1; + + Stream_Read_UINT16(s, str->cchString); /* cchString (2 bytes) */ + + if (str->cchString > 1024) + return -1; + + if (Stream_GetRemainingLength(s) < (str->cchString * 2)) + return -1; + + Stream_Read(s, &(str->wString), (str->cchString * 2)); /* String (variable) */ + + return 1; +} diff --git a/channels/encomsp/encomsp_common.h b/channels/encomsp/encomsp_common.h new file mode 100644 index 000000000..8ce493ab7 --- /dev/null +++ b/channels/encomsp/encomsp_common.h @@ -0,0 +1,33 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Multiparty Virtual Channel + * + * Copyright 2014 Marc-Andre Moreau + * + * 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 FREERDP_CHANNEL_ENCOMSP_COMMON_H +#define FREERDP_CHANNEL_ENCOMSP_COMMON_H + +#include +#include + +#include + +int encomsp_read_header(wStream* s, ENCOMSP_ORDER_HEADER* header); +int encomsp_write_header(wStream* s, ENCOMSP_ORDER_HEADER* header); + +int encomsp_read_unicode_string(wStream* s, ENCOMSP_UNICODE_STRING* str); + +#endif /* FREERDP_CHANNEL_ENCOMSP_COMMON_H */ diff --git a/channels/encomsp/server/CMakeLists.txt b/channels/encomsp/server/CMakeLists.txt index 90c4e8f31..1fe84d63e 100644 --- a/channels/encomsp/server/CMakeLists.txt +++ b/channels/encomsp/server/CMakeLists.txt @@ -17,9 +17,13 @@ define_channel_server("encomsp") +include_directories(..) + set(${MODULE_PREFIX}_SRCS encomsp_main.c - encomsp_main.h) + encomsp_main.h + ../encomsp_common.c + ../encomsp_common.h) add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry") diff --git a/channels/encomsp/server/encomsp_main.c b/channels/encomsp/server/encomsp_main.c index 9d7fc5ae5..bab08d351 100644 --- a/channels/encomsp/server/encomsp_main.c +++ b/channels/encomsp/server/encomsp_main.c @@ -25,11 +25,82 @@ #include #include +#include "encomsp_common.h" + #include "encomsp_main.h" static int encomsp_server_receive_pdu(EncomspServerContext* context, wStream* s) { - return 0; + int status = 1; + ENCOMSP_ORDER_HEADER header; + + while (Stream_GetRemainingLength(s) > 0) + { + if (encomsp_read_header(s, &header) < 0) + return -1; + + printf("EncomspReceive: Type: %d Length: %d\n", header.Type, header.Length); + + return 1; + +#if 0 + switch (header.Type) + { + case ODTYPE_FILTER_STATE_UPDATED: + status = encomsp_recv_filter_updated_pdu(context, s, &header); + break; + + case ODTYPE_APP_REMOVED: + status = encomsp_recv_application_removed_pdu(context, s, &header); + break; + + case ODTYPE_APP_CREATED: + status = encomsp_recv_application_created_pdu(context, s, &header); + break; + + case ODTYPE_WND_REMOVED: + status = encomsp_recv_window_removed_pdu(context, s, &header); + break; + + case ODTYPE_WND_CREATED: + status = encomsp_recv_window_created_pdu(context, s, &header); + break; + + case ODTYPE_WND_SHOW: + status = encomsp_recv_show_window_pdu(context, s, &header); + break; + + case ODTYPE_PARTICIPANT_REMOVED: + status = encomsp_recv_participant_removed_pdu(context, s, &header); + break; + + case ODTYPE_PARTICIPANT_CREATED: + status = encomsp_recv_participant_created_pdu(context, s, &header); + break; + + case ODTYPE_PARTICIPANT_CTRL_CHANGED: + status = encomsp_recv_change_participant_control_level_pdu(context, s, &header); + break; + + case ODTYPE_GRAPHICS_STREAM_PAUSED: + status = encomsp_recv_graphics_stream_paused_pdu(context, s, &header); + break; + + case ODTYPE_GRAPHICS_STREAM_RESUMED: + status = encomsp_recv_graphics_stream_resumed_pdu(context, s, &header); + break; + + default: + status = -1; + break; + } + + if (status < 0) + return -1; +#endif + } + + return status; } static void* encomsp_server_thread(void* arg) @@ -83,10 +154,7 @@ static void* encomsp_server_thread(void* arg) Stream_EnsureRemainingCapacity(s, BytesReturned); } - if (0) - { - encomsp_server_receive_pdu(context, s); - } + encomsp_server_receive_pdu(context, s); } Stream_Free(s, TRUE); diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index 56de3fcf9..cd66d3bb5 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -885,9 +885,9 @@ BOOL xf_post_connect(freerdp *instance) XFillRectangle(xfc->display, xfc->primary, xfc->gc, 0, 0, xfc->width, xfc->height); XFlush(xfc->display); xfc->image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, - (char *) xfc->primary_buffer, xfc->width, xfc->height, xfc->scanline_pad, 0); + (char*) xfc->primary_buffer, xfc->width, xfc->height, xfc->scanline_pad, 0); xfc->bmp_codec_none = (BYTE *) malloc(64 * 64 * 4); - + if (xfc->settings->SoftwareGdi) { instance->update->BeginPaint = xf_sw_begin_paint; diff --git a/include/freerdp/server/shadow.h b/include/freerdp/server/shadow.h index ed2483788..2092275c2 100644 --- a/include/freerdp/server/shadow.h +++ b/include/freerdp/server/shadow.h @@ -26,6 +26,12 @@ #include #include +#include +#include + +#include +#include + #include #include @@ -62,8 +68,16 @@ struct rdp_shadow_client HANDLE thread; BOOL activated; + BOOL inLobby; + BOOL mayView; + BOOL mayInteract; HANDLE StopEvent; rdpShadowServer* server; + rdpShadowSurface* lobby; + + HANDLE vcm; + EncomspServerContext* encomsp; + RemdeskServerContext* remdesk; }; struct rdp_shadow_server @@ -77,6 +91,8 @@ struct rdp_shadow_server rdpShadowSubsystem* subsystem; DWORD port; + BOOL mayView; + BOOL mayInteract; freerdp_listener* listener; pfnShadowCreateSubsystem CreateSubsystem; }; diff --git a/server/shadow/CMakeLists.txt b/server/shadow/CMakeLists.txt index 27b2aa94f..9bec3b117 100644 --- a/server/shadow/CMakeLists.txt +++ b/server/shadow/CMakeLists.txt @@ -126,6 +126,8 @@ set(${MODULE_PREFIX}_SRCS shadow_surface.h shadow_encoder.c shadow_encoder.h + shadow_channels.c + shadow_channels.h shadow.c shadow.h) @@ -141,6 +143,8 @@ endif() add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME "freerdp-shadow") +list(APPEND ${MODULE_PREFIX}_LIBS freerdp-server) + set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} MODULE freerdp @@ -151,7 +155,7 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MODULE winpr MODULES winpr-sspi winpr-crt winpr-utils winpr-input winpr-sysinfo) -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr-makecert-tool) +list(APPEND ${MODULE_PREFIX}_LIBS winpr-makecert-tool) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/server/shadow/shadow.c b/server/shadow/shadow.c index a1406cf5a..4ae7cf0c3 100644 --- a/server/shadow/shadow.c +++ b/server/shadow/shadow.c @@ -44,6 +44,8 @@ static COMMAND_LINE_ARGUMENT_A shadow_args[] = { { "port", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Server port" }, { "monitors", COMMAND_LINE_VALUE_OPTIONAL, "<0,1,2...>", NULL, NULL, -1, NULL, "Select or list monitors" }, + { "may-view", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Clients may view without prompt" }, + { "may-interact", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Clients may interact without prompt" }, { "version", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_VERSION, NULL, NULL, NULL, -1, NULL, "Print version" }, { "help", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_HELP, NULL, NULL, NULL, -1, "?", "Print help" }, { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } @@ -165,8 +167,17 @@ int shadow_server_parse_command_line(rdpShadowServer* server, int argc, char** a { server->port = (DWORD) atoi(arg->Value); } + CommandLineSwitchCase(arg, "may-view") + { + server->mayView = arg->Value ? TRUE : FALSE; + } + CommandLineSwitchCase(arg, "may-interact") + { + server->mayInteract = arg->Value ? TRUE : FALSE; + } CommandLineSwitchDefault(arg) { + } CommandLineSwitchEnd(arg) @@ -175,7 +186,7 @@ int shadow_server_parse_command_line(rdpShadowServer* server, int argc, char** a arg = CommandLineFindArgumentA(shadow_args, "monitors"); - if (arg) + if (arg && (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)) { if (arg->Flags & COMMAND_LINE_VALUE_PRESENT) { @@ -297,6 +308,8 @@ int shadow_server_stop(rdpShadowServer* server) int shadow_server_init(rdpShadowServer* server) { + WTSRegisterWtsApiFunctionTable(FreeRDP_InitWtsApi()); + server->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); server->listener = freerdp_listener_new(); @@ -368,6 +381,8 @@ rdpShadowServer* shadow_server_new() return NULL; server->port = 3389; + server->mayView = TRUE; + server->mayInteract = TRUE; return server; } diff --git a/server/shadow/shadow.h b/server/shadow/shadow.h index 65f20f332..b474c68c6 100644 --- a/server/shadow/shadow.h +++ b/server/shadow/shadow.h @@ -26,6 +26,7 @@ #include "shadow_screen.h" #include "shadow_surface.h" #include "shadow_encoder.h" +#include "shadow_channels.h" #ifdef __cplusplus extern "C" { diff --git a/server/shadow/shadow_channels.c b/server/shadow/shadow_channels.c new file mode 100644 index 000000000..eeb4e7e0e --- /dev/null +++ b/server/shadow/shadow_channels.c @@ -0,0 +1,46 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * Copyright 2014 Marc-Andre Moreau + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "shadow.h" + +#include "shadow_channels.h" + +int shadow_client_channels_post_connect(rdpShadowClient* client) +{ + if (WTSVirtualChannelManagerIsChannelJoined(client->vcm, ENCOMSP_SVC_CHANNEL_NAME)) + { + client->encomsp = encomsp_server_context_new(client->vcm); + + if (client->encomsp) + client->encomsp->Start(client->encomsp); + } + + if (WTSVirtualChannelManagerIsChannelJoined(client->vcm, REMDESK_SVC_CHANNEL_NAME)) + { + client->remdesk = remdesk_server_context_new(client->vcm); + + if (client->remdesk) + client->remdesk->Start(client->remdesk); + } + + return 0; +} diff --git a/server/shadow/shadow_channels.h b/server/shadow/shadow_channels.h new file mode 100644 index 000000000..fab849ded --- /dev/null +++ b/server/shadow/shadow_channels.h @@ -0,0 +1,37 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * Copyright 2014 Marc-Andre Moreau + * + * 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 FREERDP_SHADOW_SERVER_CHANNELS_H +#define FREERDP_SHADOW_SERVER_CHANNELS_H + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int shadow_client_channels_post_connect(rdpShadowClient* client); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_SHADOW_SERVER_CHANNELS_H */ diff --git a/server/shadow/shadow_client.c b/server/shadow/shadow_client.c index acf3eff1e..a6a641993 100644 --- a/server/shadow/shadow_client.c +++ b/server/shadow/shadow_client.c @@ -46,12 +46,26 @@ void shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client) settings->FrameMarkerCommandEnabled = TRUE; settings->SurfaceFrameMarkerEnabled = TRUE; + client->inLobby = TRUE; + client->mayView = server->mayView; + client->mayInteract = server->mayInteract; + + client->vcm = WTSOpenServerA((LPSTR) peer->context); + client->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); } void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client) { + WTSCloseServer((HANDLE) client->vcm); + CloseHandle(client->StopEvent); + + if (client->lobby) + { + shadow_surface_free(client->lobby); + client->lobby = NULL; + } } BOOL shadow_client_capabilities(freerdp_peer* peer) @@ -63,6 +77,8 @@ BOOL shadow_client_post_connect(freerdp_peer* peer) { rdpSettings* settings; rdpShadowClient* client; + rdpShadowSurface* lobby; + RECTANGLE_16 invalidRect; client = (rdpShadowClient*) peer->context; settings = peer->settings; @@ -76,6 +92,23 @@ BOOL shadow_client_post_connect(freerdp_peer* peer) peer->update->DesktopResize(peer->update->context); + shadow_client_channels_post_connect(client); + + lobby = client->lobby = shadow_surface_new(client->server, 0, 0, settings->DesktopWidth, settings->DesktopHeight); + + if (!client->lobby) + return FALSE; + + freerdp_image_fill(lobby->data, PIXEL_FORMAT_XRGB32, lobby->scanline, + 0, 0, lobby->width, lobby->height, 0x3BB9FF); + + invalidRect.left = 0; + invalidRect.top = 0; + invalidRect.right = lobby->width; + invalidRect.bottom = lobby->height; + + region16_union_rect(&(lobby->invalidRegion), &(lobby->invalidRegion), &invalidRect); + return TRUE; } @@ -86,6 +119,7 @@ BOOL shadow_client_activate(freerdp_peer* peer) client = (rdpShadowClient*) peer->context; client->activated = TRUE; + client->inLobby = client->mayView ? FALSE : TRUE; return TRUE; } @@ -152,7 +186,8 @@ int shadow_client_send_surface_bits(rdpShadowClient* client) server = client->server; encoder = server->encoder; - surface = server->surface; + + surface = client->inLobby ? client->lobby : server->surface; surfaceRect.left = surface->x; surfaceRect.top = surface->y; diff --git a/server/shadow/shadow_input.c b/server/shadow/shadow_input.c index 5e8c1acd6..4f28b0bc5 100644 --- a/server/shadow/shadow_input.c +++ b/server/shadow/shadow_input.c @@ -27,6 +27,9 @@ void shadow_input_synchronize_event(rdpInput* input, UINT32 flags) rdpShadowClient* client = (rdpShadowClient*) input->context; rdpShadowSubsystem* subsystem = client->server->subsystem; + if (!client->mayInteract) + return; + if (subsystem->SynchronizeEvent) { subsystem->SynchronizeEvent(subsystem, flags); @@ -38,6 +41,9 @@ void shadow_input_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) rdpShadowClient* client = (rdpShadowClient*) input->context; rdpShadowSubsystem* subsystem = client->server->subsystem; + if (!client->mayInteract) + return; + if (subsystem->KeyboardEvent) { subsystem->KeyboardEvent(subsystem, flags, code); @@ -49,6 +55,9 @@ void shadow_input_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 c rdpShadowClient* client = (rdpShadowClient*) input->context; rdpShadowSubsystem* subsystem = client->server->subsystem; + if (!client->mayInteract) + return; + if (subsystem->UnicodeKeyboardEvent) { subsystem->UnicodeKeyboardEvent(subsystem, flags, code); @@ -60,6 +69,9 @@ void shadow_input_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) rdpShadowClient* client = (rdpShadowClient*) input->context; rdpShadowSubsystem* subsystem = client->server->subsystem; + if (!client->mayInteract) + return; + if (subsystem->MouseEvent) { subsystem->MouseEvent(subsystem, flags, x, y); @@ -71,6 +83,9 @@ void shadow_input_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, rdpShadowClient* client = (rdpShadowClient*) input->context; rdpShadowSubsystem* subsystem = client->server->subsystem; + if (!client->mayInteract) + return; + if (subsystem->ExtendedMouseEvent) { subsystem->ExtendedMouseEvent(subsystem, flags, x, y);