diff --git a/README.md b/README.md index 42436ac700..c9a9247f62 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 and the only Microsoft clients that support resizing without reconnection) + +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/libxrdp/xrdp_channel.c b/libxrdp/xrdp_channel.c index 9a374cac33..5024e4c426 100644 --- a/libxrdp/xrdp_channel.c +++ b/libxrdp/xrdp_channel.c @@ -777,6 +777,12 @@ xrdp_channel_drdynvc_start(struct xrdp_channel *self) struct mcs_channel_item *dci; + LOG(LOG_LEVEL_INFO, "xrdp_channel_drdynvc_start: drdynvc_channel_id %d", self->drdynvc_channel_id); + if (self->drdynvc_channel_id != -1) + { + LOG(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/vnc/vnc.c b/vnc/vnc.c index d2732a6d88..640a9adddc 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 bpp) +{ + 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 c890fe7cb9..a01715a2f5 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 bpp); + 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_mm.c b/xrdp/xrdp_mm.c index 4679bd6b3e..8d5119ec0a 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -37,6 +37,7 @@ #include "xrdp_encoder.h" #include "xrdp_sockets.h" +#include "xrdp_egfx.h" @@ -63,7 +64,13 @@ xrdp_mm_create(struct xrdp_wm *owner) self->wm->client_info->rfx_codec_id, self->wm->client_info->h264_codec_id); - self->encoder = xrdp_encoder_create(self); + if ((self->wm->client_info->gfx == 0) && + ((self->wm->client_info->h264_codec_id != 0) || + (self->wm->client_info->jpeg_codec_id != 0) || + (self->wm->client_info->rfx_codec_id != 0))) + { + self->encoder = xrdp_encoder_create(self); + } return self; } @@ -147,6 +154,7 @@ xrdp_mm_delete(struct xrdp_mm *self) self->sesman_trans_up = 0; list_delete(self->login_names); list_delete(self->login_values); + xrdp_egfx_delete(self->egfx); g_free(self); } @@ -991,11 +999,614 @@ xrdp_mm_process_rail_drawing_orders(struct xrdp_mm *self, struct stream *s) return rv; } + +#define GFX_PLANAR_BYTES (32 * 1024) + +/******************************************************************************/ +int +xrdp_mm_egfx_send_planar_bitmap(struct xrdp_mm *self, + struct xrdp_bitmap *bitmap, + struct xrdp_rect *rect) +{ + struct xrdp_egfx_rect gfx_rect; + struct stream *comp_s; + struct stream *temp_s; + char *pixels; + char *src8; + char *dst8; + int index; + int lines; + int comp_bytes; + int xindex; + int yindex; + int bwidth; + int bheight; + int cx; + int cy; + + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_egfx_send_planar_bitmap:"); + bwidth = rect->right - rect->left; + bheight = rect->bottom - rect->top; + if ((bwidth < 1) || (bheight < 1)) + { + return 0; + } + if (bwidth < 64) + { + cx = bwidth; + cy = 4096 / cx; + } + else if (bheight < 64) + { + cy = bheight; + cx = 4096 / cy; + } + else + { + cx = 64; + cy = 64; + } + while (cx * cy < 4096) + { + if (cx < cy) + { + cx++; + cy = 4096 / cx; + } + else + { + cy++; + cx = 4096 / cy; + } + } + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_egfx_send_planar_bitmap: cx %d cy %d", cx, cy); + pixels = g_new(char, GFX_PLANAR_BYTES); + make_stream(comp_s); + init_stream(comp_s, GFX_PLANAR_BYTES); + make_stream(temp_s); + init_stream(temp_s, GFX_PLANAR_BYTES); + if (xrdp_egfx_send_frame_start(self->egfx, 1, 0) != 0) + { + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_send_planar_bitmap: error"); + } + + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_egfx_send_planar_bitmap: left %d top %d right %d " + "bottom %d", rect->left, rect->top, rect->right, rect->bottom); + for (yindex = rect->top; yindex < rect->bottom; yindex += cy) + { + bheight = rect->bottom - yindex; + bheight = MIN(bheight, cy); + for (xindex = rect->left; xindex < rect->right; xindex += cx) + { + bwidth = rect->right - xindex; + bwidth = MIN(bwidth, cx); + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_egfx_send_planar_bitmap: xindex %d " + "yindex %d, bwidth %d bheight %d", + xindex, yindex, bwidth, bheight); + src8 = bitmap->data + bitmap->line_size * yindex + xindex * 4; + dst8 = pixels + (bheight - 1) * bwidth * 4; + for (index = 0; index < bheight; index++) + { + g_memcpy(dst8, src8, bwidth * 4); + src8 += bitmap->line_size; + dst8 -= bwidth * 4; + } + lines = libxrdp_planar_compress(pixels, bwidth, bheight, comp_s, + 32, GFX_PLANAR_BYTES, bheight - 1, + temp_s, 0, 0x10); + comp_s->end = comp_s->p; + comp_s->p = comp_s->data; + if (lines != bheight) + { + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_send_planar_bitmap: error"); + } + else + { + comp_bytes = (int)(comp_s->end - comp_s->data); + LOG_DEVEL(LOG_LEVEL_TRACE, ("xrdp_mm_egfx_send_planar_bitmap: lines %d " + "comp_bytes %d", lines, comp_bytes)); + gfx_rect.x1 = xindex; + gfx_rect.y1 = yindex; + gfx_rect.x2 = xindex + bwidth; + gfx_rect.y2 = yindex + bheight; + if (xrdp_egfx_send_wire_to_surface1(self->egfx, 1, + XR_RDPGFX_CODECID_PLANAR, + XR_PIXEL_FORMAT_XRGB_8888, + &gfx_rect, comp_s->data, + comp_bytes) != 0) + { + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_send_planar_bitmap: error"); + } + } + } + } + if (xrdp_egfx_send_frame_end(self->egfx, 1) != 0) + { + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_send_planar_bitmap: error"); + } + g_free(pixels); + free_stream(comp_s); + free_stream(temp_s); + return 0; +} + +/******************************************************************************/ +static int +xrdp_mm_egfx_caps_advertise(void* user, int caps_count, + int *versions, int *flagss) +{ + struct xrdp_mm* self; + struct xrdp_bitmap *screen; + int index; + int best_index; + int best_h264_index; + int best_pro_index; + int error; + int version; + int flags; + struct xrdp_rect xr_rect; + + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise:"); + self = (struct xrdp_mm *) user; + screen = self->wm->screen; + if (screen->data == NULL) + { + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise: can not do gfx"); + } + best_index = -1; + best_h264_index = -1; + best_pro_index = -1; + for (index = 0; index < caps_count; index++) + { + version = versions[index]; + flags = flagss[index]; + LOG(LOG_LEVEL_INFO, " version 0x%8.8x flags 0x%8.8x", version, flags); + switch (version) + { + case XR_RDPGFX_CAPVERSION_8: + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_81: + if (flags & XR_RDPGFX_CAPS_FLAG_AVC420_ENABLED) + { + best_h264_index = index; + } + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_10: + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_101: + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_102: + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_103: + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_104: + if (!(flags & XR_RDPGFX_CAPS_FLAG_AVC_DISABLED)) + { + best_h264_index = index; + } + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_105: + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_106: + best_pro_index = index; + break; + } + } + if (best_pro_index >= 0) + { + best_index = best_pro_index; + self->egfx_flags = 2; + } + if (best_h264_index >= 0) /* prefer h264, todo use setting in xrdp.ini for this */ + { +#ifdef XRDP_X264 + best_index = best_h264_index; + self->egfx_flags = 1; +#endif + } + if (best_index >= 0) + { + LOG(LOG_LEVEL_INFO, " replying version 0x%8.8x flags 0x%8.8x", + versions[best_index], flagss[best_index]); + error = xrdp_egfx_send_capsconfirm(self->egfx, + versions[best_index], + flagss[best_index]); + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise: xrdp_egfx_send_capsconfirm " + "error %d", error); + error = xrdp_egfx_send_reset_graphics(self->egfx, + screen->width, screen->height, + self->wm->client_info->monitorCount, + self->wm->client_info->minfo_wm); + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise: xrdp_egfx_send_reset_graphics " + "error %d monitorCount %d", + error, self->wm->client_info->monitorCount); + self->egfx_up = 1; + xrdp_egfx_send_create_surface(self->egfx, 1, + screen->width, screen->height, + XR_PIXEL_FORMAT_XRGB_8888); + xrdp_egfx_send_map_surface(self->egfx, 1, 0, 0); + xr_rect.left = 0; + xr_rect.top = 0; + xr_rect.right = screen->width; + xr_rect.bottom = screen->height; + if (self->wm->screen_dirty_region == NULL) + { + self->wm->screen_dirty_region = xrdp_region_create(self->wm); + } + xrdp_region_add_rect(self->wm->screen_dirty_region, &xr_rect); + self->encoder = xrdp_encoder_create(self); + if (self->gfx_delay_autologin) + { + self->gfx_delay_autologin = 0; + xrdp_wm_set_login_state(self->wm, WMLS_START_CONNECT); + } + } + else + { + struct xrdp_rect lrect; + + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise: no good gfx, canceling"); + lrect.left = 0; + lrect.top = 0; + lrect.right = screen->width; + lrect.bottom = screen->height; + self->wm->client_info->gfx = 0; + xrdp_encoder_delete(self->encoder); + self->encoder = xrdp_encoder_create(self); + xrdp_bitmap_invalidate(screen, &lrect); + } + return 0; +} + +static int +xrdp_mm_update_module_frame_ack(struct xrdp_mm *self); + +/******************************************************************************/ +static int +xrdp_mm_egfx_frame_ack(void* user, int queue_depth, int frame_id, + int frames_decoded) +{ + struct xrdp_mm* self; + struct xrdp_encoder *encoder; + + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_egfx_frame_ack:"); + self = (struct xrdp_mm *) user; + encoder = self->encoder; + if (encoder == NULL) + { + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_frame_ack: encoder is nil"); + return 0; + } + if (queue_depth == XR_SUSPEND_FRAME_ACKNOWLEDGEMENT) + { + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_frame_ack: queue_depth %d frame_id %d " + "frames_decoded %d", queue_depth, frame_id, frames_decoded); + if (encoder->gfx_ack_off == 0) + { + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_frame_ack: client request turn off " + "frame acks"); + encoder->gfx_ack_off = 1; + frame_id = -1; + } + } + else + { + if (encoder->gfx_ack_off) + { + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_egfx_frame_ack: client request turn on " + "frame acks"); + encoder->gfx_ack_off = 0; + } + } + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_egfx_frame_ack: incoming %d, client %d, server %d", + frame_id, encoder->frame_id_client, encoder->frame_id_server); + if ((frame_id < 0) || (frame_id > encoder->frame_id_server)) + { + /* if frame_id is negative or bigger then what server last sent + just ack all sent frames */ + /* some clients can send big number just to clear all + pending frames */ + encoder->frame_id_client = encoder->frame_id_server; + } + else + { + /* frame acks can come out of order so ignore older one */ + encoder->frame_id_client = MAX(frame_id, encoder->frame_id_client); + } + xrdp_mm_update_module_frame_ack(self); + return 0; +} + +/******************************************************************************/ +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(LOG_LEVEL_INFO, "dynamic_monitor_open_response: chan_id %d creation_status 0x%8.8x", chan_id, creation_status); + if (creation_status != 0) + { + LOG(LOG_LEVEL_INFO, "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, 16); /* 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(LOG_LEVEL_INFO, "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(LOG_LEVEL_INFO, "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; + + int Flags; + int Left; + int Top; + int Width; + int Height; + int PhysicalWidth; + int PhysicalHeight; + int Orientation; + int DesktopScaleFactor; + int DeviceScaleFactor; + + struct xrdp_rect rect; + int session_width; + int session_height; + + LOG(LOG_LEVEL_INFO, "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_INFO, "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 == 2) /* DISPLAYCONTROL_PDU_TYPE_MONITOR_LAYOUT */ + { + in_uint32_le(s, MonitorLayoutSize); + in_uint32_le(s, NumMonitor); + LOG(LOG_LEVEL_INFO, " MonitorLayoutSize %d NumMonitor %d", + MonitorLayoutSize, NumMonitor); + for (monitor_index = 0; monitor_index < NumMonitor; monitor_index++) + { + in_uint32_le(s, Flags); + in_uint32_le(s, Left); + in_uint32_le(s, Top); + in_uint32_le(s, Width); + in_uint32_le(s, Height); + in_uint32_le(s, PhysicalWidth); + in_uint32_le(s, PhysicalHeight); + in_uint32_le(s, Orientation); + in_uint32_le(s, DesktopScaleFactor); + in_uint32_le(s, DeviceScaleFactor); + LOG(LOG_LEVEL_INFO, " Flags 0x%8.8x Left %d Top %d " + "Width %d Height %d PhysicalWidth %d PhysicalHeight %d " + "Orientation %d DesktopScaleFactor %d DeviceScaleFactor %d", + Flags, Left, Top, Width, Height, + PhysicalWidth, PhysicalHeight, Orientation, + DesktopScaleFactor, DeviceScaleFactor); + + rect.left = MIN(Left, rect.left); + rect.top = MIN(Top, rect.top); + rect.right = MAX(rect.right, Left + Width); + rect.bottom = MAX(rect.bottom, Top + Height); + } + } + session_width = rect.right - rect.left; + session_height = rect.bottom - rect.top; + if ((session_width > 0) && (session_height > 0)) + { + int error = 0; + xrdp_encoder_delete(wm->mm->encoder); + + // TODO: Unify this logic with server_reset + error = libxrdp_reset(wm->session, session_width, session_height, 32); + if (error != 0) + { + LOG(LOG_LEVEL_INFO, "dynamic_monitor_data: libxrdp_reset failed %d", error); + return error; + } + + /* reset cache */ + error = xrdp_cache_reset(wm->cache, wm->client_info); + if (error != 0) + { + LOG(LOG_LEVEL_INFO, "dynamic_monitor_data: xrdp_cache_reset failed %d", error); + return error; + } + + /* resize the main window */ + error = xrdp_bitmap_resize(wm->screen, wm->client_info->width, wm->client_info->height); + if (error != 0) + { + LOG(LOG_LEVEL_INFO, "dynamic_monitor_data: xrdp_bitmap_resize failed %d", error); + return error; + } + + /* load some stuff */ + error = xrdp_wm_load_static_colors_plus(wm, 0); + if (error != 0) + { + LOG(LOG_LEVEL_INFO, "dynamic_monitor_data: xrdp_wm_load_static_colors_plus failed %d", error); + return error; + } + + error = xrdp_wm_load_static_pointers(wm); + if (error != 0) + { + LOG(LOG_LEVEL_INFO, "dynamic_monitor_data: xrdp_wm_load_static_pointers failed %d", error); + return error; + } + + /* redraw */ + error = xrdp_bitmap_invalidate(wm->screen, 0); + if (error != 0) + { + LOG(LOG_LEVEL_INFO, "dynamic_monitor_data: xrdp_bitmap_invalidate failed %d", error); + return error; + } + + struct xrdp_mod* module = wm->mm->mod; + if (error == 0 && module != 0) { + error = module->mod_server_version_message(module); + if (error != 0) + { + LOG_DEVEL(LOG_LEVEL_INFO, "dynamic_monitor_data: mod_server_version_message failed %d", error); + return error; + } + + error = module->mod_server_monitor_resize(module, session_width, session_height, wm->screen->bpp); + if (error != 0) + { + LOG_DEVEL(LOG_LEVEL_INFO, "dynamic_monitor_data: mod_server_monitor_resize failed %d", error); + return error; + } + + error = module->mod_server_monitor_full_invalidate(module, session_width, session_height); + if (error != 0) + { + LOG_DEVEL(LOG_LEVEL_INFO, "dynamic_monitor_data: mod_server_monitor_full_invalidate failed %d", error); + return error; + } + } +#ifdef XRDP_X264 + struct xrdp_egfx* egfx = wm->mm->egfx; + if (error == 0 && module != 0 && wm->mm->egfx_up != 0 && egfx != 0) { + error = xrdp_egfx_send_delete_surface(egfx, 1); + if (error != 0) + { + LOG_DEVEL(LOG_LEVEL_INFO, "dynamic_monitor_data: xrdp_egfx_send_delete_surface failed %d", error); + return error; + } + error = xrdp_egfx_send_reset_graphics(egfx, session_width, session_height, wm->client_info->monitorCount, wm->client_info->minfo_wm); + if (error != 0) + { + LOG_DEVEL(LOG_LEVEL_INFO, "dynamic_monitor_data: xrdp_egfx_send_reset_graphics failed %d", error); + return error; + } + error = xrdp_egfx_send_create_surface(egfx, 1, session_width, session_height, XR_PIXEL_FORMAT_XRGB_8888); + if (error != 0) + { + LOG_DEVEL(LOG_LEVEL_INFO, "dynamic_monitor_data: xrdp_egfx_send_create_surface failed %d", error); + return error; + } + + error = xrdp_egfx_send_map_surface(egfx, 1, 0, 0); + if (error != 0) + { + LOG_DEVEL(LOG_LEVEL_INFO, "dynamic_monitor_data: xrdp_egfx_send_map_surface failed %d", error); + return error; + } + } +#endif + //The size of the surface is hard-coded into the encoder. + wm->mm->encoder = xrdp_encoder_create(wm->mm); + } + return 0; +} + /******************************************************************************/ int xrdp_mm_drdynvc_up(struct xrdp_mm *self) { LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_mm_drdynvc_up:"); + struct xrdp_drdynvc_procs d_procs; + int flags; + int error; + + 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_DEVEL(LOG_LEVEL_INFO, "xrdp_mm_drdynvc_up: libxrdp_drdynvc_open failed %d", error); + return 1; + } + + /* 0x100 RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL */ + if (self->wm->client_info->mcs_early_capability_flags & 0x100) + { + LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_mm_drdynvc_up: gfx capable client"); + if (xrdp_egfx_create(self, &(self->egfx)) == 0) + { + self->egfx->user = self; + self->egfx->caps_advertise = xrdp_mm_egfx_caps_advertise; + self->egfx->frame_ack = xrdp_mm_egfx_frame_ack; + } + else + { + LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_mm_drdynvc_up: xrdp_egfx_create failed"); + return 1; + } + } return 0; } @@ -2417,7 +3028,23 @@ xrdp_mm_get_wait_objs(struct xrdp_mm *self, { read_objs[(*rcount)++] = self->encoder->xrdp_encoder_event_processed; } - + if (self->wm->screen_dirty_region != NULL) + { + if (xrdp_region_not_empty(self->wm->screen_dirty_region)) + { + int now = g_time3(); + int next_screen_draw_time = self->wm->last_screen_draw_time + 40; + int diff = next_screen_draw_time - now; + int ltimeout = *timeout; + diff = MAX(diff, 5); + diff = MIN(diff, 40); + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_get_wait_objs: not empty diff %d", diff); + if ((ltimeout < 0) || (ltimeout > diff)) + { + *timeout = diff; + } + } + } return rv; } @@ -2529,6 +3156,7 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self) int y; int cx; int cy; + struct xrdp_egfx_rect rect; while (1) { @@ -2549,32 +3177,86 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self) cy = enc_done->cy; if (enc_done->comp_bytes > 0) { - libxrdp_fastpath_send_frame_marker(self->wm->session, 0, - enc_done->enc->frame_id); - libxrdp_fastpath_send_surface(self->wm->session, - enc_done->comp_pad_data, - enc_done->pad_bytes, - enc_done->comp_bytes, - x, y, x + cx, y + cy, - 32, self->encoder->codec_id, - cx, cy); - libxrdp_fastpath_send_frame_marker(self->wm->session, 1, - enc_done->enc->frame_id); + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_process_enc_done: x %d y %d cx %d cy %d " + "frame_id %d use_frame_acks %d", x, y, cx, cy, + enc_done->enc->frame_id, + self->wm->client_info->use_frame_acks); + if (enc_done->flags & 1) /* gfx h264 */ + { + xrdp_egfx_send_frame_start(self->egfx, + enc_done->enc->frame_id, 0); + rect.x1 = x; + rect.y1 = y; + rect.x2 = x + cx; + rect.y2 = y + cy; + xrdp_egfx_send_wire_to_surface1(self->egfx, 1, + XR_RDPGFX_CODECID_AVC420, + XR_PIXEL_FORMAT_XRGB_8888, + &rect, + enc_done->comp_pad_data + + enc_done->pad_bytes, + enc_done->comp_bytes); + xrdp_egfx_send_frame_end(self->egfx, enc_done->enc->frame_id); + } + else if (enc_done->flags & 2) /* gfx progressive rfx */ + { + xrdp_egfx_send_frame_start(self->egfx, + enc_done->enc->frame_id, 0); + xrdp_egfx_send_wire_to_surface2(self->egfx, 1, 9, 1, + XR_PIXEL_FORMAT_XRGB_8888, + enc_done->comp_pad_data + + enc_done->pad_bytes, + enc_done->comp_bytes); + xrdp_egfx_send_frame_end(self->egfx, enc_done->enc->frame_id); + } + else + { + libxrdp_fastpath_send_frame_marker(self->wm->session, 0, + enc_done->enc->frame_id); + libxrdp_fastpath_send_surface(self->wm->session, + enc_done->comp_pad_data, + enc_done->pad_bytes, + enc_done->comp_bytes, + x, y, x + cx, y + cy, + 32, self->encoder->codec_id, + cx, cy); + libxrdp_fastpath_send_frame_marker(self->wm->session, 1, + enc_done->enc->frame_id); + } } /* free enc_done */ if (enc_done->last) { LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_mm_process_enc_done: last set"); - if (self->wm->client_info->use_frame_acks == 0) + if (enc_done->flags & 3) /* gfx */ { - self->mod->mod_frame_ack(self->mod, - enc_done->enc->flags, - enc_done->enc->frame_id); + if (self->encoder->gfx_ack_off) + { + /* gfx and client turned off client frame acks */ + self->mod->mod_frame_ack(self->mod, + enc_done->enc->flags, + enc_done->enc->frame_id); + } + else + { + self->encoder->frame_id_server = enc_done->enc->frame_id; + xrdp_mm_update_module_frame_ack(self); + } } else { - self->encoder->frame_id_server = enc_done->enc->frame_id; - xrdp_mm_update_module_frame_ack(self); + if (self->wm->client_info->use_frame_acks == 0) + { + /* surface commmand and client does not do frame acks */ + self->mod->mod_frame_ack(self->mod, + enc_done->enc->flags, + enc_done->enc->frame_id); + } + else + { + self->encoder->frame_id_server = enc_done->enc->frame_id; + xrdp_mm_update_module_frame_ack(self); + } } g_free(enc_done->enc->drects); g_free(enc_done->enc->crects); @@ -2652,6 +3334,36 @@ xrdp_mm_check_wait_objs(struct xrdp_mm *self) xrdp_mm_process_enc_done(self); } } + if (self->wm->screen_dirty_region != NULL) + { + if (xrdp_region_not_empty(self->wm->screen_dirty_region)) + { + int error; + struct xrdp_rect rect; + int now = g_time3(); + int diff = now - self->wm->last_screen_draw_time; + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_check_wait_objs: not empty diff %d", diff); + if ((diff < 0) || (diff >= 40)) + { + if (self->egfx_up) + { + error = xrdp_region_get_bounds(self->wm->screen_dirty_region, &rect); + if (error == 0) + { + xrdp_mm_egfx_send_planar_bitmap(self, self->wm->screen, &rect); + } + } + xrdp_region_delete(self->wm->screen_dirty_region); + self->wm->screen_dirty_region = NULL; + self->wm->last_screen_draw_time = now; + } + } + else + { + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_check_wait_objs: empty"); + } + } + return rv; } @@ -2962,7 +3674,12 @@ server_paint_rects(struct xrdp_mod *mod, int num_drects, short *drects, return 0; } - LOG(LOG_LEVEL_TRACE, "server_paint_rects:"); + if (wm->client_info->gfx) + { + LOG(LOG_LEVEL_TRACE, "server_paint_rects: gfx session and no encoder"); + mm->mod->mod_frame_ack(mm->mod, flags, frame_id); + return 0; + } p = (struct xrdp_painter *)(mod->painter); if (p == 0) diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index 586752ebeb..8a9ce31f41 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 bpp); + 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 bc9a9c6830..f28892e881 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,119 @@ 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); + 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_INFO, "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_INFO, "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, int bpp) +{ + /* send screen size message */ + struct stream *s; + make_stream(s); + int rv = send_server_monitor_resize(mod, s, width, height, 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 +1715,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 d31365538e..c4bc76faae 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 bpp); + 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);