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/client/X11/xf_gdi.c b/client/X11/xf_gdi.c index 1c93a4a78..70d024d78 100644 --- a/client/X11/xf_gdi.c +++ b/client/X11/xf_gdi.c @@ -17,6 +17,8 @@ * limitations under the License. */ +#include + #include "xf_gdi.h" static const uint8 xf_rop2_table[] = @@ -186,14 +188,55 @@ boolean xf_set_rop3(xfInfo* xfi, int rop3) return True; } -void xf_bitmap_new(xfInfo* xfi, int width, int height, int bpp, uint8* data) +Pixmap xf_bitmap_new(xfInfo* xfi, int width, int height, int bpp, uint8* data) { + Pixmap bitmap; + uint8* cdata; + XImage* image; + bitmap = XCreatePixmap(xfi->display, xfi->window->handle, width, height, xfi->depth); + + cdata = gdi_image_convert(data, NULL, width, height, bpp, xfi->bpp, xfi->clrconv); + + image = XCreateImage(xfi->display, xfi->visual, xfi->depth, + ZPixmap, 0, (char *) cdata, width, height, xfi->scanline_pad, 0); + + XPutImage(xfi->display, bitmap, xfi->gc, image, 0, 0, 0, 0, width, height); + XFree(image); + + if (cdata != data) + xfree(cdata); + + return bitmap; } void xf_gdi_bitmap_update(rdpUpdate* update, BITMAP_UPDATE* bitmap) { + int i; + int x, y; + int w, h; + uint8* data; + XImage* image; + BITMAP_DATA* bmp; + xfInfo* xfi = GET_XFI(update); + for (i = 0; i < bitmap->number; i++) + { + bmp = &bitmap->bitmaps[i]; + + data = gdi_image_convert(bmp->data, NULL, bmp->width, bmp->height, bmp->bpp, xfi->bpp, xfi->clrconv); + + image = XCreateImage(xfi->display, xfi->visual, xfi->depth, + ZPixmap, 0, (char*) data, bmp->width, bmp->height, xfi->scanline_pad, 0); + + x = bmp->left; + y = bmp->top; + w = bmp->right - bmp->left + 1; + h = bmp->bottom - bmp->top + 1; + + XPutImage(xfi->display, xfi->primary, xfi->gc, image, 0, 0, x, y, w, h); + XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc, x, y, w, h, x, y); + } } void xf_gdi_palette_update(rdpUpdate* update, PALETTE_UPDATE* palette) @@ -203,12 +246,40 @@ void xf_gdi_palette_update(rdpUpdate* update, PALETTE_UPDATE* palette) void xf_gdi_set_bounds(rdpUpdate* update, BOUNDS* bounds) { + XRectangle clip; + xfInfo* xfi = GET_XFI(update); + if (bounds != NULL) + { + clip.x = bounds->left; + clip.y = bounds->top; + clip.width = bounds->right - bounds->left + 1; + clip.height = bounds->bottom - bounds->top + 1; + XSetClipRectangles(xfi->display, xfi->gc, 0, 0, &clip, 1, YXBanded); + } + else + { + XSetClipMask(xfi->display, xfi->gc, None); + } } void xf_gdi_dstblt(rdpUpdate* update, DSTBLT_ORDER* dstblt) { + xfInfo* xfi = GET_XFI(update); + xf_set_rop3(xfi, gdi_rop3_code(dstblt->bRop)); + + XSetFillStyle(xfi->display, xfi->gc, FillSolid); + XFillRectangle(xfi->display, xfi->drawing, xfi->gc, + dstblt->nLeftRect, dstblt->nTopRect, + dstblt->nWidth, dstblt->nHeight); + + if (xfi->drawing == xfi->primary) + { + XFillRectangle(xfi->display, xfi->window->handle, xfi->gc, + dstblt->nLeftRect, dstblt->nTopRect, + dstblt->nWidth, dstblt->nHeight); + } } void xf_gdi_patblt(rdpUpdate* update, PATBLT_ORDER* patblt) @@ -218,17 +289,80 @@ void xf_gdi_patblt(rdpUpdate* update, PATBLT_ORDER* patblt) void xf_gdi_scrblt(rdpUpdate* update, SCRBLT_ORDER* scrblt) { + xfInfo* xfi = GET_XFI(update); + xf_set_rop3(xfi, gdi_rop3_code(scrblt->bRop)); + XCopyArea(xfi->display, xfi->primary, xfi->drawing, xfi->gc, scrblt->nXSrc, scrblt->nYSrc, + scrblt->nWidth, scrblt->nHeight, scrblt->nLeftRect, scrblt->nTopRect); + + if (xfi->drawing == xfi->primary) + { + if (xfi->unobscured) + { + XCopyArea(xfi->display, xfi->window->handle, xfi->window->handle, xfi->gc, + scrblt->nXSrc, scrblt->nYSrc, scrblt->nWidth, scrblt->nHeight, + scrblt->nLeftRect, scrblt->nTopRect); + } + else + { + XSetFunction(xfi->display, xfi->gc, GXcopy); + XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc, + scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth, scrblt->nHeight, + scrblt->nLeftRect, scrblt->nTopRect); + } + } } void xf_gdi_opaque_rect(rdpUpdate* update, OPAQUE_RECT_ORDER* opaque_rect) { + uint32 color; + xfInfo* xfi = GET_XFI(update); + color = gdi_color_convert(opaque_rect->color, xfi->srcBpp, xfi->bpp, xfi->clrconv); + + XSetFunction(xfi->display, xfi->gc, GXcopy); + XSetFillStyle(xfi->display, xfi->gc, FillSolid); + XSetForeground(xfi->display, xfi->gc, color); + XFillRectangle(xfi->display, xfi->drawing, xfi->gc, + opaque_rect->nLeftRect, opaque_rect->nTopRect, + opaque_rect->nWidth, opaque_rect->nHeight); + + if (xfi->drawing == xfi->primary) + { + XFillRectangle(xfi->display, xfi->window->handle, xfi->gc, + opaque_rect->nLeftRect, opaque_rect->nTopRect, + opaque_rect->nWidth, opaque_rect->nHeight); + } } void xf_gdi_multi_opaque_rect(rdpUpdate* update, MULTI_OPAQUE_RECT_ORDER* multi_opaque_rect) { + int i; + uint32 color; + DELTA_RECT* rectangle; + xfInfo* xfi = GET_XFI(update); + color = gdi_color_convert(multi_opaque_rect->color, xfi->srcBpp, xfi->bpp, xfi->clrconv); + + XSetFunction(xfi->display, xfi->gc, GXcopy); + XSetFillStyle(xfi->display, xfi->gc, FillSolid); + XSetForeground(xfi->display, xfi->gc, color); + + for (i = 1; i < multi_opaque_rect->numRectangles + 1; i++) + { + rectangle = &multi_opaque_rect->rectangles[i]; + + XFillRectangle(xfi->display, xfi->drawing, xfi->gc, + rectangle->left, rectangle->top, + rectangle->width, rectangle->height); + + if (xfi->drawing == xfi->primary) + { + XFillRectangle(xfi->display, xfi->window->handle, xfi->gc, + rectangle->left, rectangle->top, + rectangle->width, rectangle->height); + } + } } void xf_gdi_line_to(rdpUpdate* update, LINE_TO_ORDER* line_to) @@ -248,12 +382,28 @@ void xf_gdi_fast_index(rdpUpdate* update, FAST_INDEX_ORDER* fast_index) void xf_gdi_create_offscreen_bitmap(rdpUpdate* update, CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap) { + Pixmap surface; + xfInfo* xfi = GET_XFI(update); + surface = xf_bitmap_new(xfi, create_offscreen_bitmap->cx, create_offscreen_bitmap->cy, xfi->bpp, NULL); + + offscreen_put(xfi->cache->offscreen, create_offscreen_bitmap->id, (void*) surface); } void xf_gdi_switch_surface(rdpUpdate* update, SWITCH_SURFACE_ORDER* switch_surface) { + Pixmap surface; + xfInfo* xfi = GET_XFI(update); + if (switch_surface->bitmapId == SCREEN_BITMAP_SURFACE) + { + xfi->drawing = xfi->primary; + } + else + { + surface = (Pixmap) offscreen_get(xfi->cache->offscreen, switch_surface->bitmapId); + xfi->drawing = surface; + } } void xf_gdi_cache_bitmap_v2(rdpUpdate* update, CACHE_BITMAP_V2_ORDER* cache_bitmap_v2) diff --git a/client/X11/xfreerdp.c b/client/X11/xfreerdp.c index 2fe6fe6cc..48da95fb1 100644 --- a/client/X11/xfreerdp.c +++ b/client/X11/xfreerdp.c @@ -73,41 +73,44 @@ void xf_end_paint(rdpUpdate* update) if (xfi->remote_app != True) { -#if 1 - if (gdi->primary->hdc->hwnd->invalid->null) - return; - - x = gdi->primary->hdc->hwnd->invalid->x; - y = gdi->primary->hdc->hwnd->invalid->y; - w = gdi->primary->hdc->hwnd->invalid->w; - h = gdi->primary->hdc->hwnd->invalid->h; - - XPutImage(xfi->display, xfi->primary, xfi->gc, xfi->image, x, y, x, y, w, h); - XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc, x, y, w, h, x, y); -#else - int i; - int ninvalid; - HGDI_RGN* cinvalid; - - if (gdi->primary->hdc->hwnd->ninvalid < 1) - return; - - ninvalid = gdi->primary->hdc->hwnd->ninvalid; - cinvalid = gdi->primary->hdc->hwnd->cinvalid; - - for (i = 0; i < ninvalid; i++) + if (xfi->complex_regions != True) { - x = cinvalid[i]->x; - y = cinvalid[i]->y; - w = cinvalid[i]->w; - h = cinvalid[i]->h; + if (gdi->primary->hdc->hwnd->invalid->null) + return; + + x = gdi->primary->hdc->hwnd->invalid->x; + y = gdi->primary->hdc->hwnd->invalid->y; + w = gdi->primary->hdc->hwnd->invalid->w; + h = gdi->primary->hdc->hwnd->invalid->h; XPutImage(xfi->display, xfi->primary, xfi->gc, xfi->image, x, y, x, y, w, h); XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc, x, y, w, h, x, y); } + else + { + int i; + int ninvalid; + HGDI_RGN cinvalid; - XFlush(xfi->display); -#endif + if (gdi->primary->hdc->hwnd->ninvalid < 1) + return; + + ninvalid = gdi->primary->hdc->hwnd->ninvalid; + cinvalid = gdi->primary->hdc->hwnd->cinvalid; + + for (i = 0; i < ninvalid; i++) + { + x = cinvalid[i].x; + y = cinvalid[i].y; + w = cinvalid[i].w; + h = cinvalid[i].h; + + XPutImage(xfi->display, xfi->primary, xfi->gc, xfi->image, x, y, x, y, w, h); + XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc, x, y, w, h, x, y); + } + + XFlush(xfi->display); + } } else { @@ -293,6 +296,14 @@ boolean xf_pre_connect(freerdp* instance) xf_kbd_init(xfi); + xfi->clrconv = (HCLRCONV) malloc(sizeof(CLRCONV)); + xfi->clrconv->palette = NULL; + xfi->clrconv->alpha = 1; + xfi->clrconv->invert = 0; + xfi->clrconv->rgb555 = 0; + + xfi->cache = cache_new(instance->settings); + xfi->xfds = ConnectionNumber(xfi->display); xfi->screen_number = DefaultScreen(xfi->display); xfi->screen = ScreenOfDisplay(xfi->display, xfi->screen_number); @@ -300,6 +311,7 @@ boolean xf_pre_connect(freerdp* instance) xfi->big_endian = (ImageByteOrder(xfi->display) == MSBFirst); xfi->mouse_motion = False; + xfi->complex_regions = True; xfi->decoration = settings->decorations; xfi->remote_app = settings->remote_app; xfi->fullscreen = settings->fullscreen; @@ -381,7 +393,11 @@ boolean xf_post_connect(freerdp* instance) gdi_init(instance, CLRCONV_ALPHA | CLRBUF_32BPP); gdi = GET_GDI(instance->update); - //xf_gdi_register_update_callbacks(instance->update); + if (instance->settings->sw_gdi != True) + { + xfi->srcBpp = instance->settings->color_depth; + xf_gdi_register_update_callbacks(instance->update); + } if (xfi->fullscreen) xfi->decoration = False; @@ -423,6 +439,7 @@ boolean xf_post_connect(freerdp* instance) xfi->gc = XCreateGC(xfi->display, DefaultRootWindow(xfi->display), GCGraphicsExposures, &gcv); xfi->primary = XCreatePixmap(xfi->display, DefaultRootWindow(xfi->display), xfi->width, xfi->height, xfi->depth); + xfi->drawing = xfi->primary; XSetForeground(xfi->display, xfi->gc, BlackPixelOfScreen(xfi->screen)); XFillRectangle(xfi->display, xfi->primary, xfi->gc, 0, 0, xfi->width, xfi->height); @@ -701,6 +718,8 @@ int main(int argc, char* argv[]) chanman = freerdp_chanman_new(); SET_CHANMAN(instance, chanman); + instance->settings->sw_gdi = True; + if (freerdp_parse_args(instance->settings, argc, argv, xf_process_plugin_args, chanman, xf_process_ui_args, NULL) < 0) return 1; diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index dc88c3ef2..38a9792cd 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -26,6 +26,7 @@ #include #include #include +#include typedef struct xf_info xfInfo; @@ -54,9 +55,11 @@ struct xf_info int depth; int width; int height; + int srcBpp; Screen* screen; XImage* image; Pixmap primary; + Pixmap drawing; Visual* visual; Display* display; Colormap colormap; @@ -71,7 +74,9 @@ struct xf_info xfWorkArea workArea; int current_desktop; boolean remote_app; + HCLRCONV clrconv; rdpRail* rail; + rdpCache* cache; boolean focused; boolean mouse_active; @@ -81,6 +86,7 @@ struct xf_info boolean pressed_keys[256]; XModifierKeymap* modifier_map; XSetWindowAttributes attribs; + boolean complex_regions; Atom _NET_WM_ICON; Atom _MOTIF_WM_HINTS; diff --git a/cunit/CMakeLists.txt b/cunit/CMakeLists.txt index 5b5171259..88fe5cc3f 100644 --- a/cunit/CMakeLists.txt +++ b/cunit/CMakeLists.txt @@ -44,6 +44,8 @@ add_executable(test_freerdp test_list.h test_orders.c test_orders.h + test_pcap.c + test_pcap.h test_license.c test_license.h test_stream.c diff --git a/cunit/test_freerdp.c b/cunit/test_freerdp.c index d07206914..d5ffa047c 100644 --- a/cunit/test_freerdp.c +++ b/cunit/test_freerdp.c @@ -37,6 +37,7 @@ #include "test_librfx.h" #include "test_freerdp.h" #include "test_rail.h" +#include "test_pcap.h" void dump_data(unsigned char * p, int len, int width, char* name) { @@ -188,6 +189,10 @@ int main(int argc, char* argv[]) { add_per_suite(); } + else if (strcmp("pcap", argv[*pindex]) == 0) + { + add_pcap_suite(); + } else if (strcmp("ber", argv[*pindex]) == 0) { add_ber_suite(); diff --git a/cunit/test_pcap.c b/cunit/test_pcap.c new file mode 100644 index 000000000..d18856f4d --- /dev/null +++ b/cunit/test_pcap.c @@ -0,0 +1,99 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * pcap File Format Unit Tests + * + * Copyright 2011 Marc-Andre Moreau + * + * 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. + */ + +#include +#include +#include + +#include "test_pcap.h" + +int init_pcap_suite(void) +{ + return 0; +} + +int clean_pcap_suite(void) +{ + return 0; +} + +int add_pcap_suite(void) +{ + add_test_suite(pcap); + + add_test_function(pcap); + + return 0; +} + +uint8 test_packet_1[16] = + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"; + +uint8 test_packet_2[32] = + "\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB" + "\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB"; + +uint8 test_packet_3[64] = + "\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC" + "\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC" + "\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC" + "\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC"; + +typedef struct +{ + void* data; + uint32 length; +} test_packet; + +void test_pcap(void) +{ + rdpPcap* pcap; + pcap_record record; + test_packet packets[3]; + + packets[0].data = test_packet_1; + packets[0].length = sizeof(test_packet_1); + packets[1].data = test_packet_2; + packets[1].length = sizeof(test_packet_2); + packets[2].data = test_packet_3; + packets[2].length = sizeof(test_packet_3); + + pcap = pcap_open("/tmp/test.pcap", True); + pcap_add_record(pcap, test_packet_1, sizeof(test_packet_1)); + pcap_flush(pcap); + pcap_add_record(pcap, test_packet_2, sizeof(test_packet_2)); + pcap_flush(pcap); + pcap_add_record(pcap, test_packet_3, sizeof(test_packet_3)); + pcap_close(pcap); + + pcap = pcap_open("/tmp/test.pcap", False); + + int i = 0; + while (pcap_has_next_record(pcap)) + { + pcap_get_next_record(pcap, &record); + CU_ASSERT(record.length == packets[i].length) + i++; + } + + CU_ASSERT(i == 3); + + pcap_close(pcap); +} + diff --git a/cunit/test_pcap.h b/cunit/test_pcap.h new file mode 100644 index 000000000..f506edcaa --- /dev/null +++ b/cunit/test_pcap.h @@ -0,0 +1,26 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * pcap File Format Unit Tests + * + * Copyright 2011 Marc-Andre Moreau + * + * 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. + */ + +#include "test_freerdp.h" + +int init_pcap_suite(void); +int clean_pcap_suite(void); +int add_pcap_suite(void); + +void test_pcap(void); diff --git a/include/freerdp/gdi/gdi.h b/include/freerdp/gdi/gdi.h index 2eac3fb5b..75c1d0f51 100644 --- a/include/freerdp/gdi/gdi.h +++ b/include/freerdp/gdi/gdi.h @@ -193,9 +193,10 @@ typedef GDI_BRUSH* HGDI_BRUSH; struct _GDI_WND { + int count; int ninvalid; HGDI_RGN invalid; - HGDI_RGN* cinvalid; + HGDI_RGN cinvalid; }; typedef struct _GDI_WND GDI_WND; typedef GDI_WND* HGDI_WND; @@ -216,7 +217,6 @@ struct _GDI_DC int alpha; int invert; int rgb555; - int complex; }; typedef struct _GDI_DC GDI_DC; typedef GDI_DC* HGDI_DC; diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 8af844120..cc870e9d9 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -176,6 +176,7 @@ struct rdp_settings { uint16 width; uint16 height; + boolean sw_gdi; boolean workarea; boolean fullscreen; boolean decorations; @@ -296,6 +297,9 @@ struct rdp_settings uint8 rfx_codec_id; boolean frame_acknowledge; + boolean dump_rfx; + char* dump_rfx_file; + boolean remote_app; uint8 num_icon_caches; uint16 num_icon_cache_entries; diff --git a/include/freerdp/update.h b/include/freerdp/update.h index 591d5bef2..006f624b2 100644 --- a/include/freerdp/update.h +++ b/include/freerdp/update.h @@ -22,6 +22,8 @@ #include #include +#include +#include /* Common */ @@ -1063,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 { @@ -1072,6 +1075,9 @@ struct rdp_update void* param1; void* param2; + boolean dump_rfx; + rdpPcap* pcap_rfx; + pcBeginPaint BeginPaint; pcEndPaint EndPaint; pcSetBounds SetBounds; @@ -1142,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 new file mode 100644 index 000000000..a431fbc60 --- /dev/null +++ b/include/freerdp/utils/pcap.h @@ -0,0 +1,83 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * pcap File Format Utils + * + * Copyright 2011 Marc-Andre Moreau + * + * 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. + */ + +#ifndef __UTILS_PCAP_H +#define __UTILS_PCAP_H + +#include +#include +#include + +struct _pcap_header +{ + uint32 magic_number; /* magic number */ + uint16 version_major; /* major version number */ + uint16 version_minor; /* minor version number */ + sint32 thiszone; /* GMT to local correction */ + uint32 sigfigs; /* accuracy of timestamps */ + uint32 snaplen; /* max length of captured packets, in octets */ + uint32 network; /* data link type */ +}; +typedef struct _pcap_header pcap_header; + +struct _pcap_record_header +{ + uint32 ts_sec; /* timestamp seconds */ + uint32 ts_usec; /* timestamp microseconds */ + uint32 incl_len; /* number of octets of packet saved in file */ + uint32 orig_len; /* actual length of packet */ +}; +typedef struct _pcap_record_header pcap_record_header; + +typedef struct _pcap_record pcap_record; + +struct _pcap_record +{ + pcap_record_header header; + void* data; + uint32 length; + pcap_record* next; +}; + +struct rdp_pcap +{ + FILE* fp; + char* name; + STOPWATCH* sw; + boolean write; + int file_size; + int record_count; + pcap_header header; + pcap_record* head; + pcap_record* tail; + pcap_record* record; +}; +typedef struct rdp_pcap rdpPcap; + +FREERDP_API rdpPcap* pcap_open(char* name, boolean write); +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/include/freerdp/utils/stopwatch.h b/include/freerdp/utils/stopwatch.h index c7fa46457..58d7be5e1 100644 --- a/include/freerdp/utils/stopwatch.h +++ b/include/freerdp/utils/stopwatch.h @@ -22,6 +22,7 @@ #include #include +#include #include struct _STOPWATCH @@ -40,6 +41,7 @@ FREERDP_API void stopwatch_start(STOPWATCH* stopwatch); FREERDP_API void stopwatch_stop(STOPWATCH* stopwatch); FREERDP_API void stopwatch_reset(STOPWATCH* stopwatch); -double stopwatch_get_elapsed_time_in_seconds(STOPWATCH* stopwatch); +FREERDP_API double stopwatch_get_elapsed_time_in_seconds(STOPWATCH* stopwatch); +FREERDP_API void stopwatch_get_elapsed_time_in_useconds(STOPWATCH* stopwatch, uint32* sec, uint32* usec); #endif /* __UTILS_STOPWATCH_H */ diff --git a/libfreerdp-core/fastpath.c b/libfreerdp-core/fastpath.c index 155a036bf..848170080 100644 --- a/libfreerdp-core/fastpath.c +++ b/libfreerdp-core/fastpath.c @@ -38,7 +38,7 @@ * two less significant bits of the first byte. */ -#define FASTPATH_MAX_PACKET_SIZE 0x7FFF +#define FASTPATH_MAX_PACKET_SIZE 0x3FFF /** * Read a Fast-Path packet header.\n @@ -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; @@ -519,7 +549,7 @@ boolean fastpath_send_surfcmd_surface_bits(rdpFastPath* fastpath, SURFACE_BITS_C size += SURFCMD_SURFACE_BITS_HEADER_LENGTH; } - fragment_size = MIN(stream_get_left(s), bitmapDataLength); + 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); 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/freerdp.c b/libfreerdp-core/freerdp.c index 504079fc9..4b06392e5 100644 --- a/libfreerdp-core/freerdp.c +++ b/libfreerdp-core/freerdp.c @@ -34,9 +34,19 @@ boolean freerdp_connect(freerdp* instance) rdp = (rdpRdp*) instance->rdp; IFCALL(instance->PreConnect, instance); + status = rdp_client_connect((rdpRdp*) instance->rdp); + if (status) + { + if (instance->settings->dump_rfx) + { + instance->update->dump_rfx = instance->settings->dump_rfx; + instance->update->pcap_rfx = pcap_open(instance->settings->dump_rfx_file, True); + } + IFCALL(instance->PostConnect, instance); + } return status; } diff --git a/libfreerdp-core/mcs.c b/libfreerdp-core/mcs.c index f884ba633..01c75e69a 100644 --- a/libfreerdp-core/mcs.c +++ b/libfreerdp-core/mcs.c @@ -792,6 +792,26 @@ boolean mcs_send_channel_join_confirm(rdpMcs* mcs, uint16 channel_id) return True; } +/** + * Send MCS Disconnect Provider Ultimatum PDU.\n + * @param mcs mcs module + */ + +boolean mcs_send_disconnect_provider_ultimatum(rdpMcs* mcs) +{ + STREAM* s; + uint16 length = 9; + s = transport_send_stream_init(mcs->transport, 9); + + mcs_write_domain_mcspdu_header(s, DomainMCSPDU_DisconnectProviderUltimatum, length, 1); + + per_write_enumerated(s, 0, 0); /* reason */ + + transport_write(mcs->transport, s); + + return True; +} + /** * Instantiate new MCS module. * @param transport transport diff --git a/libfreerdp-core/mcs.h b/libfreerdp-core/mcs.h index f7ecc1ea0..97dcf40f7 100644 --- a/libfreerdp-core/mcs.h +++ b/libfreerdp-core/mcs.h @@ -146,6 +146,7 @@ boolean mcs_recv_channel_join_request(rdpMcs* mcs, STREAM* s, uint16* channel_id boolean mcs_send_channel_join_request(rdpMcs* mcs, uint16 channel_id); boolean mcs_recv_channel_join_confirm(rdpMcs* mcs, STREAM* s, uint16* channel_id); boolean mcs_send_channel_join_confirm(rdpMcs* mcs, uint16 channel_id); +boolean mcs_send_disconnect_provider_ultimatum(rdpMcs* mcs); boolean mcs_read_domain_mcspdu_header(STREAM* s, enum DomainMCSPDU* domainMCSPDU, uint16* length); void mcs_write_domain_mcspdu_header(STREAM* s, enum DomainMCSPDU domainMCSPDU, uint16 length, uint8 options); diff --git a/libfreerdp-core/peer.c b/libfreerdp-core/peer.c index 8493977b1..529bc1d62 100644 --- a/libfreerdp-core/peer.c +++ b/libfreerdp-core/peer.c @@ -89,6 +89,10 @@ static boolean peer_recv_data_pdu(rdpPeer* peer, STREAM* s) } break; + case DATA_PDU_TYPE_SHUTDOWN_REQUEST: + mcs_send_disconnect_provider_ultimatum(peer->rdp->mcs); + return False; + default: printf("Data PDU type %d\n", type); break; diff --git a/libfreerdp-core/surface.c b/libfreerdp-core/surface.c index 6c17e310c..fb3075c4f 100644 --- a/libfreerdp-core/surface.c +++ b/libfreerdp-core/surface.c @@ -17,12 +17,14 @@ * limitations under the License. */ +#include + #include "surface.h" 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); @@ -60,6 +62,12 @@ 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) { stream_read_uint16(s, cmdType); diff --git a/libfreerdp-core/tls.c b/libfreerdp-core/tls.c index d8299b3c3..09139f2e1 100644 --- a/libfreerdp-core/tls.c +++ b/libfreerdp-core/tls.c @@ -124,6 +124,7 @@ boolean tls_accept(rdpTls* tls, const char* cert_file, const char* privatekey_fi boolean tls_disconnect(rdpTls* tls) { + SSL_shutdown(tls->ssl); return True; } diff --git a/libfreerdp-core/update.c b/libfreerdp-core/update.c index b5475e199..b63e4b8a0 100644 --- a/libfreerdp-core/update.c +++ b/libfreerdp-core/update.c @@ -77,8 +77,7 @@ void update_read_bitmap_data(STREAM* s, BITMAP_DATA* bitmap_data) dstSize = cbUncompressedSize; bitmap_data->length = cbCompMainBodySize; - - bitmap_data->data = (uint8*) xzalloc(dstSize); + bitmap_data->data = (uint8*) xmalloc(dstSize); stream_get_mark(s, srcData); stream_seek(s, bitmap_data->length); @@ -323,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); } @@ -363,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-gdi/gdi.c b/libfreerdp-gdi/gdi.c index 6af25762b..685f073bf 100644 --- a/libfreerdp-gdi/gdi.c +++ b/libfreerdp-gdi/gdi.c @@ -308,7 +308,7 @@ inline uint32 gdi_rop3_code(uint8 code) inline void gdi_copy_mem(uint8 * d, uint8 * s, int n) { - memcpy(d, s, n); + memmove(d, s, n); } inline void gdi_copy_mem_backwards(uint8 * d, uint8 * s, int n) @@ -949,7 +949,6 @@ int gdi_init(freerdp* instance, uint32 flags) gdi->hdc->alpha = gdi->clrconv->alpha; gdi->hdc->invert = gdi->clrconv->invert; gdi->hdc->rgb555 = gdi->clrconv->rgb555; - gdi->hdc->complex = 1; gdi->primary = gdi_bitmap_new(gdi, gdi->width, gdi->height, gdi->dstBpp, NULL); gdi->primary_buffer = gdi->primary->bitmap->data; @@ -958,7 +957,9 @@ int gdi_init(freerdp* instance, uint32 flags) gdi->primary->hdc->hwnd = (HGDI_WND) malloc(sizeof(GDI_WND)); gdi->primary->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0); gdi->primary->hdc->hwnd->invalid->null = 1; - gdi->primary->hdc->hwnd->cinvalid = NULL; + + gdi->primary->hdc->hwnd->count = 32; + gdi->primary->hdc->hwnd->cinvalid = (HGDI_RGN) malloc(sizeof(GDI_RGN) * gdi->primary->hdc->hwnd->count); gdi->primary->hdc->hwnd->ninvalid = 0; gdi->tile = gdi_bitmap_new(gdi, 64, 64, 32, NULL); diff --git a/libfreerdp-gdi/region.c b/libfreerdp-gdi/region.c index bd31f5393..249b41fb9 100644 --- a/libfreerdp-gdi/region.c +++ b/libfreerdp-gdi/region.c @@ -374,35 +374,25 @@ inline int gdi_InvalidateRegion(HGDI_DC hdc, int x, int y, int w, int h) GDI_RECT inv; GDI_RECT rgn; HGDI_RGN invalid; + HGDI_RGN cinvalid; if (hdc->hwnd == NULL) return 0; - if (hdc->complex) - { - HGDI_RGN* cinvalid; - - cinvalid = hdc->hwnd->cinvalid; - - if (hdc->hwnd->ninvalid <= 0) - { - hdc->hwnd->ninvalid = 0; - cinvalid = (HGDI_RGN*) malloc(sizeof(HGDI_RGN)); - } - else - { - cinvalid = (HGDI_RGN*) realloc(cinvalid, sizeof(HGDI_RGN) * (hdc->hwnd->ninvalid + 1)); - } - - invalid = gdi_CreateRectRgn(x, y, x + w - 1, y + h - 1); - cinvalid[hdc->hwnd->ninvalid] = invalid; - hdc->hwnd->cinvalid = cinvalid; - hdc->hwnd->ninvalid++; - } - if (hdc->hwnd->invalid == NULL) return 0; + cinvalid = hdc->hwnd->cinvalid; + + if (hdc->hwnd->ninvalid + 1 > hdc->hwnd->count) + { + hdc->hwnd->count *= 2; + cinvalid = (HGDI_RGN) realloc(cinvalid, sizeof(GDI_RGN) * (hdc->hwnd->count)); + } + + gdi_SetRgn(&cinvalid[hdc->hwnd->ninvalid++], x, y, w, h); + hdc->hwnd->cinvalid = cinvalid; + invalid = hdc->hwnd->invalid; if (invalid->null) diff --git a/libfreerdp-utils/CMakeLists.txt b/libfreerdp-utils/CMakeLists.txt index a0b6037dd..cb7adbfbc 100644 --- a/libfreerdp-utils/CMakeLists.txt +++ b/libfreerdp-utils/CMakeLists.txt @@ -30,6 +30,7 @@ set(FREERDP_UTILS_SRCS load_plugin.c memory.c mutex.c + pcap.c profiler.c rail.c registry.c diff --git a/libfreerdp-utils/args.c b/libfreerdp-utils/args.c index 32d392c0f..2d177d306 100644 --- a/libfreerdp-utils/args.c +++ b/libfreerdp-utils/args.c @@ -51,7 +51,47 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, while (index < argc) { - if (strcmp("-a", argv[index]) == 0) + if ((strcmp("-h", argv[index]) == 0 ) || (strcmp("--help", argv[index]) == 0 )) + { + printf("\n" + "FreeRDP - A Free Remote Desktop Protocol Client\n" + "See http://www.freerdp.com for more information\n" + "\n" + "Usage: %s [options] server:port\n" + " -0: connect to console session\n" + " -a: set color depth in bit, default is 16\n" + " -c: initial working directory\n" + " -D: hide window decorations\n" + " -d: domain\n" + " -f: fullscreen mode\n" + " -g: set geometry, using format WxH or X%% or 'workarea', default is 1024x768\n" + " -h: print this help\n" + " -k: set keyboard layout ID\n" + " -m: don't send mouse motion events\n" + " -n: hostname\n" + " -o: console audio\n" + " -p: password\n" + " -s: set startup-shell\n" + " -t: alternative port number, default is 3389\n" + " -u: username\n" + " -x: performance flags (m[odem], b[roadband] or l[an])\n" + " -z: enable compression\n" + " --app: RemoteApp connection. This implies -g workarea\n" + " --ext: load an extension\n" + " --no-auth: disable authentication\n" + " --no-fastpath: disable fast-path\n" + " --no-osb: disable off screen bitmaps, default on\n" + " --plugin: load a virtual channel plugin\n" + " --rfx: enable RemoteFX\n" + " --no-rdp: disable Standard RDP encryption\n" + " --no-tls: disable TLS encryption\n" + " --no-nla: disable network level authentication\n" + " --sec: force protocol security (rdp, tls or nla)\n" + " --version: print version information\n" + "\n", argv[0]); + return -1; //TODO: What is the correct return + } + else if (strcmp("-a", argv[index]) == 0) { index++; if (index == argc) @@ -211,6 +251,28 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, settings->fastpath_input = False; settings->fastpath_output = False; } + else if (strcmp("--gdi", argv[index]) == 0) + { + index++; + if (index == argc) + { + printf("missing GDI backend\n"); + return -1; + } + if (strncmp("sw", argv[index], 1) == 0) /* software */ + { + settings->sw_gdi = True; + } + else if (strncmp("hw", argv[index], 1) == 0) /* hardware */ + { + settings->sw_gdi = False; + } + else + { + printf("unknown GDI backend\n"); + return -1; + } + } else if (strcmp("--rfx", argv[index]) == 0) { settings->rfx_codec = True; @@ -220,6 +282,17 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, settings->performance_flags = PERF_FLAG_NONE; settings->large_pointer = True; } + else if (strcmp("--dump-rfx", argv[index]) == 0) + { + index++; + if (index == argc) + { + printf("missing file name\n"); + return -1; + } + settings->dump_rfx_file = xstrdup(argv[index]); + settings->dump_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 new file mode 100644 index 000000000..a0ca538c8 --- /dev/null +++ b/libfreerdp-utils/pcap.c @@ -0,0 +1,193 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * pcap File Format Utils + * + * Copyright 2011 Marc-Andre Moreau + * + * 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. + */ + +#include +#include +#include + +#include +#include + +#include + +#define PCAP_MAGIC 0xA1B2C3D4 + +void pcap_read_header(rdpPcap* pcap, pcap_header* header) +{ + fread((void*) header, sizeof(pcap_header), 1, pcap->fp); +} + +void pcap_write_header(rdpPcap* pcap, pcap_header* header) +{ + fwrite((void*) header, sizeof(pcap_header), 1, pcap->fp); +} + +void pcap_read_record_header(rdpPcap* pcap, pcap_record_header* record) +{ + fread((void*) record, sizeof(pcap_record_header), 1, pcap->fp); +} + +void pcap_write_record_header(rdpPcap* pcap, pcap_record_header* record) +{ + fwrite((void*) record, sizeof(pcap_record_header), 1, pcap->fp); +} + +void pcap_read_record(rdpPcap* pcap, pcap_record* record) +{ + pcap_read_record_header(pcap, &record->header); + record->length = record->header.incl_len; + record->data = xmalloc(record->length); + fread(record->data, record->length, 1, pcap->fp); +} + +void pcap_write_record(rdpPcap* pcap, pcap_record* record) +{ + pcap_write_record_header(pcap, &record->header); + fwrite(record->data, record->length, 1, pcap->fp); +} + +void pcap_add_record(rdpPcap* pcap, void* data, uint32 length) +{ + pcap_record* record; + + if (pcap->tail == NULL) + { + pcap->tail = (pcap_record*) xzalloc(sizeof(pcap_record)); + pcap->head = pcap->tail; + pcap->record = pcap->head; + record = pcap->tail; + } + else + { + record = (pcap_record*) xzalloc(sizeof(pcap_record)); + pcap->tail->next = record; + pcap->tail = record; + } + + if (pcap->record == NULL) + pcap->record = record; + + record->data = data; + record->length = length; + record->header.incl_len = length; + record->header.orig_len = length; + + stopwatch_stop(pcap->sw); + stopwatch_get_elapsed_time_in_useconds(pcap->sw, &record->header.ts_sec, &record->header.ts_usec); + stopwatch_start(pcap->sw); +} + +boolean pcap_has_next_record(rdpPcap* pcap) +{ + if (pcap->file_size - (ftell(pcap->fp)) <= 16) + return False; + + 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) + return False; + + pcap_read_record(pcap, record); + + return True; +} + +rdpPcap* pcap_open(char* name, boolean write) +{ + rdpPcap* pcap; + + pcap = (rdpPcap*) xzalloc(sizeof(rdpPcap)); + + if (pcap != NULL) + { + pcap->name = name; + pcap->write = write; + pcap->record_count = 0; + + if (write) + { + pcap->fp = fopen(name, "w+"); + pcap->header.magic_number = 0xA1B2C3D4; + pcap->header.version_major = 2; + pcap->header.version_minor = 4; + pcap->header.thiszone = 0; + pcap->header.sigfigs = 0; + pcap->header.snaplen = 65535; + pcap->header.network = 0; + pcap_write_header(pcap, &pcap->header); + } + else + { + pcap->fp = fopen(name, "r"); + fseek(pcap->fp, 0, SEEK_END); + pcap->file_size = (int) ftell(pcap->fp); + fseek(pcap->fp, 0, SEEK_SET); + pcap_read_header(pcap, &pcap->header); + } + + pcap->sw = stopwatch_create(); + stopwatch_start(pcap->sw); + } + + return pcap; +} + +void pcap_flush(rdpPcap* pcap) +{ + while (pcap->record != NULL) + { + pcap_write_record(pcap, pcap->record); + pcap->record = pcap->record->next; + } + + if (pcap->fp != NULL) + fflush(pcap->fp); +} + +void pcap_close(rdpPcap* pcap) +{ + pcap_flush(pcap); + + if (pcap->fp != NULL) + fclose(pcap->fp); + + stopwatch_stop(pcap->sw); + stopwatch_free(pcap->sw); +} diff --git a/libfreerdp-utils/stopwatch.c b/libfreerdp-utils/stopwatch.c index 55b814f06..e74c1d909 100644 --- a/libfreerdp-utils/stopwatch.c +++ b/libfreerdp-utils/stopwatch.c @@ -56,5 +56,15 @@ void stopwatch_reset(STOPWATCH* stopwatch) double stopwatch_get_elapsed_time_in_seconds(STOPWATCH* stopwatch) { - return ((double)stopwatch->elapsed) / CLOCKS_PER_SEC; + return ((double) stopwatch->elapsed) / CLOCKS_PER_SEC; } + +void stopwatch_get_elapsed_time_in_useconds(STOPWATCH* stopwatch, uint32* sec, uint32* usec) +{ + double uelapsed; + + *sec = ((uint32) stopwatch->elapsed) / CLOCKS_PER_SEC; + uelapsed = stopwatch->elapsed - ((double)(*sec) * CLOCKS_PER_SEC); + *usec = (uelapsed / (CLOCKS_PER_SEC / 1000000)); +} + diff --git a/server/test/freerdp_server.c b/server/test/freerdp_server.c index b474cabb5..afab4a8b9 100644 --- a/server/test/freerdp_server.c +++ b/server/test/freerdp_server.c @@ -183,7 +183,7 @@ static void test_peer_draw_icon(freerdp_peer* client, int x, int y) RFX_RECT rect; STREAM* s; - if (!client->settings->rfx_codec) + if (!client->settings->rfx_codec || !info) return; if (info->icon_width < 1) return; @@ -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; }