Make RDP backend supports arbitrary modes

This patch removes the extra modes parameter for the RDP compositor. And
make it support any mode that is requested (be aware that RDP client may not
support all possible modes, especially odd resolution).

This new version fixes remarks done by Jason Ekstrand. It also fixes
some missing spaces between if and (.
dev
Hardening 11 years ago committed by Kristian Høgsberg
parent 842a36ae4a
commit fb24eaac03
  1. 161
      src/compositor-rdp.c
  2. 1
      src/compositor.c

@ -49,6 +49,7 @@
#define MAX_FREERDP_FDS 32 #define MAX_FREERDP_FDS 32
#define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int(10) #define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int(10)
#define RDP_MODE_FREQ 60 * 1000
struct rdp_compositor_config { struct rdp_compositor_config {
int width; int width;
@ -58,7 +59,6 @@ struct rdp_compositor_config {
char *rdp_key; char *rdp_key;
char *server_cert; char *server_cert;
char *server_key; char *server_key;
char *extra_modes;
int env_socket; int env_socket;
}; };
@ -121,7 +121,6 @@ rdp_compositor_config_init(struct rdp_compositor_config *config) {
config->rdp_key = NULL; config->rdp_key = NULL;
config->server_cert = NULL; config->server_cert = NULL;
config->server_key = NULL; config->server_key = NULL;
config->extra_modes = NULL;
config->env_socket = 0; config->env_socket = 0;
} }
@ -320,11 +319,13 @@ rdp_output_repaint(struct weston_output *output_base, pixman_region32_t *damage)
pixman_renderer_output_set_buffer(output_base, output->shadow_surface); pixman_renderer_output_set_buffer(output_base, output->shadow_surface);
ec->renderer->repaint_output(&output->base, damage); ec->renderer->repaint_output(&output->base, damage);
wl_list_for_each(outputPeer, &output->peers, link) { if (pixman_region32_not_empty(damage)) {
if ((outputPeer->flags & RDP_PEER_ACTIVATED) && wl_list_for_each(outputPeer, &output->peers, link) {
(outputPeer->flags & RDP_PEER_OUTPUT_ENABLED)) if ((outputPeer->flags & RDP_PEER_ACTIVATED) &&
{ (outputPeer->flags & RDP_PEER_OUTPUT_ENABLED))
rdp_peer_refresh_region(damage, outputPeer->peer); {
rdp_peer_refresh_region(damage, outputPeer->peer);
}
} }
} }
@ -352,16 +353,29 @@ finish_frame_handler(void *data)
return 1; return 1;
} }
static struct weston_mode *
rdp_insert_new_mode(struct weston_output *output, int width, int height, int rate) {
struct weston_mode *ret;
ret = zalloc(sizeof *ret);
if (!ret)
return NULL;
ret->width = width;
ret->height = height;
ret->refresh = rate;
wl_list_insert(&output->mode_list, &ret->link);
return ret;
}
static struct weston_mode * static struct weston_mode *
find_matching_mode(struct weston_output *output, struct weston_mode *target) { ensure_matching_mode(struct weston_output *output, struct weston_mode *target) {
struct weston_mode *local; struct weston_mode *local;
wl_list_for_each(local, &output->mode_list, link) { wl_list_for_each(local, &output->mode_list, link) {
if((local->width == target->width) && (local->height == target->height)) if ((local->width == target->width) && (local->height == target->height))
return local; return local;
} }
return 0;
return rdp_insert_new_mode(output, target->width, target->height, RDP_MODE_FREQ);
} }
static int static int
@ -372,13 +386,13 @@ rdp_switch_mode(struct weston_output *output, struct weston_mode *target_mode) {
pixman_image_t *new_shadow_buffer; pixman_image_t *new_shadow_buffer;
struct weston_mode *local_mode; struct weston_mode *local_mode;
local_mode = find_matching_mode(output, target_mode); local_mode = ensure_matching_mode(output, target_mode);
if(!local_mode) { if (!local_mode) {
weston_log("mode %dx%d not available\n", target_mode->width, target_mode->height); weston_log("mode %dx%d not available\n", target_mode->width, target_mode->height);
return -ENOENT; return -ENOENT;
} }
if(local_mode == output->current_mode) if (local_mode == output->current_mode)
return 0; return 0;
output->current_mode->flags &= ~WL_OUTPUT_MODE_CURRENT; output->current_mode->flags &= ~WL_OUTPUT_MODE_CURRENT;
@ -398,7 +412,10 @@ rdp_switch_mode(struct weston_output *output, struct weston_mode *target_mode) {
wl_list_for_each(rdpPeer, &rdpOutput->peers, link) { wl_list_for_each(rdpPeer, &rdpOutput->peers, link) {
settings = rdpPeer->peer->settings; settings = rdpPeer->peer->settings;
if(!settings->DesktopResize) { if (settings->DesktopWidth == target_mode->width && settings->DesktopHeight == target_mode->height)
continue;
if (!settings->DesktopResize) {
/* too bad this peer does not support desktop resize */ /* too bad this peer does not support desktop resize */
rdpPeer->peer->Close(rdpPeer->peer); rdpPeer->peer->Close(rdpPeer->peer);
} else { } else {
@ -411,49 +428,12 @@ rdp_switch_mode(struct weston_output *output, struct weston_mode *target_mode) {
} }
static int static int
parse_extra_modes(const char *modes_str, struct rdp_output *output) { rdp_compositor_create_output(struct rdp_compositor *c, int width, int height)
const char *startAt = modes_str;
const char *nextPos;
int w, h;
struct weston_mode *mode;
while(startAt && *startAt) {
nextPos = strchr(startAt, 'x');
if(!nextPos)
return -1;
w = strtoul(startAt, NULL, 0);
startAt = nextPos + 1;
if(!*startAt)
return -1;
h = strtoul(startAt, NULL, 0);
if(!w || (w > 3000) || !h || (h > 3000))
return -1;
mode = malloc(sizeof *mode);
if(!mode)
return -1;
mode->width = w;
mode->height = h;
mode->refresh = 5;
mode->flags = 0;
wl_list_insert(&output->base.mode_list, &mode->link);
startAt = strchr(startAt, ',');
if(startAt && *startAt == ',')
startAt++;
}
return 0;
}
static int
rdp_compositor_create_output(struct rdp_compositor *c, int width, int height,
const char *extraModes)
{ {
struct rdp_output *output; struct rdp_output *output;
struct wl_event_loop *loop; struct wl_event_loop *loop;
struct weston_mode *currentMode, *next; struct weston_mode *currentMode;
struct weston_mode initMode;
output = zalloc(sizeof *output); output = zalloc(sizeof *output);
if (output == NULL) if (output == NULL)
@ -462,19 +442,14 @@ rdp_compositor_create_output(struct rdp_compositor *c, int width, int height,
wl_list_init(&output->peers); wl_list_init(&output->peers);
wl_list_init(&output->base.mode_list); wl_list_init(&output->base.mode_list);
currentMode = malloc(sizeof *currentMode); initMode.flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
if(!currentMode) initMode.width = width;
initMode.height = height;
initMode.refresh = RDP_MODE_FREQ;
currentMode = ensure_matching_mode(&output->base, &initMode);
if (!currentMode)
goto out_free_output; goto out_free_output;
currentMode->flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
currentMode->width = width;
currentMode->height = height;
currentMode->refresh = 5;
wl_list_insert(&output->base.mode_list, &currentMode->link);
if(parse_extra_modes(extraModes, output) < 0) {
weston_log("invalid extra modes\n");
goto out_free_output_and_modes;
}
output->base.current_mode = output->base.native_mode = currentMode; output->base.current_mode = output->base.native_mode = currentMode;
weston_output_init(&output->base, &c->base, 0, 0, width, height, weston_output_init(&output->base, &c->base, 0, 0, width, height,
@ -513,9 +488,6 @@ out_shadow_surface:
pixman_image_unref(output->shadow_surface); pixman_image_unref(output->shadow_surface);
out_output: out_output:
weston_output_destroy(&output->base); weston_output_destroy(&output->base);
out_free_output_and_modes:
wl_list_for_each_safe(currentMode, next, &output->base.mode_list, link)
free(currentMode);
out_free_output: out_free_output:
free(output); free(output);
return -1; return -1;
@ -599,7 +571,7 @@ static void
rdp_peer_context_free(freerdp_peer* client, RdpPeerContext* context) rdp_peer_context_free(freerdp_peer* client, RdpPeerContext* context)
{ {
int i; int i;
if(!context) if (!context)
return; return;
wl_list_remove(&context->item.link); wl_list_remove(&context->item.link);
@ -608,7 +580,7 @@ rdp_peer_context_free(freerdp_peer* client, RdpPeerContext* context)
wl_event_source_remove(context->events[i]); wl_event_source_remove(context->events[i]);
} }
if(context->item.flags & RDP_PEER_ACTIVATED) { if (context->item.flags & RDP_PEER_ACTIVATED) {
weston_seat_release_keyboard(&context->item.seat); weston_seat_release_keyboard(&context->item.seat);
weston_seat_release_pointer(&context->item.seat); weston_seat_release_pointer(&context->item.seat);
weston_seat_release(&context->item.seat); weston_seat_release(&context->item.seat);
@ -704,7 +676,7 @@ xf_peer_post_connect(freerdp_peer* client)
struct weston_mode *target_mode; struct weston_mode *target_mode;
new_mode.width = (int)settings->DesktopWidth; new_mode.width = (int)settings->DesktopWidth;
new_mode.height = (int)settings->DesktopHeight; new_mode.height = (int)settings->DesktopHeight;
target_mode = find_matching_mode(&output->base, &new_mode); target_mode = ensure_matching_mode(&output->base, &new_mode);
if (!target_mode) { if (!target_mode) {
weston_log("client mode not found\n"); weston_log("client mode not found\n");
return FALSE; return FALSE;
@ -719,19 +691,19 @@ xf_peer_post_connect(freerdp_peer* client)
settings->KeyboardFunctionKey); settings->KeyboardFunctionKey);
memset(&xkbRuleNames, 0, sizeof(xkbRuleNames)); memset(&xkbRuleNames, 0, sizeof(xkbRuleNames));
if(settings->KeyboardType <= 7) if (settings->KeyboardType <= 7)
xkbRuleNames.model = rdp_keyboard_types[settings->KeyboardType]; xkbRuleNames.model = rdp_keyboard_types[settings->KeyboardType];
for(i = 0; rdp_keyboards[i].xkbLayout; i++) { for(i = 0; rdp_keyboards[i].xkbLayout; i++) {
if(rdp_keyboards[i].rdpLayoutCode == settings->KeyboardLayout) { if (rdp_keyboards[i].rdpLayoutCode == settings->KeyboardLayout) {
xkbRuleNames.layout = rdp_keyboards[i].xkbLayout; xkbRuleNames.layout = rdp_keyboards[i].xkbLayout;
break; break;
} }
} }
keymap = NULL; keymap = NULL;
if(xkbRuleNames.layout) { if (xkbRuleNames.layout) {
xkbContext = xkb_context_new(0); xkbContext = xkb_context_new(0);
if(!xkbContext) { if (!xkbContext) {
weston_log("unable to create a xkb_context\n"); weston_log("unable to create a xkb_context\n");
return FALSE; return FALSE;
} }
@ -779,7 +751,7 @@ xf_mouseEvent(rdpInput *input, UINT16 flags, UINT16 x, UINT16 y) {
if (flags & PTR_FLAGS_MOVE) { if (flags & PTR_FLAGS_MOVE) {
output = peerContext->rdpCompositor->output; output = peerContext->rdpCompositor->output;
if(x < output->base.width && y < output->base.height) { if (x < output->base.width && y < output->base.height) {
wl_x = wl_fixed_from_int((int)x); wl_x = wl_fixed_from_int((int)x);
wl_y = wl_fixed_from_int((int)y); wl_y = wl_fixed_from_int((int)y);
notify_motion_absolute(&peerContext->item.seat, weston_compositor_get_time(), notify_motion_absolute(&peerContext->item.seat, weston_compositor_get_time(),
@ -794,7 +766,7 @@ xf_mouseEvent(rdpInput *input, UINT16 flags, UINT16 x, UINT16 y) {
else if (flags & PTR_FLAGS_BUTTON3) else if (flags & PTR_FLAGS_BUTTON3)
button = BTN_MIDDLE; button = BTN_MIDDLE;
if(button) { if (button) {
notify_button(&peerContext->item.seat, weston_compositor_get_time(), button, notify_button(&peerContext->item.seat, weston_compositor_get_time(), button,
(flags & PTR_FLAGS_DOWN) ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED (flags & PTR_FLAGS_DOWN) ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED
); );
@ -824,7 +796,7 @@ xf_extendedMouseEvent(rdpInput *input, UINT16 flags, UINT16 x, UINT16 y) {
struct rdp_output *output; struct rdp_output *output;
output = peerContext->rdpCompositor->output; output = peerContext->rdpCompositor->output;
if(x < output->base.width && y < output->base.height) { if (x < output->base.width && y < output->base.height) {
wl_x = wl_fixed_from_int((int)x); wl_x = wl_fixed_from_int((int)x);
wl_y = wl_fixed_from_int((int)y); wl_y = wl_fixed_from_int((int)y);
notify_motion_absolute(&peerContext->item.seat, weston_compositor_get_time(), notify_motion_absolute(&peerContext->item.seat, weston_compositor_get_time(),
@ -882,13 +854,13 @@ xf_input_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code)
notify = 1; notify = 1;
} }
if(notify) { if (notify) {
full_code = code; full_code = code;
if(flags & KBD_FLAGS_EXTENDED) if (flags & KBD_FLAGS_EXTENDED)
full_code |= KBD_FLAGS_EXTENDED; full_code |= KBD_FLAGS_EXTENDED;
vk_code = GetVirtualKeyCodeFromVirtualScanCode(full_code, 4); vk_code = GetVirtualKeyCodeFromVirtualScanCode(full_code, 4);
if(vk_code > 0xff) { if (vk_code > 0xff) {
weston_log("invalid vk_code %x", vk_code); weston_log("invalid vk_code %x", vk_code);
return; return;
} }
@ -912,7 +884,7 @@ xf_input_unicode_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code)
static void static void
xf_suppress_output(rdpContext *context, BYTE allow, RECTANGLE_16 *area) { xf_suppress_output(rdpContext *context, BYTE allow, RECTANGLE_16 *area) {
RdpPeerContext *peerContext = (RdpPeerContext *)context; RdpPeerContext *peerContext = (RdpPeerContext *)context;
if(allow) if (allow)
peerContext->item.flags |= RDP_PEER_OUTPUT_ENABLED; peerContext->item.flags |= RDP_PEER_OUTPUT_ENABLED;
else else
peerContext->item.flags &= (~RDP_PEER_OUTPUT_ENABLED); peerContext->item.flags &= (~RDP_PEER_OUTPUT_ENABLED);
@ -940,7 +912,7 @@ rdp_peer_init(freerdp_peer *client, struct rdp_compositor *c)
settings = client->settings; settings = client->settings;
settings->RdpKeyFile = c->rdp_key; settings->RdpKeyFile = c->rdp_key;
if(c->tls_enabled) { if (c->tls_enabled) {
settings->CertificateFile = c->server_cert; settings->CertificateFile = c->server_cert;
settings->PrivateKeyFile = c->server_key; settings->PrivateKeyFile = c->server_key;
} else { } else {
@ -1018,11 +990,11 @@ rdp_compositor_create(struct wl_display *display,
c->rdp_key = config->rdp_key ? strdup(config->rdp_key) : NULL; c->rdp_key = config->rdp_key ? strdup(config->rdp_key) : NULL;
/* activate TLS only if certificate/key are available */ /* activate TLS only if certificate/key are available */
if(config->server_cert && config->server_key) { if (config->server_cert && config->server_key) {
weston_log("TLS support activated\n"); weston_log("TLS support activated\n");
c->server_cert = strdup(config->server_cert); c->server_cert = strdup(config->server_cert);
c->server_key = strdup(config->server_key); c->server_key = strdup(config->server_key);
if(!c->server_cert || !c->server_key) if (!c->server_cert || !c->server_key)
goto err_free_strings; goto err_free_strings;
c->tls_enabled = 1; c->tls_enabled = 1;
} }
@ -1030,14 +1002,14 @@ rdp_compositor_create(struct wl_display *display,
if (pixman_renderer_init(&c->base) < 0) if (pixman_renderer_init(&c->base) < 0)
goto err_compositor; goto err_compositor;
if (rdp_compositor_create_output(c, config->width, config->height, config->extra_modes) < 0) if (rdp_compositor_create_output(c, config->width, config->height) < 0)
goto err_compositor; goto err_compositor;
if(!config->env_socket) { if (!config->env_socket) {
c->listener = freerdp_listener_new(); c->listener = freerdp_listener_new();
c->listener->PeerAccepted = rdp_incoming_peer; c->listener->PeerAccepted = rdp_incoming_peer;
c->listener->param4 = c; c->listener->param4 = c;
if(!c->listener->Open(c->listener, config->bind_address, config->port)) { if (!c->listener->Open(c->listener, config->bind_address, config->port)) {
weston_log("unable to bind rdp socket\n"); weston_log("unable to bind rdp socket\n");
goto err_listener; goto err_listener;
} }
@ -1047,13 +1019,13 @@ rdp_compositor_create(struct wl_display *display,
} else { } else {
/* get the socket from RDP_FD var */ /* get the socket from RDP_FD var */
fd_str = getenv("RDP_FD"); fd_str = getenv("RDP_FD");
if(!fd_str) { if (!fd_str) {
weston_log("RDP_FD env variable not set"); weston_log("RDP_FD env variable not set");
goto err_output; goto err_output;
} }
fd = strtoul(fd_str, NULL, 10); fd = strtoul(fd_str, NULL, 10);
if(rdp_peer_init(freerdp_peer_new(fd), c)) if (rdp_peer_init(freerdp_peer_new(fd), c))
goto err_output; goto err_output;
} }
@ -1066,11 +1038,11 @@ err_output:
err_compositor: err_compositor:
weston_compositor_shutdown(&c->base); weston_compositor_shutdown(&c->base);
err_free_strings: err_free_strings:
if(c->rdp_key) if (c->rdp_key)
free(c->rdp_key); free(c->rdp_key);
if(c->server_cert) if (c->server_cert)
free(c->server_cert); free(c->server_cert);
if(c->server_key) if (c->server_key)
free(c->server_key); free(c->server_key);
err_free: err_free:
free(c); free(c);
@ -1093,7 +1065,6 @@ backend_init(struct wl_display *display, int *argc, char *argv[],
{ WESTON_OPTION_BOOLEAN, "env-socket", 0, &config.env_socket }, { WESTON_OPTION_BOOLEAN, "env-socket", 0, &config.env_socket },
{ WESTON_OPTION_INTEGER, "width", 0, &config.width }, { WESTON_OPTION_INTEGER, "width", 0, &config.width },
{ WESTON_OPTION_INTEGER, "height", 0, &config.height }, { WESTON_OPTION_INTEGER, "height", 0, &config.height },
{ WESTON_OPTION_STRING, "extra-modes", 0, &config.extra_modes },
{ WESTON_OPTION_STRING, "address", 0, &config.bind_address }, { WESTON_OPTION_STRING, "address", 0, &config.bind_address },
{ WESTON_OPTION_INTEGER, "port", 0, &config.port }, { WESTON_OPTION_INTEGER, "port", 0, &config.port },
{ WESTON_OPTION_STRING, "rdp4-key", 0, &config.rdp_key }, { WESTON_OPTION_STRING, "rdp4-key", 0, &config.rdp_key },

@ -4056,7 +4056,6 @@ usage(int error_code)
"Options for rdp-backend.so:\n\n" "Options for rdp-backend.so:\n\n"
" --width=WIDTH\t\tWidth of desktop\n" " --width=WIDTH\t\tWidth of desktop\n"
" --height=HEIGHT\tHeight of desktop\n" " --height=HEIGHT\tHeight of desktop\n"
" --extra-modes=MODES\t\n"
" --env-socket=SOCKET\tUse that socket as peer connection\n" " --env-socket=SOCKET\tUse that socket as peer connection\n"
" --address=ADDR\tThe address to bind\n" " --address=ADDR\tThe address to bind\n"
" --port=PORT\tThe port to listen on\n" " --port=PORT\tThe port to listen on\n"

Loading…
Cancel
Save