diff --git a/.gitignore b/.gitignore index 99a76ffaa..0dcd5daa7 100644 --- a/.gitignore +++ b/.gitignore @@ -14,8 +14,9 @@ Makefile *.cproject *.settings -# Doxygen +# Documentation docs/api +client/X11/xfreerdp.1 # Mac OS X .DS_Store diff --git a/channels/rdpsnd/pulse/rdpsnd_pulse.c b/channels/rdpsnd/pulse/rdpsnd_pulse.c index af316fbe7..1b2c59473 100644 --- a/channels/rdpsnd/pulse/rdpsnd_pulse.c +++ b/channels/rdpsnd/pulse/rdpsnd_pulse.c @@ -122,6 +122,8 @@ static void rdpsnd_pulse_stream_success_callback(pa_stream* stream, int success, static void rdpsnd_pulse_wait_for_operation(rdpsndPulsePlugin* pulse, pa_operation* operation) { + if (operation == NULL) + return; while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) { pa_threaded_mainloop_wait(pulse->mainloop); diff --git a/client/X11/CMakeLists.txt b/client/X11/CMakeLists.txt index 38364105d..2311d1250 100644 --- a/client/X11/CMakeLists.txt +++ b/client/X11/CMakeLists.txt @@ -17,6 +17,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +include(FindXmlto) include_directories(${X11_INCLUDE_DIRS}) add_executable(xfreerdp @@ -32,26 +33,41 @@ add_executable(xfreerdp xf_window.h xfreerdp.c xfreerdp.h) - + +if(WITH_MANPAGES) + if(XMLTO_FOUND) + add_custom_command(OUTPUT xfreerdp.1 + COMMAND ${XMLTO_EXECUTABLE} man ${CMAKE_CURRENT_SOURCE_DIR}/xfreerdp.1.xml + DEPENDS xfreerdp.1.xml) + + add_custom_target(xfreerdp.manpage ALL + DEPENDS xfreerdp.1) + + install(FILES xfreerdp.1 DESTINATION share/man/man1) + else(XMLTO_FOUND) + message(WARNING "WITH_MANPAGES was set, but xmlto was not found. man-pages will not be installed") + endif(XMLTO_FOUND) +endif(WITH_MANPAGES) + find_package(Xinerama) if(XINERAMA_FOUND) - add_definitions(-DWITH_XINERAMA) + add_definitions(-DWITH_XINERAMA -DWITH_XEXT) include_directories(${XINERAMA_INCLUDE_DIRS}) target_link_libraries(xfreerdp ${XINERAMA_LIBRARIES}) endif() find_package(Xext) -if(Xext_FOUND) +if(XEXT_FOUND) add_definitions(-DWITH_XEXT) - include_directories(${Xext_INCLUDE_DIRS}) - target_link_libraries(xfreerdp ${Xext_LIBRARIES}) + include_directories(${XEXT_INCLUDE_DIRS}) + target_link_libraries(xfreerdp ${XEXT_LIBRARIES}) endif() find_package(Xcursor) if(Xcursor_FOUND) add_definitions(-DWITH_XCURSOR) include_directories(${Xcursor_INCLUDE_DIRS}) - target_link_libraries(xfreerdp ${Xext_LIBRARIES}) + target_link_libraries(xfreerdp ${Xcursor_LIBRARIES}) endif() target_link_libraries(xfreerdp freerdp-core) @@ -63,3 +79,4 @@ target_link_libraries(xfreerdp freerdp-utils) target_link_libraries(xfreerdp ${X11_LIBRARIES}) install(TARGETS xfreerdp DESTINATION bin) + diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c index 15dc8ddd8..11bc57c9d 100644 --- a/client/X11/xf_event.c +++ b/client/X11/xf_event.c @@ -343,7 +343,7 @@ boolean xf_event_FocusIn(xfInfo* xfi, XEvent* event, boolean app) if (xfi->mouse_active && (app != True)) XGrabKeyboard(xfi->display, xfi->window->handle, True, GrabModeAsync, GrabModeAsync, CurrentTime); - xf_rail_send_activate(xfi, event->xany.window, True); + //xf_rail_send_activate(xfi, event->xany.window, True); xf_kbd_focus_in(xfi); return True; @@ -359,7 +359,7 @@ boolean xf_event_FocusOut(xfInfo* xfi, XEvent* event, boolean app) if (event->xfocus.mode == NotifyWhileGrabbed) XUngrabKeyboard(xfi->display, CurrentTime); - xf_rail_send_activate(xfi, event->xany.window, False); + //xf_rail_send_activate(xfi, event->xany.window, False); return True; } @@ -476,7 +476,7 @@ boolean xf_event_process(freerdp* instance, XEvent* event) app = True; } -#if 1 +#if 0 if (event->type != MotionNotify) printf("X11 %s Event: wnd=0x%X\n", X11_EVENT_STRINGS[event->type], (uint32)event->xany.window); #endif diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c index c43f47dc9..ca815a771 100644 --- a/client/X11/xf_rail.c +++ b/client/X11/xf_rail.c @@ -82,6 +82,7 @@ void xf_rail_CreateWindow(rdpRail* rail, rdpWindow* window) window->windowId, window->ownerWindowId); xfparent = NULL; + if (window->ownerWindowId != 0) { rdpWindow* p = NULL; @@ -89,7 +90,7 @@ void xf_rail_CreateWindow(rdpRail* rail, rdpWindow* window) p = window_list_get_by_id(xfi->rail->list, window->ownerWindowId); if (p != NULL) - xfparent = (xfWindow *)p->extra; + xfparent = (xfWindow *) p->extra; } xfw = xf_CreateWindow((xfInfo*) rail->extra, xfparent, @@ -97,10 +98,10 @@ void xf_rail_CreateWindow(rdpRail* rail, rdpWindow* window) window->windowWidth, window->windowHeight, window->windowId); - XStoreName(xfi->display, xfw->handle, window->title); - xf_SetWindowStyle(xfi, xfw, window->style, window->extendedStyle); + XStoreName(xfi->display, xfw->handle, window->title); + window->extra = (void*) xfw; window->extraId = (void*) xfw->handle; } @@ -165,6 +166,17 @@ void xf_rail_SetWindowRects(rdpRail* rail, rdpWindow* window) xf_SetWindowRects(xfi, xfw, window->windowRects, window->numWindowRects); } +void xf_rail_SetWindowVisibilityRects(rdpRail* rail, rdpWindow* window) +{ + xfInfo* xfi; + xfWindow* xfw; + + xfi = (xfInfo*) rail->extra; + xfw = (xfWindow*) window->extra; + + xf_SetWindowVisibilityRects(xfi, xfw, window->windowRects, window->numWindowRects); +} + void xf_rail_DestroyWindow(rdpRail* rail, rdpWindow* window) { xfWindow* xfw; @@ -181,6 +193,7 @@ void xf_rail_register_callbacks(xfInfo* xfi, rdpRail* rail) rail->SetWindowText = xf_rail_SetWindowText; rail->SetWindowIcon = xf_rail_SetWindowIcon; rail->SetWindowRects = xf_rail_SetWindowRects; + rail->SetWindowVisibilityRects = xf_rail_SetWindowVisibilityRects; rail->DestroyWindow = xf_rail_DestroyWindow; } diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c index 2a22bb0f7..28f9a45ee 100644 --- a/client/X11/xf_window.c +++ b/client/X11/xf_window.c @@ -41,9 +41,6 @@ struct _PropMotifWmHints }; typedef struct _PropMotifWmHints PropMotifWmHints; -void xf_ReferenceWindow(xfInfo* xfi, xfWindow* window); -void xf_DereferenceWindow(xfInfo* xfi, xfWindow* window); - void xf_SendClientMessage(xfInfo* xfi, xfWindow* window, Atom atom, long msg, long d1, long d2, long d3) { XEvent xevent; @@ -162,43 +159,38 @@ void xf_SetWindowDecorations(xfInfo* xfi, xfWindow* window, boolean show) window->decorations = show; } +void xf_SetWindowUnlisted(xfInfo* xfi, xfWindow* window) +{ + Atom window_state[2]; + + window_state[0] = xfi->_NET_WM_STATE_SKIP_PAGER; + window_state[1] = xfi->_NET_WM_STATE_SKIP_TASKBAR; + + XChangeProperty(xfi->display, window->handle, xfi->_NET_WM_STATE, + XA_ATOM, 32, PropModeReplace, (uint8*) &window_state, 2); +} + void xf_SetWindowStyle(xfInfo* xfi, xfWindow* window, uint32 style, uint32 ex_style) { Atom window_type; window_type = xfi->_NET_WM_WINDOW_TYPE_NORMAL; - if (((style & WS_POPUP) !=0) || - ((style & WS_DLGFRAME) != 0) || - ((ex_style & WS_EX_DLGMODALFRAME) != 0) - ) + if ((style & WS_POPUP) || (style & WS_DLGFRAME) || (ex_style & WS_EX_DLGMODALFRAME)) { window_type = xfi->_NET_WM_WINDOW_TYPE_DIALOG; } - else if ((ex_style & WS_EX_TOOLWINDOW) != 0) + + if (ex_style & WS_EX_TOOLWINDOW) { + xf_SetWindowUnlisted(xfi, window); window_type = xfi->_NET_WM_WINDOW_TYPE_UTILITY; } XChangeProperty(xfi->display, window->handle, xfi->_NET_WM_WINDOW_TYPE, - xfi->_NET_WM_WINDOW_TYPE, 32, PropModeReplace, (unsigned char*)&window_type, 1); + XA_ATOM, 32, PropModeReplace, (uint8*) &window_type, 1); } -void xf_SetWindowChildState(xfInfo* xfi, xfWindow* window) -{ - Atom window_state[2]; - - if (window->parent != NULL) - { - window_state[0] = xfi->_NET_WM_STATE_SKIP_PAGER; - window_state[1] = xfi->_NET_WM_STATE_SKIP_TASKBAR; - - XChangeProperty(xfi->display, window->handle, xfi->_NET_WM_STATE, - xfi->_NET_WM_STATE, 32, PropModeReplace, (unsigned char*)&window_state, 2); - } -} - - xfWindow* xf_CreateDesktopWindow(xfInfo* xfi, char* name, int width, int height) { xfWindow* window; @@ -295,36 +287,18 @@ xfWindow* xf_CreateWindow(xfInfo* xfi, xfWindow* parent, int x, int y, int width XGCValues gcv; int input_mask; XClassHint* class_hints; - Window parent_handle; - int lx; - int ly; window->ref_count = 0; window->decorations = False; window->fullscreen = False; window->parent = parent; - lx = x; - ly = y; - parent_handle = RootWindowOfScreen(xfi->screen); - - if (window->parent != NULL) - { - lx = x - window->parent->left; - ly = y - window->parent->top; - parent_handle = parent->handle; - } - - window->handle = XCreateWindow(xfi->display, parent_handle, - lx, ly, window->width, window->height, 0, xfi->depth, InputOutput, xfi->visual, + window->handle = XCreateWindow(xfi->display, RootWindowOfScreen(xfi->screen), + x, y, window->width, window->height, 0, xfi->depth, InputOutput, xfi->visual, CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap | CWBorderPixel, &xfi->attribs); - xf_ReferenceWindow(xfi, window); - xf_ReferenceWindow(xfi, window->parent); - xf_SetWindowDecorations(xfi, window, window->decorations); - xf_SetWindowChildState(xfi, window); class_hints = XAllocClassHint(); @@ -352,10 +326,6 @@ xfWindow* xf_CreateWindow(xfInfo* xfi, xfWindow* parent, int x, int y, int width window->gc = XCreateGC(xfi->display, window->handle, GCGraphicsExposures, &gcv); window->surface = XCreatePixmap(xfi->display, window->handle, window->width, window->height, xfi->depth); - printf("xf_CreateWindow: h=0x%X p=0x%X x=%d y=%d w=%d h=%d\n", (uint32)window->handle, - (window->parent != NULL) ? (uint32)window->parent->handle : 0, - x, y, width, height); - xf_MoveWindow(xfi, window, x, y, width, height); } @@ -364,37 +334,19 @@ xfWindow* xf_CreateWindow(xfInfo* xfi, xfWindow* parent, int x, int y, int width void xf_MoveWindow(xfInfo* xfi, xfWindow* window, int x, int y, int width, int height) { - int lx, ly; Pixmap surface; if ((width * height) < 1) return; - printf("xf_MoveWindow: BEFORE correctness h=0x%X x=%d y=%d w=%d h=%d\n", - (uint32) window->handle, x, y, width, height); - xf_FixWindowCoordinates(&x, &y, &width, &height); - if (window->parent != NULL) - { - lx = x - window->parent->left; - ly = y - window->parent->top; - } - else - { - lx = x; - ly = y; - } - - printf("xf_MoveWindow: AFTER correctness h=0x%X x=%d y=%d lx=%d ly=%d w=%d h=%d \n", - (uint32) window->handle, x, y, lx, ly, width, height); - if (window->width == width && window->height == height) - XMoveWindow(xfi->display, window->handle, lx, ly); + XMoveWindow(xfi->display, window->handle, x, y); else if (window->left == x && window->top == y) XResizeWindow(xfi->display, window->handle, width, height); else - XMoveResizeWindow(xfi->display, window->handle, lx, ly, width, height); + XMoveResizeWindow(xfi->display, window->handle, x, y, width, height); surface = XCreatePixmap(xfi->display, window->handle, width, height, xfi->depth); XCopyArea(xfi->display, surface, window->surface, window->gc, 0, 0, window->width, window->height, 0, 0); @@ -490,42 +442,41 @@ void xf_SetWindowRects(xfInfo* xfi, xfWindow* window, RECTANGLE_16* rects, int n xfree(xrects); } -void xf_ReferenceWindow(xfInfo* xfi, xfWindow* window) +void xf_SetWindowVisibilityRects(xfInfo* xfi, xfWindow* window, RECTANGLE_16* rects, int nrects) { - if (window == NULL) return; - window->ref_count++; -} + int i; + XRectangle* xrects; -void xf_DereferenceWindow(xfInfo* xfi, xfWindow* window) -{ - if (window == NULL) return; + xrects = xmalloc(sizeof(XRectangle) * nrects); - window->ref_count--; - if (window->ref_count == 0) + for (i = 0; i < nrects; i++) { - printf("xf_DerefrenceWindow: destroying h=0x%X p=0x%X\n", (uint32)window->handle, - (window->parent != NULL) ? (uint32)window->parent->handle : 0); - - if (window->gc) - XFreeGC(xfi->display, window->gc); - if (window->surface) - XFreePixmap(xfi->display, window->surface); - if (window->handle) - { - XUnmapWindow(xfi->display, window->handle); - XDestroyWindow(xfi->display, window->handle); - } - xfree(window); + xrects[i].x = rects[i].left; + xrects[i].y = rects[i].top; + xrects[i].width = rects[i].right - rects[i].left; + xrects[i].height = rects[i].bottom - rects[i].top; } + +#ifdef WITH_XEXT + XShapeCombineRectangles(xfi->display, window->handle, ShapeBounding, 0, 0, xrects, nrects, ShapeSet, 0); +#endif + + xfree(xrects); } void xf_DestroyWindow(xfInfo* xfi, xfWindow* window) { - xfWindow* parent = window->parent; + if (window->gc) + XFreeGC(xfi->display, window->gc); - printf("xf_DestroyWindow: h=0x%X p=0x%X\n", (uint32)window->handle, - (window->parent != NULL) ? (uint32)window->parent->handle : 0); + if (window->surface) + XFreePixmap(xfi->display, window->surface); - xf_DereferenceWindow(xfi, window); - xf_DereferenceWindow(xfi, parent); + if (window->handle) + { + XUnmapWindow(xfi->display, window->handle); + XDestroyWindow(xfi->display, window->handle); + } + + xfree(window); } diff --git a/client/X11/xf_window.h b/client/X11/xf_window.h index e71eacae1..d9046d89d 100644 --- a/client/X11/xf_window.h +++ b/client/X11/xf_window.h @@ -52,6 +52,7 @@ boolean xf_GetWorkArea(xfInfo* xfi); void xf_SetWindowFullscreen(xfInfo* xfi, xfWindow* window, boolean fullscreen); void xf_SetWindowDecorations(xfInfo* xfi, xfWindow* window, boolean show); +void xf_SetWindowUnlisted(xfInfo* xfi, xfWindow* window); xfWindow* xf_CreateDesktopWindow(xfInfo* xfi, char* name, int width, int height); @@ -60,6 +61,7 @@ void xf_MoveWindow(xfInfo* xfi, xfWindow* window, int x, int y, int width, int h void xf_ShowWindow(xfInfo* xfi, xfWindow* window, uint8 state); void xf_SetWindowIcon(xfInfo* xfi, xfWindow* window, rdpIcon* icon); void xf_SetWindowRects(xfInfo* xfi, xfWindow* window, RECTANGLE_16* rects, int nrects); +void xf_SetWindowVisibilityRects(xfInfo* xfi, xfWindow* window, RECTANGLE_16* rects, int nrects); void xf_SetWindowStyle(xfInfo* xfi, xfWindow* window, uint32 style, uint32 ex_style); void xf_DestroyWindow(xfInfo* xfi, xfWindow* window); diff --git a/client/X11/xfreerdp.1.xml b/client/X11/xfreerdp.1.xml new file mode 100644 index 000000000..88b897dac --- /dev/null +++ b/client/X11/xfreerdp.1.xml @@ -0,0 +1,389 @@ + + + + 2011-08-27 + + The FreeRDP-Team + + + + xfreerdp + 1 + freerdp + xfreerdp + + + xfreerdp + X11 frontend to libFreeRDP + + + + 2011-08-27 + + + xfreerdp [options] server[:port] [[options] server[:port] …] + + + + + 2011-08-27 + + DESCRIPTION + + xfreerdp is a frontend to libFreeRDP, + which implements a client to the Remote Desktop Protocol (RDP). + RDP is used in a number of Microsoft products including Microsoft Windows + versions starting from NT Terminal Server. RDP is also implemented by xrdp and VirtualBox. + + + + OPTIONS + + + -0 + + + Attach to the admin console of the server. + + + + + -a bpp + + + Sets the color depth for the connection to bpp bits per pixel. + Valid values are 8, 15, 16, 24 and 32. The default value is the color depth of the FreeRDP-window. + + + + + -c dir + + + Sets the working-dir to dir. + This parameter is only used when an AlternateShell () is requested. + dir should contain the executable file specified in the AlternateShell. + + + + + -D + + + Removes the windows decorations. + + + + + -d + + + Domain used in authentication. + + + + + -f + + + start in full screen mode. This mode can always be en- and disabled using Ctrl-Alt-Enter. + + + + + -g geometry + + + Sets the size of the FreeRDP-window (and of the remote desktop, when establishing a new connection). + geometry can have one of the following forms: + + + + WxH - + in this case the resulting window will be of + WxH pixels. + + + + + P% - + in this case the resulting window will be P% + of your screen. + + + + + The special keyword workarea - + in this case the resulting window will be of the same size as your workarea. + + + + + + + + -k id + + + Sets the keyboard-layout-id to id. + + + + + -m + + + Don't send mouse motion events. + + + + + + -n hostname + + + Set the reported client hostname to hostname. + Default is to automatically detect the hostname. + + + + + -o + + + Play audio on the console instead of redirecting to the client. + + + + + -p password + + + Password used in authentication. + + + + + -s shell + + + Sets the startup-shell to shell. + This parameter should contain a complete path to the alternate shell. + If the alternete shell requires a different working directory use . + + + + + -t port + + + Connect to port, instead of the default 3389. + + + + + -u username + + + Username used in authentication. + + + + + -x flag + + + Set the experiance performance flags. + flag can be one of: + + + + m - (modem): Equivalent to 15. + + + + + b - (broadband): Equivalent to 1. + + + + + l - (lan): Equivalent to 0. + + + + + num - A number that represents a + bit-mask, were numbers mean the following + Taken from + MS-RDPBCGR Scetion 2.2.1.11.1.1.1 - Extended Info Packet: + + + 1: Disable desktop wallpaper. + + + 2: Disable full-window drag (only the window outline is displayed when the window is moved). + + + 4: Disable menu animations. + + + 8: Disable user interface themes. + + + 32: Disable mouse cursor shadows. + + + 64: Disable cursor blinking. + + + 128: Enable font smoothing. + + + 256: Enable Desktop Composition. + + + + + + + + + + -z + + + Enable compression. + + + + + --app + + + initialize a RemoteApp connection. This implies -g workarea. + FIXME: How to do RemoteApp + + + + + --ext + + + load an extension + FIXME: How to do this + + + + + --no-auth + + + Skips authentication. This is useful e.g. for the current FreeRDP server that doesn't yet support server-side authentication. + + + + + --no-fastpath + + + Disables fast-path. Use slow-path packets instead, which have larger headers. + It might be good for debugging certain issues when you suspect it might be + linked to the parsing of one of the two header types. + + + + + --no-osb + + + Disable off screen bitmaps. + + + + + --plugin + + + load a plugin + FIXME: How to do this + + + + + --rfx + + + Enable RemoteFX. + + + + + --no-rdp + + + Disable Standard RDP encryption. + + + + + --no-tls + + + Disable TLS encryption. + + + + + --no-nla + + + Disable network level authentication. + + + + + --sec proto + + + force protocol security. proto can be one of rdp, tls or nla. + + + + + --version + + + Print version information. + + + + + + + + + + LINKS + + http://www.freerdp.com/ + + + diff --git a/client/X11/xfreerdp.c b/client/X11/xfreerdp.c index 97898239c..0fb5ea9bc 100644 --- a/client/X11/xfreerdp.c +++ b/client/X11/xfreerdp.c @@ -718,7 +718,7 @@ int main(int argc, char* argv[]) chanman = freerdp_chanman_new(); SET_CHANMAN(instance, chanman); - instance->settings->sw_gdi = False; + instance->settings->sw_gdi = True; if (freerdp_parse_args(instance->settings, argc, argv, xf_process_plugin_args, chanman, xf_process_ui_args, NULL) < 0) diff --git a/cmake/ConfigOptions.cmake b/cmake/ConfigOptions.cmake index c49541b80..295b0cd88 100644 --- a/cmake/ConfigOptions.cmake +++ b/cmake/ConfigOptions.cmake @@ -9,5 +9,6 @@ option(WITH_DEBUG_CERTIFICATE "Print certificate related debug messages." OFF) option(WITH_DEBUG_LICENSE "Print license debug messages." OFF) option(WITH_DEBUG_GDI "Print graphics debug messages." OFF) option(WITH_DEBUG_RFX "Print RemoteFX debug messages." OFF) +option(WITH_MANPAGES "Generate manpages." ON) option(WITH_PROFILER "Compile profiler." OFF) option(WITH_SSE2 "Use SSE2 optimization." OFF) diff --git a/cmake/FindXext.cmake b/cmake/FindXext.cmake index 211de22bc..cc4bf5dbd 100644 --- a/cmake/FindXext.cmake +++ b/cmake/FindXext.cmake @@ -28,22 +28,22 @@ # limitations under the License. #============================================================================= -find_path(Xext_INCLUDE_DIR NAMES Xext.h +find_path(XEXT_INCLUDE_DIR NAMES Xext.h PATH_SUFFIXES X11/extensions DOC "The Xext include directory" ) -find_library(Xext_LIBRARY NAMES Xext +find_library(XEXT_LIBRARY NAMES Xext DOC "The Xext library" ) include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(Xext DEFAULT_MSG Xext_LIBRARY Xext_INCLUDE_DIR) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(XEXT DEFAULT_MSG XEXT_LIBRARY XEXT_INCLUDE_DIR) -if(Xext_FOUND) - set( Xext_LIBRARIES ${Xext_LIBRARY} ) - set( Xext_INCLUDE_DIRS ${Xext_INCLUDE_DIR} ) +if(XEXT_FOUND) + set( XEXT_LIBRARIES ${XEXT_LIBRARY} ) + set( XEXT_INCLUDE_DIRS ${XEXT_INCLUDE_DIR} ) endif() -mark_as_advanced(Xext_INCLUDE_DIR Xext_LIBRARY) +mark_as_advanced(XEXT_INCLUDE_DIR XEXT_LIBRARY) diff --git a/cmake/FindXmlto.cmake b/cmake/FindXmlto.cmake new file mode 100644 index 000000000..7d2107bab --- /dev/null +++ b/cmake/FindXmlto.cmake @@ -0,0 +1,35 @@ +# - Find xmlto +# Find the xmlto docbook xslt frontend +# +# This module defines the following variables: +# XMLTO_FOUND - True if xmlto was found +# XMLTO_EXECUTABLE - Path to xmlto, if xmlto was found +# + +#============================================================================= +# Copyright 2011 Nils Andresen +# +# 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. +#============================================================================= +set(XMLTO_FOUND false) + +find_program(XMLTO_EXECUTABLE + NAMES xmlto + DOC "docbook xslt frontend") + +if(XMLTO_EXECUTABLE) + set(XMLTO_FOUND true) + message(STATUS "Found XMLTO: ${XMLTO_EXECUTABLE}") +endif() + +mark_as_advanced(XMLTO_EXECUTABLE) 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/CMakeLists.txt b/include/CMakeLists.txt index 444d227f6..463315557 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -17,5 +17,5 @@ # See the License for the specific language governing permissions and # limitations under the License. -file(GLOB HEADERS "freerdp/*.h") +file(GLOB HEADERS "freerdp/*") install_files(/include/freerdp FILES ${HEADERS}) diff --git a/include/freerdp/rail/rail.h b/include/freerdp/rail/rail.h index 9e50d28fc..00f90b5e9 100644 --- a/include/freerdp/rail/rail.h +++ b/include/freerdp/rail/rail.h @@ -40,6 +40,7 @@ typedef void (*railShowWindow)(rdpRail* rail, rdpWindow* window, uint8 state); typedef void (*railSetWindowText)(rdpRail* rail, rdpWindow* window); typedef void (*railSetWindowIcon)(rdpRail* rail, rdpWindow* window, rdpIcon* icon); typedef void (*railSetWindowRects)(rdpRail* rail, rdpWindow* window); +typedef void (*railSetWindowVisibilityRects)(rdpRail* rail, rdpWindow* window); struct rdp_rail { @@ -56,6 +57,7 @@ struct rdp_rail railSetWindowText SetWindowText; railSetWindowIcon SetWindowIcon; railSetWindowRects SetWindowRects; + railSetWindowVisibilityRects SetWindowVisibilityRects; }; FREERDP_API void rail_register_update_callbacks(rdpRail* rail, rdpUpdate* update); diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 861620fc6..9adf77bb7 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -297,6 +297,11 @@ struct rdp_settings uint8 rfx_codec_id; boolean frame_acknowledge; + boolean dump_rfx; + boolean play_rfx; + char* dump_rfx_file; + char* play_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..aaaf56567 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,10 @@ struct rdp_update void* param1; void* param2; + boolean dump_rfx; + boolean play_rfx; + rdpPcap* pcap_rfx; + pcBeginPaint BeginPaint; pcEndPaint EndPaint; pcSetBounds SetBounds; @@ -1142,6 +1149,7 @@ struct rdp_update pcNonMonitoredDesktop NonMonitoredDesktop; pcSurfaceBits SurfaceBits; + pcSurfaceCommand SurfaceCommand; BITMAP_UPDATE bitmap_update; PALETTE_UPDATE palette_update; diff --git a/include/freerdp/utils/certstore.h b/include/freerdp/utils/certstore.h new file mode 100644 index 000000000..75e8ea3ce --- /dev/null +++ b/include/freerdp/utils/certstore.h @@ -0,0 +1,42 @@ +#ifndef __CERTSTORE_UTILS_H +#define __CERTSTORE_UTILS_H + +typedef struct rdp_certstore rdpCertstore; +typedef struct rdp_certdata rdpCertdata; + +#include +#include +#include +#include +#include +#include + +struct rdp_certdata +{ + char* thumbprint; + char* hostname; +}; + +struct rdp_certstore +{ + FILE* fp; + char* path; + char* file; + char* home; + int match; + struct rdp_certdata* certdata; +}; + +void certstore_create(rdpCertstore* certstore); +void certstore_open(rdpCertstore* certstore); +void certstore_load(rdpCertstore* certstore); +void certstore_close(rdpCertstore* certstore); +char* get_local_certloc(); +rdpCertdata* certdata_new(char* host_name,char* fingerprint); +void certdata_free(rdpCertdata* certdata); +void certstore_init(rdpCertstore* certstore); +rdpCertstore* certstore_new(rdpCertdata* certdata); +void certstore_free(rdpCertstore* certstore); +int match_certdata(rdpCertstore* certstore); +void print_certdata(rdpCertstore* certstore); +#endif /* __CERTSTORE_UTILS_H */ 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/capabilities.c b/libfreerdp-core/capabilities.c index daa697cc9..fb0269c23 100644 --- a/libfreerdp-core/capabilities.c +++ b/libfreerdp-core/capabilities.c @@ -1371,6 +1371,10 @@ void rdp_read_bitmap_codecs_capability_set(STREAM* s, rdpSettings* settings) */ void rdp_write_rfx_client_capability_container(STREAM* s, rdpSettings* settings) { + uint16 captureFlags; + + captureFlags = settings->dump_rfx ? 0 : CARDP_CAPS_CAPTURE_NON_CAC; + stream_write_uint16(s, 49); /* codecPropertiesLength */ /* TS_RFX_CLNT_CAPS_CONTAINER */ diff --git a/libfreerdp-core/credssp.c b/libfreerdp-core/credssp.c index d58969ce8..27134ebb7 100644 --- a/libfreerdp-core/credssp.c +++ b/libfreerdp-core/credssp.c @@ -8,7 +8,7 @@ * 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 + * 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, @@ -25,7 +25,6 @@ #include "ntlmssp.h" #include "credssp.h" - /** * TSRequest ::= SEQUENCE { * version [0] INTEGER, @@ -109,7 +108,7 @@ int credssp_get_public_key(rdpCredssp* credssp) { int ret; CryptoCert cert; - + cert = tls_get_certificate(credssp->transport->tls); if (cert == NULL) @@ -117,7 +116,8 @@ int credssp_get_public_key(rdpCredssp* credssp) printf("credssp_get_public_key: tls_get_certificate failed to return the server certificate.\n"); return 0; } - + if(tls_verify_certificate(cert,credssp->transport->settings->hostname)) + tls_disconnect(credssp->transport->tls); ret = crypto_cert_get_public_key(cert, &credssp->public_key); crypto_cert_free(cert); diff --git a/libfreerdp-core/crypto.c b/libfreerdp-core/crypto.c index 05a969bef..9aa65f0ab 100644 --- a/libfreerdp-core/crypto.c +++ b/libfreerdp-core/crypto.c @@ -8,7 +8,7 @@ * 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 + * 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, @@ -189,3 +189,113 @@ void crypto_nonce(uint8* nonce, int size) { RAND_bytes((void*) nonce, size); } + +char* crypto_cert_fingerprint(X509* xcert) +{ + char* p; + int i = 0; + char* fp_buffer; + unsigned int fp_len; + unsigned char fp[EVP_MAX_MD_SIZE]; + + X509_digest(xcert, EVP_sha1(), fp, &fp_len); + + fp_buffer = xzalloc(3 * fp_len); + p = fp_buffer; + + for (i = 0; i < fp_len - 1; i++) + { + sprintf(p, "%02x:", fp[i]); + p = (char*) &fp_buffer[i * 3]; + } + sprintf(p, "%02x", fp[i]); + + return fp_buffer; +} + +boolean x509_verify_cert(CryptoCert cert) +{ + char* cert_loc; + X509_STORE_CTX* csc; + boolean status = False; + X509_STORE* cert_ctx = NULL; + X509_LOOKUP* lookup = NULL; + X509* xcert = cert->px509; + + cert_ctx = X509_STORE_new(); + + if (cert_ctx == NULL) + goto end; + + OpenSSL_add_all_algorithms(); + lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file()); + + if (lookup == NULL) + goto end; + + lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_hash_dir()); + + if (lookup == NULL) + goto end; + + X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT); + cert_loc = get_local_certloc(); + + if(cert_loc != NULL) + { + X509_LOOKUP_add_dir(lookup, cert_loc, X509_FILETYPE_ASN1); + xfree(cert_loc); + } + + csc = X509_STORE_CTX_new(); + + if (csc == NULL) + goto end; + + X509_STORE_set_flags(cert_ctx, 0); + + if(!X509_STORE_CTX_init(csc, cert_ctx, xcert, 0)) + goto end; + + if (X509_verify_cert(csc) == 1) + status = True; + + X509_STORE_CTX_free(csc); + X509_STORE_free(cert_ctx); + +end: + return status; +} + +rdpCertdata* crypto_get_certdata(X509* xcert, char* hostname) +{ + char* fp; + rdpCertdata* certdata; + + fp = crypto_cert_fingerprint(xcert); + certdata = certdata_new(hostname, fp); + xfree(fp); + + return certdata; +} + +void crypto_cert_printinfo(X509* xcert) +{ + char* fp; + char* issuer; + char* subject; + + subject = X509_NAME_oneline(X509_get_subject_name(xcert), NULL, 0); + issuer = X509_NAME_oneline(X509_get_issuer_name(xcert), NULL, 0); + fp = crypto_cert_fingerprint(xcert); + + printf("Certificate details:\n"); + printf("\tSubject: %s\n", subject); + printf("\tIssuer: %s\n", issuer); + printf("\tThumbprint: %s\n", fp); + printf("The above X.509 certificate could not be verified, possibly because you do not have " + "the CA certificate in your certificate store, or the certificate has expired." + "Please look at the documentation on how to create local certificate store for a private CA.\n"); + + xfree(fp); +} diff --git a/libfreerdp-core/crypto.h b/libfreerdp-core/crypto.h index 5a8746790..b63ff16c4 100644 --- a/libfreerdp-core/crypto.h +++ b/libfreerdp-core/crypto.h @@ -45,6 +45,7 @@ #include #include #include +#include struct crypto_sha1_struct { @@ -83,8 +84,12 @@ void crypto_rc4_free(CryptoRc4 rc4); typedef struct crypto_cert_struct* CryptoCert; CryptoCert crypto_cert_read(uint8* data, uint32 length); +char* cypto_cert_fingerprint(X509* xcert); +void crypto_cert_printinfo(X509* xcert); void crypto_cert_free(CryptoCert cert); +boolean x509_verify_cert(CryptoCert cert); boolean crypto_cert_verify(CryptoCert server_cert, CryptoCert cacert); +rdpCertdata* crypto_get_certdata(X509* xcert, char* hostname); boolean crypto_cert_get_public_key(CryptoCert cert, rdpBlob* public_key); void crypto_rsa_encrypt(uint8* input, int length, uint32 key_length, uint8* modulus, uint8* exponent, uint8* output); diff --git a/libfreerdp-core/fastpath.c b/libfreerdp-core/fastpath.c index e48e4a2ae..b5bf10653 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 & 0x03) << 4; + updateHeader |= (compression & 0x03) << 6; + 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); } @@ -394,7 +412,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) @@ -457,9 +475,10 @@ boolean fastpath_send_update_pdu(rdpFastPath* fastpath, STREAM* s) uint16 length; length = stream_get_length(s); + if (length > FASTPATH_MAX_PACKET_SIZE) { - printf("Maximum FastPath Update PDU length is %d\n", FASTPATH_MAX_PACKET_SIZE); + printf("Maximum FastPath Update PDU length is %d (actual:%d)\n", FASTPATH_MAX_PACKET_SIZE, length); return False; } @@ -475,6 +494,41 @@ boolean fastpath_send_update_pdu(rdpFastPath* fastpath, STREAM* s) return True; } +boolean fastpath_send_fragmented_update_pdu(rdpFastPath* fastpath, STREAM* s) +{ + int fragment; + uint16 length; + uint16 maxLength; + uint32 totalLength; + uint8 fragmentation; + STREAM* update; + + maxLength = FASTPATH_MAX_PACKET_SIZE - 6; + totalLength = stream_get_length(s); + stream_set_pos(s, 0); + + for (fragment = 0; totalLength > 0; fragment++) + { + update = fastpath_update_pdu_init(fastpath); + length = MIN(maxLength, totalLength); + totalLength -= length; + + if (totalLength == 0) + fragmentation = (fragment == 0) ? FASTPATH_FRAGMENT_SINGLE : FASTPATH_FRAGMENT_LAST; + else + fragmentation = (fragment == 0) ? FASTPATH_FRAGMENT_FIRST : FASTPATH_FRAGMENT_NEXT; + + 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; +} + boolean fastpath_send_surfcmd_frame_marker(rdpFastPath* fastpath, uint16 frameAction, uint32 frameId) { STREAM* s; @@ -520,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/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..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" @@ -34,10 +35,51 @@ 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); + 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 6c17e310c..b0bc45411 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); @@ -56,12 +58,16 @@ 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; + uint32 cmdLength; while (size > 2) { + stream_get_mark(s, mark); + stream_read_uint16(s, cmdType); size -= 2; @@ -69,17 +75,25 @@ boolean update_recv_surfcmds(rdpUpdate* update, uint16 size, STREAM* s) { case CMDTYPE_SET_SURFACE_BITS: case CMDTYPE_STREAM_SURFACE_BITS: - size -= update_recv_surfcmd_surface_bits(update, s); + cmdLength = update_recv_surfcmd_surface_bits(update, s); break; case CMDTYPE_FRAME_MARKER: - size -= update_recv_surfcmd_frame_marker(update, s); + cmdLength = update_recv_surfcmd_frame_marker(update, s); break; default: DEBUG_WARN("unknown cmdType 0x%X", cmdType); return False; } + + size -= cmdLength; + + if (update->dump_rfx) + { + pcap_add_record(update->pcap_rfx, mark, cmdLength + 2); + pcap_flush(update->pcap_rfx); + } } return True; } 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-core/tls.c b/libfreerdp-core/tls.c index e6d3c3ea2..c5760f0bd 100644 --- a/libfreerdp-core/tls.c +++ b/libfreerdp-core/tls.c @@ -8,7 +8,7 @@ * 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 + * 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, @@ -240,7 +240,7 @@ rdpTls* tls_new() tls->connect = tls_connect; tls->accept = tls_accept; tls->disconnect = tls_disconnect; - + SSL_load_error_strings(); SSL_library_init(); } @@ -248,6 +248,69 @@ rdpTls* tls_new() return tls; } +int tls_verify_certificate(CryptoCert cert, char* hostname) +{ + boolean ret; + ret = x509_verify_cert(cert); + + if (!ret) + { + rdpCertdata* certdata; + certdata = crypto_get_certdata(cert->px509, hostname); + rdpCertstore* certstore = certstore_new(certdata); + + if (match_certdata(certstore) == 0) + goto end; + + if (certstore->match == 1) + { + char answer; + crypto_cert_printinfo(cert->px509); + + while(1) + { + printf("Do you trust the above certificate? (Y/N) "); + answer=fgetc(stdin); + + if(answer=='y' || answer =='Y') + { + print_certdata(certstore); + break; + } + else if(answer=='n' || answer=='N') + { + certstore_free(certstore); + return 1; + } + } + } + else if (certstore->match == -1) + { + tls_print_cert_error(); + certstore_free(certstore); + return 1; + } + +end: + certstore_free(certstore); + } + + return 0; +} + +void tls_print_cert_error() +{ + printf("#####################################\n"); + printf("##############WARNING################\n"); + printf("#####################################\n"); + printf("The thumbprint of certificate received\n"); + printf("did not match the stored thumbprint.You\n"); + printf("might be a victim of MAN in the MIDDLE\n"); + printf("ATTACK.It is also possible that server's\n"); + printf("certificate have been changed.In that case\n"); + printf("contact your server administrator\n"); +} + void tls_free(rdpTls* tls) { if (tls != NULL) diff --git a/libfreerdp-core/tls.h b/libfreerdp-core/tls.h index 9a7da598a..52b301c40 100644 --- a/libfreerdp-core/tls.h +++ b/libfreerdp-core/tls.h @@ -49,8 +49,9 @@ boolean tls_disconnect(rdpTls* tls); int tls_read(rdpTls* tls, uint8* data, int length); int tls_write(rdpTls* tls, uint8* data, int length); CryptoCert tls_get_certificate(rdpTls* tls); +int tls_verify_certificate(CryptoCert cert,char* hostname); +void tls_print_cert_error(); boolean tls_print_error(char* func, SSL* connection, int value); - rdpTls* tls_new(); void tls_free(rdpTls* tls); 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-rail/window.c b/libfreerdp-rail/window.c index 51fb6ef0e..9a55e01c0 100644 --- a/libfreerdp-rail/window.c +++ b/libfreerdp-rail/window.c @@ -284,6 +284,10 @@ void rail_CreateWindow(rdpRail* rail, rdpWindow* window) { IFCALL(rail->SetWindowRects, rail, window); } + if (window->fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY) + { + IFCALL(rail->SetWindowVisibilityRects, rail, window); + } } void rail_UpdateWindow(rdpRail* rail, rdpWindow* window) @@ -356,7 +360,7 @@ void rail_UpdateWindow(rdpRail* rail, rdpWindow* window) if (window->fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY) { - + IFCALL(rail->SetWindowVisibilityRects, rail, window); } } diff --git a/libfreerdp-utils/CMakeLists.txt b/libfreerdp-utils/CMakeLists.txt index a0b6037dd..71a9eda63 100644 --- a/libfreerdp-utils/CMakeLists.txt +++ b/libfreerdp-utils/CMakeLists.txt @@ -30,9 +30,11 @@ set(FREERDP_UTILS_SRCS load_plugin.c memory.c mutex.c + pcap.c profiler.c rail.c registry.c + certstore.c semaphore.c sleep.c stopwatch.c diff --git a/libfreerdp-utils/args.c b/libfreerdp-utils/args.c index 00e189e96..522543648 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) @@ -242,6 +282,28 @@ 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("--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 = True; diff --git a/libfreerdp-utils/certstore.c b/libfreerdp-utils/certstore.c new file mode 100644 index 000000000..b784d33a3 --- /dev/null +++ b/libfreerdp-utils/certstore.c @@ -0,0 +1,213 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * certstore Utils + * + * Copyright 2011 Jiten Pathy + * + * 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 + +#ifdef _WIN32 +#include +#endif + +static char cert_dir[] = "freerdp"; +static char cert_loc[] = "cacert"; +static char certstore_file[] = "known_hosts"; + +void certstore_create(rdpCertstore* certstore) +{ + certstore->fp = fopen((char*)certstore->file, "w+"); + + if (certstore->fp == NULL) + { + printf("certstore_create: error opening [%s] for writing\n", certstore->file); + return; + } + fflush(certstore->fp); +} + +void certstore_load(rdpCertstore* certstore) +{ + certstore->fp = fopen((char*)certstore->file, "r+"); +} + +void certstore_open(rdpCertstore* certstore) +{ + struct stat stat_info; + + if (stat((char*)certstore->file, &stat_info) != 0) + certstore_create(certstore); + else + certstore_load(certstore); +} + +void certstore_close(rdpCertstore* certstore) +{ + if (certstore->fp != NULL) + fclose(certstore->fp); +} + +char* get_local_certloc() +{ + char *home_path; + char *certloc; + struct stat stat_info; + home_path=getenv("HOME"); + certloc=(char*)xmalloc(strlen(home_path)+strlen("/.")+strlen(cert_dir)+strlen("/")+strlen(cert_loc)+1); + sprintf(certloc,"%s/.%s/%s",home_path,cert_dir,cert_loc); + if(stat((char*)certloc, &stat_info) != 0) + mkdir(certloc, S_IRUSR | S_IWUSR | S_IXUSR); + return certloc; +} + +void certstore_init(rdpCertstore* certstore) +{ + int length; + char* home_path; + struct stat stat_info; + + certstore->match=1; + home_path = getenv("HOME"); + + if (home_path == NULL) + { + printf("could not get home path\n"); + return; + } + + certstore->home = (char*) xstrdup(home_path); + printf("home path: %s\n", certstore->home); + + certstore->path = (char*) xmalloc(strlen(certstore->home) + strlen("/.") + strlen(cert_dir) + 1); + sprintf(certstore->path, "%s/.%s", certstore->home, cert_dir); + printf("certstore path: %s\n", certstore->path); + + if (stat(certstore->path, &stat_info) != 0) + { +#ifndef _WIN32 + mkdir(certstore->path, S_IRUSR | S_IWUSR | S_IXUSR); +#else + CreateDirectory(certstore->path, 0); +#endif + printf("creating directory %s\n", certstore->path); + } + + length = strlen(certstore->path); + certstore->file = (char*) xmalloc(strlen(certstore->path) + strlen("/") + strlen(certstore_file) + 1); + sprintf(certstore->file, "%s/%s", certstore->path, certstore_file); + printf("certstore file: %s\n", certstore->file); + + certstore_open(certstore); +} + +rdpCertdata* certdata_new(char* host_name,char* fingerprint) +{ + rdpCertdata* certdata=(rdpCertdata*)xzalloc(sizeof(rdpCertdata)); + if(certdata !=NULL) + { + certdata->hostname=xzalloc(strlen(host_name)+1); + certdata->thumbprint=xzalloc(strlen(fingerprint)+1); + sprintf(certdata->hostname,"%s",host_name); + sprintf(certdata->thumbprint,"%s",fingerprint); + } + return certdata; +} + +void certdata_free(rdpCertdata* certdata) +{ + if(certdata != NULL) + { + xfree(certdata->hostname); + xfree(certdata->thumbprint); + xfree(certdata); + } +} + +rdpCertstore* certstore_new(rdpCertdata* certdata) +{ + rdpCertstore* certstore = (rdpCertstore*) xzalloc(sizeof(rdpCertstore)); + + if (certstore != NULL) + { + certstore->certdata = certdata; + certstore_init(certstore); + } + + return certstore; +} + +void certstore_free(rdpCertstore* certstore) +{ + if (certstore != NULL) + { + certstore_close(certstore); + xfree(certstore->path); + xfree(certstore->file); + xfree(certstore->home); + certdata_free(certstore->certdata); + xfree(certstore); + } +} + +int match_certdata(rdpCertstore* certstore) +{ + char *host; + char *p; + char *thumb_print; + int length; + unsigned char c; + FILE* cfp; + cfp=certstore->fp; + rdpCertdata* cert_data=certstore->certdata; + length=strlen(cert_data->thumbprint); + host=xzalloc(strlen(cert_data->hostname)+1); + for(;;) + { + if((int)fread(host,sizeof(char),strlen(cert_data->hostname),cfp) < strlen(cert_data->hostname)) + break; + if((!strcmp(host,cert_data->hostname)) && ((c=fgetc(cfp))==' ' || c=='\t') ) + { + ungetc(c,cfp); + while((c=fgetc(cfp))==' ' || c=='\t'); + if(c==EOF) + break; + ungetc(c,cfp); + thumb_print=xzalloc(length+1); + p=thumb_print; + while((p-thumb_print) < length && (*p=fgetc(cfp))!=EOF && *p!='\n' && *p==*(cert_data->thumbprint+(p-thumb_print))) + p++; + if(p-thumb_print==length) + certstore->match=0; + else + certstore->match=-1; + break; + } + else + { + while(c!='\n' && c!=EOF) + c=fgetc(cfp); + if(c==EOF) + break; + } + } + xfree(host); + return certstore->match; +} +void print_certdata(rdpCertstore* certstore) +{ + fseek(certstore->fp,0,SEEK_END); + fprintf(certstore->fp,"%s %s\n",certstore->certdata->hostname,certstore->certdata->thumbprint); +} diff --git a/libfreerdp-utils/pcap.c b/libfreerdp-utils/pcap.c new file mode 100644 index 000000000..48f2a711d --- /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 = 0xFFFFFFFF; + 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 00d07da47..c926363c6 100644 --- a/server/test/freerdp_server.c +++ b/server/test/freerdp_server.c @@ -30,6 +30,8 @@ #include #include +static char* test_pcap_file = NULL; + /* HL1, LH1, HH1, HL2, LH2, HH2, HL3, LH3, HH3, LL3 */ static const unsigned int test_quantization_values[] = { @@ -183,6 +185,8 @@ static void test_peer_draw_icon(freerdp_peer* client, int x, int y) RFX_RECT rect; STREAM* s; + if (client->update->dump_rfx) + return; if (!client->settings->rfx_codec || !info) return; if (info->icon_width < 1) @@ -232,6 +236,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(test_pcap_file, 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) { /** @@ -256,9 +287,18 @@ boolean test_peer_post_connect(freerdp_peer* client) /* A real server should tag the peer as activated here and start sending updates in mainloop. */ test_peer_init(client); - test_peer_draw_background(client); test_peer_load_icon(client); + if (test_pcap_file != NULL) + { + client->update->dump_rfx = True; + test_peer_dump_rfx(client); + } + else + { + test_peer_draw_background(client); + } + /* Return False here would stop the execution of the peer mainloop. */ return True; } @@ -292,13 +332,13 @@ void test_peer_extended_mouse_event(rdpInput* input, uint16 flags, uint16 x, uin static void* test_peer_mainloop(void* arg) { - freerdp_peer* client = (freerdp_peer*)arg; int i; int fds; int max_fds; int rcount; void* rfds[32]; fd_set rfds_set; + freerdp_peer* client = (freerdp_peer*) arg; memset(rfds, 0, sizeof(rfds)); @@ -452,8 +492,11 @@ int main(int argc, char* argv[]) instance->PeerAccepted = test_peer_accepted; + if (argc > 1) + test_pcap_file = argv[1]; + /* Open the server socket and start listening. */ - if (instance->Open(instance, (argc > 1 ? argv[1] : NULL), 3389)) + if (instance->Open(instance, NULL, 3389)) { /* Entering the server main loop. In a real server the listener can be run in its own thread. */ test_server_mainloop(instance); 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