diff --git a/.gitignore b/.gitignore index 67dec24f2..99a76ffaa 100644 --- a/.gitignore +++ b/.gitignore @@ -30,9 +30,6 @@ docs/api ipch Debug -# test files -*.pcap - # Binaries *.a *.so diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index cc870e9d9..9adf77bb7 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -298,7 +298,9 @@ struct rdp_settings boolean frame_acknowledge; boolean dump_rfx; + boolean play_rfx; char* dump_rfx_file; + char* play_rfx_file; boolean remote_app; uint8 num_icon_caches; diff --git a/include/freerdp/update.h b/include/freerdp/update.h index 006f624b2..aaaf56567 100644 --- a/include/freerdp/update.h +++ b/include/freerdp/update.h @@ -1076,6 +1076,7 @@ struct rdp_update void* param2; boolean dump_rfx; + boolean play_rfx; rdpPcap* pcap_rfx; pcBeginPaint BeginPaint; diff --git a/libfreerdp-core/fastpath.c b/libfreerdp-core/fastpath.c index 322417da1..3aab07873 100644 --- a/libfreerdp-core/fastpath.c +++ b/libfreerdp-core/fastpath.c @@ -73,6 +73,26 @@ uint16 fastpath_read_header(rdpFastPath* fastpath, STREAM* s) return length; } +inline void fastpath_read_update_header(STREAM* s, uint8* updateCode, uint8* fragmentation, uint8* compression) +{ + uint8 updateHeader; + + stream_read_uint8(s, updateHeader); + *updateCode = updateHeader & 0x0F; + *fragmentation = (updateHeader >> 4) & 0x03; + *compression = (updateHeader >> 6) & 0x03; +} + +inline void fastpath_write_update_header(STREAM* s, uint8 updateCode, uint8 fragmentation, uint8 compression) +{ + uint8 updateHeader = 0; + + updateHeader |= updateCode & 0x0F; + updateHeader |= (fragmentation << 4) & 0x03; + updateHeader |= (compression << 6) & 0x03; + stream_write_uint8(s, updateHeader); +} + boolean fastpath_read_security_header(rdpFastPath* fastpath, STREAM* s) { /* TODO: fipsInformation */ @@ -122,7 +142,7 @@ static void fastpath_recv_update_common(rdpFastPath* fastpath, STREAM* s) } } -static void fastpath_recv_update(rdpFastPath* fastpath, uint8 updateCode, uint16 size, STREAM* s) +static void fastpath_recv_update(rdpFastPath* fastpath, uint8 updateCode, uint32 size, STREAM* s) { switch (updateCode) { @@ -175,19 +195,16 @@ static void fastpath_recv_update(rdpFastPath* fastpath, uint8 updateCode, uint16 static void fastpath_recv_update_data(rdpFastPath* fastpath, STREAM* s) { - uint8 updateHeader; + uint16 size; + int next_pos; + uint32 totalSize; uint8 updateCode; uint8 fragmentation; uint8 compression; uint8 compressionFlags; - uint16 size; STREAM* update_stream; - int next_pos; - stream_read_uint8(s, updateHeader); - updateCode = updateHeader & 0x0F; - fragmentation = (updateHeader >> 4) & 0x03; - compression = (updateHeader >> 6) & 0x03; + fastpath_read_update_header(s, &updateCode, &fragmentation, &compression); if (compression == FASTPATH_OUTPUT_COMPRESSION_USED) stream_read_uint8(s, compressionFlags); @@ -207,6 +224,7 @@ static void fastpath_recv_update_data(rdpFastPath* fastpath, STREAM* s) update_stream = NULL; if (fragmentation == FASTPATH_FRAGMENT_SINGLE) { + totalSize = size; update_stream = s; } else @@ -220,13 +238,13 @@ static void fastpath_recv_update_data(rdpFastPath* fastpath, STREAM* s) if (fragmentation == FASTPATH_FRAGMENT_LAST) { update_stream = fastpath->updateData; - size = stream_get_length(update_stream); + totalSize = stream_get_length(update_stream); stream_set_pos(update_stream, 0); } } if (update_stream) - fastpath_recv_update(fastpath, updateCode, size, update_stream); + fastpath_recv_update(fastpath, updateCode, totalSize, update_stream); stream_set_pos(s, next_pos); } @@ -482,60 +500,30 @@ boolean fastpath_send_fragmented_update_pdu(rdpFastPath* fastpath, STREAM* s) uint16 length; uint16 maxLength; uint32 totalLength; + uint8 fragmentation; STREAM* update; - totalLength = stream_get_length(s); maxLength = FASTPATH_MAX_PACKET_SIZE - 6; + totalLength = stream_get_length(s); + stream_set_pos(s, 0); - if (totalLength <= maxLength) + for (fragment = 0; totalLength > 0; fragment++) { update = fastpath_update_pdu_init(fastpath); - stream_write_uint8(update, FASTPATH_UPDATETYPE_SURFCMDS | (FASTPATH_FRAGMENT_SINGLE << 4)); - stream_write_uint16(update, totalLength); - stream_write(update, s->data, totalLength); - return fastpath_send_update_pdu(fastpath, update); - } - - fragment = 0; - while (totalLength > 0) - { - if (totalLength < maxLength) - length = totalLength; - else - length = maxLength; - + length = MIN(maxLength, totalLength); totalLength -= length; - update = fastpath_update_pdu_init(fastpath); - if (fragment == 0) - { - stream_write_uint8(update, FASTPATH_UPDATETYPE_SURFCMDS | (FASTPATH_FRAGMENT_FIRST << 4)); - stream_write_uint16(update, length); - stream_write(update, s->p, length); - fastpath_send_update_pdu(fastpath, update); - s->p += length; - } + if (totalLength == 0) + fragmentation = (fragment == 0) ? FASTPATH_FRAGMENT_SINGLE : FASTPATH_FRAGMENT_LAST; else - { - if (totalLength == 0) - { - stream_write_uint8(update, FASTPATH_UPDATETYPE_SURFCMDS | (FASTPATH_FRAGMENT_LAST << 4)); - stream_write_uint16(update, length); - stream_write(update, s->p, length); - fastpath_send_update_pdu(fastpath, update); - s->p += length; - } - else - { - stream_write_uint8(update, FASTPATH_UPDATETYPE_SURFCMDS | (FASTPATH_FRAGMENT_NEXT << 4)); - stream_write_uint16(update, length); - stream_write(update, s->p, length); - fastpath_send_update_pdu(fastpath, update); - s->p += length; - } - } + fragmentation = (fragment == 0) ? FASTPATH_FRAGMENT_FIRST : FASTPATH_FRAGMENT_NEXT; - fragment++; + fastpath_write_update_header(update, FASTPATH_UPDATETYPE_SURFCMDS, fragmentation, 0); + stream_write_uint16(update, length); + stream_write(update, s->p, length); + stream_seek(s, length); + + fastpath_send_update_pdu(fastpath, update); } return True; @@ -586,19 +574,17 @@ boolean fastpath_send_surfcmd_surface_bits(rdpFastPath* fastpath, SURFACE_BITS_C } fragment_size = MIN(FASTPATH_MAX_PACKET_SIZE - stream_get_length(s), bitmapDataLength); + if (fragment_size == bitmapDataLength) - { fragmentation = (i == 0 ? FASTPATH_FRAGMENT_SINGLE : FASTPATH_FRAGMENT_LAST); - } else - { fragmentation = (i == 0 ? FASTPATH_FRAGMENT_FIRST : FASTPATH_FRAGMENT_NEXT); - } + size += fragment_size; ep = stream_get_pos(s); stream_set_pos(s, bp); - stream_write_uint8(s, FASTPATH_UPDATETYPE_SURFCMDS | (fragmentation << 4)); + fastpath_write_update_header(s, FASTPATH_UPDATETYPE_SURFCMDS, fragmentation, 0); stream_write_uint16(s, size); stream_set_pos(s, ep); diff --git a/libfreerdp-core/freerdp.c b/libfreerdp-core/freerdp.c index 4b06392e5..bd88f449d 100644 --- a/libfreerdp-core/freerdp.c +++ b/libfreerdp-core/freerdp.c @@ -20,6 +20,7 @@ #include "rdp.h" #include "input.h" #include "update.h" +#include "surface.h" #include "transport.h" #include "connection.h" @@ -46,6 +47,37 @@ boolean freerdp_connect(freerdp* instance) } IFCALL(instance->PostConnect, instance); + + if (instance->settings->play_rfx) + { + STREAM* s; + rdpUpdate* update; + pcap_record record; + + s = stream_new(1024); + instance->update->play_rfx = instance->settings->play_rfx; + instance->update->pcap_rfx = pcap_open(instance->settings->play_rfx_file, False); + update = instance->update; + + while (pcap_has_next_record(update->pcap_rfx)) + { + pcap_get_next_record_header(update->pcap_rfx, &record); + + s->data = xrealloc(s->data, record.length); + record.data = s->data; + s->size = record.length; + + pcap_get_next_record_content(update->pcap_rfx, &record); + stream_set_pos(s, 0); + + update->BeginPaint(update); + update_recv_surfcmds(update, s->size, s); + update->EndPaint(update); + } + + xfree(s->data); + return True; + } } return status; diff --git a/libfreerdp-core/surface.c b/libfreerdp-core/surface.c index ad55f5d3f..b0bc45411 100644 --- a/libfreerdp-core/surface.c +++ b/libfreerdp-core/surface.c @@ -58,11 +58,11 @@ static int update_recv_surfcmd_frame_marker(rdpUpdate* update, STREAM* s) return 6; } -boolean update_recv_surfcmds(rdpUpdate* update, uint16 size, STREAM* s) +boolean update_recv_surfcmds(rdpUpdate* update, uint32 size, STREAM* s) { uint8* mark; uint16 cmdType; - uint16 cmdLength; + uint32 cmdLength; while (size > 2) { diff --git a/libfreerdp-core/surface.h b/libfreerdp-core/surface.h index 1c18adf39..c19ed0d57 100644 --- a/libfreerdp-core/surface.h +++ b/libfreerdp-core/surface.h @@ -39,7 +39,7 @@ enum SURFCMD_FRAMEACTION SURFACECMD_FRAMEACTION_END = 0x0001 }; -boolean update_recv_surfcmds(rdpUpdate* update, uint16 size, STREAM* s); +boolean update_recv_surfcmds(rdpUpdate* update, uint32 size, STREAM* s); void update_write_surfcmd_surface_bits_header(STREAM* s, SURFACE_BITS_COMMAND* cmd); void update_write_surfcmd_frame_marker(STREAM* s, uint16 frameAction, uint32 frameId); diff --git a/libfreerdp-utils/args.c b/libfreerdp-utils/args.c index 2d177d306..b6ce38145 100644 --- a/libfreerdp-utils/args.c +++ b/libfreerdp-utils/args.c @@ -293,6 +293,17 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, settings->dump_rfx_file = xstrdup(argv[index]); settings->dump_rfx = True; } + else if (strcmp("--play-rfx", argv[index]) == 0) + { + index++; + if (index == argc) + { + printf("missing file name\n"); + return -1; + } + settings->play_rfx_file = xstrdup(argv[index]); + settings->play_rfx = True; + } else if (strcmp("-m", argv[index]) == 0) { settings->mouse_motion = 0; diff --git a/libfreerdp-utils/pcap.c b/libfreerdp-utils/pcap.c index a0ca538c8..48f2a711d 100644 --- a/libfreerdp-utils/pcap.c +++ b/libfreerdp-utils/pcap.c @@ -149,7 +149,7 @@ rdpPcap* pcap_open(char* name, boolean write) pcap->header.version_minor = 4; pcap->header.thiszone = 0; pcap->header.sigfigs = 0; - pcap->header.snaplen = 65535; + pcap->header.snaplen = 0xFFFFFFFF; pcap->header.network = 0; pcap_write_header(pcap, &pcap->header); } diff --git a/server/test/freerdp_server.c b/server/test/freerdp_server.c index 7aaa3129d..8762622c0 100644 --- a/server/test/freerdp_server.c +++ b/server/test/freerdp_server.c @@ -286,7 +286,7 @@ boolean test_peer_post_connect(freerdp_peer* client) test_peer_draw_background(client); test_peer_load_icon(client); - //client->update->dump_rfx = True; + client->update->dump_rfx = True; if (client->update->dump_rfx) { diff --git a/server/test/rfx_test.pcap b/server/test/rfx_test.pcap new file mode 100644 index 000000000..c830e10b5 Binary files /dev/null and b/server/test/rfx_test.pcap differ