diff --git a/xrdp/Makefile.am b/xrdp/Makefile.am index b7d71c88..11db5264 100644 --- a/xrdp/Makefile.am +++ b/xrdp/Makefile.am @@ -58,6 +58,8 @@ xrdp_SOURCES = \ xrdp_process.c \ xrdp_region.c \ xrdp_types.h \ + xrdp_egfx.c \ + xrdp_egfx.h \ xrdp_wm.c xrdp_LDADD = \ diff --git a/xrdp/xrdp_egfx.c b/xrdp/xrdp_egfx.c new file mode 100644 index 00000000..0d83c326 --- /dev/null +++ b/xrdp/xrdp_egfx.c @@ -0,0 +1,1180 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2019 + * + * 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. + * + * MS-RDPEGFX + */ + +#if defined(HAVE_CONFIG_H) +#include +#endif + +#include +#include +#include + +#include "arch.h" +#include "os_calls.h" +#include "parse.h" +#include "xrdp.h" +#include "xrdp_egfx.h" +#include "libxrdp.h" +#include "xrdp_channel.h" +#include + +#define MAX_PART_SIZE 0xFFFF +#define PACKET_COMPR_TYPE_RDP8 0x04 /* MS-RDPEGFX 2.2.5.3 */ + +/******************************************************************************/ +int +xrdp_egfx_send_data(struct xrdp_egfx *egfx, const char *data, int bytes) +{ + int error; + int to_send; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_send_data:"); + + if (bytes <= 1500) + { + error = libxrdp_drdynvc_data(egfx->session, egfx->channel_id, + data, bytes); + } + else + { + error = libxrdp_drdynvc_data_first(egfx->session, egfx->channel_id, + data, 1500, bytes); + data += 1500; + bytes -= 1500; + while ((bytes > 0) && (error == 0)) + { + to_send = bytes; + if (to_send > 1500) + { + to_send = 1500; + } + error = libxrdp_drdynvc_data(egfx->session, egfx->channel_id, + data, to_send); + data += to_send; + bytes -= to_send; + } + } + return error; +} + +/******************************************************************************/ +int +xrdp_egfx_send_s(struct xrdp_egfx *egfx, struct stream *s) +{ + int error; + int bytes; + + if (s == NULL) + { + return 1; + } + bytes = (int) (s->end - s->data); + error = xrdp_egfx_send_data(egfx, s->data, bytes); + return error; +} + +/******************************************************************************/ +struct stream * +xrdp_egfx_create_surface(struct xrdp_egfx_bulk *bulk, int surface_id, + int width, int height, int pixel_format) +{ + int bytes; + struct stream *s; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_create_surface:"); + make_stream(s); + init_stream(s, 8192); + /* RDP_SEGMENTED_DATA */ + out_uint8(s, 0xE0); /* descriptor = SINGLE */ + /* RDP8_BULK_ENCODED_DATA */ + out_uint8(s, PACKET_COMPR_TYPE_RDP8); /* header */ + /* RDPGFX_HEADER */ + out_uint16_le(s, XR_RDPGFX_CMDID_CREATESURFACE); /* cmdId */ + out_uint16_le(s, 0); /* flags = 0 */ + s_push_layer(s, iso_hdr, 4); /* pduLength, set later */ + out_uint16_le(s, surface_id); + out_uint16_le(s, width); + out_uint16_le(s, height); + out_uint8(s, pixel_format); + s_mark_end(s); + bytes = (int) ((s->end - s->iso_hdr) + 4); + s_pop_layer(s, iso_hdr); + out_uint32_le(s, bytes); + return s; +} + +/******************************************************************************/ +int +xrdp_egfx_send_create_surface(struct xrdp_egfx *egfx, int surface_id, + int width, int height, int pixel_format) +{ + int error; + struct stream *s; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_send_create_surface:"); + s = xrdp_egfx_create_surface(egfx->bulk, surface_id, width, height, + pixel_format); + error = xrdp_egfx_send_s(egfx, s); + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_create_surface: xrdp_egfx_send_s " + "error %d", error); + free_stream(s); + return error; +} + +/******************************************************************************/ +struct stream * +xrdp_egfx_delete_surface(struct xrdp_egfx_bulk *bulk, int surface_id) +{ + int bytes; + struct stream *s; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_delete_surface:"); + make_stream(s); + init_stream(s, 8192); + /* RDP_SEGMENTED_DATA */ + out_uint8(s, 0xE0); /* descriptor = SINGLE */ + /* RDP8_BULK_ENCODED_DATA */ + out_uint8(s, PACKET_COMPR_TYPE_RDP8); /* header */ + /* RDPGFX_HEADER */ + out_uint16_le(s, XR_RDPGFX_CMDID_DELETESURFACE); /* cmdId */ + out_uint16_le(s, 0); /* flags = 0 */ + s_push_layer(s, iso_hdr, 4); /* pduLength, set later */ + out_uint16_le(s, surface_id); + s_mark_end(s); + bytes = (int) ((s->end - s->iso_hdr) + 4); + s_pop_layer(s, iso_hdr); + out_uint32_le(s, bytes); + return s; +} + +/******************************************************************************/ +int +xrdp_egfx_send_delete_surface(struct xrdp_egfx *egfx, int surface_id) +{ + int error; + struct stream *s; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_send_delete_surface:"); + s = xrdp_egfx_delete_surface(egfx->bulk, surface_id); + error = xrdp_egfx_send_s(egfx, s); + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_delete_surface: xrdp_egfx_send_s " + "error %d", error); + free_stream(s); + return error; +} + +/******************************************************************************/ +struct stream * +xrdp_egfx_map_surface(struct xrdp_egfx_bulk *bulk, int surface_id, + int x, int y) +{ + int bytes; + struct stream *s; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_map_surface:"); + make_stream(s); + init_stream(s, 8192); + /* RDP_SEGMENTED_DATA */ + out_uint8(s, 0xE0); /* descriptor = SINGLE */ + /* RDP8_BULK_ENCODED_DATA */ + out_uint8(s, PACKET_COMPR_TYPE_RDP8); /* header */ + /* RDPGFX_HEADER */ + out_uint16_le(s, XR_RDPGFX_CMDID_MAPSURFACETOOUTPUT); /* cmdId */ + out_uint16_le(s, 0); /* flags = 0 */ + s_push_layer(s, iso_hdr, 4); /* pduLength, set later */ + out_uint16_le(s, surface_id); + out_uint16_le(s, 0); + out_uint32_le(s, x); + out_uint32_le(s, y); + s_mark_end(s); + bytes = (int) ((s->end - s->iso_hdr) + 4); + s_pop_layer(s, iso_hdr); + out_uint32_le(s, bytes); + return s; +} + +/******************************************************************************/ +int +xrdp_egfx_send_map_surface(struct xrdp_egfx *egfx, int surface_id, + int x, int y) +{ + int error; + struct stream *s; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_send_map_surface:"); + s = xrdp_egfx_map_surface(egfx->bulk, surface_id, x, y); + error = xrdp_egfx_send_s(egfx, s); + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_map_surface: xrdp_egfx_send_s " + "error %d", error); + free_stream(s); + return error; +} + +/******************************************************************************/ +struct stream * +xrdp_egfx_fill_surface(struct xrdp_egfx_bulk *bulk, int surface_id, + int fill_color, int num_rects, + const struct xrdp_egfx_rect *rects) +{ + int bytes; + int index; + struct stream *s; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_fill_surface:"); + make_stream(s); + init_stream(s, 1024 + num_rects * 8); + /* RDP_SEGMENTED_DATA */ + out_uint8(s, 0xE0); /* descriptor = SINGLE */ + /* RDP8_BULK_ENCODED_DATA */ + out_uint8(s, PACKET_COMPR_TYPE_RDP8); /* header */ + /* RDPGFX_HEADER */ + out_uint16_le(s, XR_RDPGFX_CMDID_SOLIDFILL); /* cmdId */ + out_uint16_le(s, 0); /* flags = 0 */ + s_push_layer(s, iso_hdr, 4); /* pduLength, set later */ + out_uint16_le(s, surface_id); + out_uint32_le(s, fill_color); + out_uint16_le(s, num_rects); + for (index = 0; index < num_rects; index++) + { + out_uint16_le(s, rects[index].x1); + out_uint16_le(s, rects[index].y1); + out_uint16_le(s, rects[index].x2); + out_uint16_le(s, rects[index].y2); + } + s_mark_end(s); + bytes = (int) ((s->end - s->iso_hdr) + 4); + s_pop_layer(s, iso_hdr); + out_uint32_le(s, bytes); + return s; +} + +/******************************************************************************/ +int +xrdp_egfx_send_fill_surface(struct xrdp_egfx *egfx, int surface_id, + int fill_color, int num_rects, + const struct xrdp_egfx_rect *rects) +{ + int error; + struct stream *s; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_send_fill_surface:"); + s = xrdp_egfx_fill_surface(egfx->bulk, surface_id, fill_color, + num_rects, rects); + error = xrdp_egfx_send_s(egfx, s); + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_fill_surface: xrdp_egfx_send_s " + "error %d", error); + free_stream(s); + return error; +} + +/******************************************************************************/ +struct stream * +xrdp_egfx_surface_to_surface(struct xrdp_egfx_bulk *bulk, int src_surface_id, + int dst_surface_id, + const struct xrdp_egfx_rect *src_rect, + int num_dst_points, + const struct xrdp_egfx_point *dst_points) +{ + int bytes; + int index; + struct stream *s; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_surface_to_surface:"); + make_stream(s); + init_stream(s, 1024 + num_dst_points * 4); + /* RDP_SEGMENTED_DATA */ + out_uint8(s, 0xE0); /* descriptor = SINGLE */ + /* RDP8_BULK_ENCODED_DATA */ + out_uint8(s, PACKET_COMPR_TYPE_RDP8); /* header */ + /* RDPGFX_HEADER */ + out_uint16_le(s, XR_RDPGFX_CMDID_SURFACETOSURFACE); /* cmdId */ + out_uint16_le(s, 0); /* flags = 0 */ + s_push_layer(s, iso_hdr, 4); /* pduLength, set later */ + out_uint16_le(s, src_surface_id); + out_uint16_le(s, dst_surface_id); + out_uint16_le(s, src_rect->x1); + out_uint16_le(s, src_rect->y1); + out_uint16_le(s, src_rect->x2); + out_uint16_le(s, src_rect->y2); + out_uint16_le(s, num_dst_points); + for (index = 0; index < num_dst_points; index++) + { + out_uint16_le(s, dst_points[index].x); + out_uint16_le(s, dst_points[index].y); + } + s_mark_end(s); + bytes = (int) ((s->end - s->iso_hdr) + 4); + s_pop_layer(s, iso_hdr); + out_uint32_le(s, bytes); + return s; +} + +/******************************************************************************/ +int +xrdp_egfx_send_surface_to_surface(struct xrdp_egfx *egfx, int src_surface_id, + int dst_surface_id, + const struct xrdp_egfx_rect *src_rect, + int num_dst_points, + const struct xrdp_egfx_point *dst_points) +{ + int error; + struct stream *s; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_send_surface_to_surface:"); + s = xrdp_egfx_surface_to_surface(egfx->bulk, src_surface_id, + dst_surface_id, src_rect, + num_dst_points, dst_points); + error = xrdp_egfx_send_s(egfx, s); + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_surface_to_surface: xrdp_egfx_send_s " + "error %d", error); + free_stream(s); + return error; +} + +/******************************************************************************/ +struct stream * +xrdp_egfx_frame_start(struct xrdp_egfx_bulk *bulk, int frame_id, int timestamp) +{ + int bytes; + struct stream *s; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_frame_start:"); + make_stream(s); + init_stream(s, 8192); + /* RDP_SEGMENTED_DATA */ + out_uint8(s, 0xE0); /* descriptor = SINGLE */ + /* RDP8_BULK_ENCODED_DATA */ + out_uint8(s, PACKET_COMPR_TYPE_RDP8); /* header */ + /* RDPGFX_HEADER */ + out_uint16_le(s, XR_RDPGFX_CMDID_STARTFRAME); /* cmdId */ + out_uint16_le(s, 0); /* flags = 0 */ + s_push_layer(s, iso_hdr, 4); /* pduLength, set later */ + out_uint32_le(s, timestamp); + out_uint32_le(s, frame_id); + s_mark_end(s); + bytes = (int) ((s->end - s->iso_hdr) + 4); + s_pop_layer(s, iso_hdr); + out_uint32_le(s, bytes); + return s; +} + +/******************************************************************************/ +int +xrdp_egfx_send_frame_start(struct xrdp_egfx *egfx, int frame_id, int timestamp) +{ + int error; + struct stream *s; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_send_frame_start:"); + s = xrdp_egfx_frame_start(egfx->bulk, frame_id, timestamp); + error = xrdp_egfx_send_s(egfx, s); + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_frame_start: xrdp_egfx_send_s " + "error %d", error); + free_stream(s); + return error; +} + +/******************************************************************************/ +struct stream * +xrdp_egfx_frame_end(struct xrdp_egfx_bulk *bulk, int frame_id) +{ + int bytes; + struct stream *s; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_frame_end:"); + make_stream(s); + init_stream(s, 8192); + /* RDP_SEGMENTED_DATA */ + out_uint8(s, 0xE0); /* descriptor = SINGLE */ + /* RDP8_BULK_ENCODED_DATA */ + out_uint8(s, PACKET_COMPR_TYPE_RDP8); /* header */ + /* RDPGFX_HEADER */ + out_uint16_le(s, XR_RDPGFX_CMDID_ENDFRAME); /* cmdId */ + out_uint16_le(s, 0); /* flags = 0 */ + s_push_layer(s, iso_hdr, 4); /* pduLength, set later */ + out_uint32_le(s, frame_id); + s_mark_end(s); + bytes = (int) ((s->end - s->iso_hdr) + 4); + s_pop_layer(s, iso_hdr); + out_uint32_le(s, bytes); + return s; +} + +/******************************************************************************/ +int +xrdp_egfx_send_frame_end(struct xrdp_egfx *egfx, int frame_id) +{ + int error; + struct stream *s; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_send_frame_end:"); + s = xrdp_egfx_frame_end(egfx->bulk, frame_id); + error = xrdp_egfx_send_s(egfx, s); + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_frame_end: xrdp_egfx_send_s " + "error %d", error); + free_stream(s); + return error; +} + +/******************************************************************************/ +struct stream * +xrdp_egfx_capsconfirm(struct xrdp_egfx_bulk *bulk, int version, int flags) +{ + int bytes; + struct stream *s; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_capsconfirm:"); + make_stream(s); + init_stream(s, 8192); + /* RDP_SEGMENTED_DATA */ + out_uint8(s, 0xE0); /* descriptor = SINGLE */ + /* RDP8_BULK_ENCODED_DATA */ + out_uint8(s, PACKET_COMPR_TYPE_RDP8); /* header */ + /* RDPGFX_HEADER */ + out_uint16_le(s, XR_RDPGFX_CMDID_CAPSCONFIRM); /* cmdId */ + out_uint16_le(s, 0); /* flags = 0 */ + s_push_layer(s, iso_hdr, 4); /* pduLength, set later */ + out_uint32_le(s, version); /* version */ + out_uint32_le(s, 4); /* capsDataLength */ + out_uint32_le(s, flags); + s_mark_end(s); + bytes = (int) ((s->end - s->iso_hdr) + 4); + s_pop_layer(s, iso_hdr); + out_uint32_le(s, bytes); + return s; +} + +/******************************************************************************/ +int +xrdp_egfx_send_capsconfirm(struct xrdp_egfx *egfx, int version, int flags) +{ + int error; + struct stream *s; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_send_capsconfirm:"); + s = xrdp_egfx_capsconfirm(egfx->bulk, version, flags); + error = xrdp_egfx_send_s(egfx, s); + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_capsconfirm: xrdp_egfx_send_s " + "error %d", error); + free_stream(s); + return error; +} + +/******************************************************************************/ +struct stream * +xrdp_egfx_wire_to_surface1(struct xrdp_egfx_bulk *bulk, int surface_id, + int codec_id, int pixel_format, + struct xrdp_egfx_rect *dest_rect, + void *bitmap_data, int bitmap_data_length) +{ + int bytes; + int index; + int segment_size; + int segment_count; + struct stream *s; + char *bitmap_data8; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_wire_to_surface1:"); + make_stream(s); + bytes = bitmap_data_length + 8192; + bytes += 5 * (bitmap_data_length / MAX_PART_SIZE); + init_stream(s, bytes); + /* RDP_SEGMENTED_DATA */ + out_uint8(s, 0xE1); /* descriptor = MULTIPART */ + s_push_layer(s, iso_hdr, 2); /* segmentCount, set later */ + out_uint32_le(s, 25 + bitmap_data_length); /* uncompressedSize */ + /* RDP_DATA_SEGMENT */ + out_uint32_le(s, 1 + 25); /* segmentArray size */ + /* RDP8_BULK_ENCODED_DATA */ + out_uint8(s, PACKET_COMPR_TYPE_RDP8); /* header */ + /* RDPGFX_HEADER */ + out_uint16_le(s, XR_RDPGFX_CMDID_WIRETOSURFACE_1); /* cmdId */ + out_uint16_le(s, 0); /* flags = 0 */ + out_uint32_le(s, 25 + bitmap_data_length); /* pduLength */ + out_uint16_le(s, surface_id); + out_uint16_le(s, codec_id); + out_uint8(s, pixel_format); + out_uint16_le(s, dest_rect->x1); + out_uint16_le(s, dest_rect->y1); + out_uint16_le(s, dest_rect->x2); + out_uint16_le(s, dest_rect->y2); + out_uint32_le(s, bitmap_data_length); + segment_count = 1; + index = 0; + bitmap_data8 = (char *) bitmap_data; + while (index < bitmap_data_length) + { + segment_size = bitmap_data_length - index; + if (segment_size > MAX_PART_SIZE) + { + segment_size = MAX_PART_SIZE; + } + /* RDP_DATA_SEGMENT */ + out_uint32_le(s, 1 + segment_size); /* segmentArray size */ + /* RDP8_BULK_ENCODED_DATA */ + out_uint8(s, PACKET_COMPR_TYPE_RDP8); /* header */ + out_uint8a(s, bitmap_data8 + index, segment_size); + LOG(LOG_LEVEL_DEBUG, " segment index %d" + " segment_size %d", segment_count, segment_size); + index += segment_size; + segment_count++; + } + s_mark_end(s); + s_pop_layer(s, iso_hdr); + out_uint16_le(s, segment_count); + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_wire_to_surface1: segment_count %d", + segment_count); + return s; +} + +/******************************************************************************/ +int +xrdp_egfx_send_wire_to_surface1(struct xrdp_egfx *egfx, int surface_id, + int codec_id, int pixel_format, + struct xrdp_egfx_rect *dest_rect, + void *bitmap_data, int bitmap_data_length) +{ + int error; + struct stream *s; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_send_wire_to_surface1:"); + s = xrdp_egfx_wire_to_surface1(egfx->bulk, surface_id, codec_id, + pixel_format, dest_rect, + bitmap_data, bitmap_data_length); + error = xrdp_egfx_send_s(egfx, s); + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_wire_to_surface1: xrdp_egfx_send_s " + "error %d", error); + free_stream(s); + return error; +} + +/******************************************************************************/ +struct stream * +xrdp_egfx_wire_to_surface2(struct xrdp_egfx_bulk *bulk, int surface_id, + int codec_id, int codec_context_id, + int pixel_format, + void *bitmap_data, int bitmap_data_length) +{ + int bytes; + int index; + int segment_size; + int segment_count; + struct stream *s; + char *bitmap_data8; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_wire_to_surface2:"); + make_stream(s); + bytes = bitmap_data_length + 8192; + bytes += 5 * (bitmap_data_length / MAX_PART_SIZE); + init_stream(s, bytes); + /* RDP_SEGMENTED_DATA */ + out_uint8(s, 0xE1); /* descriptor = MULTIPART */ + s_push_layer(s, iso_hdr, 2); /* segmentCount, set later */ + out_uint32_le(s, 21 + bitmap_data_length); /* uncompressedSize */ + /* RDP_DATA_SEGMENT */ + out_uint32_le(s, 1 + 21); /* segmentArray size */ + /* RDP8_BULK_ENCODED_DATA */ + out_uint8(s, PACKET_COMPR_TYPE_RDP8); /* header */ + /* RDPGFX_HEADER */ + out_uint16_le(s, XR_RDPGFX_CMDID_WIRETOSURFACE_2); /* cmdId */ + out_uint16_le(s, 0); /* flags = 0 */ + out_uint32_le(s, 21 + bitmap_data_length); /* pduLength */ + out_uint16_le(s, surface_id); + out_uint16_le(s, codec_id); + out_uint32_le(s, codec_context_id); + out_uint8(s, pixel_format); + out_uint32_le(s, bitmap_data_length); + segment_count = 1; + index = 0; + bitmap_data8 = (char *) bitmap_data; + while (index < bitmap_data_length) + { + segment_size = bitmap_data_length - index; + if (segment_size > MAX_PART_SIZE) + { + segment_size = MAX_PART_SIZE; + } + /* RDP_DATA_SEGMENT */ + out_uint32_le(s, 1 + segment_size); /* segmentArray size */ + /* RDP8_BULK_ENCODED_DATA */ + out_uint8(s, PACKET_COMPR_TYPE_RDP8); /* header */ + out_uint8a(s, bitmap_data8 + index, segment_size); + LOG(LOG_LEVEL_DEBUG, " segment index %d segment_size %d", + segment_count, segment_size); + index += segment_size; + segment_count++; + } + s_mark_end(s); + s_pop_layer(s, iso_hdr); + out_uint16_le(s, segment_count); + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_wire_to_surface2: segment_count %d", + segment_count); + return s; +} + +/******************************************************************************/ +int +xrdp_egfx_send_wire_to_surface2(struct xrdp_egfx *egfx, int surface_id, + int codec_id, int codec_context_id, + int pixel_format, + void *bitmap_data, int bitmap_data_length) +{ + int error; + struct stream *s; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_send_wire_to_surface2:"); + s = xrdp_egfx_wire_to_surface2(egfx->bulk, surface_id, codec_id, + codec_context_id, pixel_format, + bitmap_data, bitmap_data_length); + error = xrdp_egfx_send_s(egfx, s); + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_wire_to_surface2: xrdp_egfx_send_s " + "error %d", error); + free_stream(s); + return error; +} + +/******************************************************************************/ +struct stream * +xrdp_egfx_reset_graphics(struct xrdp_egfx_bulk *bulk, int width, int height, + int monitor_count, struct monitor_info *mi) +{ + int bytes; + int index; + struct stream *s; + + LOG(LOG_LEVEL_INFO, "xrdp_egfx_reset_graphics:"); + if (monitor_count > 16) + { + return NULL; + } + make_stream(s); + /* this should always be enough because limited to 16 monitors + and message is always 340 bytes */ + init_stream(s, 8192); + /* RDP_SEGMENTED_DATA */ + out_uint8(s, 0xE0); /* descriptor = SINGLE */ + /* RDP8_BULK_ENCODED_DATA */ + out_uint8(s, PACKET_COMPR_TYPE_RDP8); /* header */ + /* RDPGFX_HEADER */ + out_uint16_le(s, XR_RDPGFX_CMDID_RESETGRAPHICS); /* cmdId */ + out_uint16_le(s, 0); /* flags = 0 */ + out_uint32_le(s, 340); /* pduLength */ + out_uint32_le(s, width); + out_uint32_le(s, height); + /* + TODO: Fix hack where working around 0 monitors is necessary. + + In cases where multi-mon is not used for XRDP, internally 0 monitors + are represented, even though we implicitly have one: The entire session! + + Some Microsoft clients (Mainly the Mac OS one) require that at least + one monitor be transmitted for EGFX to function, which is why this + change was necessary. + + See https://github.com/neutrinolabs/xrdp/pull/2338#discussion_r944685856 + https://github.com/neutrinolabs/xrdp/issues/2503 + */ + out_uint32_le(s, monitor_count == 0 ? 1 : monitor_count); + if (monitor_count == 0) + { + out_uint32_le(s, 0); + out_uint32_le(s, 0); + out_uint32_le(s, width - 1); + out_uint32_le(s, height - 1); + out_uint32_le(s, 1); + monitor_count = 1; + } + else + { + for (index = 0; index < monitor_count; ++index) + { + out_uint32_le(s, mi[index].left); + out_uint32_le(s, mi[index].top); + out_uint32_le(s, mi[index].right); + out_uint32_le(s, mi[index].bottom); + out_uint32_le(s, mi[index].is_primary); + LOG(LOG_LEVEL_INFO, "xrdp_egfx_reset_graphics: (index %d) " + "monitor left %d top %d right %d bottom %d is_primary %d", + index, mi[index].left, mi[index].top, + mi[index].right, mi[index].bottom, + mi[index].is_primary); + } + } + LOG(LOG_LEVEL_INFO, "xrdp_egfx_send_reset_graphics:" + " width %d height %d monitorcount %d", + width, height, monitor_count); + if (monitor_count < 16) + { + bytes = 340 - (20 + (monitor_count * 20)); + out_uint8s(s, bytes); + } + s_mark_end(s); + return s; +} + +/******************************************************************************/ +int +xrdp_egfx_send_reset_graphics(struct xrdp_egfx *egfx, int width, int height, + int monitor_count, struct monitor_info *mi) +{ + int error; + struct stream *s; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_send_reset_graphics:"); + s = xrdp_egfx_reset_graphics(egfx->bulk, width, height, monitor_count, mi); + error = xrdp_egfx_send_s(egfx, s); + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_reset_graphics: xrdp_egfx_send_s " + "error %d", error); + free_stream(s); + return error; +} + +/******************************************************************************/ +/* RDPGFX_CMDID_FRAMEACKNOWLEDGE */ +static int +xrdp_egfx_process_frame_ack(struct xrdp_egfx *egfx, struct stream *s) +{ + uint32_t queueDepth; + uint32_t intframeId; + uint32_t totalFramesDecoded; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_process_frame_ack:"); + if (!s_check_rem(s, 12)) + { + return 1; + } + in_uint32_le(s, queueDepth); + in_uint32_le(s, intframeId); + in_uint32_le(s, totalFramesDecoded); + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_process_frame_ack: queueDepth %d" + " intframeId %d totalFramesDecoded %d", + queueDepth, intframeId, totalFramesDecoded); + if (egfx->frame_ack != NULL) + { + egfx->frame_ack(egfx->user, queueDepth, intframeId, totalFramesDecoded); + } + return 0; +} + +/******************************************************************************/ +/* RDPGFX_CMDID_CAPSADVERTISE */ +static int +xrdp_egfx_process_capsadvertise(struct xrdp_egfx *egfx, struct stream *s) +{ + int index; + int capsSetCount; + int caps_count; + int version; + int capsDataLength; + int flags; + char *holdp; + int *versions; + int *flagss; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_process_capsadvertise:"); + if (egfx->caps_advertise == NULL) + { + return 0; + } + in_uint16_le(s, capsSetCount); + if ((capsSetCount < 1) || (capsSetCount > 1024)) + { + return 1; + } + caps_count = 0; + versions = g_new(int, capsSetCount); + if (versions == NULL) + { + return 1; + } + flagss = g_new(int, capsSetCount); + if (flagss == NULL) + { + g_free(versions); + return 1; + } + for (index = 0; index < capsSetCount; index++) + { + if (!s_check_rem(s, 8)) + { + return 1; + } + in_uint32_le(s, version); + in_uint32_le(s, capsDataLength); + if (!s_check_rem(s, capsDataLength)) + { + return 1; + } + holdp = s->p; + // This implicity excludes caps version 101. + if (capsDataLength == 4) + { + in_uint32_le(s, flags); + versions[caps_count] = version; + flagss[caps_count] = flags; + caps_count++; + } + s->p = holdp + capsDataLength; + } + if (caps_count > 0) + { + egfx->caps_advertise(egfx->user, caps_count, versions, flagss); + } + g_free(versions); + g_free(flagss); + return 0; +} + +/******************************************************************************/ +static int +xrdp_egfx_process(struct xrdp_egfx *egfx, struct stream *s) +{ + int error; + int cmdId; + int flags; + int pduLength; + char *holdp; + char *holdend; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_process:"); + error = 0; + while (s_check_rem(s, 8)) + { + holdp = s->p; + holdend = s->end; + in_uint16_le(s, cmdId); + in_uint16_le(s, flags); + in_uint32_le(s, pduLength); + s->end = holdp + pduLength; + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_process: cmdId 0x%x flags %d" + " pduLength %d", cmdId, flags, pduLength); + if (pduLength < 8) + { + return 1; + } + if (!s_check_rem(s, pduLength - 8)) + { + return 1; + } + switch (cmdId) + { + case XR_RDPGFX_CMDID_FRAMEACKNOWLEDGE: + error = xrdp_egfx_process_frame_ack(egfx, s); + break; + case XR_RDPGFX_CMDID_CAPSADVERTISE: + error = xrdp_egfx_process_capsadvertise(egfx, s); + break; + case XR_RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE: + break; + /* + TODO: Handle Cache Import PDU here. + https://github.com/neutrinolabs/xrdp/issues/2502 + case XR_RDPGFX_CMDID_CACHEIMPORTOFFER: + 2.2.2.16 RDPGFX_CACHE_IMPORT_OFFER_PDU + Reply with + 2.2.2.17 RDPGFX_CACHE_IMPORT_REPLY_PDU + */ + default: + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_process:" + " unknown cmdId 0x%x", cmdId); + //g_hexdump(s->p, MIN(pduLength - 8, 64)); + break; + } + if (error != 0) + { + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_process: error %d", error); + return error; + } + s->p = holdp + pduLength; + s->end = holdend; + } + return error; +} + +/******************************************************************************/ +/* from client */ +static int +xrdp_egfx_open_response(intptr_t id, int chan_id, int creation_status) +{ + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_open_response:"); + return 0; +} + +int +advance_resize_state_machine(struct xrdp_mm *mm, + enum display_resize_state new_state); + +/******************************************************************************/ +/* from client */ +static int +xrdp_egfx_close_response(intptr_t id, int chan_id) +{ + struct xrdp_process *process; + struct xrdp_mm *mm; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_close_response:"); + + process = (struct xrdp_process *) id; + mm = process->wm->mm; + + if (mm->resize_queue == 0 || mm->resize_queue->count <= 0) + { + return 0; + } + if (mm->resize_data != NULL + && mm->resize_data->state == WMRZ_EGFX_CONN_CLOSING) + { + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_close_response: egfx deleted."); + advance_resize_state_machine(mm, WMRZ_EGFX_CONN_CLOSED); + } + return 0; +} + +/******************************************************************************/ +/* from client */ +static int +xrdp_egfx_data_first(intptr_t id, int chan_id, char *data, int bytes, + int total_bytes) +{ + struct xrdp_process *process; + struct xrdp_egfx *egfx; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_data_first: bytes %d" + " total_bytes %d", bytes, total_bytes); + process = (struct xrdp_process *) id; + egfx = process->wm->mm->egfx; + if (egfx->s != NULL) + { + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_data_first: Error!" + " Stream is not working on initial data received!"); + } + make_stream(egfx->s); + init_stream(egfx->s, total_bytes); + out_uint8a(egfx->s, data, bytes); + return 0; +} + +/******************************************************************************/ +/* from client */ +static int +xrdp_egfx_data(intptr_t id, int chan_id, char *data, int bytes) +{ + int error; + struct stream ls; + struct xrdp_process *process; + struct xrdp_wm *wm; + struct xrdp_mm *mm; + struct xrdp_egfx *egfx; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_data:"); + + process = (struct xrdp_process *) id; + if (process == NULL) + { + return 0; + } + + wm = process->wm; + if (wm == NULL) + { + return 0; + } + + mm = wm->mm; + if (mm == NULL) + { + return 0; + } + + egfx = mm->egfx; + if (egfx == NULL) + { + return 0; + } + + if (egfx->s == NULL) + { + g_memset(&ls, 0, sizeof(ls)); + ls.data = data; + ls.size = bytes; + ls.p = data; + ls.end = data + bytes; + return xrdp_egfx_process(egfx, &ls); + } + if (!s_check_rem_out(egfx->s, bytes)) + { + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_data: error"); + return 1; + } + out_uint8a(egfx->s, data, bytes); + if (!s_check_rem_out(egfx->s, 1)) + { + s_mark_end(egfx->s); + egfx->s->p = egfx->s->data; + error = xrdp_egfx_process(egfx, egfx->s); + free_stream(egfx->s); + egfx->s = NULL; + return error; + } + return 0; +} + +/******************************************************************************/ +int +xrdp_egfx_create(struct xrdp_mm *mm, struct xrdp_egfx **egfx) +{ + int error; + struct xrdp_drdynvc_procs procs; + struct xrdp_egfx *self; + struct xrdp_process *process; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_create:"); + + self = g_new0(struct xrdp_egfx, 1); + if (self == NULL) + { + return 1; + } + procs.open_response = xrdp_egfx_open_response; + procs.close_response = xrdp_egfx_close_response; + procs.data_first = xrdp_egfx_data_first; + procs.data = xrdp_egfx_data; + process = mm->wm->pro_layer; + error = libxrdp_drdynvc_open(process->session, + "Microsoft::Windows::RDS::Graphics", + 1, /* WTS_CHANNEL_OPTION_DYNAMIC */ + &procs, &(self->channel_id)); + LOG(LOG_LEVEL_INFO, "xrdp_egfx_create: error %d channel_id %d", + error, self->channel_id); + self->session = process->session; + self->surface_id = 0; + *egfx = self; + return 0; +} + +/******************************************************************************/ +int +xrdp_egfx_shutdown_delete_surface(struct xrdp_egfx *egfx) +{ + int error; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_shutdown_delete_surface:"); + + if (egfx == 0) + { + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_shutdown_delete_surface:" + " EGFX is already null!"); + return 0; + } + + error = xrdp_egfx_send_delete_surface(egfx, egfx->surface_id); + if (error != 0) + { + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_shutdown_delete_surface:" + " xrdp_egfx_send_delete_surface failed %d", error); + } + return error; +} + +/******************************************************************************/ +int +xrdp_egfx_shutdown_close_connection(struct xrdp_egfx *egfx) +{ + int error; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_shutdown_close_connection:"); + + if (egfx == 0) + { + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_shutdown_close_connection:" + " EGFX is already null!"); + return 0; + } + + error = libxrdp_drdynvc_close(egfx->session, egfx->channel_id); + if (error != 0) + { + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_shutdown_close_connection:" + " libxrdp_drdynvc_close failed %d", error); + return error; + } + + return error; +} + +/******************************************************************************/ +int +xrdp_egfx_shutdown_delete(struct xrdp_egfx *egfx) +{ + int error = 0; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_delete:"); + + if (egfx == 0) + { + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_delete: EGFX is already null!"); + return 0; + } + + g_free(egfx); + + return error; +} + +/******************************************************************************/ +int +xrdp_egfx_shutdown_full(struct xrdp_egfx *egfx) +{ + int error; + + LOG(LOG_LEVEL_TRACE, "xrdp_egfx_shutdown_full:"); + + if (egfx == 0) + { + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_shutdown_full: EGFX is already null!"); + return 0; + } + + error = xrdp_egfx_shutdown_delete_surface(egfx); + if (error != 0) + { + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_shutdown_full:" + " xrdp_egfx_shutdown_delete_surface failed %d", error); + return error; + } + + error = xrdp_egfx_shutdown_close_connection(egfx); + if (error != 0) + { + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_shutdown_full:" + " xrdp_egfx_shutdown_close_connection failed %d", error); + return error; + } + + error = xrdp_egfx_shutdown_delete(egfx); + if (error != 0) + { + LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_shutdown_full:" + " xrdp_egfx_shutdown_delete failed %d", error); + return error; + } + + return error; +} diff --git a/xrdp/xrdp_egfx.h b/xrdp/xrdp_egfx.h new file mode 100644 index 00000000..bc61f600 --- /dev/null +++ b/xrdp/xrdp_egfx.h @@ -0,0 +1,222 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2019 + * + * 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. + * + * MS-RDPEGFX + */ + +#ifndef _XRDP_EGFX_H +#define _XRDP_EGFX_H + +#define XR_RDPGFX_CAPVERSION_8 0x00080004 +#define XR_RDPGFX_CAPVERSION_81 0x00080105 +#define XR_RDPGFX_CAPVERSION_10 0x000A0002 +#define XR_RDPGFX_CAPVERSION_101 0x000A0100 +#define XR_RDPGFX_CAPVERSION_102 0x000A0200 +#define XR_RDPGFX_CAPVERSION_103 0x000A0301 +#define XR_RDPGFX_CAPVERSION_104 0x000A0400 +#define XR_RDPGFX_CAPVERSION_105 0x000A0502 +#define XR_RDPGFX_CAPVERSION_106 0x000A0600 +#define XR_RDPGFX_CAPVERSION_107 0x000A0701 + +#define XR_PIXEL_FORMAT_XRGB_8888 0x20 +#define XR_PIXEL_FORMAT_ARGB_8888 0x21 + +#define XR_RDPGFX_CAPS_FLAG_THINCLIENT 0x00000001 +#define XR_RDPGFX_CAPS_FLAG_SMALL_CACHE 0x00000002 +#define XR_RDPGFX_CAPS_FLAG_AVC420_ENABLED 0x00000010 +#define XR_RDPGFX_CAPS_FLAG_AVC_DISABLED 0x00000020 +#define XR_RDPGFX_CAPS_FLAG_AVC_THINCLIENT 0x00000040 + +#define XR_RDPGFX_CMDID_WIRETOSURFACE_1 0x0001 +#define XR_RDPGFX_CMDID_WIRETOSURFACE_2 0x0002 +#define XR_RDPGFX_CMDID_DELETEENCODINGCONTEXT 0x0003 +#define XR_RDPGFX_CMDID_SOLIDFILL 0x0004 +#define XR_RDPGFX_CMDID_SURFACETOSURFACE 0x0005 +#define XR_RDPGFX_CMDID_SURFACETOCACHE 0x0006 +#define XR_RDPGFX_CMDID_CACHETOSURFACE 0x0007 +#define XR_RDPGFX_CMDID_EVICTCACHEENTRY 0x0008 +#define XR_RDPGFX_CMDID_CREATESURFACE 0x0009 +#define XR_RDPGFX_CMDID_DELETESURFACE 0x000A +#define XR_RDPGFX_CMDID_STARTFRAME 0x000B +#define XR_RDPGFX_CMDID_ENDFRAME 0x000C +#define XR_RDPGFX_CMDID_FRAMEACKNOWLEDGE 0x000D +#define XR_RDPGFX_CMDID_RESETGRAPHICS 0x000E +#define XR_RDPGFX_CMDID_MAPSURFACETOOUTPUT 0x000F +#define XR_RDPGFX_CMDID_CACHEIMPORTOFFER 0x0010 +#define XR_RDPGFX_CMDID_CACHEIMPORTREPLY 0x0011 +#define XR_RDPGFX_CMDID_CAPSADVERTISE 0x0012 +#define XR_RDPGFX_CMDID_CAPSCONFIRM 0x0013 +#define XR_RDPGFX_CMDID_MAPSURFACETOWINDOW 0x0015 +#define XR_RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE 0x0016 +#define XR_RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT 0x0017 +#define XR_RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW 0x0018 + +#define XR_QUEUE_DEPTH_UNAVAILABLE 0x00000000 +#define XR_SUSPEND_FRAME_ACKNOWLEDGEMENT 0xFFFFFFFF + +/* The bitmap data encapsulated in the bitmapData field is uncompressed. + Pixels in the uncompressed data are ordered from left to right and then + top to bottom. */ +#define XR_RDPGFX_CODECID_UNCOMPRESSED 0x0000 +/* The bitmap data encapsulated in the bitmapData field is compressed using + the RemoteFX Codec ([MS-RDPRFX] sections 2.2.1 and 3.1.8). Note that the + TS_RFX_RECT ([MS-RDPRFX] section 2.2.2.1.6) structures encapsulated in + the bitmapData field MUST all be relative to the top-left corner of the + rectangle defined by the destRect field. */ +#define XR_RDPGFX_CODECID_CAVIDEO 0x0003 +/* The bitmap data encapsulated in the bitmapData field is compressed using + the ClearCodec Codec (sections 2.2.4.1 and 3.3.8.1). */ +#define XR_RDPGFX_CODECID_CLEARCODEC 0x0008 +/* The bitmap data encapsulated in the bitmapData field is compressed using + the Planar Codec ([MS-RDPEGDI] sections 2.2.2.5.1 and 3.1.9). */ +#define XR_RDPGFX_CODECID_PLANAR 0x000A +/* The bitmap data encapsulated in the bitmapData field is compressed using + the MPEG-4 AVC/H.264 Codec in YUV420p mode (section 2.2.4.4). */ +#define XR_RDPGFX_CODECID_AVC420 0x000B +/* The bitmap data encapsulated in the bitmapData field is compressed using + the Alpha Codec (section 2.2.4.3). */ +#define XR_RDPGFX_CODECID_ALPHA 0x000C +/* The bitmap data encapsulated in the bitmapData field is compressed using + the MPEG-4 AVC/H.264 Codec in YUV444 mode (section 2.2.4.5). */ +#define XR_RDPGFX_CODECID_AVC444 0x000E +/* The bitmap data encapsulated in the bitmapData field is compressed using + the MPEG-4 AVC/H.264 Codec in YUV444v2 mode (section 2.2.4.6). */ +#define XR_RDPGFX_CODECID_AVC444V2 0x000F + +struct xrdp_egfx_rect +{ + short x1; + short y1; + short x2; + short y2; +}; + +struct xrdp_egfx_point +{ + short x; + short y; +}; + +struct xrdp_egfx +{ + struct xrdp_session *session; + int channel_id; + int surface_id; + int frame_id; + struct stream *s; + void *user; + struct xrdp_egfx_bulk *bulk; + int (*caps_advertise)(void *user, int num_caps, int *version, int *flags); + int (*frame_ack)(void *user, uint32_t queue_depth, + int frame_id, int frames_decoded); +}; + +struct xrdp_egfx_bulk +{ + int id; +}; + +int +xrdp_egfx_send_data(struct xrdp_egfx *egfx, const char *data, int bytes); +int +xrdp_egfx_send_s(struct xrdp_egfx *egfx, struct stream *s); +int +xrdp_egfx_create(struct xrdp_mm *mm, struct xrdp_egfx **egfx); +int +xrdp_egfx_shutdown_delete_surface(struct xrdp_egfx *egfx); +int +xrdp_egfx_shutdown_close_connection(struct xrdp_egfx *egfx); +int +xrdp_egfx_shutdown_delete(struct xrdp_egfx *egfx); +int +xrdp_egfx_shutdown_full(struct xrdp_egfx *egfx); +struct stream * +xrdp_egfx_create_surface(struct xrdp_egfx_bulk *bulk, int surface_id, + int width, int height, int pixel_format); +int +xrdp_egfx_send_create_surface(struct xrdp_egfx *egfx, int surface_id, + int width, int height, int pixel_format); +struct stream * +xrdp_egfx_delete_surface(struct xrdp_egfx_bulk *bulk, int surface_id); +int +xrdp_egfx_send_delete_surface(struct xrdp_egfx *egfx, int surface_id); +struct stream * +xrdp_egfx_map_surface(struct xrdp_egfx_bulk *bulk, int surface_id, + int x, int y); +int +xrdp_egfx_send_map_surface(struct xrdp_egfx *egfx, int surface_id, + int x, int y); +struct stream * +xrdp_egfx_fill_surface(struct xrdp_egfx_bulk *bulk, int surface_id, + int fill_color, int num_rects, + const struct xrdp_egfx_rect *rects); +int +xrdp_egfx_send_fill_surface(struct xrdp_egfx *egfx, int surface_id, + int fill_color, int num_rects, + const struct xrdp_egfx_rect *rects); +struct stream * +xrdp_egfx_surface_to_surface(struct xrdp_egfx_bulk *bulk, int src_surface_id, + int dst_surface_id, + const struct xrdp_egfx_rect *src_rect, + int num_dst_points, + const struct xrdp_egfx_point *dst_points); +int +xrdp_egfx_send_surface_to_surface(struct xrdp_egfx *egfx, int src_surface_id, + int dst_surface_id, + const struct xrdp_egfx_rect *src_rect, + int num_dst_points, + const struct xrdp_egfx_point *dst_points); +struct stream * +xrdp_egfx_frame_start(struct xrdp_egfx_bulk *bulk, int frame_id, int timestamp); +int +xrdp_egfx_send_frame_start(struct xrdp_egfx *egfx, int frame_id, int timestamp); +struct stream * +xrdp_egfx_frame_end(struct xrdp_egfx_bulk *bulk, int frame_id); +int +xrdp_egfx_send_frame_end(struct xrdp_egfx *egfx, int frame_id); +struct stream * +xrdp_egfx_capsconfirm(struct xrdp_egfx_bulk *bulk, int version, int flags); +int +xrdp_egfx_send_capsconfirm(struct xrdp_egfx *egfx, int version, int flags); +struct stream * +xrdp_egfx_wire_to_surface1(struct xrdp_egfx_bulk *bulk, int surface_id, + int codec_id, int pixel_format, + struct xrdp_egfx_rect *dest_rect, + void *bitmap_data, int bitmap_data_length); +int +xrdp_egfx_send_wire_to_surface1(struct xrdp_egfx *egfx, int surface_id, + int codec_id, int pixel_format, + struct xrdp_egfx_rect *dest_rect, + void *bitmap_data, int bitmap_data_length); +struct stream * +xrdp_egfx_wire_to_surface2(struct xrdp_egfx_bulk *bulk, int surface_id, + int codec_id, int codec_context_id, + int pixel_format, + void *bitmap_data, int bitmap_data_length); +int +xrdp_egfx_send_wire_to_surface2(struct xrdp_egfx *egfx, int surface_id, + int codec_id, int codec_context_id, + int pixel_format, + void *bitmap_data, int bitmap_data_length); +struct stream * +xrdp_egfx_reset_graphics(struct xrdp_egfx_bulk *bulk, int width, int height, + int monitor_count, struct monitor_info *mi); +int +xrdp_egfx_send_reset_graphics(struct xrdp_egfx *egfx, int width, int height, + int monitor_count, struct monitor_info *mi); + +#endif diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index d253543e..3cc19232 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -322,9 +322,17 @@ enum mm_connect_state enum display_resize_state { WMRZ_ENCODER_DELETE = 0, + WMRZ_EGFX_DELETE_SURFACE, + WMRZ_EGFX_CONN_CLOSE, + WMRZ_EGFX_CONN_CLOSING, + WMRZ_EGFX_CONN_CLOSED, + WRMZ_EGFX_DELETE, WMRZ_SERVER_MONITOR_RESIZE, WMRZ_SERVER_VERSION_MESSAGE, WMRZ_XRDP_CORE_RESIZE, + WMRZ_EGFX_INITIALIZE, + WMRZ_EGFX_INITALIZING, + WMRZ_EGFX_INITIALIZED, WMRZ_ENCODER_CREATE, WMRZ_SERVER_INVALIDATE, WMRZ_COMPLETE, @@ -333,9 +341,17 @@ enum display_resize_state #define XRDP_DISPLAY_RESIZE_STATE_TO_STR(status) \ ((status) == WMRZ_ENCODER_DELETE ? "WMRZ_ENCODER_DELETE" : \ + (status) == WMRZ_EGFX_DELETE_SURFACE ? "WMRZ_EGFX_DELETE_SURFACE" : \ + (status) == WMRZ_EGFX_CONN_CLOSE ? "WMRZ_EGFX_CONN_CLOSE" : \ + (status) == WMRZ_EGFX_CONN_CLOSING ? "WMRZ_EGFX_CONN_CLOSING" : \ + (status) == WMRZ_EGFX_CONN_CLOSED ? "WMRZ_EGFX_CONN_CLOSED" : \ + (status) == WRMZ_EGFX_DELETE ? "WMRZ_EGFX_DELETE" : \ (status) == WMRZ_SERVER_MONITOR_RESIZE ? "WMRZ_SERVER_MONITOR_RESIZE" : \ (status) == WMRZ_SERVER_VERSION_MESSAGE ? "WMRZ_SERVER_VERSION_MESSAGE" : \ (status) == WMRZ_XRDP_CORE_RESIZE ? "WMRZ_XRDP_CORE_RESIZE" : \ + (status) == WMRZ_EGFX_INITIALIZE ? "WMRZ_EGFX_INITIALIZE" : \ + (status) == WMRZ_EGFX_INITALIZING ? "WMRZ_EGFX_INITALIZING" : \ + (status) == WMRZ_EGFX_INITIALIZED ? "WMRZ_EGFX_INITIALIZED" : \ (status) == WMRZ_ENCODER_CREATE ? "WMRZ_ENCODER_CREATE" : \ (status) == WMRZ_SERVER_INVALIDATE ? "WMRZ_SERVER_INVALIDATE" : \ (status) == WMRZ_COMPLETE ? "WMRZ_COMPLETE" : \ @@ -374,6 +390,7 @@ struct xrdp_mm int cs2xr_cid_map[256]; int xr2cr_cid_map[256]; int dynamic_monitor_chanid; + struct xrdp_egfx *egfx; /* Resize on-the-fly control */ struct display_control_monitor_layout_data *resize_data;