From 2d4f10038ed4a422671b13844b4a4ebbc8089ea0 Mon Sep 17 00:00:00 2001 From: Vic Lee Date: Tue, 23 Aug 2011 15:51:51 +0800 Subject: [PATCH] server: process client input events. --- libfreerdp-core/fastpath.c | 187 ++++++++++++++++++++++++++++++++++- libfreerdp-core/fastpath.h | 25 ++++- libfreerdp-core/input.c | 43 ++++---- libfreerdp-core/input.h | 11 --- libfreerdp-core/peer.c | 14 ++- server/test/freerdp_server.c | 5 +- 6 files changed, 243 insertions(+), 42 deletions(-) diff --git a/libfreerdp-core/fastpath.c b/libfreerdp-core/fastpath.c index 12b1cecd3..fd64ec5c7 100644 --- a/libfreerdp-core/fastpath.c +++ b/libfreerdp-core/fastpath.c @@ -52,7 +52,10 @@ uint16 fastpath_read_header(rdpFastPath* fastpath, STREAM* s) stream_read_uint8(s, header); if (fastpath != NULL) + { fastpath->encryptionFlags = (header & 0xC0) >> 6; + fastpath->numberEvents = (header & 0x3C) >> 2; + } stream_read_uint8(s, length); /* length1 */ /* If most significant bit is not set, length2 is not presented. */ @@ -306,8 +309,168 @@ boolean fastpath_recv_updates(rdpFastPath* fastpath, STREAM* s) return True; } -boolean fastpath_recv_input(rdpFastPath* fastpath, STREAM* s) +static boolean fastpath_read_input_event_header(STREAM* s, uint8* eventFlags, uint8* eventCode) { + uint8 eventHeader; + + if (stream_get_left(s) < 1) + return False; + + stream_read_uint8(s, eventHeader); /* eventHeader (1 byte) */ + + *eventFlags = (eventHeader & 0x1F); + *eventCode = (eventHeader >> 5); + + return True; +} + +static boolean fastpath_recv_input_event_scancode(rdpFastPath* fastpath, STREAM* s, uint8 eventFlags) +{ + uint16 flags; + uint16 code; + + if (stream_get_left(s) < 1) + return False; + + stream_read_uint8(s, code); /* keyCode (1 byte) */ + + flags = 0; + if ((eventFlags & FASTPATH_INPUT_KBDFLAGS_RELEASE)) + flags |= KBD_FLAGS_RELEASE; + else + flags |= KBD_FLAGS_DOWN; + + if ((eventFlags & FASTPATH_INPUT_KBDFLAGS_EXTENDED)) + flags |= KBD_FLAGS_EXTENDED; + + IFCALL(fastpath->rdp->input->KeyboardEvent, fastpath->rdp->input, flags, code); + + return True; +} + +static boolean fastpath_recv_input_event_mouse(rdpFastPath* fastpath, STREAM* s, uint8 eventFlags) +{ + uint16 pointerFlags; + uint16 xPos; + uint16 yPos; + + if (stream_get_left(s) < 6) + return False; + + stream_read_uint16(s, pointerFlags); /* pointerFlags (2 bytes) */ + stream_read_uint16(s, xPos); /* xPos (2 bytes) */ + stream_read_uint16(s, yPos); /* yPos (2 bytes) */ + + IFCALL(fastpath->rdp->input->MouseEvent, fastpath->rdp->input, pointerFlags, xPos, yPos); + + return True; +} + +static boolean fastpath_recv_input_event_mousex(rdpFastPath* fastpath, STREAM* s, uint8 eventFlags) +{ + uint16 pointerFlags; + uint16 xPos; + uint16 yPos; + + if (stream_get_left(s) < 6) + return False; + + stream_read_uint16(s, pointerFlags); /* pointerFlags (2 bytes) */ + stream_read_uint16(s, xPos); /* xPos (2 bytes) */ + stream_read_uint16(s, yPos); /* yPos (2 bytes) */ + + IFCALL(fastpath->rdp->input->ExtendedMouseEvent, fastpath->rdp->input, pointerFlags, xPos, yPos); + + return True; +} + +static boolean fastpath_recv_input_event_sync(rdpFastPath* fastpath, STREAM* s, uint8 eventFlags) +{ + IFCALL(fastpath->rdp->input->SynchronizeEvent, fastpath->rdp->input, eventFlags); + + return True; +} + +static boolean fastpath_recv_input_event_unicode(rdpFastPath* fastpath, STREAM* s, uint8 eventFlags) +{ + uint16 unicodeCode; + + if (stream_get_left(s) < 2) + return False; + + stream_read_uint16(s, unicodeCode); /* unicodeCode (2 bytes) */ + + IFCALL(fastpath->rdp->input->UnicodeKeyboardEvent, fastpath->rdp->input, unicodeCode); + + return True; +} + +static boolean fastpath_recv_input_event(rdpFastPath* fastpath, STREAM* s) +{ + uint8 eventFlags; + uint8 eventCode; + + if (!fastpath_read_input_event_header(s, &eventFlags, &eventCode)) + return False; + + switch (eventCode) + { + case FASTPATH_INPUT_EVENT_SCANCODE: + if (!fastpath_recv_input_event_scancode(fastpath, s, eventFlags)) + return False; + break; + + case FASTPATH_INPUT_EVENT_MOUSE: + if (!fastpath_recv_input_event_mouse(fastpath, s, eventFlags)) + return False; + break; + + case FASTPATH_INPUT_EVENT_MOUSEX: + if (!fastpath_recv_input_event_mousex(fastpath, s, eventFlags)) + return False; + break; + + case FASTPATH_INPUT_EVENT_SYNC: + if (!fastpath_recv_input_event_sync(fastpath, s, eventFlags)) + return False; + break; + + case FASTPATH_INPUT_EVENT_UNICODE: + if (!fastpath_recv_input_event_unicode(fastpath, s, eventFlags)) + return False; + break; + + default: + printf("Unknown eventCode %d\n", eventCode); + break; + } + + return True; +} + +boolean fastpath_recv_inputs(rdpFastPath* fastpath, STREAM* s) +{ + uint8 i; + + if (fastpath->numberEvents == 0) + { + /** + * If numberEvents is not provided in fpInputHeader, it will be provided + * as onee additional byte here. + */ + + if (stream_get_left(s) < 1) + return False; + + stream_read_uint8(s, fastpath->numberEvents); /* eventHeader (1 byte) */ + } + + for (i = 0; i < fastpath->numberEvents; i++) + { + if (!fastpath_recv_input_event(fastpath, s)) + return False; + } + return True; } @@ -320,7 +483,7 @@ STREAM* fastpath_pdu_init(rdpFastPath* fastpath) return s; } -void fastpath_send_pdu(rdpFastPath* fastpath, STREAM* s, uint8 numberEvents) +boolean fastpath_send_pdu(rdpFastPath* fastpath, STREAM* s, uint8 numberEvents) { int length; @@ -328,7 +491,7 @@ void fastpath_send_pdu(rdpFastPath* fastpath, STREAM* s, uint8 numberEvents) if (length > 127) { printf("Maximum FastPath PDU length is 127\n"); - return; + return False; } stream_set_pos(s, 0); @@ -336,7 +499,23 @@ void fastpath_send_pdu(rdpFastPath* fastpath, STREAM* s, uint8 numberEvents) stream_write_uint8(s, length); stream_set_pos(s, length); - transport_write(fastpath->rdp->transport, s); + if (transport_write(fastpath->rdp->transport, s) < 0) + return False; + + return True; +} + +STREAM* fastpath_input_pdu_init(rdpFastPath* fastpath, uint8 eventFlags, uint8 eventCode) +{ + STREAM* s; + s = fastpath_pdu_init(fastpath); + stream_write_uint8(s, eventFlags | (eventCode << 5)); /* eventHeader (1 byte) */ + return s; +} + +boolean fastpath_send_input_pdu(rdpFastPath* fastpath, STREAM* s) +{ + return fastpath_send_pdu(fastpath, s, 1); } rdpFastPath* fastpath_new(rdpRdp* rdp) diff --git a/libfreerdp-core/fastpath.h b/libfreerdp-core/fastpath.h index bf181ffb9..a047f97e6 100644 --- a/libfreerdp-core/fastpath.h +++ b/libfreerdp-core/fastpath.h @@ -72,20 +72,41 @@ enum FASTPATH_OUTPUT_COMPRESSION FASTPATH_OUTPUT_COMPRESSION_USED = 0x2 }; +/* FastPath Input Events */ +enum FASTPATH_INPUT_EVENT_CODE +{ + FASTPATH_INPUT_EVENT_SCANCODE = 0x0, + FASTPATH_INPUT_EVENT_MOUSE = 0x1, + FASTPATH_INPUT_EVENT_MOUSEX = 0x2, + FASTPATH_INPUT_EVENT_SYNC = 0x3, + FASTPATH_INPUT_EVENT_UNICODE = 0x4 +}; + +/* FastPath Keyboard Event Flags */ +enum FASTPATH_INPUT_KBDFLAGS +{ + FASTPATH_INPUT_KBDFLAGS_RELEASE = 0x01, + FASTPATH_INPUT_KBDFLAGS_EXTENDED = 0x02 +}; + struct rdp_fastpath { rdpRdp* rdp; uint8 encryptionFlags; + uint8 numberEvents; STREAM* updateData; }; uint16 fastpath_read_header(rdpFastPath* fastpath, STREAM* s); boolean fastpath_read_security_header(rdpFastPath* fastpath, STREAM* s); boolean fastpath_recv_updates(rdpFastPath* fastpath, STREAM* s); -boolean fastpath_recv_input(rdpFastPath* fastpath, STREAM* s); +boolean fastpath_recv_inputs(rdpFastPath* fastpath, STREAM* s); STREAM* fastpath_pdu_init(rdpFastPath* fastpath); -void fastpath_send_pdu(rdpFastPath* fastpath, STREAM* s, uint8 numberEvents); +boolean fastpath_send_pdu(rdpFastPath* fastpath, STREAM* s, uint8 numberEvents); + +STREAM* fastpath_input_pdu_init(rdpFastPath* fastpath, uint8 eventFlags, uint8 eventCode); +boolean fastpath_send_input_pdu(rdpFastPath* fastpath, STREAM* s); rdpFastPath* fastpath_new(rdpRdp* rdp); void fastpath_free(rdpFastPath* fastpath); diff --git a/libfreerdp-core/input.c b/libfreerdp-core/input.c index 777443a83..acdc19ddc 100644 --- a/libfreerdp-core/input.c +++ b/libfreerdp-core/input.c @@ -119,60 +119,57 @@ void input_send_extended_mouse_event(rdpInput* input, uint16 flags, uint16 x, ui rdp_send_client_input_pdu(input->rdp, s); } -STREAM* rdp_client_fastpath_input_pdu_init(rdpRdp* rdp, uint8 flags, uint8 code) -{ - STREAM* s; - s = fastpath_pdu_init(rdp->fastpath); - stream_write_uint8(s, flags | (code << 5)); /* eventHeader */ - return s; -} - -void rdp_send_client_fastpath_input_pdu(rdpRdp* rdp, STREAM* s) -{ - fastpath_send_pdu(rdp->fastpath, s, 1); -} - void input_send_fastpath_synchronize_event(rdpInput* input, uint32 flags) { + rdpRdp* rdp = (rdpRdp*)input->rdp; STREAM* s; + /* The FastPath Synchronization eventFlags has identical values as SlowPath */ - s = rdp_client_fastpath_input_pdu_init(input->rdp, (uint8)flags, FASTPATH_INPUT_EVENT_SYNC); - rdp_send_client_fastpath_input_pdu(input->rdp, s); + s = fastpath_input_pdu_init(rdp->fastpath, (uint8)flags, FASTPATH_INPUT_EVENT_SYNC); + fastpath_send_input_pdu(rdp->fastpath, s); } void input_send_fastpath_keyboard_event(rdpInput* input, uint16 flags, uint16 code) { + rdpRdp* rdp = (rdpRdp*)input->rdp; STREAM* s; uint8 eventFlags = 0; + eventFlags |= (flags & KBD_FLAGS_RELEASE) ? FASTPATH_INPUT_KBDFLAGS_RELEASE : 0; eventFlags |= (flags & KBD_FLAGS_EXTENDED) ? FASTPATH_INPUT_KBDFLAGS_EXTENDED : 0; - s = rdp_client_fastpath_input_pdu_init(input->rdp, eventFlags, FASTPATH_INPUT_EVENT_SCANCODE); + s = fastpath_input_pdu_init(rdp->fastpath, eventFlags, FASTPATH_INPUT_EVENT_SCANCODE); stream_write_uint8(s, code); /* keyCode (1 byte) */ - rdp_send_client_fastpath_input_pdu(input->rdp, s); + fastpath_send_input_pdu(rdp->fastpath, s); } void input_send_fastpath_unicode_keyboard_event(rdpInput* input, uint16 code) { + rdpRdp* rdp = (rdpRdp*)input->rdp; STREAM* s; - s = rdp_client_fastpath_input_pdu_init(input->rdp, 0, FASTPATH_INPUT_EVENT_UNICODE); + + s = fastpath_input_pdu_init(rdp->fastpath, 0, FASTPATH_INPUT_EVENT_UNICODE); stream_write_uint16(s, code); /* unicodeCode (2 bytes) */ - rdp_send_client_fastpath_input_pdu(input->rdp, s); + fastpath_send_input_pdu(rdp->fastpath, s); } void input_send_fastpath_mouse_event(rdpInput* input, uint16 flags, uint16 x, uint16 y) { + rdpRdp* rdp = (rdpRdp*)input->rdp; STREAM* s; - s = rdp_client_fastpath_input_pdu_init(input->rdp, 0, FASTPATH_INPUT_EVENT_MOUSE); + + s = fastpath_input_pdu_init(rdp->fastpath, 0, FASTPATH_INPUT_EVENT_MOUSE); input_write_mouse_event(s, flags, x, y); - rdp_send_client_fastpath_input_pdu(input->rdp, s); + fastpath_send_input_pdu(rdp->fastpath, s); } void input_send_fastpath_extended_mouse_event(rdpInput* input, uint16 flags, uint16 x, uint16 y) { + rdpRdp* rdp = (rdpRdp*)input->rdp; STREAM* s; - s = rdp_client_fastpath_input_pdu_init(input->rdp, 0, FASTPATH_INPUT_EVENT_MOUSEX); + + s = fastpath_input_pdu_init(rdp->fastpath, 0, FASTPATH_INPUT_EVENT_MOUSEX); input_write_extended_mouse_event(s, flags, x, y); - rdp_send_client_fastpath_input_pdu(input->rdp, s); + fastpath_send_input_pdu(rdp->fastpath, s); } void input_register_client_callbacks(rdpInput* input) diff --git a/libfreerdp-core/input.h b/libfreerdp-core/input.h index a114350bb..a9ad2baf6 100644 --- a/libfreerdp-core/input.h +++ b/libfreerdp-core/input.h @@ -35,17 +35,6 @@ #define INPUT_EVENT_MOUSE 0x8001 #define INPUT_EVENT_MOUSEX 0x8002 -/* FastPath Input Events */ -#define FASTPATH_INPUT_EVENT_SCANCODE 0x0 -#define FASTPATH_INPUT_EVENT_MOUSE 0x1 -#define FASTPATH_INPUT_EVENT_MOUSEX 0x2 -#define FASTPATH_INPUT_EVENT_SYNC 0x3 -#define FASTPATH_INPUT_EVENT_UNICODE 0x4 - -/* FastPath Keyboard Event Flags */ -#define FASTPATH_INPUT_KBDFLAGS_RELEASE 0x01 -#define FASTPATH_INPUT_KBDFLAGS_EXTENDED 0x02 - #define RDP_CLIENT_INPUT_PDU_HEADER_LENGTH 4 void input_send_synchronize_event(rdpInput* input, uint32 flags); diff --git a/libfreerdp-core/peer.c b/libfreerdp-core/peer.c index 922a97366..b6048c8ab 100644 --- a/libfreerdp-core/peer.c +++ b/libfreerdp-core/peer.c @@ -137,7 +137,19 @@ static boolean peer_recv_tpkt_pdu(rdpPeer* peer, STREAM* s) static boolean peer_recv_fastpath_pdu(rdpPeer* peer, STREAM* s) { - return True; + uint16 length; + + length = fastpath_read_header(peer->rdp->fastpath, s); + if (length == 0 || length > stream_get_size(s)) + { + printf("incorrect FastPath PDU header length %d\n", length); + return False; + } + + if (!fastpath_read_security_header(peer->rdp->fastpath, s)) + return False; + + return fastpath_recv_inputs(peer->rdp->fastpath, s); } static boolean peer_recv_pdu(rdpPeer* peer, STREAM* s) diff --git a/server/test/freerdp_server.c b/server/test/freerdp_server.c index 3546351b6..8bc94663b 100644 --- a/server/test/freerdp_server.c +++ b/server/test/freerdp_server.c @@ -45,13 +45,16 @@ boolean test_peer_post_connect(freerdp_peer* client) } printf("\n"); + printf("Client requested desktop: %dx%dx%d\n", + client->settings->width, client->settings->height, client->settings->color_depth); + /* Return False here would stop the execution of the peer mainloop. */ return True; } void test_peer_synchronize_event(rdpInput* input, uint32 flags) { - printf("Client sent a synchronize event\n"); + printf("Client sent a synchronize event (flags:0x%X)\n", flags); } void test_peer_keyboard_event(rdpInput* input, uint16 flags, uint16 code)