diff --git a/common/xrdp_client_info.h b/common/xrdp_client_info.h index ca349f0a..297cdc55 100644 --- a/common/xrdp_client_info.h +++ b/common/xrdp_client_info.h @@ -156,6 +156,7 @@ struct xrdp_client_info int no_orders_supported; int use_cache_glyph_v2; int rail_enable; + int suppress_output; }; #endif diff --git a/libxrdp/xrdp_caps.c b/libxrdp/xrdp_caps.c index 4d1ab45f..1c0587f5 100644 --- a/libxrdp/xrdp_caps.c +++ b/libxrdp/xrdp_caps.c @@ -810,7 +810,8 @@ xrdp_caps_send_demand_active(struct xrdp_rdp *self) out_uint16_le(s, 0); /* Update capability */ out_uint16_le(s, 0); /* Remote unshare capability */ out_uint16_le(s, 0); /* Compression level */ - out_uint16_le(s, 0); /* Pad */ + out_uint8(s, 1); /* refreshRectSupport */ + out_uint8(s, 1); /* suppressOutputSupport */ /* Output bitmap capability set */ caps_count++; diff --git a/libxrdp/xrdp_rdp.c b/libxrdp/xrdp_rdp.c index e4ee660f..319bac23 100644 --- a/libxrdp/xrdp_rdp.c +++ b/libxrdp/xrdp_rdp.c @@ -1209,21 +1209,91 @@ xrdp_rdp_process_frame_ack(struct xrdp_rdp *self, struct stream *s) return 0; } +/*****************************************************************************/ +static int +xrdp_rdp_process_suppress(struct xrdp_rdp *self, struct stream *s) +{ + int allowDisplayUpdates; + int left; + int top; + int right; + int bottom; + + if (!s_check_rem(s, 1)) + { + return 1; + } + in_uint8(s, allowDisplayUpdates); + g_writeln("xrdp_rdp_process_suppress: allowDisplayUpdates %d bytes " + "left %d", allowDisplayUpdates, (int) (s->end - s->p)); + switch (allowDisplayUpdates) + { + case 0: /* SUPPRESS_DISPLAY_UPDATES */ + self->client_info.suppress_output = 1; + g_writeln("xrdp_rdp_process_suppress: suppress_output %d", + self->client_info.suppress_output); + if (self->session->callback != 0) + { + self->session->callback(self->session->id, 0x5559, 1, + 0, 0, 0); + } + break; + case 1: /* ALLOW_DISPLAY_UPDATES */ + self->client_info.suppress_output = 0; + if (!s_check_rem(s, 11)) + { + return 1; + } + in_uint8s(s, 3); /* pad */ + in_uint16_le(s, left); + in_uint16_le(s, top); + in_uint16_le(s, right); + in_uint16_le(s, bottom); + g_writeln("xrdp_rdp_process_suppress: suppress_output %d " + "left %d top %d right %d bottom %d", + self->client_info.suppress_output, + left, top, right, bottom); + if (self->session->callback != 0) + { + self->session->callback(self->session->id, 0x5559, 0, + MAKELONG(left, top), + MAKELONG(right, bottom), 0); + } + break; + } + return 0; +} + /*****************************************************************************/ /* RDP_PDU_DATA */ int xrdp_rdp_process_data(struct xrdp_rdp *self, struct stream *s) { - int data_type; + int uncompressedLength; + int pduType2; + int compressedType; + int compressedLength; + if (!s_check_rem(s, 12)) + { + return 1; + } in_uint8s(s, 6); - in_uint8s(s, 2); /* len */ - in_uint8(s, data_type); - in_uint8s(s, 1); /* ctype */ - in_uint8s(s, 2); /* clen */ - DEBUG(("xrdp_rdp_process_data code %d", data_type)); - - switch (data_type) + in_uint16_le(s, uncompressedLength); + in_uint8(s, pduType2); + in_uint8(s, compressedType); + in_uint16_le(s, compressedLength); + if (compressedType != 0) + { + /* don't support compression */ + return 1; + } + if (compressedLength > uncompressedLength) + { + return 1; + } + DEBUG(("xrdp_rdp_process_data pduType2 %d", pduType2)); + switch (pduType2) { case RDP_DATA_PDU_POINTER: /* 27(0x1b) */ xrdp_rdp_process_data_pointer(self, s); @@ -1240,11 +1310,8 @@ xrdp_rdp_process_data(struct xrdp_rdp *self, struct stream *s) case 33: /* 33(0x21) ?? Invalidate an area I think */ xrdp_rdp_process_screen_update(self, s); break; - case 35: /* 35(0x23) */ - /* 35 ?? this comes when minimizing a full screen mstsc.exe 2600 */ - /* I think this is saying the client no longer wants screen */ - /* updates and it will issue a 33 above to catch up */ - /* so minimized apps don't take bandwidth */ + case 35: /* 35(0x23) PDUTYPE2_SUPPRESS_OUTPUT */ + xrdp_rdp_process_suppress(self, s); break; case 36: /* 36(0x24) ?? disconnect query? */ /* when this message comes, send a 37 back so the client */ @@ -1259,10 +1326,9 @@ xrdp_rdp_process_data(struct xrdp_rdp *self, struct stream *s) xrdp_rdp_process_frame_ack(self, s); break; default: - g_writeln("unknown in xrdp_rdp_process_data %d", data_type); + g_writeln("unknown in xrdp_rdp_process_data pduType2 %d", pduType2); break; } - return 0; } /*****************************************************************************/ diff --git a/neutrinordp/xrdp-neutrinordp.c b/neutrinordp/xrdp-neutrinordp.c index 89e8f2ea..543e91d3 100644 --- a/neutrinordp/xrdp-neutrinordp.c +++ b/neutrinordp/xrdp-neutrinordp.c @@ -27,6 +27,12 @@ #include "log.h" #include +#if defined(VERSION_STRUCT_RDP_FREERDP) +#if VERSION_STRUCT_RDP_FREERDP > 1 +#define NEUTRINORDP_HAS_SUPPRESS_OUTPUT +#endif +#endif + #ifdef XRDP_DEBUG #define LOG_LEVEL 99 #else @@ -541,6 +547,24 @@ lxrdp_check_wait_objs(struct mod *mod) return 0; } +/******************************************************************************/ +static int +lxrdp_frame_ack(struct mod* mod, int flags, int frame_id) +{ + return 0; +} + +/******************************************************************************/ +static int +lxrdp_suppress_output(struct mod* mod, int suppress, + int left, int top, int right, int bottom) +{ +#if defined(NEUTRINORDP_HAS_SUPPRESS_OUTPUT) + mod->inst->SendSuppressOutput(mod->inst, !suppress, left, top, right, bottom); +#endif + return 0; +} + /******************************************************************************/ static void lfreerdp_begin_paint(rdpContext *context) @@ -2009,6 +2033,8 @@ mod_init(void) mod->mod_session_change = lxrdp_session_change; mod->mod_get_wait_objs = lxrdp_get_wait_objs; mod->mod_check_wait_objs = lxrdp_check_wait_objs; + mod->mod_frame_ack = lxrdp_frame_ack; + mod->mod_suppress_output = lxrdp_suppress_output; mod->inst = freerdp_new(); mod->inst->PreConnect = lfreerdp_pre_connect; diff --git a/neutrinordp/xrdp-neutrinordp.h b/neutrinordp/xrdp-neutrinordp.h index f5986b8a..b68eb43a 100644 --- a/neutrinordp/xrdp-neutrinordp.h +++ b/neutrinordp/xrdp-neutrinordp.h @@ -58,7 +58,7 @@ struct pointer_item int bpp; }; -#define CURRENT_MOD_VER 3 +#define CURRENT_MOD_VER 4 struct mod { @@ -76,8 +76,11 @@ struct mod int (*mod_get_wait_objs)(struct mod *v, tbus *read_objs, int *rcount, tbus *write_objs, int *wcount, int *timeout); int (*mod_check_wait_objs)(struct mod *v); - tintptr mod_dumby[100 - 9]; /* align, 100 minus the number of mod - functions above */ + 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 */ /* 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 b0eb29b3..86eff852 100644 --- a/vnc/vnc.c +++ b/vnc/vnc.c @@ -380,20 +380,23 @@ lib_mod_event(struct vnc *v, int msg, long param1, long param2, } else if (msg == 200) /* invalidate */ { - /* FramebufferUpdateRequest */ - init_stream(s, 8192); - out_uint8(s, 3); - out_uint8(s, 0); - x = (param1 >> 16) & 0xffff; - out_uint16_be(s, x); - y = param1 & 0xffff; - out_uint16_be(s, y); - cx = (param2 >> 16) & 0xffff; - out_uint16_be(s, cx); - cy = param2 & 0xffff; - out_uint16_be(s, cy); - s_mark_end(s); - error = lib_send_copy(v, s); + if (v->suppress_output == 0) + { + /* FramebufferUpdateRequest */ + init_stream(s, 8192); + out_uint8(s, 3); + out_uint8(s, 0); + x = (param1 >> 16) & 0xffff; + out_uint16_be(s, x); + y = param1 & 0xffff; + out_uint16_be(s, y); + cx = (param2 >> 16) & 0xffff; + out_uint16_be(s, cx); + cy = param2 & 0xffff; + out_uint16_be(s, cy); + s_mark_end(s); + error = lib_send_copy(v, s); + } } free_stream(s); @@ -742,16 +745,19 @@ lib_framebuffer_update(struct vnc *v) if (error == 0) { - /* FramebufferUpdateRequest */ - init_stream(s, 8192); - out_uint8(s, 3); - out_uint8(s, 1); - out_uint16_be(s, 0); - out_uint16_be(s, 0); - out_uint16_be(s, v->mod_width); - out_uint16_be(s, v->mod_height); - s_mark_end(s); - error = lib_send_copy(v, s); + if (v->suppress_output == 0) + { + /* FramebufferUpdateRequest */ + init_stream(s, 8192); + out_uint8(s, 3); + out_uint8(s, 1); + out_uint16_be(s, 0); + out_uint16_be(s, 0); + out_uint16_be(s, v->mod_width); + out_uint16_be(s, v->mod_height); + s_mark_end(s); + error = lib_send_copy(v, s); + } } free_stream(s); @@ -916,7 +922,7 @@ lib_mod_process_message(struct vnc *v, struct stream *s) } else { - g_sprintf(text, "VNC unknown in lib_mod_signal %d", type); + g_sprintf(text, "VNC unknown in lib_mod_process_message %d", type); v->server_msg(v, text, 1); } } @@ -1340,17 +1346,20 @@ lib_mod_connect(struct vnc *v) if (error == 0) { - /* FramebufferUpdateRequest */ - init_stream(s, 8192); - out_uint8(s, 3); - out_uint8(s, 0); - out_uint16_be(s, 0); - out_uint16_be(s, 0); - out_uint16_be(s, v->mod_width); - out_uint16_be(s, v->mod_height); - v->server_msg(v, "VNC sending framebuffer update request", 0); - s_mark_end(s); - error = trans_force_write_s(v->trans, s); + if (v->suppress_output == 0) + { + /* FramebufferUpdateRequest */ + init_stream(s, 8192); + out_uint8(s, 3); + out_uint8(s, 0); + out_uint16_be(s, 0); + out_uint16_be(s, 0); + out_uint16_be(s, v->mod_width); + out_uint16_be(s, v->mod_height); + v->server_msg(v, "VNC sending framebuffer update request", 0); + s_mark_end(s); + error = trans_force_write_s(v->trans, s); + } } if (error == 0) @@ -1492,6 +1501,43 @@ lib_mod_check_wait_objs(struct vnc *v) return rv; } +/******************************************************************************/ +/* return error */ +int +lib_mod_frame_ack(struct vnc* v, int flags, int frame_id) +{ + return 0; +} + +/******************************************************************************/ +/* return error */ +int +lib_mod_suppress_output(struct vnc* v, int suppress, + int left, int top, int right, int bottom) +{ + int error; + struct stream *s; + + error = 0; + v->suppress_output = suppress; + if (suppress == 0) + { + /* FramebufferUpdateRequest */ + make_stream(s); + init_stream(s, 8192); + out_uint8(s, 3); + out_uint8(s, 0); + out_uint16_be(s, 0); + out_uint16_be(s, 0); + out_uint16_be(s, v->mod_width); + out_uint16_be(s, v->mod_height); + s_mark_end(s); + error = lib_send_copy(v, s); + free_stream(s); + } + return error; +} + /******************************************************************************/ tintptr EXPORT_CC mod_init(void) @@ -1511,6 +1557,8 @@ mod_init(void) v->mod_set_param = lib_mod_set_param; v->mod_get_wait_objs = lib_mod_get_wait_objs; 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; return (tintptr) v; } diff --git a/vnc/vnc.h b/vnc/vnc.h index 3eee4e09..5aa83472 100644 --- a/vnc/vnc.h +++ b/vnc/vnc.h @@ -24,7 +24,7 @@ #include "os_calls.h" #include "defines.h" -#define CURRENT_MOD_VER 3 +#define CURRENT_MOD_VER 4 struct vnc { @@ -42,8 +42,11 @@ struct vnc int (*mod_get_wait_objs)(struct vnc* v, tbus* read_objs, int* rcount, tbus* write_objs, int* wcount, int* timeout); int (*mod_check_wait_objs)(struct vnc* v); - tintptr mod_dumby[100 - 9]; /* align, 100 minus the number of mod - functions above */ + 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 + functions above */ /* server functions */ int (*server_begin_update)(struct vnc* v); int (*server_end_update)(struct vnc* v); @@ -116,4 +119,5 @@ struct vnc struct trans *trans; int got_guid; tui8 guid[16]; + int suppress_output; }; diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h index 5ed46a3a..498dc141 100644 --- a/xrdp/xrdp.h +++ b/xrdp/xrdp.h @@ -371,6 +371,9 @@ xrdp_bitmap_compress(char* in_data, int width, int height, /* xrdp_mm.c */ int xrdp_mm_drdynvc_up(struct xrdp_mm* self); +int +xrdp_mm_suppress_output(struct xrdp_mm* self, int suppress, + int left, int top, int right, int bottom); struct xrdp_mm* xrdp_mm_create(struct xrdp_wm* owner); void diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 757620ac..96c6945c 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -999,6 +999,25 @@ xrdp_mm_drdynvc_up(struct xrdp_mm* self) return 0; } +/******************************************************************************/ +int +xrdp_mm_suppress_output(struct xrdp_mm* self, int suppress, + int left, int top, int right, int bottom) +{ + LLOGLN(0, ("xrdp_mm_suppress_output: suppress %d " + "left %d top %d right %d bottom %d", + suppress, left, top, right, bottom)); + if (self->mod != NULL) + { + if (self->mod->mod_suppress_output != NULL) + { + self->mod->mod_suppress_output(self->mod, suppress, + left, top, right, bottom); + } + } + return 0; +} + /*****************************************************************************/ /* open response from client going to channel server */ static int diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index 7e416125..dc6db4bc 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -48,7 +48,9 @@ struct xrdp_mod tbus* write_objs, int* wcount, int* timeout); int (*mod_check_wait_objs)(struct xrdp_mod* v); int (*mod_frame_ack)(struct xrdp_mod* v, int flags, int frame_id); - tintptr mod_dumby[100 - 10]; /* align, 100 minus the number of mod + 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 functions above */ /* server functions */ int (*server_begin_update)(struct xrdp_mod* v); diff --git a/xrdp/xrdp_wm.c b/xrdp/xrdp_wm.c index fd7b13b8..f68b11e9 100644 --- a/xrdp/xrdp_wm.c +++ b/xrdp/xrdp_wm.c @@ -1916,6 +1916,11 @@ callback(intptr_t id, int msg, intptr_t param1, intptr_t param2, case 0x5558: xrdp_mm_drdynvc_up(wm->mm); break; + case 0x5559: + xrdp_mm_suppress_output(wm->mm, param1, + LOWORD(param2), HIWORD(param2), + LOWORD(param3), HIWORD(param3)); + break; } return rv; } diff --git a/xup/xup.c b/xup/xup.c index 91eb0563..23722456 100644 --- a/xup/xup.c +++ b/xup/xup.c @@ -1143,6 +1143,33 @@ send_paint_rect_ex_ack(struct mod *mod, int flags, int frame_id) return 0; } +/******************************************************************************/ +/* return error */ +static int +send_suppress_output(struct mod *mod, int suppress, + int left, int top, int right, int bottom) +{ + int len; + struct stream *s; + + make_stream(s); + init_stream(s, 8192); + s_push_layer(s, iso_hdr, 4); + out_uint16_le(s, 108); + out_uint32_le(s, suppress); + out_uint32_le(s, left); + out_uint32_le(s, top); + out_uint32_le(s, right); + out_uint32_le(s, bottom); + 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); + free_stream(s); + return 0; +} + /******************************************************************************/ /* return error */ static int @@ -1556,6 +1583,18 @@ lib_mod_frame_ack(struct mod *amod, int flags, int frame_id) return 0; } +/******************************************************************************/ +/* return error */ +int +lib_mod_suppress_output(struct mod *amod, int suppress, + int left, int top, int right, int bottom) +{ + LLOGLN(10, ("lib_mod_suppress_output: suppress 0x%8.8x left %d top %d " + "right %d bottom %d", suppress, left, top, right, bottom)); + send_suppress_output(amod, suppress, left, top, right, bottom); + return 0; +} + /******************************************************************************/ tintptr EXPORT_CC mod_init(void) @@ -1575,6 +1614,7 @@ mod_init(void) mod->mod_get_wait_objs = lib_mod_get_wait_objs; 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; return (tintptr) mod; } diff --git a/xup/xup.h b/xup/xup.h index 3e5c8e8d..ddd24e36 100644 --- a/xup/xup.h +++ b/xup/xup.h @@ -26,7 +26,7 @@ #include "xrdp_client_info.h" #include "xrdp_rail.h" -#define CURRENT_MOD_VER 3 +#define CURRENT_MOD_VER 4 struct mod { @@ -45,7 +45,9 @@ struct mod tbus* write_objs, int* wcount, int* timeout); int (*mod_check_wait_objs)(struct mod* v); int (*mod_frame_ack)(struct mod* v, int flags, int frame_id); - tintptr mod_dumby[100 - 10]; /* align, 100 minus the number of mod + 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 functions above */ /* server functions */ int (*server_begin_update)(struct mod* v);