Unify monitor processing logic.

There are two places where monitor descriptions are passed through the
RDP protocol:

- TS_UD_CS_MONITOR ([MS-RDPBCGR] 2.2.1.3.6 Client Monitor Data)
- DISPLAYCONTROL_PDU_TYPE_MONITOR_LAYOUT ([MS-RDPEDISP] 2.2.2.2)

The processing logic for both of them is similar enough that they should be unified.

Also update to define the constants for the maximum and minimum desktop width/height for monitors and total area.

Also a large number of clarifications for the constants and protocol
requirements.

Note that this is also the first step to making resizing work with the extension GFX channel as well as an important
foundational step to enable HiDPI compatibility.

Also some misc logging updates.
This commit is contained in:
Christopher Pitstick 2021-05-25 00:05:54 -04:00
parent f3c37e2694
commit 4a0db63be7
9 changed files with 607 additions and 217 deletions

View File

@ -83,10 +83,24 @@
#define RDPSND_SVC_CHANNEL_NAME "rdpsnd"
#define RDPDR_SVC_CHANNEL_NAME "rdpdr"
/* 2.2.1.3.6 Client Monitor Data - */
/* 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
#define CLIENT_MONITOR_DATA_MAXIMUM_MONITORS 16
/* 2.2.1.3.6 Client Monitor Data */
/* The maximum width of the virtual desktop resulting from the union of the monitors */
/* contained in the monitorDefArray field MUST NOT exceed 32,766 pixels. Similarly, */
/* the maximum height of the virtual desktop resulting from the union of the monitors */
/* contained in the monitorDefArray field MUST NOT exceed 32,766 pixels. */
/* The minimum permitted size of the virtual desktop is 200 x 200 pixels. */
#define CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_WIDTH 0xC8
#define CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_HEIGHT 0xC8
#define CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_WIDTH 0x7FFE
#define CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_HEIGHT 0x7FFE
/* 2.2.1.3.6.1 Monitor Definition (TS_MONITOR_DEF) */
#define TS_MONITOR_PRIMARY 0x00000001
/* Options field */
/* NOTE: XR_ prefixed to avoid conflict with FreeRDP */

View File

@ -23,7 +23,19 @@
#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
#define DISPLAYCONTROL_PDU_TYPE_MONITOR_LAYOUT 0x00000002
#define DISPLAYCONTROL_PDU_TYPE_CAPS 0x00000005
/* Display Control Monitor Layout (2.2.2.2.1) */
#define DISPLAYCONTROL_MONITOR_PRIMARY 0x00000001
#define CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_MONITOR_WIDTH 0xC8
#define CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_MONITOR_HEIGHT 0xC8
#define CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_MONITOR_WIDTH 0x2000
#define CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_MONITOR_HEIGHT 0x2000
#define ORIENTATION_LANDSCAPE 0
#define ORIENTATION_PORTRAIT 90
#define ORIENTATION_LANDSCAPE_FLIPPED 180
#define ORIENTATION_PORTRAIT_FLIPPED 270
#endif /* MS_RDPEDISP_H */

View File

@ -24,12 +24,28 @@
#if !defined(XRDP_CLIENT_INFO_H)
#define XRDP_CLIENT_INFO_H
/*
* 2.2.1.3.6.1 Monitor Definition (TS_MONITOR_DEF)
* 2.2.1.3.9.1 Monitor Attributes (TS_MONITOR_ATTRIBUTES)
* 2.2.2.2.1 DISPLAYCONTROL_MONITOR_LAYOUT
*/
struct monitor_info
{
/* From 2.2.1.3.6.1 Monitor Definition (TS_MONITOR_DEF) */
int left;
int top;
int right;
int bottom;
int flags;
/* From 2.2.2.2.1 DISPLAYCONTROL_MONITOR_LAYOUT */
int physical_width;
int physical_height;
int orientation;
int desktop_scale_factor;
int device_scale_factor;
/* Derived setting */
int is_primary;
};
@ -41,6 +57,15 @@ struct xrdp_keyboard_overrides
int layout;
};
struct display_size_description
{
int monitorCount; /* number of monitors detected (max = 16) */
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 session_width;
int session_height;
};
/**
* Information about the xrdp client
*

View File

@ -25,11 +25,9 @@
#include "libxrdp.h"
#include "string_calls.h"
#include "xrdp_orders_rail.h"
#include "ms-rdpedisp.h"
#include "ms-rdpbcgr.h"
#define MAX_BITMAP_BUF_SIZE (16 * 1024) /* 16K */
/******************************************************************************/
@ -1766,3 +1764,323 @@ libxrdp_send_session_info(struct xrdp_session *session, const char *data,
return xrdp_rdp_send_session_info(rdp, data, data_bytes);
}
/*****************************************************************************/
/*
Process a [MS-RDPBCGR] TS_UD_CS_MONITOR message.
reads the client monitors data
*/
int
libxrdp_process_monitor_stream(struct stream *s,
struct display_size_description *description,
int full_parameters)
{
uint32_t num_monitor;
uint32_t monitor_index;
struct monitor_info *monitor_layout;
struct xrdp_rect all_monitors_encompassing_bounds = {0};
int got_primary = 0;
int monitor_struct_stream_check_bytes;
const char *monitor_struct_stream_check_message;
LOG_DEVEL(LOG_LEVEL_TRACE, "libxrdp_process_monitor_stream:");
if (description == NULL)
{
LOG_DEVEL(LOG_LEVEL_ERROR, "libxrdp_process_monitor_stream: description was"
" null. Valid pointer to allocated description expected.");
return SEC_PROCESS_MONITORS_ERR;
}
if (!s_check_rem_and_log(s, 4,
"libxrdp_process_monitor_stream:"
" Parsing [MS-RDPBCGR] TS_UD_CS_MONITOR"))
{
return SEC_PROCESS_MONITORS_ERR;
}
in_uint32_le(s, num_monitor);
LOG(LOG_LEVEL_DEBUG, "libxrdp_process_monitor_stream:"
" The number of monitors received is: %d",
num_monitor);
if (num_monitor >= CLIENT_MONITOR_DATA_MAXIMUM_MONITORS)
{
LOG(LOG_LEVEL_ERROR,
"libxrdp_process_monitor_stream: [MS-RDPBCGR] Protocol"
" error: TS_UD_CS_MONITOR monitorCount"
" MUST be less than %d, received: %d",
CLIENT_MONITOR_DATA_MAXIMUM_MONITORS, num_monitor);
return SEC_PROCESS_MONITORS_ERR_TOO_MANY_MONITORS;
}
/*
* Unfortunately the structure length values aren't directly defined in the
* Microsoft specifications. They are derived from the lengths of the
* specific structures referenced below.
*/
if (full_parameters == 0)
{
monitor_struct_stream_check_bytes = 20;
monitor_struct_stream_check_message =
"libxrdp_process_monitor_stream: Parsing monitor definitions"
" from [MS-RDPBCGR] 2.2.1.3.6.1 Monitor Definition"
" (TS_MONITOR_DEF).";
}
else
{
monitor_struct_stream_check_bytes = 40;
monitor_struct_stream_check_message =
"libxrdp_process_monitor_stream: Parsing monitor definitions"
" from [MS-RDPEDISP] 2.2.2.2.1 DISPLAYCONTROL_MONITOR_LAYOUT.";
}
description->monitorCount = num_monitor;
for (monitor_index = 0; monitor_index < num_monitor; ++monitor_index)
{
if (!s_check_rem_and_log(
s,
monitor_struct_stream_check_bytes,
monitor_struct_stream_check_message))
{
return SEC_PROCESS_MONITORS_ERR;
}
monitor_layout = description->minfo + monitor_index;
if (full_parameters != 0)
{
in_uint32_le(s, monitor_layout->flags);
}
in_uint32_le(s, monitor_layout->left);
in_uint32_le(s, monitor_layout->top);
if (full_parameters == 0)
{
in_uint32_le(s, monitor_layout->right);
in_uint32_le(s, monitor_layout->bottom);
in_uint32_le(s, monitor_layout->is_primary);
/*
* 2.2.1.3.6.1 Monitor Definition (TS_MONITOR_DEF)
*/
LOG_DEVEL(LOG_LEVEL_TRACE, "libxrdp_process_monitor_stream:"
" Received [MS-RDPBCGR] 2.2.1.3.6.1"
" TS_UD_CS_MONITOR.TS_MONITOR_DEF"
" Index: %d, Left %d, Top %d, Right %d, Bottom %d,"
" Flags 0x%8.8x",
monitor_index,
monitor_layout->left,
monitor_layout->top,
monitor_layout->right,
monitor_layout->bottom,
monitor_layout->is_primary);
}
else
{
/* Per spec (2.2.2.2.1 DISPLAYCONTROL_MONITOR_LAYOUT),
* this is the width.
* 200 <= width <= 8192 and must not be odd.
* Ex: in_uint32_le(s, monitor_layout->width);
*/
in_uint32_le(s, monitor_layout->right);
if (monitor_layout->right
> CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_MONITOR_WIDTH
|| monitor_layout->right
< CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_MONITOR_WIDTH
|| monitor_layout->right % 2 != 0)
{
return SEC_PROCESS_MONITORS_ERR_INVALID_MONITOR;
}
/* Per spec (2.2.2.2.1 DISPLAYCONTROL_MONITOR_LAYOUT),
* this is the height.
* 200 <= height <= 8192
* Ex: in_uint32_le(s, monitor_layout->height);
*/
in_uint32_le(s, monitor_layout->bottom);
if (monitor_layout->bottom
> CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_MONITOR_HEIGHT
|| monitor_layout->bottom
< CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_MONITOR_HEIGHT)
{
return SEC_PROCESS_MONITORS_ERR_INVALID_MONITOR;
}
in_uint32_le(s, monitor_layout->physical_width);
in_uint32_le(s, monitor_layout->physical_height);
in_uint32_le(s, monitor_layout->orientation);
switch (monitor_layout->orientation) {
case ORIENTATION_LANDSCAPE:
case ORIENTATION_PORTRAIT:
case ORIENTATION_LANDSCAPE_FLIPPED:
case ORIENTATION_PORTRAIT_FLIPPED:
break;
default:
LOG(LOG_LEVEL_WARNING, "libxrdp_process_monitor_stream:"
" Orientation is not one of %d, %d, %d, or %d."
" Value was %d and ignored.",
ORIENTATION_LANDSCAPE,
ORIENTATION_PORTRAIT,
ORIENTATION_LANDSCAPE_FLIPPED,
ORIENTATION_PORTRAIT_FLIPPED,
monitor_layout->orientation);
}
in_uint32_le(s, monitor_layout->desktop_scale_factor);
in_uint32_le(s, monitor_layout->device_scale_factor);
/*
* 2.2.2.2.1 DISPLAYCONTROL_MONITOR_LAYOUT
*/
LOG_DEVEL(LOG_LEVEL_TRACE, "libxrdp_process_monitor_stream:"
" Received [MS-RDPEDISP] 2.2.2.2.1"
" DISPLAYCONTROL_MONITOR_LAYOUT_PDU"
".DISPLAYCONTROL_MONITOR_LAYOUT"
" Index: %d, Flags 0x%8.8x, Left %d, Top %d, Width %d,"
" Height %d, PhysicalWidth %d, PhysicalHeight %d,"
" Orientation %d, DesktopScaleFactor %d,"
" DeviceScaleFactor %d",
monitor_index,
monitor_layout->flags,
monitor_layout->left,
monitor_layout->top,
monitor_layout->right,
monitor_layout->bottom,
monitor_layout->physical_width,
monitor_layout->physical_height,
monitor_layout->orientation,
monitor_layout->desktop_scale_factor,
monitor_layout->device_scale_factor);
monitor_layout->right =
monitor_layout->left + monitor_layout->right;
monitor_layout->bottom =
monitor_layout->top + monitor_layout->bottom;
if (monitor_layout->flags == DISPLAYCONTROL_MONITOR_PRIMARY)
{
monitor_layout->is_primary = TS_MONITOR_PRIMARY;
}
}
if (monitor_index == 0)
{
all_monitors_encompassing_bounds.left = monitor_layout->left;
all_monitors_encompassing_bounds.top = monitor_layout->top;
all_monitors_encompassing_bounds.right = monitor_layout->right;
all_monitors_encompassing_bounds.bottom = monitor_layout->bottom;
}
else
{
all_monitors_encompassing_bounds.left =
MIN(monitor_layout->left,
all_monitors_encompassing_bounds.left);
all_monitors_encompassing_bounds.top =
MIN(monitor_layout->top,
all_monitors_encompassing_bounds.top);
all_monitors_encompassing_bounds.right =
MAX(all_monitors_encompassing_bounds.right,
monitor_layout->right);
all_monitors_encompassing_bounds.bottom =
MAX(all_monitors_encompassing_bounds.bottom,
monitor_layout->bottom);
}
if (monitor_layout->is_primary == TS_MONITOR_PRIMARY)
{
got_primary = 1;
}
}
if (!got_primary)
{
/* no primary monitor was set,
* choose the leftmost monitor as primary.
*/
for (monitor_index = 0; monitor_index < num_monitor; ++monitor_index)
{
monitor_layout = description->minfo + monitor_index;
if (monitor_layout->left
== all_monitors_encompassing_bounds.left
&& monitor_layout->top
== all_monitors_encompassing_bounds.top)
{
monitor_layout->is_primary = TS_MONITOR_PRIMARY;
break;
}
}
}
/* set wm geometry if the encompassing area is well formed. Otherwise, log and return an error.*/
if (all_monitors_encompassing_bounds.right
> all_monitors_encompassing_bounds.left
&& all_monitors_encompassing_bounds.bottom
> all_monitors_encompassing_bounds.top)
{
description->session_width =
all_monitors_encompassing_bounds.right
- all_monitors_encompassing_bounds.left + 1;
description->session_height =
all_monitors_encompassing_bounds.bottom
- all_monitors_encompassing_bounds.top + 1;
}
else
{
LOG(LOG_LEVEL_ERROR, "libxrdp_process_monitor_stream:"
" The area encompassing the monitors is not a"
" well-formed rectangle. Received"
" (top: %d, left: %d, right: %d, bottom: %d)."
" This will prevent initialization.",
all_monitors_encompassing_bounds.top,
all_monitors_encompassing_bounds.left,
all_monitors_encompassing_bounds.right,
all_monitors_encompassing_bounds.bottom);
return SEC_PROCESS_MONITORS_ERR_INVALID_DESKTOP;
}
/* Make sure virtual desktop size is OK
* 2.2.1.3.6 Client Monitor Data (TS_UD_CS_MONITOR)
*/
if (description->session_width
> CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_WIDTH
|| description->session_width
< CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_WIDTH
|| description->session_height
> CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_HEIGHT
|| description->session_height
< CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_HEIGHT)
{
LOG(LOG_LEVEL_ERROR,
"libxrdp_process_monitor_stream: Client supplied virtual"
" desktop width or height is invalid."
" Allowed width range: min %d, max %d. Width received: %d."
" Allowed height range: min %d, max %d. Height received: %d",
CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_WIDTH,
CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_WIDTH,
description->session_width,
CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_HEIGHT,
CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_HEIGHT,
description->session_width);
return SEC_PROCESS_MONITORS_ERR_INVALID_DESKTOP;
}
/* keep a copy of non negative monitor info values for xrdp_wm usage */
for (monitor_index = 0; monitor_index < num_monitor; ++monitor_index)
{
monitor_layout = description->minfo_wm + monitor_index;
g_memcpy(monitor_layout,
description->minfo + monitor_index,
sizeof(struct monitor_info));
monitor_layout->left =
monitor_layout->left - all_monitors_encompassing_bounds.left;
monitor_layout->top =
monitor_layout->top - all_monitors_encompassing_bounds.top;
monitor_layout->right =
monitor_layout->right - all_monitors_encompassing_bounds.left;
monitor_layout->bottom =
monitor_layout->bottom - all_monitors_encompassing_bounds.top;
}
return 0;
}

View File

@ -359,6 +359,16 @@ int
xrdp_mcs_disconnect(struct xrdp_mcs *self);
/* xrdp_sec.c */
/*
These are return values for xrdp_sec_process_mcs_data_monitors
to clarify any reason for a non-zero response code.
*/
#define SEC_PROCESS_MONITORS_ERR 1
#define SEC_PROCESS_MONITORS_ERR_TOO_MANY_MONITORS 2
#define SEC_PROCESS_MONITORS_ERR_INVALID_DESKTOP 3
#define SEC_PROCESS_MONITORS_ERR_INVALID_MONITOR 4
struct xrdp_sec *
xrdp_sec_create(struct xrdp_rdp *owner, struct trans *trans);
void
@ -383,6 +393,8 @@ int
xrdp_sec_incoming(struct xrdp_sec *self);
int
xrdp_sec_disconnect(struct xrdp_sec *self);
int
xrdp_sec_process_mcs_data_monitors(struct xrdp_sec *self, struct stream *s);
/* xrdp_rdp.c */
struct xrdp_rdp *

View File

@ -86,6 +86,9 @@ struct xrdp_drdynvc_procs
int (*data)(intptr_t id, int chan_id, char *data, int bytes);
};
/* Defined in xrdp_client_info.h */
struct display_size_description;
/***
* Initialise the XRDP library
*
@ -304,4 +307,21 @@ int EXPORT_CC
libxrdp_send_session_info(struct xrdp_session *session, const char *data,
int data_bytes);
/**
* Processes a stream that is based on either
* 2.2.1.3.6 Client Monitor Data (TS_UD_CS_MONITOR) or 2.2.2.2 DISPLAYCONTROL_MONITOR_LAYOUT_PDU
* and then stores the processed monitor data into the description parameter.
* @param s
* The stream to process.
* @param description
* Must be pre-allocated. Monitor data is filled in as part of processing the stream.
* @param full_parameters
* 0 if the monitor stream is from 2.2.1.3.6 Client Monitor Data (TS_UD_CS_MONITOR)
* 1 if the monitor stream is from 2.2.2.2 DISPLAYCONTROL_MONITOR_LAYOUT_PDU
* @return 0 if the data is processed, non-zero if there is an error.
*/
int EXPORT_CC
libxrdp_process_monitor_stream(struct stream *s, struct display_size_description *description,
int full_parameters);
#endif

View File

@ -27,8 +27,6 @@
#include "log.h"
#include "string_calls.h"
/* some compilers need unsigned char to avoid warnings */
static tui8 g_pad_54[40] =
{
@ -2333,155 +2331,61 @@ xrdp_sec_process_mcs_data_channels(struct xrdp_sec *self, struct stream *s)
int
xrdp_sec_process_mcs_data_monitors(struct xrdp_sec *self, struct stream *s)
{
int index;
int monitorCount;
int flags;
int x1;
int y1;
int x2;
int y2;
int got_primary;
struct xrdp_client_info *client_info = (struct xrdp_client_info *)NULL;
int error = 0;
struct xrdp_client_info *client_info = &(self->rdp_layer->client_info);
client_info = &(self->rdp_layer->client_info);
LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_sec_process_mcs_data_monitors:");
/* this is an option set in xrdp.ini */
if (client_info->multimon != 1) /* are multi-monitors allowed ? */
{
LOG(LOG_LEVEL_INFO, "Multi-monitor is disabled by server config");
LOG(LOG_LEVEL_INFO,
"xrdp_sec_process_mcs_data_monitors:"
" Multi-monitor is disabled by server config");
return 0;
}
if (!s_check_rem_and_log(s, 8, "Parsing [MS-RDPBCGR] TS_UD_CS_MONITOR"))
if (!s_check_rem_and_log(s, 4,
"xrdp_sec_process_mcs_data_monitors:"
" Parsing [MS-RDPBCGR] TS_UD_CS_MONITOR"))
{
return 1;
return SEC_PROCESS_MONITORS_ERR;
}
in_uint32_le(s, flags); /* flags */
in_uint32_le(s, monitorCount);
LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPBCGR] TS_UD_CS_MONITOR "
"flags 0x%8.8x, monitorCount %d", flags, monitorCount);
//verify flags - must be 0x0
if (flags != 0)
{
LOG(LOG_LEVEL_ERROR,
"[MS-RDPBCGR] Protocol error: TS_UD_CS_MONITOR flags MUST be zero, "
"received: 0x%8.8x", flags);
return 1;
"xrdp_sec_process_mcs_data_monitors: [MS-RDPBCGR]"
" Protocol error: TS_UD_CS_MONITOR flags MUST be zero,"
" received: 0x%8.8x", flags);
return SEC_PROCESS_MONITORS_ERR;
}
//verify monitorCount - max 16
if (monitorCount > 16)
struct display_size_description *description =
(struct display_size_description *)
g_malloc(sizeof(struct display_size_description), 1);
error = libxrdp_process_monitor_stream(s, description, 0);
if (error == 0)
{
LOG(LOG_LEVEL_ERROR,
"[MS-RDPBCGR] Protocol error: TS_UD_CS_MONITOR monitorCount "
"MUST be less than 16, received: %d", monitorCount);
return 2;
client_info->monitorCount = description->monitorCount;
LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_sec_process_mcs_data_monitors:"
" Received [MS-RDPBCGR] TS_UD_CS_MONITOR"
" flags 0x%8.8x, monitorCount %d",
flags, description->monitorCount);
client_info->width = description->session_width;
client_info->height = description->session_height;
g_memcpy(client_info->minfo, description->minfo, sizeof(struct monitor_info) * CLIENT_MONITOR_DATA_MAXIMUM_MONITORS);
g_memcpy(client_info->minfo_wm, description->minfo_wm, sizeof(struct monitor_info) * CLIENT_MONITOR_DATA_MAXIMUM_MONITORS);
}
client_info->monitorCount = monitorCount;
g_free(description);
x1 = 0;
y1 = 0;
x2 = 0;
y2 = 0;
got_primary = 0;
/* Add client_monitor_data to client_info struct, will later pass to X11rdp */
for (index = 0; index < monitorCount; index++)
{
if (!s_check_rem_and_log(s, 20, "Parsing [MS-RDPBCGR] TS_UD_CS_MONITOR.TS_MONITOR_DEF"))
{
return 1;
}
in_uint32_le(s, client_info->minfo[index].left);
in_uint32_le(s, client_info->minfo[index].top);
in_uint32_le(s, client_info->minfo[index].right);
in_uint32_le(s, client_info->minfo[index].bottom);
in_uint32_le(s, client_info->minfo[index].is_primary);
LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPBCGR] "
"TS_UD_CS_MONITOR.TS_MONITOR_DEF %d "
"left %d, top %d, right %d, bottom %d, flags 0x%8.8x",
index,
client_info->minfo[index].left,
client_info->minfo[index].top,
client_info->minfo[index].right,
client_info->minfo[index].bottom,
client_info->minfo[index].is_primary);
if (index == 0)
{
x1 = client_info->minfo[index].left;
y1 = client_info->minfo[index].top;
x2 = client_info->minfo[index].right;
y2 = client_info->minfo[index].bottom;
}
else
{
x1 = MIN(x1, client_info->minfo[index].left);
y1 = MIN(y1, client_info->minfo[index].top);
x2 = MAX(x2, client_info->minfo[index].right);
y2 = MAX(y2, client_info->minfo[index].bottom);
}
if (client_info->minfo[index].is_primary)
{
got_primary = 1;
}
LOG(LOG_LEVEL_DEBUG,
"Client monitor [%d]: left= %d, top= %d, right= %d, bottom= %d, "
"is_primary?= %d",
index,
client_info->minfo[index].left,
client_info->minfo[index].top,
client_info->minfo[index].right,
client_info->minfo[index].bottom,
client_info->minfo[index].is_primary);
}
if (!got_primary)
{
/* no primary monitor was set, choose the leftmost monitor as primary */
for (index = 0; index < monitorCount; index++)
{
if (client_info->minfo[index].left == x1 &&
client_info->minfo[index].top == y1)
{
client_info->minfo[index].is_primary = 1;
break;
}
}
}
/* set wm geometry */
if ((x2 > x1) && (y2 > y1))
{
client_info->width = (x2 - x1) + 1;
client_info->height = (y2 - y1) + 1;
}
/* make sure virtual desktop size is ok */
if (client_info->width > 0x7FFE || client_info->width < 0xC8 ||
client_info->height > 0x7FFE || client_info->height < 0xC8)
{
LOG(LOG_LEVEL_ERROR,
"Client supplied virtual desktop width or height is invalid. "
"Allowed width range: min %d, max %d. Width received: %d. "
"Allowed height range: min %d, max %d. Height received: %d",
0xC8, 0x7FFE, client_info->width,
0xC8, 0x7FFE, client_info->height);
return 3; /* error */
}
/* keep a copy of non negative monitor info values for xrdp_wm usage */
for (index = 0; index < monitorCount; index++)
{
client_info->minfo_wm[index].left = client_info->minfo[index].left - x1;
client_info->minfo_wm[index].top = client_info->minfo[index].top - y1;
client_info->minfo_wm[index].right = client_info->minfo[index].right - x1;
client_info->minfo_wm[index].bottom = client_info->minfo[index].bottom - y1;
client_info->minfo_wm[index].is_primary = client_info->minfo[index].is_primary;
}
return 0;
return error;
}
/*****************************************************************************/

View File

@ -11,9 +11,6 @@ struct xrdp_sec *sec_layer;
struct xrdp_rdp *rdp_layer;
struct xrdp_session *session;
int
xrdp_sec_process_mcs_data_monitors(struct xrdp_sec *self, struct stream *s);
void setup(void)
{
rdp_layer = (struct xrdp_rdp *)g_malloc(sizeof(struct xrdp_rdp), 1);
@ -45,7 +42,7 @@ START_TEST(test_process_monitors__when_flags_is_not_zero__fail)
s->p = s->data;
int error = xrdp_sec_process_mcs_data_monitors(sec_layer, s);
ck_assert_int_eq(error, 1);
ck_assert_int_eq(error, SEC_PROCESS_MONITORS_ERR);
free_stream(s);
}
@ -64,7 +61,7 @@ START_TEST(test_process_monitors__when_mounter_count_is_greater_than_sixteen__fa
s->p = s->data;
int error = xrdp_sec_process_mcs_data_monitors(sec_layer, s);
ck_assert_int_eq(error, 2);
ck_assert_int_eq(error, SEC_PROCESS_MONITORS_ERR_TOO_MANY_MONITORS);
free_stream(s);
}
@ -190,7 +187,7 @@ START_TEST(test_process_monitors__when_virtual_desktop_width_is_too_large)
//Verify function call passed.
int error = xrdp_sec_process_mcs_data_monitors(sec_layer, s);
ck_assert_int_eq(error, 3);
ck_assert_int_eq(error, SEC_PROCESS_MONITORS_ERR_INVALID_DESKTOP);
free_stream(s);
}
@ -218,7 +215,7 @@ START_TEST(test_process_monitors__when_virtual_desktop_width_is_too_small)
//Verify function call passed.
int error = xrdp_sec_process_mcs_data_monitors(sec_layer, s);
ck_assert_int_eq(error, 3);
ck_assert_int_eq(error, SEC_PROCESS_MONITORS_ERR_INVALID_DESKTOP);
free_stream(s);
}
@ -246,7 +243,7 @@ START_TEST(test_process_monitors__when_virtual_desktop_height_is_too_large)
//Verify function call passed.
int error = xrdp_sec_process_mcs_data_monitors(sec_layer, s);
ck_assert_int_eq(error, 3);
ck_assert_int_eq(error, SEC_PROCESS_MONITORS_ERR_INVALID_DESKTOP);
free_stream(s);
}
@ -274,7 +271,7 @@ START_TEST(test_process_monitors__when_virtual_desktop_height_is_too_small)
//Verify function call passed.
int error = xrdp_sec_process_mcs_data_monitors(sec_layer, s);
ck_assert_int_eq(error, 3);
ck_assert_int_eq(error, SEC_PROCESS_MONITORS_ERR_INVALID_DESKTOP);
free_stream(s);
}

View File

@ -1022,27 +1022,154 @@ dynamic_monitor_data_first(intptr_t id, int chan_id, char *data, int bytes,
return 0;
}
/******************************************************************************/
static int
process_dynamic_monitor_description(struct xrdp_wm *wm,
struct display_size_description *description)
{
int error = 0;
struct xrdp_mm *mm = wm->mm;
struct xrdp_mod *module = mm->mod;
LOG_DEVEL(LOG_LEVEL_TRACE, "process_dynamic_monitor_description:");
if (wm->client_info->suppress_output == 1)
{
LOG(LOG_LEVEL_ERROR,
"process_dynamic_monitor_description:"
" Not allowing resize. Suppress output is active.");
return 0;
}
if (description == NULL)
{
LOG_DEVEL(LOG_LEVEL_ERROR,
"process_dynamic_monitor_description:"
" description is null.");
return 0;
}
if (description->session_width <= 0 || description->session_height <= 0)
{
LOG(LOG_LEVEL_ERROR,
"process_dynamic_monitor_description: Not allowing resize due to"
" invalid dimensions (w: %d x h: %d)",
description->session_width, description->session_height);
return 0;
}
// TODO: Unify this logic with server_reset
error = libxrdp_reset(wm->session,
description->session_width,
description->session_height,
wm->screen->bpp);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_ERROR,
"process_dynamic_monitor_description:"
" libxrdp_reset failed %d", error);
return error;
}
/* reset cache */
error = xrdp_cache_reset(wm->cache, wm->client_info);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_ERROR,
"process_dynamic_monitor_description: xrdp_cache_reset"
" failed %d", error);
return error;
}
/* load some stuff */
error = xrdp_wm_load_static_colors_plus(wm, 0);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_ERROR, "process_dynamic_monitor_description:"
" xrdp_wm_load_static_colors_plus failed %d", error);
return error;
}
error = xrdp_wm_load_static_pointers(wm);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_ERROR, "process_dynamic_monitor_description:"
" xrdp_wm_load_static_pointers failed %d", error);
return error;
}
/* resize the main window */
error = xrdp_bitmap_resize(wm->screen,
description->session_width,
description->session_height);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_ERROR, "process_dynamic_monitor_description:"
" xrdp_bitmap_resize failed %d", error);
return error;
}
/* redraw */
error = xrdp_bitmap_invalidate(wm->screen, 0);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_ERROR,
"process_dynamic_monitor_description:"
" xrdp_bitmap_invalidate failed %d", error);
return error;
}
if (module != 0)
{
error = module->mod_server_version_message(module);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_ERROR, "process_dynamic_monitor_description:"
" mod_server_version_message failed %d", error);
return error;
}
error = module->mod_server_monitor_resize(
module,
description->session_width,
description->session_height);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_ERROR, "process_dynamic_monitor_description:"
"mod_server_monitor_resize failed %d", error);
return error;
}
error = module->mod_server_monitor_full_invalidate(
module,
description->session_width,
description->session_height);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_ERROR, "process_dynamic_monitor_description:"
"mod_server_monitor_full_invalidate failed %d", error);
return error;
}
}
wm->client_info->monitorCount = description->monitorCount;
wm->client_info->width = description->session_width;
wm->client_info->height = description->session_height;
g_memcpy(wm->client_info->minfo,
description->minfo,
sizeof(struct monitor_info)
* CLIENT_MONITOR_DATA_MAXIMUM_MONITORS);
g_memcpy(wm->client_info->minfo_wm,
description->minfo_wm,
sizeof(struct monitor_info)
* CLIENT_MONITOR_DATA_MAXIMUM_MONITORS);
return 0;
}
/******************************************************************************/
static int
dynamic_monitor_data(intptr_t id, int chan_id, char *data, int bytes)
{
int error = 0;
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;
int monitor_layout_size;
LOG_DEVEL(LOG_LEVEL_TRACE, "dynamic_monitor_data:");
pro = (struct xrdp_process *) id;
@ -1058,70 +1185,31 @@ dynamic_monitor_data(intptr_t id, int chan_id, char *data, int bytes)
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)
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);
}
return 0;
}
session_width = rect.right - rect.left;
session_height = rect.bottom - rect.top;
if ((session_width > 0) && (session_height > 0))
in_uint32_le(s, monitor_layout_size);
if (monitor_layout_size != 40)
{
// 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);
}
LOG(LOG_LEVEL_ERROR, "dynamic_monitor_data: monitor_layout_size"
" is %d. Per spec ([MS-RDPEDISP] 2.2.2.2"
" DISPLAYCONTROL_MONITOR_LAYOUT_PDU) it must be 40.",
monitor_layout_size);
return 1;
}
return 0;
struct display_size_description *description =
(struct display_size_description *)
g_malloc(sizeof(struct display_size_description), 1);
error = libxrdp_process_monitor_stream(s, description, 1);
if (error == 0)
{
error = process_dynamic_monitor_description(wm, description);
}
g_free(description);
return error;
}
/******************************************************************************/