diff --git a/README.md b/README.md index fa2e445a..4e7e3dbd 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,15 @@ ## Overview **xrdp** provides a graphical login to remote machines using Microsoft -Remote Desktop Protocol (RDP). xrdp accepts connections from a variety of -RDP clients: FreeRDP, rdesktop, KRDC, NeutrinoRDP and Microsoft Remote Desktop -Client (for Windows, Mac OS, iOS and Android). +Remote Desktop Protocol (RDP). xrdp accepts connections from a variety of RDP clients: + - FreeRDP + - rdesktop + - KRDC + - NeutrinoRDP + - Windows MSTSC (Microsoft Terminal Services Client) + - Microsoft Remote Desktop (which is distinct from MSTSC) + +Many of these work on some or all of Windows, Mac OS, iOS, and/or Android. RDP transport is encrypted using TLS by default. @@ -24,7 +30,7 @@ RDP transport is encrypted using TLS by default. * Connect to a Linux desktop using RDP from anywhere (requires [xorgxrdp](https://github.com/neutrinolabs/xorgxrdp) Xorg module) * Reconnect to an existing session - * Session resizing + * Session resizing on connect and while an existing session is active. * RDP/VNC proxy (connect to another RDP/VNC server via xrdp) ### Access to Remote Resources diff --git a/common/Makefile.am b/common/Makefile.am index 95351b49..76142199 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -14,6 +14,7 @@ include_HEADERS = \ ms-rdpegdi.h \ ms-rdpele.h \ ms-rdperp.h \ + ms-rdpedisp.h \ ms-smb2.h \ xrdp_client_info.h \ xrdp_constants.h \ diff --git a/common/ms-rdpbcgr.h b/common/ms-rdpbcgr.h index 71fa5d58..35e53869 100644 --- a/common/ms-rdpbcgr.h +++ b/common/ms-rdpbcgr.h @@ -78,7 +78,12 @@ /* This isn't explicitly named in MS-RDPBCGR */ #define CHANNEL_NAME_LEN 7 -/* Oprions field */ +/* 2.2.1.3.6 Client Monitor Data - */ +/* monitorCount (4 bytes): A 32-bit, unsigned integer. The number of display */ +/* monitor definitions in the monitorDefArray field (the maximum allowed is 16). */ +#define CLIENT_MONITOR_DATA_MAXIMUM_MONITORS 16 + +/* Options field */ /* NOTE: XR_ prefixed to avoid conflict with FreeRDP */ #define XR_CHANNEL_OPTION_INITIALIZED 0x80000000 #define XR_CHANNEL_OPTION_ENCRYPT_RDP 0x40000000 diff --git a/common/ms-rdpedisp.h b/common/ms-rdpedisp.h new file mode 100644 index 00000000..dd3d51e7 --- /dev/null +++ b/common/ms-rdpedisp.h @@ -0,0 +1,29 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * MS-RDPEDISP : Definitions from [MS-RDPEDISP] + * + * 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. + * + * References to MS-RDPEDISP are currently correct for v20201030 of that + * document + */ + +#if !defined(MS_RDPEDISP_H) +#define MS_RDPEDISP_H + +/* Display Control Messages: Display Virtual Channel Extension (2.2.2) */ +#define DISPLAYCONTROL_PDU_TYPE_MONITOR_LAYOUT 0x00000002 +#define DISPLAYCONTROL_PDU_TYPE_CAPS 0x00000005 + +#endif /* MS_RDPEDISP_H */ diff --git a/common/xrdp_client_info.h b/common/xrdp_client_info.h index 5b746e08..48522105 100644 --- a/common/xrdp_client_info.h +++ b/common/xrdp_client_info.h @@ -19,6 +19,7 @@ */ #include "xrdp_constants.h" +#include "ms-rdpbcgr.h" #if !defined(XRDP_CLIENT_INFO_H) #define XRDP_CLIENT_INFO_H @@ -120,8 +121,8 @@ struct xrdp_client_info int security_layer; /* 0 = rdp, 1 = tls , 2 = hybrid */ int multimon; /* 0 = deny , 1 = allow */ int monitorCount; /* number of monitors detected (max = 16) */ - struct monitor_info minfo[16]; /* client monitor data */ - struct monitor_info minfo_wm[16]; /* client monitor data, non-negative values */ + struct monitor_info minfo[CLIENT_MONITOR_DATA_MAXIMUM_MONITORS]; /* client monitor data */ + struct monitor_info minfo_wm[CLIENT_MONITOR_DATA_MAXIMUM_MONITORS]; /* client monitor data, non-negative values */ int keyboard_type; int keyboard_subtype; diff --git a/libxrdp/xrdp_channel.c b/libxrdp/xrdp_channel.c index 9a374cac..c88ba99e 100644 --- a/libxrdp/xrdp_channel.c +++ b/libxrdp/xrdp_channel.c @@ -776,7 +776,12 @@ xrdp_channel_drdynvc_start(struct xrdp_channel *self) struct mcs_channel_item *ci; struct mcs_channel_item *dci; - + LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_channel_drdynvc_start: drdynvc_channel_id %d", self->drdynvc_channel_id); + if (self->drdynvc_channel_id != -1) + { + LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_channel_drdynvc_start: already started"); + return 0; + } dci = NULL; count = self->mcs_layer->channel_list->count; for (index = 0; index < count; index++) diff --git a/neutrinordp/xrdp-neutrinordp.c b/neutrinordp/xrdp-neutrinordp.c index 2771dae4..cc267827 100644 --- a/neutrinordp/xrdp-neutrinordp.c +++ b/neutrinordp/xrdp-neutrinordp.c @@ -492,6 +492,10 @@ lxrdp_set_param(struct mod *mod, const char *name, const char *value) { settings->nla_security = g_text2bool(value); } + else if (g_strcmp(name, "enable_dynamic_resizing") == 0) + { + settings->desktop_resize = g_text2bool(value); + } else { LOG(LOG_LEVEL_WARNING, "lxrdp_set_param: unknown name [%s] value [%s]", name, value); @@ -599,6 +603,27 @@ lxrdp_suppress_output(struct mod *mod, int suppress, return 0; } +/******************************************************************************/ +static int +lxrdp_server_version_message(struct mod *mod) +{ + return 0; +} + +/******************************************************************************/ +static int +lxrdp_server_monitor_resize(struct mod *mod, int width, int height) +{ + return 0; +} + +/******************************************************************************/ +static int +lxrdp_server_monitor_full_invalidate(struct mod *mod, int width, int height) +{ + return 0; +} + /******************************************************************************/ static void lfreerdp_begin_paint(rdpContext *context) @@ -2074,6 +2099,9 @@ mod_init(void) mod->mod_check_wait_objs = lxrdp_check_wait_objs; mod->mod_frame_ack = lxrdp_frame_ack; mod->mod_suppress_output = lxrdp_suppress_output; + mod->mod_server_version_message = lxrdp_server_version_message; + mod->mod_server_monitor_resize = lxrdp_server_monitor_resize; + mod->mod_server_monitor_full_invalidate = lxrdp_server_monitor_full_invalidate; mod->inst = freerdp_new(); mod->inst->PreConnect = lfreerdp_pre_connect; diff --git a/neutrinordp/xrdp-neutrinordp.h b/neutrinordp/xrdp-neutrinordp.h index 4fc7116d..b4e5ae86 100644 --- a/neutrinordp/xrdp-neutrinordp.h +++ b/neutrinordp/xrdp-neutrinordp.h @@ -82,8 +82,13 @@ struct mod int (*mod_frame_ack)(struct mod *mod, int flags, int frame_id); int (*mod_suppress_output)(struct mod *mod, int suppress, int left, int top, int right, int bottom); - tintptr mod_dumby[100 - 11]; /* align, 100 minus the number of mod - functions above */ + int (*mod_server_monitor_resize)(struct mod *mod, + int width, int height); + int (*mod_server_monitor_full_invalidate)(struct mod *mod, + int width, int height); + int (*mod_server_version_message)(struct mod *mod); + tintptr mod_dumby[100 - 14]; /* align, 100 minus the number of mod + functions above */ /* server functions */ int (*server_begin_update)(struct mod *v); int (*server_end_update)(struct mod *v); diff --git a/vnc/vnc.c b/vnc/vnc.c index d2732a6d..a34f73db 100644 --- a/vnc/vnc.c +++ b/vnc/vnc.c @@ -1224,7 +1224,7 @@ send_update_request_for_resize_status(struct vnc *v) make_stream(s); init_stream(s, 8192); - switch (v->initial_resize_status) + switch (v->resize_status) { case VRS_WAITING_FOR_FIRST_UPDATE: /* @@ -1364,14 +1364,14 @@ lib_framebuffer_first_update(struct vnc *v) { LOG(LOG_LEVEL_DEBUG, "Server layout is the same " "as the client layout"); - v->initial_resize_status = VRS_DONE; + v->resize_status = VRS_DONE; } else { LOG(LOG_LEVEL_DEBUG, "Server layout differs from " "the client layout. Changing server layout"); error = send_set_desktop_size(v, &v->client_layout); - v->initial_resize_status = VRS_WAITING_FOR_RESIZE_CONFIRM; + v->resize_status = VRS_WAITING_FOR_RESIZE_CONFIRM; } } else @@ -1382,7 +1382,7 @@ lib_framebuffer_first_update(struct vnc *v) LOG(LOG_LEVEL_DEBUG, "Resizing client to server %dx%d", v->server_width, v->server_height); error = resize_client(v, 0, v->server_width, v->server_height); - v->initial_resize_status = VRS_DONE; + v->resize_status = VRS_DONE; } g_free(layout.s); @@ -1437,7 +1437,7 @@ lib_framebuffer_waiting_for_resize_confirm(struct vnc *v) v->server_width, v->server_height); error = resize_client(v, 0, v->server_width, v->server_height); } - v->initial_resize_status = VRS_DONE; + v->resize_status = VRS_DONE; } g_free(layout.s); @@ -1777,7 +1777,7 @@ lib_mod_process_message(struct vnc *v, struct stream *s) { if (type == S2C_FRAMEBUFFER_UPDATE) { - switch (v->initial_resize_status) + switch (v->resize_status) { case VRS_WAITING_FOR_FIRST_UPDATE: error = lib_framebuffer_first_update(v); @@ -2237,7 +2237,7 @@ lib_mod_connect(struct vnc *v) if (error == 0) { - v->initial_resize_status = VRS_WAITING_FOR_FIRST_UPDATE; + v->resize_status = VRS_WAITING_FOR_FIRST_UPDATE; error = send_update_request_for_resize_status(v); } @@ -2465,6 +2465,34 @@ lib_mod_suppress_output(struct vnc *v, int suppress, return error; } +/******************************************************************************/ +/* return error */ +int +lib_mod_server_version_message(struct vnc *v) +{ + return 0; +} + +/******************************************************************************/ +/* return error */ +int +lib_mod_server_monitor_resize(struct vnc *v, int width, int height) +{ + int error = 0; + set_single_screen_layout(&v->client_layout, width, height); + v->resize_status = VRS_WAITING_FOR_FIRST_UPDATE; + error = send_update_request_for_resize_status(v); + return error; +} + +/******************************************************************************/ +/* return error */ +int +lib_mod_server_monitor_full_invalidate(struct vnc *v, int param1, int param2) +{ + return 0; +} + /******************************************************************************/ tintptr EXPORT_CC mod_init(void) @@ -2486,6 +2514,9 @@ mod_init(void) v->mod_check_wait_objs = lib_mod_check_wait_objs; v->mod_frame_ack = lib_mod_frame_ack; v->mod_suppress_output = lib_mod_suppress_output; + v->mod_server_monitor_resize = lib_mod_server_monitor_resize; + v->mod_server_monitor_full_invalidate = lib_mod_server_monitor_full_invalidate; + v->mod_server_version_message = lib_mod_server_version_message; /* Member variables */ v->enabled_encodings_mask = -1; diff --git a/vnc/vnc.h b/vnc/vnc.h index c890fe7c..cccdeaf5 100644 --- a/vnc/vnc.h +++ b/vnc/vnc.h @@ -77,7 +77,12 @@ struct vnc int (*mod_frame_ack)(struct vnc *v, int flags, int frame_id); int (*mod_suppress_output)(struct vnc *v, int suppress, int left, int top, int right, int bottom); - tintptr mod_dumby[100 - 11]; /* align, 100 minus the number of mod + int (*mod_server_monitor_resize)(struct vnc *v, + int width, int height); + int (*mod_server_monitor_full_invalidate)(struct vnc *v, + int width, int height); + int (*mod_server_version_message)(struct vnc *v); + tintptr mod_dumby[100 - 14]; /* align, 100 minus the number of mod functions above */ /* server functions */ int (*server_begin_update)(struct vnc *v); @@ -152,5 +157,5 @@ struct vnc unsigned int enabled_encodings_mask; /* Resizeable support */ struct vnc_screen_layout client_layout; - enum vnc_resize_status initial_resize_status; + enum vnc_resize_status resize_status; }; diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h index 93b6a96f..376136e0 100644 --- a/xrdp/xrdp.h +++ b/xrdp/xrdp.h @@ -367,6 +367,21 @@ xrdp_bitmap_compress(char *in_data, int width, int height, int e); /* xrdp_mm.c */ + +struct dynamic_monitor_layout +{ + int flags; + int left; + int top; + int width; + int height; + int physical_width; + int physical_height; + int orientation; + int desktop_scale_factor; + int device_scale_factor; +}; + int xrdp_mm_drdynvc_up(struct xrdp_mm *self); int diff --git a/xrdp/xrdp.ini.in b/xrdp/xrdp.ini.in index d6bb0595..0a077a8b 100644 --- a/xrdp/xrdp.ini.in +++ b/xrdp/xrdp.ini.in @@ -235,6 +235,9 @@ ip=ask port=ask3389 username=ask password=ask +; Currently NeutrinoRDP doesn't support dynamic resizing. Uncomment +; this line if you're using a client which does. +#enable_dynamic_resizing=false ; You can override the common channel settings for each session type #channel.rdpdr=true diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 915c3b32..6f501fd4 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -24,6 +24,8 @@ #include "xrdp.h" #include "log.h" #include "string_calls.h" +#include "ms-rdpedisp.h" +#include "ms-rdpbcgr.h" #ifdef USE_PAM #if defined(HAVE__PAM_TYPES_H) @@ -992,12 +994,208 @@ xrdp_mm_process_rail_drawing_orders(struct xrdp_mm *self, struct stream *s) return rv; } +/******************************************************************************/ +static int +dynamic_monitor_open_response(intptr_t id, int chan_id, int creation_status) +{ + struct xrdp_process *pro; + struct xrdp_wm *wm; + struct stream *s; + int bytes; + + LOG_DEVEL(LOG_LEVEL_TRACE, "dynamic_monitor_open_response: chan_id %d creation_status 0x%8.8x", chan_id, creation_status); + if (creation_status != 0) + { + LOG(LOG_LEVEL_ERROR, "dynamic_monitor_open_response: error"); + return 1; + } + pro = (struct xrdp_process *) id; + wm = pro->wm; + make_stream(s); + init_stream(s, 1024); + out_uint32_le(s, 5); /* DISPLAYCONTROL_PDU_TYPE_CAPS */ + out_uint32_le(s, 8 + 12); + out_uint32_le(s, CLIENT_MONITOR_DATA_MAXIMUM_MONITORS); /* MaxNumMonitors */ + out_uint32_le(s, 4096); /* MaxMonitorAreaFactorA */ + out_uint32_le(s, 2048); /* MaxMonitorAreaFactorB */ + s_mark_end(s); + bytes = (int) (s->end - s->data); + libxrdp_drdynvc_data(wm->session, chan_id, s->data, bytes); + free_stream(s); + return 0; +} + +/******************************************************************************/ +static int +dynamic_monitor_close_response(intptr_t id, int chan_id) +{ + LOG_DEVEL(LOG_LEVEL_TRACE, "dynamic_monitor_close_response:"); + return 0; +} + +/******************************************************************************/ +static int +dynamic_monitor_data_first(intptr_t id, int chan_id, char *data, int bytes, + int total_bytes) +{ + LOG_DEVEL(LOG_LEVEL_TRACE, "dynamic_monitor_data_first:"); + return 0; +} + +/******************************************************************************/ +static int +dynamic_monitor_data(intptr_t id, int chan_id, char *data, int bytes) +{ + struct stream ls; + struct stream *s; + int msg_type; + int msg_length; + int monitor_index; + struct xrdp_process *pro; + struct xrdp_wm *wm; + + int MonitorLayoutSize; + int NumMonitor; + + struct dynamic_monitor_layout monitor_layouts[CLIENT_MONITOR_DATA_MAXIMUM_MONITORS]; + struct dynamic_monitor_layout *monitor_layout; + + struct xrdp_rect rect; + int session_width; + int session_height; + + LOG_DEVEL(LOG_LEVEL_TRACE, "dynamic_monitor_data:"); + pro = (struct xrdp_process *) id; + wm = pro->wm; + g_memset(&ls, 0, sizeof(ls)); + ls.data = data; + ls.p = ls.data; + ls.size = bytes; + ls.end = ls.data + bytes; + s = &ls; + in_uint32_le(s, msg_type); + in_uint32_le(s, msg_length); + LOG(LOG_LEVEL_DEBUG, "dynamic_monitor_data: msg_type %d msg_length %d", + msg_type, msg_length); + + rect.left = 8192; + rect.top = 8192; + rect.right = -8192; + rect.bottom = -8192; + + if (msg_type == DISPLAYCONTROL_PDU_TYPE_MONITOR_LAYOUT) + { + in_uint32_le(s, MonitorLayoutSize); + in_uint32_le(s, NumMonitor); + LOG(LOG_LEVEL_DEBUG, " MonitorLayoutSize %d NumMonitor %d", + MonitorLayoutSize, NumMonitor); + for (monitor_index = 0; monitor_index < NumMonitor; monitor_index++) + { + monitor_layout = monitor_layouts + monitor_index; + in_uint32_le(s, monitor_layout->flags); + in_uint32_le(s, monitor_layout->left); + in_uint32_le(s, monitor_layout->top); + in_uint32_le(s, monitor_layout->width); + in_uint32_le(s, monitor_layout->height); + in_uint32_le(s, monitor_layout->physical_width); + in_uint32_le(s, monitor_layout->physical_height); + in_uint32_le(s, monitor_layout->orientation); + in_uint32_le(s, monitor_layout->desktop_scale_factor); + in_uint32_le(s, monitor_layout->device_scale_factor); + LOG_DEVEL(LOG_LEVEL_DEBUG, " Flags 0x%8.8x Left %d Top %d " + "Width %d Height %d PhysicalWidth %d PhysicalHeight %d " + "Orientation %d DesktopScaleFactor %d DeviceScaleFactor %d", + monitor_layout->flags, monitor_layout->left, monitor_layout->top, + monitor_layout->width, monitor_layout->height, + monitor_layout->physical_width, monitor_layout->physical_height, + monitor_layout->orientation, monitor_layout->desktop_scale_factor, + monitor_layout->device_scale_factor); + + rect.left = MIN(monitor_layout->left, rect.left); + rect.top = MIN(monitor_layout->top, rect.top); + rect.right = MAX(rect.right, monitor_layout->left + monitor_layout->width); + rect.bottom = MAX(rect.bottom, monitor_layout->top + monitor_layout->height); + } + } + session_width = rect.right - rect.left; + session_height = rect.bottom - rect.top; + if ((session_width > 0) && (session_height > 0)) + { + // TODO: Unify this logic with server_reset + libxrdp_reset(wm->session, session_width, session_height, wm->screen->bpp); + /* reset cache */ + xrdp_cache_reset(wm->cache, wm->client_info); + /* resize the main window */ + xrdp_bitmap_resize(wm->screen, session_width, session_height); + /* load some stuff */ + xrdp_wm_load_static_colors_plus(wm, 0); + xrdp_wm_load_static_pointers(wm); + /* redraw */ + xrdp_bitmap_invalidate(wm->screen, 0); + + struct xrdp_mod* v = wm->mm->mod; + if (v != 0) { + v->mod_server_version_message(v); + v->mod_server_monitor_resize(v, session_width, session_height); + v->mod_server_monitor_full_invalidate(v, session_width, session_height); + } + } + return 0; +} + +/******************************************************************************/ +int +dynamic_monitor_initialize(struct xrdp_mm *self) +{ + struct xrdp_drdynvc_procs d_procs; + int flags; + int error; + + LOG_DEVEL(LOG_LEVEL_TRACE, "dynamic_monitor_initialize:"); + + g_memset(&d_procs, 0, sizeof(d_procs)); + d_procs.open_response = dynamic_monitor_open_response; + d_procs.close_response = dynamic_monitor_close_response; + d_procs.data_first = dynamic_monitor_data_first; + d_procs.data = dynamic_monitor_data; + flags = 0; + error = libxrdp_drdynvc_open(self->wm->session, + "Microsoft::Windows::RDS::DisplayControl", + flags, &d_procs, + &(self->dynamic_monitor_chanid)); + if (error != 0) + { + LOG(LOG_LEVEL_ERROR, "xrdp_mm_drdynvc_up: " + "libxrdp_drdynvc_open failed %d", error); + } + return error; +} + /******************************************************************************/ int xrdp_mm_drdynvc_up(struct xrdp_mm *self) { - LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_mm_drdynvc_up:"); - return 0; + char enable_dynamic_resize[32]; + int error = 0; + + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_drdynvc_up:"); + + xrdp_mm_get_value(self, "enable_dynamic_resizing", + enable_dynamic_resize, + sizeof(enable_dynamic_resize) - 1); + + /* + * User can disable dynamic resizing if necessary + */ + if (enable_dynamic_resize[0] != '\0' && !g_text2bool(enable_dynamic_resize)) + { + LOG(LOG_LEVEL_INFO, "User has disabled dynamic resizing."); + } + else + { + error = dynamic_monitor_initialize(self); + } + return error; } /******************************************************************************/ diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index 586752eb..9cab5046 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -53,7 +53,12 @@ struct xrdp_mod int (*mod_frame_ack)(struct xrdp_mod *v, int flags, int frame_id); int (*mod_suppress_output)(struct xrdp_mod *v, int suppress, int left, int top, int right, int bottom); - tintptr mod_dumby[100 - 11]; /* align, 100 minus the number of mod + int (*mod_server_monitor_resize)(struct xrdp_mod* v, + int width, int height); + int (*mod_server_monitor_full_invalidate)(struct xrdp_mod* v, + int width, int height); + int (*mod_server_version_message)(struct xrdp_mod* v); + tintptr mod_dumby[100 - 14]; /* align, 100 minus the number of mod functions above */ /* server functions */ int (*server_begin_update)(struct xrdp_mod *v); @@ -302,6 +307,7 @@ struct xrdp_mm struct xrdp_encoder *encoder; int cs2xr_cid_map[256]; int xr2cr_cid_map[256]; + int dynamic_monitor_chanid; }; struct xrdp_key_info diff --git a/xup/xup.c b/xup/xup.c index bc9a9c68..c696e031 100644 --- a/xup/xup.c +++ b/xup/xup.c @@ -27,6 +27,15 @@ #include "trans.h" #include "string_calls.h" +static int +send_server_monitor_resize(struct mod *mod, struct stream *s, int width, int height, int bpp); + +static int +send_server_monitor_full_invalidate(struct mod *mod, struct stream *s, int width, int height); + +static int +send_server_version_message(struct mod *v, struct stream *s); + static int lib_mod_process_message(struct mod *mod, struct stream *s); @@ -139,7 +148,6 @@ int lib_mod_connect(struct mod *mod) { int error; - int len; int i; int use_uds; struct stream *s; @@ -243,60 +251,18 @@ lib_mod_connect(struct mod *mod) if (error == 0) { - /* send version message */ - init_stream(s, 8192); - s_push_layer(s, iso_hdr, 4); - out_uint16_le(s, 103); - out_uint32_le(s, 301); - out_uint32_le(s, 0); - out_uint32_le(s, 0); - out_uint32_le(s, 0); - out_uint32_le(s, 1); - s_mark_end(s); - len = (int)(s->end - s->data); - s_pop_layer(s, iso_hdr); - out_uint32_le(s, len); - lib_send_copy(mod, s); + error = send_server_version_message(mod, s); } if (error == 0) { /* send screen size message */ - init_stream(s, 8192); - s_push_layer(s, iso_hdr, 4); - out_uint16_le(s, 103); - out_uint32_le(s, 300); - out_uint32_le(s, mod->width); - out_uint32_le(s, mod->height); - out_uint32_le(s, mod->bpp); - out_uint32_le(s, 0); - s_mark_end(s); - len = (int)(s->end - s->data); - s_pop_layer(s, iso_hdr); - out_uint32_le(s, len); - lib_send_copy(mod, s); + error = send_server_monitor_resize(mod, s, mod->width, mod->height, mod->bpp); } if (error == 0) { - /* send invalidate message */ - init_stream(s, 8192); - s_push_layer(s, iso_hdr, 4); - out_uint16_le(s, 103); - out_uint32_le(s, 200); - /* x and y */ - i = 0; - out_uint32_le(s, i); - /* width and height */ - i = ((mod->width & 0xffff) << 16) | mod->height; - out_uint32_le(s, i); - out_uint32_le(s, 0); - out_uint32_le(s, 0); - s_mark_end(s); - len = (int)(s->end - s->data); - s_pop_layer(s, iso_hdr); - out_uint32_le(s, len); - lib_send_copy(mod, s); + error = send_server_monitor_full_invalidate(mod, s, mod->width, mod->height); } free_stream(s); @@ -1292,6 +1258,124 @@ process_server_paint_rect_shmem_ex(struct mod *amod, struct stream *s) return rv; } +/******************************************************************************/ +/* return error */ +static int +send_server_version_message(struct mod *mod, struct stream *s) +{ + /* send version message */ + init_stream(s, 8192); + s_push_layer(s, iso_hdr, 4); + out_uint16_le(s, 103); + out_uint32_le(s, 301); + out_uint32_le(s, 0); + out_uint32_le(s, 0); + out_uint32_le(s, 0); + out_uint32_le(s, 1); + s_mark_end(s); + int len = (int)(s->end - s->data); + s_pop_layer(s, iso_hdr); + out_uint32_le(s, len); + int rv = lib_send_copy(mod, s); + return rv; +} + +/******************************************************************************/ +/* return error */ +static int +send_server_monitor_resize(struct mod *mod, struct stream *s, int width, int height, int bpp) +{ + /* send screen size message */ + init_stream(s, 8192); + s_push_layer(s, iso_hdr, 4); + out_uint16_le(s, 103); + out_uint32_le(s, 300); + out_uint32_le(s, width); + out_uint32_le(s, height); + /* + TODO: The bpp here is only necessary for initial creation. We should modify XUP to require this + only on server initialization, but not on resize. Microsoft's RDP protocol does not support changing + the bpp on resize. + */ + out_uint32_le(s, bpp); + out_uint32_le(s, 0); + s_mark_end(s); + int len = (int)(s->end - s->data); + s_pop_layer(s, iso_hdr); + out_uint32_le(s, len); + int rv = lib_send_copy(mod, s); + LOG_DEVEL(LOG_LEVEL_DEBUG, "send_server_monitor_resize: sent resize message with following properties to xorgxrdp backend " + "width=%d, height=%d, bpp=%d, return value=%d", + width, height, bpp, rv); + return rv; +} + +static int +send_server_monitor_full_invalidate(struct mod *mod, struct stream *s, int width, int height) +{ + /* send invalidate message */ + init_stream(s, 8192); + s_push_layer(s, iso_hdr, 4); + out_uint16_le(s, 103); + out_uint32_le(s, 200); + /* x and y */ + int i = 0; + out_uint32_le(s, i); + /* width and height */ + i = ((width & 0xffff) << 16) | height; + out_uint32_le(s, i); + out_uint32_le(s, 0); + out_uint32_le(s, 0); + s_mark_end(s); + int len = (int)(s->end - s->data); + s_pop_layer(s, iso_hdr); + out_uint32_le(s, len); + int rv = lib_send_copy(mod, s); + LOG_DEVEL(LOG_LEVEL_DEBUG, "send_server_monitor_full_invalidate: sent invalidate message with following properties to xorgxrdp backend " + "width=%d, height=%d, return value=%d", + width, height, rv); + return rv; +} + +/******************************************************************************/ +/* return error */ +static int +lib_send_server_version_message(struct mod *mod) +{ + /* send server version message */ + struct stream *s; + make_stream(s); + int rv = send_server_version_message(mod, s); + free_stream(s); + return rv; +} + +/******************************************************************************/ +/* return error */ +static int +lib_send_server_monitor_resize(struct mod *mod, int width, int height) +{ + /* send screen size message */ + struct stream *s; + make_stream(s); + int rv = send_server_monitor_resize(mod, s, width, height, mod->bpp); + free_stream(s); + return rv; +} + +/******************************************************************************/ +/* return error */ +static int +lib_send_server_monitor_full_invalidate(struct mod *mod, int width, int height) +{ + /* send invalidate message */ + struct stream *s; + make_stream(s); + int rv = send_server_monitor_full_invalidate(mod, s, width, height); + free_stream(s); + return rv; +} + /******************************************************************************/ /* return error */ static int @@ -1636,6 +1720,9 @@ mod_init(void) mod->mod_check_wait_objs = lib_mod_check_wait_objs; mod->mod_frame_ack = lib_mod_frame_ack; mod->mod_suppress_output = lib_mod_suppress_output; + mod->mod_server_monitor_resize = lib_send_server_monitor_resize; + mod->mod_server_monitor_full_invalidate = lib_send_server_monitor_full_invalidate; + mod->mod_server_version_message = lib_send_server_version_message; return (tintptr) mod; } diff --git a/xup/xup.h b/xup/xup.h index d3136553..006daf28 100644 --- a/xup/xup.h +++ b/xup/xup.h @@ -51,7 +51,12 @@ struct mod int (*mod_frame_ack)(struct mod *v, int flags, int frame_id); int (*mod_suppress_output)(struct mod *v, int suppress, int left, int top, int right, int bottom); - tintptr mod_dumby[100 - 11]; /* align, 100 minus the number of mod + int (*mod_server_monitor_resize)(struct mod* v, + int width, int height); + int (*mod_server_monitor_full_invalidate)(struct mod* v, + int width, int height); + int (*mod_server_version_message)(struct mod* v); + tintptr mod_dumby[100 - 14]; /* align, 100 minus the number of mod functions above */ /* server functions */ int (*server_begin_update)(struct mod *v);