diff --git a/.gitignore b/.gitignore index 99a76ffaa..67dec24f2 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,9 @@ docs/api ipch Debug +# test files +*.pcap + # Binaries *.a *.so diff --git a/include/freerdp/update.h b/include/freerdp/update.h index 96ae25526..006f624b2 100644 --- a/include/freerdp/update.h +++ b/include/freerdp/update.h @@ -23,6 +23,7 @@ #include #include #include +#include /* Common */ @@ -1064,6 +1065,7 @@ typedef void (*pcMonitoredDesktop)(rdpUpdate* update, WINDOW_ORDER_INFO* orderIn typedef void (*pcNonMonitoredDesktop)(rdpUpdate* update, WINDOW_ORDER_INFO* orderInfo); typedef void (*pcSurfaceBits)(rdpUpdate* update, SURFACE_BITS_COMMAND* surface_bits_command); +typedef void (*pcSurfaceCommand)(rdpUpdate* update, STREAM* s); struct rdp_update { @@ -1146,6 +1148,7 @@ struct rdp_update pcNonMonitoredDesktop NonMonitoredDesktop; pcSurfaceBits SurfaceBits; + pcSurfaceCommand SurfaceCommand; BITMAP_UPDATE bitmap_update; PALETTE_UPDATE palette_update; diff --git a/include/freerdp/utils/pcap.h b/include/freerdp/utils/pcap.h index db840c8d9..a431fbc60 100644 --- a/include/freerdp/utils/pcap.h +++ b/include/freerdp/utils/pcap.h @@ -76,6 +76,8 @@ FREERDP_API void pcap_close(rdpPcap* pcap); FREERDP_API void pcap_add_record(rdpPcap* pcap, void* data, uint32 length); FREERDP_API boolean pcap_has_next_record(rdpPcap* pcap); FREERDP_API boolean pcap_get_next_record(rdpPcap* pcap, pcap_record* record); +FREERDP_API boolean pcap_get_next_record_header(rdpPcap* pcap, pcap_record* record); +FREERDP_API boolean pcap_get_next_record_content(rdpPcap* pcap, pcap_record* record); FREERDP_API void pcap_flush(rdpPcap* pcap); #endif /* __UTILS_PCAP_H */ diff --git a/libfreerdp-core/fastpath.c b/libfreerdp-core/fastpath.c index e48e4a2ae..848170080 100644 --- a/libfreerdp-core/fastpath.c +++ b/libfreerdp-core/fastpath.c @@ -394,7 +394,7 @@ boolean fastpath_recv_inputs(rdpFastPath* fastpath, STREAM* s) { /** * If numberEvents is not provided in fpInputHeader, it will be provided - * as onee additional byte here. + * as one additional byte here. */ if (stream_get_left(s) < 1) @@ -475,6 +475,36 @@ boolean fastpath_send_update_pdu(rdpFastPath* fastpath, STREAM* s) return True; } +boolean fastpath_send_fragmented_update_pdu(rdpFastPath* fastpath, STREAM* s) +{ + uint16 length; + uint32 totalLength; + STREAM* update; + + totalLength = stream_get_length(s); + update = fastpath_update_pdu_init(fastpath); + + if (totalLength <= FASTPATH_MAX_PACKET_SIZE) + { + 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); + } + + while (totalLength > 0) + { + if (totalLength < FASTPATH_MAX_PACKET_SIZE) + length = totalLength; + else + length = FASTPATH_MAX_PACKET_SIZE; + + totalLength -= length; + } + + return True; +} + boolean fastpath_send_surfcmd_frame_marker(rdpFastPath* fastpath, uint16 frameAction, uint32 frameId) { STREAM* s; diff --git a/libfreerdp-core/fastpath.h b/libfreerdp-core/fastpath.h index 5a6166aef..25899b3ba 100644 --- a/libfreerdp-core/fastpath.h +++ b/libfreerdp-core/fastpath.h @@ -100,6 +100,7 @@ boolean fastpath_send_input_pdu(rdpFastPath* fastpath, STREAM* s); STREAM* fastpath_update_pdu_init(rdpFastPath* fastpath); boolean fastpath_send_update_pdu(rdpFastPath* fastpath, STREAM* s); +boolean fastpath_send_fragmented_update_pdu(rdpFastPath* fastpath, STREAM* s); boolean fastpath_send_surfcmd_frame_marker(rdpFastPath* fastpath, uint16 frameAction, uint32 frameId); boolean fastpath_send_surfcmd_surface_bits(rdpFastPath* fastpath, SURFACE_BITS_COMMAND* cmd); diff --git a/libfreerdp-core/surface.c b/libfreerdp-core/surface.c index 98748cac4..fb3075c4f 100644 --- a/libfreerdp-core/surface.c +++ b/libfreerdp-core/surface.c @@ -23,8 +23,8 @@ static int update_recv_surfcmd_surface_bits(rdpUpdate* update, STREAM* s) { - SURFACE_BITS_COMMAND* cmd = &update->surface_bits_command; int pos; + SURFACE_BITS_COMMAND* cmd = &update->surface_bits_command; stream_read_uint16(s, cmd->destLeft); stream_read_uint16(s, cmd->destTop); @@ -62,14 +62,14 @@ boolean update_recv_surfcmds(rdpUpdate* update, uint16 size, STREAM* s) { uint16 cmdType; + if (update->dump_rfx) + { + pcap_add_record(update->pcap_rfx, s->p, size); + pcap_flush(update->pcap_rfx); + } + while (size > 2) { - if (update->dump_rfx) - { - pcap_add_record(update->pcap_rfx, s->p, size); - pcap_flush(update->pcap_rfx); - } - stream_read_uint16(s, cmdType); size -= 2; diff --git a/libfreerdp-core/update.c b/libfreerdp-core/update.c index ffc1e3c49..b63e4b8a0 100644 --- a/libfreerdp-core/update.c +++ b/libfreerdp-core/update.c @@ -322,10 +322,15 @@ static void update_end_paint(rdpUpdate* update) { } +static void update_send_surface_command(rdpUpdate* update, STREAM* s) +{ + rdpRdp* rdp = (rdpRdp*) update->rdp; + fastpath_send_fragmented_update_pdu(rdp->fastpath, s); +} + static void update_send_surface_bits(rdpUpdate* update, SURFACE_BITS_COMMAND* surface_bits_command) { rdpRdp* rdp = (rdpRdp*)update->rdp; - fastpath_send_surfcmd_surface_bits(rdp->fastpath, surface_bits_command); } @@ -362,6 +367,7 @@ void update_register_server_callbacks(rdpUpdate* update) update->Synchronize = update_send_synchronize; update->PointerSystem = update_send_pointer_system; update->SurfaceBits = update_send_surface_bits; + update->SurfaceCommand = update_send_surface_command; } rdpUpdate* update_new(rdpRdp* rdp) diff --git a/libfreerdp-utils/pcap.c b/libfreerdp-utils/pcap.c index e07f9c244..a0ca538c8 100644 --- a/libfreerdp-utils/pcap.c +++ b/libfreerdp-utils/pcap.c @@ -101,6 +101,24 @@ boolean pcap_has_next_record(rdpPcap* pcap) return True; } +boolean pcap_get_next_record_header(rdpPcap* pcap, pcap_record* record) +{ + if (pcap_has_next_record(pcap) != True) + return False; + + pcap_read_record_header(pcap, &record->header); + record->length = record->header.incl_len; + record->data = xmalloc(record->length); + + return True; +} + +boolean pcap_get_next_record_content(rdpPcap* pcap, pcap_record* record) +{ + fread(record->data, record->length, 1, pcap->fp); + return True; +} + boolean pcap_get_next_record(rdpPcap* pcap, pcap_record* record) { if (pcap_has_next_record(pcap) != True) diff --git a/server/test/freerdp_server.c b/server/test/freerdp_server.c index 00d07da47..afab4a8b9 100644 --- a/server/test/freerdp_server.c +++ b/server/test/freerdp_server.c @@ -232,6 +232,33 @@ static void test_peer_draw_icon(freerdp_peer* client, int x, int y) info->icon_y = y; } +void test_peer_dump_rfx(freerdp_peer* client) +{ + STREAM* s; + rdpUpdate* update; + rdpPcap* pcap_rfx; + pcap_record record; + + s = stream_new(512); + update = client->update; + client->update->pcap_rfx = pcap_open("rfx_test.pcap", False); + pcap_rfx = client->update->pcap_rfx; + + while (pcap_has_next_record(pcap_rfx)) + { + pcap_get_next_record_header(pcap_rfx, &record); + + s->data = xrealloc(s->data, record.length); + record.data = s->data; + s->size = record.length; + + pcap_get_next_record_content(pcap_rfx, &record); + s->p = s->data + s->size; + + update->SurfaceCommand(update, s); + } +} + boolean test_peer_post_connect(freerdp_peer* client) { /** @@ -259,6 +286,11 @@ boolean test_peer_post_connect(freerdp_peer* client) test_peer_draw_background(client); test_peer_load_icon(client); + if (client->update->dump_rfx) + { + test_peer_dump_rfx(client); + } + /* Return False here would stop the execution of the peer mainloop. */ return True; }