diff --git a/CMakeLists.txt b/CMakeLists.txt index e90006be5..dce790c54 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,7 +142,7 @@ if(CMAKE_COMPILER_IS_GNUCC) endif() endif() if(CMAKE_BUILD_TYPE STREQUAL "Release") - set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG") + set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2") else() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g") @@ -160,10 +160,10 @@ endif() if(MSVC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Gd") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MT") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /O2") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Ob2") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W2") + #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MD") + #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /O2") + #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Ob2") + #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W2") if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_AMD64_") else() @@ -171,6 +171,13 @@ if(MSVC) endif() SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}) SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}) + + if(CMAKE_BUILD_TYPE STREQUAL "Release") + else() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Zi") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zi") + endif() + endif() if(WIN32) @@ -261,6 +268,7 @@ endif() if(UNIX OR CYGWIN) check_include_files(sys/eventfd.h HAVE_EVENTFD_H) + check_include_files(sys/timerfd.h HAVE_TIMERFD_H) set(X11_FEATURE_TYPE "RECOMMENDED") else() set(X11_FEATURE_TYPE "DISABLED") @@ -461,7 +469,9 @@ if(WITH_THIRD_PARTY) endif() endif() -add_subdirectory(include) +if (NOT WITH_WAYK) + add_subdirectory(include) +endif() add_subdirectory(libfreerdp) @@ -486,6 +496,8 @@ endif() SET(CPACK_BINARY_ZIP "ON") +if(NOT WITH_WAYK) + set(CPACK_SOURCE_IGNORE_FILES "/\\\\.git/;/\\\\.gitignore;/CMakeCache.txt") if(NOT WIN32) @@ -541,9 +553,12 @@ if(MSVC) if(MSVC_RUNTIME STREQUAL "dynamic") set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE) include(InstallRequiredSystemLibraries) + +if(NOT WITH_WAYK) install(PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT libraries) +endif() endif() set(EXTRA_DATA_DIR "extra/") @@ -589,3 +604,4 @@ endif() include(CPack) +endif() diff --git a/channels/rdpei/client/rdpei_main.c b/channels/rdpei/client/rdpei_main.c index 3984b6c32..81099e6d8 100644 --- a/channels/rdpei/client/rdpei_main.c +++ b/channels/rdpei/client/rdpei_main.c @@ -96,9 +96,10 @@ struct _RDPEI_PLUGIN RDPINPUT_CONTACT_DATA contacts[MAX_CONTACTS]; RDPINPUT_CONTACT_POINT* contactPoints; - HANDLE mutex; HANDLE event; HANDLE thread; + + CRITICAL_SECTION lock; }; typedef struct _RDPEI_PLUGIN RDPEI_PLUGIN; @@ -160,7 +161,7 @@ static void* rdpei_schedule_thread(void* arg) { status = WaitForSingleObject(rdpei->event, 20); - WaitForSingleObject(rdpei->mutex, INFINITE); + EnterCriticalSection(&rdpei->lock); rdpei_add_frame(context); @@ -170,7 +171,7 @@ static void* rdpei_schedule_thread(void* arg) if (status == WAIT_OBJECT_0) ResetEvent(rdpei->event); - ReleaseMutex(rdpei->mutex); + LeaveCriticalSection(&rdpei->lock); } return NULL; @@ -219,7 +220,7 @@ int rdpei_send_cs_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback) if (!rdpei->thread) { - rdpei->mutex = CreateMutex(NULL, FALSE, NULL); + InitializeCriticalSection(&rdpei->lock); rdpei->event = CreateEvent(NULL, TRUE, FALSE, NULL); rdpei->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) rdpei_schedule_thread, (void*) rdpei, 0, NULL); } @@ -542,7 +543,7 @@ int rdpei_add_contact(RdpeiClientContext* context, RDPINPUT_CONTACT_DATA* contac RDPINPUT_CONTACT_POINT* contactPoint; RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) context->handle; - WaitForSingleObject(rdpei->mutex, INFINITE); + EnterCriticalSection(&rdpei->lock); contactPoint = (RDPINPUT_CONTACT_POINT*) &rdpei->contactPoints[contact->contactId]; CopyMemory(&(contactPoint->data), contact, sizeof(RDPINPUT_CONTACT_DATA)); @@ -550,7 +551,7 @@ int rdpei_add_contact(RdpeiClientContext* context, RDPINPUT_CONTACT_DATA* contac SetEvent(rdpei->event); - ReleaseMutex(rdpei->mutex); + LeaveCriticalSection(&rdpei->lock); return 1; } diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 2543bb028..e78c37517 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -57,4 +57,4 @@ endif() if (WITH_DOTNET) add_subdirectory(DotNetClient) -endif() \ No newline at end of file +endif() diff --git a/client/Mac/CMakeLists.txt b/client/Mac/CMakeLists.txt index 8b7ae739f..20ce92d82 100755 --- a/client/Mac/CMakeLists.txt +++ b/client/Mac/CMakeLists.txt @@ -66,8 +66,8 @@ set_target_properties(${MODULE_NAME} PROPERTIES MACOSX_FRAMEWORK_IDENTIFIER com.awakecoding.${MODULE_NAME} FRAMEWORK_VERSION 1.1.0 MACOSX_FRAMEWORK_SHORT_VERSION_STRING 1.1.0 - MACOSX_FRAMEWORK_BUNDLE_VERSION 1.1.0 - INSTALL_NAME_DIR "@executable_path/../../Frameworks" + MACOSX_FRAMEWORK_BUNDLE_BUNDLE_VERSION 1.1.0 + INSTALL_NAME_DIR "@executable_path/../Frameworks" MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/Info.plist BUILD_WITH_INSTALL_RPATH 1) @@ -132,7 +132,7 @@ if (${BUILD_SHARED_LIBS}) endif() # Add post-build NIB file generation in unix makefiles. XCode handles this implicitly. -if("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles") +# if("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles") message(STATUS "Adding post-build NIB file generation event for ${MODULE_NAME}") # Make sure we can find the 'ibtool' program. If we can NOT find it we @@ -156,7 +156,7 @@ if("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles") --compile ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/Versions/${MACOSX_BUNDLE_SHORT_VERSION_STRING}/Resources/${XIB_WE}.nib ${xib} COMMENT "Compiling ${xib}") endforeach() -endif() +# endif() # Copy the public header files into the framework foreach(HEADER ${${MODULE_NAME}_HEADERS}) @@ -169,6 +169,7 @@ endforeach() # Copy the FreeRDP header files into the framework add_custom_command(TARGET ${MODULE_NAME} POST_BUILD COMMAND ditto ${CMAKE_SOURCE_DIR}/include/freerdp ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/Headers/freerdp + COMMAND ditto ${CMAKE_SOURCE_DIR}/winpr/include/winpr ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/Headers/winpr COMMENT Copying FreeRDP header files to ${MODULE_NAME}) add_subdirectory(cli) diff --git a/client/Mac/MRDPView.h b/client/Mac/MRDPView.h index 653c2d391..289dae5ce 100755 --- a/client/Mac/MRDPView.h +++ b/client/Mac/MRDPView.h @@ -41,14 +41,11 @@ @interface MRDPView : NSView { - CFRunLoopSourceRef run_loop_src_channels; - CFRunLoopSourceRef run_loop_src_update; - CFRunLoopSourceRef run_loop_src_input; - NSBitmapImageRep* bmiRep; NSMutableArray* cursors; NSMutableArray* windows; NSTimer* pasteboard_timer; + NSCursor* currentCursor; NSRect prevWinPosition; int titleBarHeight; freerdp* instance; @@ -61,7 +58,6 @@ char** argv; NSPoint savedDragLocation; - BOOL mouseInClientArea; BOOL firstCreateWindow; BOOL isMoveSizeInProgress; BOOL skipResizeOnce; @@ -80,6 +76,8 @@ int kdcapslock; BOOL initialized; + + NSImageView* imageView; @public NSPasteboard* pasteboard_rd; /* for reading from clipboard */ @@ -90,11 +88,11 @@ } - (int) rdpStart :(rdpContext*) rdp_context; -- (void) rdpConnectError; -- (void) rdpRemoteAppError; +- (void) setCursor: (NSCursor*) cursor; + - (void) onPasteboardTimerFired :(NSTimer *) timer; - (void) releaseResources; -- (void) setViewSize : (int) width : (int) height; +- (void) setViewSize : (int) w : (int) h; @property (assign) int is_connected; @@ -114,3 +112,4 @@ BOOL mac_pre_connect(freerdp* instance); BOOL mac_post_connect(freerdp* instance); BOOL mac_authenticate(freerdp* instance, char** username, char** password, char** domain); int mac_receive_channel_data(freerdp* instance, int chan_id, BYTE* data, int size, int flags, int total_size); +DWORD mac_client_thread(void* param); diff --git a/client/Mac/MRDPView.m b/client/Mac/MRDPView.m index c92731914..8facc7d1b 100644 --- a/client/Mac/MRDPView.m +++ b/client/Mac/MRDPView.m @@ -42,6 +42,8 @@ * - */ +#include + #include "mf_client.h" #import "mfreerdp.h" #import "MRDPView.h" @@ -80,11 +82,9 @@ void mac_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmap); void mac_begin_paint(rdpContext* context); void mac_end_paint(rdpContext* context); void mac_save_state_info(freerdp* instance, rdpContext* context); -static void update_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info); -static void input_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info); -static void channel_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info); -int register_update_fds(freerdp* instance); -int register_input_fds(freerdp* instance); +static void update_activity_cb(freerdp* instance); +static void input_activity_cb(freerdp* instance); +static void channel_activity_cb(freerdp* instance); int invoke_draw_rect(rdpContext* context); int process_plugin_args(rdpSettings* settings, const char* name, RDP_PLUGIN_DATA* plugin_data, void* user_data); int receive_channel_data(freerdp* instance, int chan_id, BYTE* data, int size, int flags, int total_size); @@ -98,6 +98,9 @@ void cliprdr_process_text(freerdp* instance, BYTE* data, int len); void cliprdr_send_supported_format_list(freerdp* instance); int register_channel_fds(int* fds, int count, freerdp* instance); + +DWORD mac_client_thread(void* param); + struct cursor { rdpPointer* pointer; @@ -121,7 +124,6 @@ struct rgba_data - (int) rdpStart:(rdpContext*) rdp_context { - int status; mfContext* mfc; rdpSettings* settings; EmbedWindowEventArgs e; @@ -137,32 +139,97 @@ struct rgba_data e.embed = TRUE; e.handle = (void*) self; PubSub_OnEmbedWindow(context->pubSub, context, &e); + [self setViewSize :instance->settings->DesktopWidth :instance->settings->DesktopHeight]; - status = freerdp_connect(context->instance); + mfc->thread = CreateThread(NULL, 0, mac_client_thread, (void*) context, 0, &mfc->mainThreadId); - if (!status) - { - [self setIs_connected:0]; - [self rdpConnectError]; - return 1; - } - - /* register update message queue with the RunLoop */ - register_update_fds(context->instance); - - /* register update message queue with the RunLoop */ - register_input_fds(context->instance); - - /* register channel events with the RunLoop */ - register_channels_fds(context->instance); - - freerdp_check_fds(context->instance); - - [self setIs_connected:1]; - return 0; } +DWORD mac_client_thread(void* param) +{ + @autoreleasepool + { + int status; + HANDLE events[4]; + HANDLE input_event; + HANDLE update_event; + HANDLE channels_event; + + DWORD nCount; + rdpContext* context = (rdpContext*) param; + mfContext* mfc = (mfContext*) context; + freerdp* instance = context->instance; + MRDPView* view = mfc->view; + + status = freerdp_connect(context->instance); + + if (!status) + { + [view setIs_connected:0]; + return 0; + } + + [view setIs_connected:1]; + + nCount = 0; + + events[nCount++] = mfc->stopEvent; + + if (instance->settings->AsyncUpdate) + { + events[nCount++] = update_event = freerdp_get_message_queue_event_handle(instance, FREERDP_UPDATE_MESSAGE_QUEUE); + } + + if (instance->settings->AsyncInput) + { + events[nCount++] = input_event = freerdp_get_message_queue_event_handle(instance, FREERDP_INPUT_MESSAGE_QUEUE); + } + + if (instance->settings->AsyncChannels) + { + events[nCount++] = channels_event = freerdp_channels_get_event_handle(instance); + } + + while (1) + { + status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + + if (WaitForSingleObject(mfc->stopEvent, 0) == WAIT_OBJECT_0) + { + break; + } + + if (instance->settings->AsyncUpdate) + { + if (WaitForSingleObject(update_event, 0) == WAIT_OBJECT_0) + { + update_activity_cb(instance); + } + } + + if (instance->settings->AsyncInput) + { + if (WaitForSingleObject(input_event, 0) == WAIT_OBJECT_0) + { + input_activity_cb(instance); + } + } + + if (instance->settings->AsyncChannels) + { + if (WaitForSingleObject(channels_event, 0) == WAIT_OBJECT_0) + { + channel_activity_cb(instance); + } + } + } + + ExitThread(0); + return 0; + } +} + /************************************************************************ methods we override ************************************************************************/ @@ -212,13 +279,29 @@ struct rgba_data NSTrackingArea * trackingArea = [[NSTrackingArea alloc] initWithRect:[self visibleRect] options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingCursorUpdate | NSTrackingEnabledDuringMouseDrag | NSTrackingActiveWhenFirstResponder owner:self userInfo:nil]; [self addTrackingArea:trackingArea]; - - mouseInClientArea = YES; + + // Set the default cursor + currentCursor = [NSCursor arrowCursor]; initialized = YES; } } +- (void) setCursor: (NSCursor*) cursor +{ + self->currentCursor = cursor; + [[self window] invalidateCursorRectsForView:self]; + + [imageView setImage:[currentCursor image]]; +} + + +// Set the current cursor +- (void) resetCursorRects +{ + [self addCursorRect:[self visibleRect] cursor:currentCursor]; +} + /** ********************************************************************* * become first responder so we can get keyboard and mouse events ***********************************************************************/ @@ -594,7 +677,8 @@ struct rgba_data - (void) releaseResources { int i; - + + for (i = 0; i < argc; i++) { if (argv[i]) @@ -608,15 +692,6 @@ struct rgba_data if (pixel_data) free(pixel_data); - - if (run_loop_src_update != 0) - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_src_update, kCFRunLoopDefaultMode); - - if (run_loop_src_input != 0) - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_src_input, kCFRunLoopDefaultMode); - - if (run_loop_src_channels != 0) - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_src_channels, kCFRunLoopDefaultMode); } /** ********************************************************************* @@ -650,94 +725,6 @@ struct rgba_data instance methods ************************************************************************/ -/** ********************************************************************* - * double check that a mouse event occurred in our client view - ***********************************************************************/ - -- (BOOL) eventIsInClientArea :(NSEvent *) event :(int *) xptr :(int *) yptr -{ - NSPoint loc = [event locationInWindow]; - int x = (int) loc.x; - int y = (int) loc.y; - - if ((x < 0) || (y < 0)) - { - if (mouseInClientArea) - { - // set default cursor before leaving client area - mouseInClientArea = NO; - NSCursor *cur = [NSCursor arrowCursor]; - [cur set]; - } - - return NO; - } - - if ((x > width) || (y > height)) - { - if (mouseInClientArea) - { - // set default cursor before leaving client area - mouseInClientArea = NO; - NSCursor *cur = [NSCursor arrowCursor]; - [cur set]; - } - - return NO; - } - - // on Mac origin is at lower left, but we want it on upper left - y = height - y; - - *xptr = x; - *yptr = y; - mouseInClientArea = YES; - return YES; -} - -/** ********************************************************************* - * called when we fail to connect to a RDP server - ***********************************************************************/ - -- (void) rdpConnectError -{ - NSString* message = @"Error connecting to server"; - if (connectErrorCode == AUTHENTICATIONERROR) - { - message = [NSString stringWithFormat:@"%@:\n%@", message, @"Authentication failure, check credentials."]; - } - - NSAlert *alert = [[NSAlert alloc] init]; - [alert setMessageText:message]; - [alert beginSheetModalForWindow:[self window] - modalDelegate:self - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:nil]; -} - -/** ********************************************************************* - * called when we fail to launch remote app on RDP server - ***********************************************************************/ - -- (void) rdpRemoteAppError -{ - NSAlert *alert = [[NSAlert alloc] init]; - [alert setMessageText:@"Error starting remote app on specified server"]; - [alert beginSheetModalForWindow:[self window] - modalDelegate:self - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:nil]; -} - -/** ********************************************************************* - * just a terminate selector for above call - ***********************************************************************/ - -- (void) alertDidEnd:(NSAlert *)a returnCode:(NSInteger)rc contextInfo:(void *)ci -{ - [NSApp terminate:nil]; -} - - (void) onPasteboardTimerFired :(NSTimer*) timer { int i; @@ -870,7 +857,6 @@ BOOL mac_pre_connect(freerdp* instance) settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE; settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE; - [view setViewSize :instance->settings->DesktopWidth :instance->settings->DesktopHeight]; freerdp_channels_pre_connect(instance->context->channels, instance); return TRUE; @@ -975,7 +961,7 @@ void mf_Pointer_New(rdpContext* context, rdpPointer* pointer) MRDPCursor* mrdpCursor = [[MRDPCursor alloc] init]; mfContext* mfc = (mfContext*) context; MRDPView* view = (MRDPView*) mfc->view; - + rect.size.width = pointer->width; rect.size.height = pointer->height; rect.origin.x = pointer->xPos; @@ -984,9 +970,17 @@ void mf_Pointer_New(rdpContext* context, rdpPointer* pointer) cursor_data = (BYTE*) malloc(rect.size.width * rect.size.height * 4); mrdpCursor->cursor_data = cursor_data; + if (pointer->xorBpp > 24) + { + freerdp_image_swap_color_order(pointer->xorMaskData, pointer->width, pointer->height); + } + freerdp_alpha_cursor_convert(cursor_data, pointer->xorMaskData, pointer->andMaskData, pointer->width, pointer->height, pointer->xorBpp, context->gdi->clrconv); - + + // TODO if xorBpp is > 24 need to call freerdp_image_swap_color_order + // see file df_graphics.c + /* store cursor bitmap image in representation - required by NSImage */ bmiRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **) &cursor_data pixelsWide:rect.size.width @@ -1054,18 +1048,17 @@ void mf_Pointer_Set(rdpContext* context, rdpPointer* pointer) MRDPView* view = (MRDPView*) mfc->view; NSMutableArray* ma = view->cursors; - - if (!view->mouseInClientArea) - return; - + for (MRDPCursor* cursor in ma) { if (cursor->pointer == pointer) { - [cursor->nsCursor set]; + [view setCursor:cursor->nsCursor]; return; } } + + NSLog(@"Cursor not found"); } /** ********************************************************************* @@ -1083,7 +1076,9 @@ void mf_Pointer_SetNull(rdpContext* context) void mf_Pointer_SetDefault(rdpContext* context) { - + mfContext* mfc = (mfContext*) context; + MRDPView* view = (MRDPView*) mfc->view; + [view setCursor:[NSCursor arrowCursor]]; } /** ********************************************************************* @@ -1155,16 +1150,15 @@ void mac_end_paint(rdpContext* context) * called when update data is available ***********************************************************************/ -static void update_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info) +static void update_activity_cb(freerdp* instance) { int status; wMessage message; wMessageQueue* queue; - freerdp* instance = (freerdp*) info; status = 1; queue = freerdp_get_message_queue(instance, FREERDP_UPDATE_MESSAGE_QUEUE); - + if (queue) { while (MessageQueue_Peek(queue, &message, TRUE)) @@ -1175,21 +1169,21 @@ static void update_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBack break; } } - - CFRelease(fdref); - register_update_fds(instance); + else + { + fprintf(stderr, "update_activity_cb: No queue!\n"); + } } /** ********************************************************************* * called when input data is available ***********************************************************************/ -static void input_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info) +static void input_activity_cb(freerdp* instance) { int status; wMessage message; - wMessageQueue* queue; - freerdp* instance = (freerdp*) info; + wMessageQueue* queue; status = 1; queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE); @@ -1198,34 +1192,32 @@ static void input_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackT { while (MessageQueue_Peek(queue, &message, TRUE)) { - fprintf(stderr, "input_activity_cb: message %d\n", message.id); - status = freerdp_message_queue_process_message(instance, FREERDP_INPUT_MESSAGE_QUEUE, &message); if (!status) break; } } - - CFRelease(fdref); - register_input_fds(instance); + else + { + fprintf(stderr, "input_activity_cb: No queue!\n"); + } } /** ********************************************************************* * called when data is available on a virtual channel ***********************************************************************/ -static void channel_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info) +static void channel_activity_cb(freerdp* instance) { - wMessage* event; - freerdp* instance = (freerdp*) info; + wMessage* event; freerdp_channels_process_pending_messages(instance); event = freerdp_channels_pop_event(instance->context->channels); - if (event) { - switch (GetMessageClass(event->id)) + fprintf(stderr, "channel_activity_cb: message %d\n", event->id); + switch (GetMessageClass(event->id)) { case CliprdrChannel_Class: process_cliprdr_event(instance, event); @@ -1234,90 +1226,6 @@ static void channel_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBac freerdp_event_free(event); } - - CFRelease(fdref); - register_channels_fds(instance); -} - -/** ********************************************************************* - * setup callbacks for data availability on update message queue - ***********************************************************************/ - -int register_update_fds(freerdp* instance) -{ - int fd_update_event; - HANDLE update_event; - CFFileDescriptorRef fdref; - CFFileDescriptorContext fd_context = { 0, instance, NULL, NULL, NULL }; - mfContext* mfc = (mfContext*) instance->context; - MRDPView* view = (MRDPView*) mfc->view; - - if (instance->settings->AsyncUpdate) - { - update_event = freerdp_get_message_queue_event_handle(instance, FREERDP_UPDATE_MESSAGE_QUEUE); - fd_update_event = GetEventFileDescriptor(update_event); - - fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd_update_event, true, update_activity_cb, &fd_context); - CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack); - view->run_loop_src_update = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0); - CFRunLoopAddSource(CFRunLoopGetCurrent(), view->run_loop_src_update, kCFRunLoopDefaultMode); - } - - return 0; -} - -/** ********************************************************************* - * setup callbacks for data availability on input message queue - ***********************************************************************/ - -int register_input_fds(freerdp* instance) -{ - int fd_input_event; - HANDLE input_event; - CFFileDescriptorRef fdref; - CFFileDescriptorContext fd_context = { 0, instance, NULL, NULL, NULL }; - mfContext* mfc = (mfContext*) instance->context; - MRDPView* view = (MRDPView*) mfc->view; - - if (instance->settings->AsyncInput) - { - input_event = freerdp_get_message_queue_event_handle(instance, FREERDP_INPUT_MESSAGE_QUEUE); - fd_input_event = GetEventFileDescriptor(input_event); - - fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd_input_event, true, input_activity_cb, &fd_context); - CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack); - view->run_loop_src_input = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0); - CFRunLoopAddSource(CFRunLoopGetCurrent(), view->run_loop_src_input, kCFRunLoopDefaultMode); - } - - return 0; -} - -/** ********************************************************************* - * setup callbacks for data availability on channels - ***********************************************************************/ - -int register_channels_fds(freerdp* instance) -{ - int fd_channel_event; - HANDLE channel_event; - CFFileDescriptorRef fdref; - CFFileDescriptorContext fd_context = { 0, instance, NULL, NULL, NULL }; - mfContext* mfc = (mfContext*) instance->context; - MRDPView* view = (MRDPView*) mfc->view; - - if (instance->settings->AsyncChannels) - { - channel_event = freerdp_channels_get_event_handle(instance); - fd_channel_event = GetEventFileDescriptor(channel_event); - - fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd_channel_event, true, channel_activity_cb, &fd_context); - CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack); - view->run_loop_src_channels = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0); - CFRunLoopAddSource(CFRunLoopGetCurrent(), view->run_loop_src_channels, kCFRunLoopDefaultMode); - } - - return 0; } /** ********************************************************************* @@ -1555,20 +1463,12 @@ void cliprdr_send_supported_format_list(freerdp* instance) freerdp_channels_send_event(instance->context->channels, (wMessage*) event); } - -/** - * given a rect with 0,0 at the bottom left (apple cords) - * convert it to a rect with 0,0 at the top left (windows cords) - */ - -void apple_to_windows_cords(MRDPView* view, NSRect* r) -{ - r->origin.y = view->height - (r->origin.y + r->size.height); -} - /** * given a rect with 0,0 at the top left (windows cords) * convert it to a rect with 0,0 at the bottom left (apple cords) + * + * Note: the formula works for conversions in both directions. + * */ void windows_to_apple_cords(MRDPView* view, NSRect* r) diff --git a/client/Mac/cli/AppDelegate.h b/client/Mac/cli/AppDelegate.h index 2ce5ca858..91439c06f 100644 --- a/client/Mac/cli/AppDelegate.h +++ b/client/Mac/cli/AppDelegate.h @@ -18,6 +18,8 @@ MRDPView* mrdpView; } +- (void) rdpConnectError: (NSString*) customMessage; + @property (assign) IBOutlet NSWindow *window; @property (assign) rdpContext *context; diff --git a/client/Mac/cli/AppDelegate.m b/client/Mac/cli/AppDelegate.m index 6c53f4805..aec62be91 100644 --- a/client/Mac/cli/AppDelegate.m +++ b/client/Mac/cli/AppDelegate.m @@ -11,8 +11,9 @@ #import "MacFreeRDP/mf_client.h" static AppDelegate* _singleDelegate = nil; -void AppDelegate_EmbedWindowEventHandler(rdpContext* context, EmbedWindowEventArgs* e); - +void AppDelegate_EmbedWindowEventHandler(void* context, EmbedWindowEventArgs* e); +void AppDelegate_ConnectionResultEventHandler(void* context, ConnectionResultEventArgs* e); +void AppDelegate_ErrorInfoEventHandler(void* ctx, ErrorInfoEventArgs* e); @implementation AppDelegate @@ -45,7 +46,10 @@ void AppDelegate_EmbedWindowEventHandler(rdpContext* context, EmbedWindowEventAr } else { - PubSub_Subscribe(context->pubSub, "EmbedWindow", (pEventHandler) AppDelegate_EmbedWindowEventHandler); + PubSub_SubscribeConnectionResult(context->pubSub, AppDelegate_ConnectionResultEventHandler); + PubSub_SubscribeErrorInfo(context->pubSub, AppDelegate_ErrorInfoEventHandler); + PubSub_SubscribeEmbedWindow(context->pubSub, AppDelegate_EmbedWindowEventHandler); + freerdp_client_start(context); } } @@ -110,10 +114,39 @@ void AppDelegate_EmbedWindowEventHandler(rdpContext* context, EmbedWindowEventAr } +/** ********************************************************************* + * called when we fail to connect to a RDP server - Make sure this is called from the main thread. + ***********************************************************************/ + +- (void) rdpConnectError : (NSString*) withMessage +{ + NSString* message = withMessage ? withMessage : @"Error connecting to server"; + + NSAlert *alert = [[NSAlert alloc] init]; + [alert setMessageText:message]; + [alert beginSheetModalForWindow:[self window] + modalDelegate:self + didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) + contextInfo:nil]; +} + + +/** ********************************************************************* + * just a terminate selector for above call + ***********************************************************************/ + +- (void) alertDidEnd:(NSAlert *)a returnCode:(NSInteger)rc contextInfo:(void *)ci +{ + [NSApp terminate:nil]; +} + + @end -void AppDelegate_EmbedWindowEventHandler(rdpContext* context, EmbedWindowEventArgs* e) +void AppDelegate_EmbedWindowEventHandler(void* ctx, EmbedWindowEventArgs* e) { + rdpContext* context = (rdpContext*) ctx; + if (_singleDelegate) { mfContext* mfc = (mfContext*) context; @@ -124,4 +157,48 @@ void AppDelegate_EmbedWindowEventHandler(rdpContext* context, EmbedWindowEventAr [[_singleDelegate->window contentView] addSubview:mfc->view]; } } +} + +/** ********************************************************************* + * On connection error, display message and quit application + ***********************************************************************/ + +void AppDelegate_ConnectionResultEventHandler(void* ctx, ConnectionResultEventArgs* e) +{ + NSLog(@"ConnectionResult event result:%d\n", e->result); + if (_singleDelegate) + { + if (e->result != 0) + { + NSString* message = nil; + if (connectErrorCode == AUTHENTICATIONERROR) + { + message = [NSString stringWithFormat:@"%@:\n%@", message, @"Authentication failure, check credentials."]; + } + + + // Making sure this should be invoked on the main UI thread. + [_singleDelegate performSelectorOnMainThread:@selector(rdpConnectError:) withObject:message waitUntilDone:FALSE]; + [message release]; + } + } +} + +void AppDelegate_ErrorInfoEventHandler(void* ctx, ErrorInfoEventArgs* e) +{ + NSLog(@"ErrorInfo event code:%d\n", e->code); + if (_singleDelegate) + { + // Retrieve error message associated with error code + NSString* message = nil; + if (e->code != ERRINFO_NONE) + { + const char* errorMessage = freerdp_get_error_info_string(e->code); + message = [[NSString alloc] initWithUTF8String:errorMessage]; + } + + // Making sure this should be invoked on the main UI thread. + [_singleDelegate performSelectorOnMainThread:@selector(rdpConnectError:) withObject:message waitUntilDone:TRUE]; + [message release]; + } } \ No newline at end of file diff --git a/client/Mac/cli/CMakeLists.txt b/client/Mac/cli/CMakeLists.txt index 46643227d..81f940d1d 100644 --- a/client/Mac/cli/CMakeLists.txt +++ b/client/Mac/cli/CMakeLists.txt @@ -86,7 +86,7 @@ set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/Mac") add_custom_command(TARGET ${MODULE_NAME} POST_BUILD COMMAND mkdir ARGS -p ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.app/Contents/Frameworks COMMAND ditto ${CMAKE_CURRENT_BINARY_DIR}/../$(CONFIGURATION)/MacFreeRDP.framework ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.app/Contents/Frameworks/MacFreeRDP.framework - COMMAND install_name_tool -change "@executable_path/../../Frameworks/MacFreeRDP.framework/Versions/1.1.0/MacFreeRDP" + COMMAND install_name_tool -change "@executable_path/../Frameworks/MacFreeRDP.framework/Versions/${MAC_OS_X_BUNDLE_BUNDLE_VERSION}/MacFreeRDP" "@executable_path/../Frameworks/MacFreeRDP.framework/Versions/Current/MacFreeRDP" "${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.app/Contents/MacOS/${MODULE_NAME}" COMMENT Setting install name for MacFreeRDP) diff --git a/client/Mac/mf_client.m b/client/Mac/mf_client.m index 900c488ed..cf830d3c7 100755 --- a/client/Mac/mf_client.m +++ b/client/Mac/mf_client.m @@ -73,8 +73,7 @@ int mfreerdp_client_stop(rdpContext* context) MessageQueue_PostQuit(queue, 0); } } - - if (context->settings->AsyncInput) + else if (context->settings->AsyncInput) { wMessageQueue* queue; queue = freerdp_get_message_queue(context->instance, FREERDP_INPUT_MESSAGE_QUEUE); @@ -87,6 +86,14 @@ int mfreerdp_client_stop(rdpContext* context) { mfc->disconnect = TRUE; } + + if (mfc->thread) + { + SetEvent(mfc->stopEvent); + WaitForSingleObject(mfc->thread, INFINITE); + CloseHandle(mfc->thread); + mfc->thread = NULL; + } if (mfc->view_ownership) { @@ -106,6 +113,8 @@ int mfreerdp_client_new(freerdp* instance, rdpContext* context) mfc = (mfContext*) instance->context; + mfc->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + context->instance->PreConnect = mac_pre_connect; context->instance->PostConnect = mac_post_connect; context->instance->ReceiveChannelData = mac_receive_channel_data; @@ -115,8 +124,8 @@ int mfreerdp_client_new(freerdp* instance, rdpContext* context) settings = instance->settings; - settings->AsyncUpdate = TRUE; - // TODO settings->AsyncInput = TRUE; + settings->AsyncUpdate = TRUE; + settings->AsyncInput = TRUE; settings->AsyncChannels = TRUE; settings->AsyncTransport = TRUE; settings->RedirectClipboard = TRUE; diff --git a/client/Mac/mfreerdp.h b/client/Mac/mfreerdp.h index ff3bd6176..52e7be122 100644 --- a/client/Mac/mfreerdp.h +++ b/client/Mac/mfreerdp.h @@ -44,6 +44,7 @@ struct mf_context int client_height; HANDLE keyboardThread; + HANDLE stopEvent; HGDI_DC hdc; UINT16 srcBpp; diff --git a/client/Windows/CMakeLists.txt b/client/Windows/CMakeLists.txt index 0f2b26d65..f32422cd3 100644 --- a/client/Windows/CMakeLists.txt +++ b/client/Windows/CMakeLists.txt @@ -63,8 +63,10 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) if(WITH_CLIENT_INTERFACE) + if (NOT WITH_WAYK) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) add_subdirectory(cli) + endif() else() install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT client) endif() diff --git a/client/Windows/wf_gdi.c b/client/Windows/wf_gdi.c index 41fae28d0..7b497cf82 100644 --- a/client/Windows/wf_gdi.c +++ b/client/Windows/wf_gdi.c @@ -664,8 +664,8 @@ void wf_gdi_register_update_callbacks(rdpUpdate* update) { rdpPrimaryUpdate* primary = update->primary; - update->Palette = wf_gdi_palette_update; - update->SetBounds = wf_gdi_set_bounds; + update->Palette = (pPalette) wf_gdi_palette_update; + update->SetBounds = (pSetBounds) wf_gdi_set_bounds; primary->DstBlt = (pDstBlt) wf_gdi_dstblt; primary->PatBlt = (pPatBlt) wf_gdi_patblt; @@ -690,8 +690,8 @@ void wf_gdi_register_update_callbacks(rdpUpdate* update) primary->EllipseSC = NULL; primary->EllipseCB = NULL; - update->SurfaceBits = wf_gdi_surface_bits; - update->SurfaceFrameMarker = wf_gdi_surface_frame_marker; + update->SurfaceBits = (pSurfaceBits) wf_gdi_surface_bits; + update->SurfaceFrameMarker = (pSurfaceFrameMarker) wf_gdi_surface_frame_marker; } void wf_update_canvas_diff(wfContext* wfc) diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c index 44842b83c..7205a7b67 100644 --- a/client/X11/xf_event.c +++ b/client/X11/xf_event.c @@ -101,13 +101,15 @@ static BOOL xf_event_Expose(xfContext* xfc, XEvent* event, BOOL app) { xf_draw_screen_scaled(xfc, x - xfc->offset_x, y - xfc->offset_y, w, h, FALSE); - } else + } + else { XCopyArea(xfc->display, xfc->primary, xfc->window->handle, xfc->gc, x, y, w, h, x, y); } - } else + } + else { xfWindow* xfw; rdpWindow* window; @@ -116,7 +118,7 @@ static BOOL xf_event_Expose(xfContext* xfc, XEvent* event, BOOL app) window = window_list_get_by_extra_id(rail->list, (void*) event->xexpose.window); - if (window != NULL ) + if (window) { xfw = (xfWindow*) window->extra; xf_UpdateWindowArea(xfc, xfw, x, y, w, h); diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index 8b185ce7e..b3e296966 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -255,7 +255,7 @@ void xf_Pointer_Free(rdpContext* context, rdpPointer* pointer) xf_lock_x11(xfc, FALSE); - if (((xfPointer*) pointer)->cursor != 0) + if (((xfPointer*) pointer)->cursor) XFreeCursor(xfc->display, ((xfPointer*) pointer)->cursor); xf_unlock_x11(xfc, FALSE); @@ -269,10 +269,12 @@ void xf_Pointer_Set(rdpContext* context, rdpPointer* pointer) xf_lock_x11(xfc, FALSE); + xfc->pointer = (xfPointer*) pointer; + /* in RemoteApp mode, window can be null if none has had focus */ - if (xfc->window != NULL) - XDefineCursor(xfc->display, xfc->window->handle, ((xfPointer*) pointer)->cursor); + if (xfc->window) + XDefineCursor(xfc->display, xfc->window->handle, xfc->pointer->cursor); xf_unlock_x11(xfc, FALSE); #endif @@ -299,7 +301,9 @@ void xf_Pointer_SetNull(rdpContext* context) nullcursor = XcursorImageLoadCursor(xfc->display, &ci); } - if (xfc->window != NULL && nullcursor != None) + xfc->pointer = NULL; + + if ((xfc->window) && (nullcursor != None)) XDefineCursor(xfc->display, xfc->window->handle, nullcursor); xf_unlock_x11(xfc, FALSE); @@ -313,7 +317,9 @@ void xf_Pointer_SetDefault(rdpContext* context) xf_lock_x11(xfc, FALSE); - if (xfc->window != NULL) + xfc->pointer = NULL; + + if (xfc->window) XUndefineCursor(xfc->display, xfc->window->handle); xf_unlock_x11(xfc, FALSE); diff --git a/client/X11/xf_input.c b/client/X11/xf_input.c index 9e4f90cc1..7f19d4ba3 100644 --- a/client/X11/xf_input.c +++ b/client/X11/xf_input.c @@ -21,6 +21,13 @@ #include "config.h" #endif +#include +#include + +#ifdef WITH_XCURSOR +#include +#endif + #ifdef WITH_XI #include #endif @@ -551,6 +558,57 @@ char* xf_input_touch_state_string(DWORD flags) return "TouchUnknown"; } +void xf_input_hide_cursor(xfContext* xfc) +{ +#ifdef WITH_XCURSOR + if (!xfc->cursorHidden) + { + XcursorImage ci; + XcursorPixel xp = 0; + static Cursor nullcursor = None; + + xf_lock_x11(xfc, FALSE); + + ZeroMemory(&ci, sizeof(ci)); + ci.version = XCURSOR_IMAGE_VERSION; + ci.size = sizeof(ci); + ci.width = ci.height = 1; + ci.xhot = ci.yhot = 0; + ci.pixels = &xp; + nullcursor = XcursorImageLoadCursor(xfc->display, &ci); + + if ((xfc->window) && (nullcursor != None)) + XDefineCursor(xfc->display, xfc->window->handle, nullcursor); + + xfc->cursorHidden = TRUE; + + xf_unlock_x11(xfc, FALSE); + } +#endif +} + +void xf_input_show_cursor(xfContext* xfc) +{ +#ifdef WITH_XCURSOR + xf_lock_x11(xfc, FALSE); + + if (xfc->cursorHidden) + { + if (xfc->window) + { + if (!xfc->pointer) + XUndefineCursor(xfc->display, xfc->window->handle); + else + XDefineCursor(xfc->display, xfc->window->handle, xfc->pointer->cursor); + } + + xfc->cursorHidden = FALSE; + } + + xf_unlock_x11(xfc, FALSE); +#endif +} + int xf_input_touch_remote(xfContext* xfc, XIDeviceEvent* event, int evtype) { int x, y; @@ -561,6 +619,8 @@ int xf_input_touch_remote(xfContext* xfc, XIDeviceEvent* event, int evtype) if (!rdpei) return 0; + xf_input_hide_cursor(xfc); + touchId = event->detail; x = (int) event->event_x; y = (int) event->event_y; @@ -586,7 +646,8 @@ int xf_input_touch_remote(xfContext* xfc, XIDeviceEvent* event, int evtype) int xf_input_event(xfContext* xfc, XIDeviceEvent* event, int evtype) { - + xf_input_show_cursor(xfc); + switch (evtype) { case XI_ButtonPress: diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index a7a3cd5ff..a7aaa70a2 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -89,6 +89,7 @@ struct xf_context BOOL unobscured; BOOL debug; xfWindow* window; + xfPointer* pointer; xfWorkArea workArea; int current_desktop; BOOL remote_app; @@ -96,6 +97,7 @@ struct xf_context HCLRCONV clrconv; HANDLE mutex; BOOL UseXThreads; + BOOL cursorHidden; HGDI_DC hdc; BYTE* primary_buffer; @@ -106,7 +108,6 @@ struct xf_context UINT16 frame_x2; UINT16 frame_y2; - //double scale; int originalWidth; int originalHeight; int currentWidth; diff --git a/client/common/CMakeLists.txt b/client/common/CMakeLists.txt index e249cd0db..954f3a46f 100644 --- a/client/common/CMakeLists.txt +++ b/client/common/CMakeLists.txt @@ -53,7 +53,9 @@ target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) set_target_properties(${MODULE_NAME} PROPERTIES LINK_INTERFACE_LIBRARIES "") -install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) +if (NOT WITH_WAYK) + install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) +endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/Common") diff --git a/client/common/file.c b/client/common/file.c index 324b4d619..a1ec5a362 100644 --- a/client/common/file.c +++ b/client/common/file.c @@ -480,7 +480,7 @@ BOOL freerdp_client_parse_rdp_file(rdpFile* file, const char* name) return freerdp_client_parse_rdp_file_buffer(file, buffer, file_size); } -#define WRITE_ALL_SETTINGS TRUE +#define WRITE_ALL_SETTINGS FALSE #define SETTING_MODIFIED(_settings, _field) (WRITE_ALL_SETTINGS || _settings->settings_modified[FreeRDP_##_field]) #define SETTING_MODIFIED_SET(_target, _settings, _field) if SETTING_MODIFIED(_settings, _field) _target = _settings->_field @@ -605,7 +605,6 @@ if (~__rdpFile->_field) \ #define WRITE_RDP_FILE_VALUE_RETURN \ return __required_size; -// TODO: Optimize by only writing the fields that have a value i.e ~((size_t) file->FieldName) != 0 size_t freerdp_client_write_rdp_file_buffer(rdpFile* file, char* buffer, size_t size) { WRITE_RDP_FILE_DECLARE(file, buffer, size) diff --git a/cmake/FindPixman.cmake b/cmake/FindPixman.cmake new file mode 100644 index 000000000..7bfca77bd --- /dev/null +++ b/cmake/FindPixman.cmake @@ -0,0 +1,40 @@ +# - Find Pixman +# Find the Pixman libraries +# +# This module defines the following variables: +# PIXMAN_FOUND - true if PIXMAN_INCLUDE_DIR & PIXMAN_LIBRARY are found +# PIXMAN_LIBRARIES - Set when PIXMAN_LIBRARY is found +# PIXMAN_INCLUDE_DIRS - Set when PIXMAN_INCLUDE_DIR is found +# +# PIXMAN_INCLUDE_DIR - where to find pixman.h, etc. +# PIXMAN_LIBRARY - the Pixman library +# + +#============================================================================= +# Copyright 2013 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. +#============================================================================= + +find_path(PIXMAN_INCLUDE_DIR NAMES pixman.h PATH_SUFFIXES pixman-1) + +find_library(PIXMAN_LIBRARY NAMES pixman-1) + +find_package_handle_standard_args(pixman-1 DEFAULT_MSG PIXMAN_LIBRARY PIXMAN_INCLUDE_DIR) + +if(PIXMAN-1_FOUND) + set(PIXMAN_LIBRARIES ${PIXMAN_LIBRARY}) + set(PIXMAN_INCLUDE_DIRS ${PIXMAN_INCLUDE_DIR}) +endif() + +mark_as_advanced(PIXMAN_INCLUDE_DIR PIXMAN_LIBRARY) diff --git a/cmake/MSVCRuntime.cmake b/cmake/MSVCRuntime.cmake index c71a750a5..1c59932c3 100644 --- a/cmake/MSVCRuntime.cmake +++ b/cmake/MSVCRuntime.cmake @@ -5,17 +5,20 @@ macro(configure_msvc_runtime) if("${MSVC_RUNTIME}" STREQUAL "") set(MSVC_RUNTIME "dynamic") endif() + # Set compiler options. set(variables + CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELEASE - CMAKE_CXX_FLAGS_RELWITHDEBINFO - ) + CMAKE_CXX_FLAGS_RELWITHDEBINFO) + if(${MSVC_RUNTIME} STREQUAL "static") message(STATUS "MSVC: using statically-linked runtime (/MT and /MTd).") foreach(variable ${variables}) @@ -31,6 +34,25 @@ macro(configure_msvc_runtime) endif() endforeach() endif() + + foreach(variable ${variables}) + if(${variable} MATCHES "/Ob0") + string(REGEX REPLACE "/Ob0" "/Ob2" ${variable} "${${variable}}") + endif() + endforeach() + + foreach(variable ${variables}) + if(${variable} MATCHES "/W3") + string(REGEX REPLACE "/W3" "/W2" ${variable} "${${variable}}") + endif() + endforeach() + + set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") + set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") + foreach(variable ${variables}) set(${variable} "${${variable}}" CACHE STRING "MSVC_${variable}" FORCE) endforeach() diff --git a/config.h.in b/config.h.in index 63de66d8d..83b0abecb 100755 --- a/config.h.in +++ b/config.h.in @@ -30,6 +30,7 @@ #cmakedefine HAVE_SYS_SELECT_H #cmakedefine HAVE_SYS_STRTIO_H #cmakedefine HAVE_EVENTFD_H +#cmakedefine HAVE_TIMERFD_H #cmakedefine HAVE_TM_GMTOFF diff --git a/include/freerdp/channels/rdpdr.h b/include/freerdp/channels/rdpdr.h index 4aa209481..88b1bbe79 100644 --- a/include/freerdp/channels/rdpdr.h +++ b/include/freerdp/channels/rdpdr.h @@ -138,17 +138,7 @@ enum FILE_CREATE_OPTION #define FILE_WRITE_ATTRIBUTES 0x00000100 #endif -#define DELETE 0x00010000 -#define READ_CONTROL 0x00020000 -#define WRITE_DAC 0x00040000 -#define WRITE_OWNER 0x00080000 -#define SYNCHRONIZE 0x00100000 -#define ACCESS_SYSTEM_SECURITY 0x01000000 -#define MAXIMUM_ALLOWED 0x02000000 -#define GENERIC_ALL 0x10000000 -#define GENERIC_EXECUTE 0x20000000 -#define GENERIC_WRITE 0x40000000 -#define GENERIC_READ 0x80000000 +#include #endif diff --git a/include/freerdp/error.h b/include/freerdp/error.h old mode 100644 new mode 100755 index 8b0abd8f0..3c00b5c13 --- a/include/freerdp/error.h +++ b/include/freerdp/error.h @@ -20,6 +20,10 @@ #ifndef FREERDP_ERROR_H #define FREERDP_ERROR_H +#include + +#include + #ifdef __cplusplus extern "C" { #endif @@ -128,6 +132,9 @@ extern "C" { #define ERRINFO_SUCCESS 0x00000000 #define ERRINFO_NONE 0xFFFFFFFF +FREERDP_API const char* freerdp_get_error_info_string(UINT32 code); +FREERDP_API const char* freerdp_get_error_info_name(UINT32 code); + /** * This static variable holds an error code if the return value from connect is FALSE. * This variable is always set to 0 in the beginning of the connect sequence. @@ -135,7 +142,7 @@ extern "C" { * The value can hold one of the defined error codes below OR an error according to errno */ -extern int connectErrorCode; +FREERDP_API extern int connectErrorCode; #define ERRORSTART 10000 #define PREECONNECTERROR ERRORSTART + 1 diff --git a/include/freerdp/listener.h b/include/freerdp/listener.h index 49cd12217..9ae1156d6 100644 --- a/include/freerdp/listener.h +++ b/include/freerdp/listener.h @@ -34,6 +34,7 @@ extern "C" { typedef BOOL (*psListenerOpen)(freerdp_listener* instance, const char* bind_address, UINT16 port); typedef BOOL (*psListenerOpenLocal)(freerdp_listener* instance, const char* path); typedef BOOL (*psListenerGetFileDescriptor)(freerdp_listener* instance, void** rfds, int* rcount); +typedef int (*psListenerGetEventHandles)(freerdp_listener* instance, HANDLE* events, DWORD* nCount); typedef BOOL (*psListenerCheckFileDescriptor)(freerdp_listener* instance); typedef void (*psListenerClose)(freerdp_listener* instance); typedef void (*psPeerAccepted)(freerdp_listener* instance, freerdp_peer* client); @@ -50,6 +51,7 @@ struct rdp_freerdp_listener psListenerOpen Open; psListenerOpenLocal OpenLocal; psListenerGetFileDescriptor GetFileDescriptor; + psListenerGetEventHandles GetEventHandles; psListenerCheckFileDescriptor CheckFileDescriptor; psListenerClose Close; diff --git a/include/freerdp/locale/keyboard.h b/include/freerdp/locale/keyboard.h index 32a7ed5fe..147067d8e 100644 --- a/include/freerdp/locale/keyboard.h +++ b/include/freerdp/locale/keyboard.h @@ -205,6 +205,7 @@ extern "C" { FREERDP_API DWORD freerdp_keyboard_init(DWORD keyboardLayoutId); FREERDP_API RDP_KEYBOARD_LAYOUT* freerdp_keyboard_get_layouts(DWORD types); +FREERDP_API void freerdp_keyboard_layouts_free(RDP_KEYBOARD_LAYOUT* layouts); FREERDP_API const char* freerdp_keyboard_get_layout_name_from_id(DWORD keyboardLayoutId); FREERDP_API DWORD freerdp_keyboard_get_layout_id_from_name(const char* name); FREERDP_API DWORD freerdp_keyboard_get_rdp_scancode_from_x11_keycode(DWORD keycode); diff --git a/include/freerdp/peer.h b/include/freerdp/peer.h index 6279c92bc..e447ba014 100644 --- a/include/freerdp/peer.h +++ b/include/freerdp/peer.h @@ -33,6 +33,7 @@ typedef void (*psPeerContextFree)(freerdp_peer* client, rdpContext* context); typedef BOOL (*psPeerInitialize)(freerdp_peer* client); typedef BOOL (*psPeerGetFileDescriptor)(freerdp_peer* client, void** rfds, int* rcount); +typedef HANDLE (*psPeerGetEventHandle)(freerdp_peer* client); typedef BOOL (*psPeerCheckFileDescriptor)(freerdp_peer* client); typedef BOOL (*psPeerClose)(freerdp_peer* client); typedef void (*psPeerDisconnect)(freerdp_peer* client); @@ -60,6 +61,7 @@ struct rdp_freerdp_peer psPeerInitialize Initialize; psPeerGetFileDescriptor GetFileDescriptor; + psPeerGetEventHandle GetEventHandle; psPeerCheckFileDescriptor CheckFileDescriptor; psPeerClose Close; psPeerDisconnect Disconnect; diff --git a/libfreerdp/CMakeLists.txt b/libfreerdp/CMakeLists.txt index 6dccb0771..bbc714b15 100644 --- a/libfreerdp/CMakeLists.txt +++ b/libfreerdp/CMakeLists.txt @@ -59,9 +59,11 @@ if(MONOLITHIC_BUILD) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} - DESTINATION ${CMAKE_INSTALL_LIBDIR} - COMPONENT libraries) + if(NOT WITH_WAYK) + install(TARGETS ${MODULE_NAME} + DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT libraries) + endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp") endif() diff --git a/libfreerdp/codec/bitmap_encode.c b/libfreerdp/codec/bitmap_encode.c index 5cdca0b93..84ab3b14a 100644 --- a/libfreerdp/codec/bitmap_encode.c +++ b/libfreerdp/codec/bitmap_encode.c @@ -1572,3 +1572,153 @@ int freerdp_bitmap_compress(char* in_data, int width, int height, return lines_sent; } + +/** + * RDP6 Bitmap Test Case ([MS-RDPEGDI]) + */ + +const BYTE TEST_RDP6_COMPRESSED_BITMAP[220] = + "\x85\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x06\x8B\x99\xD6\x99" + "\xD6\x99\xD6\x10\x84\x08\x42\x08\x42\x10\x84\x99\xD6\x99\xD6\x99" + "\xD6\x99\xD6\x06\x84\x99\xD6\x99\xD6\x99\xD6\xFF\xFF\x16\x69\x99" + "\xD6\x06\x69\x99\xD6\x04\xCC\x89\x52\x03\x6E\xFF\xFF\x02\x6E\x08" + "\x42\x01\x70\x08\x42\x71\xFF\xFF\xCE\x18\xC6\x01\x81\x08\x42\xCE" + "\x66\x29\x02\xCD\x89\x52\x03\x88\x10\x84\x99\xD6\x99\xD6\x99\xD6" + "\x00\x00\x00\x00\x00\x00\x00\x00\xD8\x99\xD6\x03\xF8\x01\x00\x00" + "\x00\x00\xF0\x66\x99\xD6\x05\x6A\x99\xD6\x00\xC4\xCC\x89\x52\x03" + "\x6E\xFF\xFF\x02\x6E\x08\x42\x01\x70\x08\x42\x71\xFF\xFF\xCE\x18" + "\xC6\x01\x81\x08\x42\xCE\x66\x29\x02\xCD\x89\x52\x03\x00\x04\xD6" + "\x99\xD6\xC3\x80\x61\x00\xA5\x80\x40\xEC\x52\x00\x5A\x00\x2D\x00" + "\x24\x00\x12\x00\x24\x00\x12\x00\x5A\x00\x2D\x00\xA5\x80\x52\x00" + "\xC3\x80\x61\x00\x00\x00\x00\x00\xCC\x89\x52\x03\x6E\xFF\xFF\x02" + "\xCB\x18\xC6\x84\x08\x42\x08\x42\x08\x42\xFF\xFF"; + +const BYTE TEST_RDP6_UNCOMPRESSED_BITMAP[2048] = + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84" + "\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x99\xD6\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x08\x42" + "\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42" + "\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\xFF\xFF" + "\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42" + "\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84" + "\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x08\x42" + "\x08\x42\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84" + "\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x99\xD6\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x08\x42" + "\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42" + "\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\xFF\xFF" + "\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42" + "\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84" + "\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x08\x42" + "\x08\x42\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00" + "\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6" + "\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00" + "\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00" + "\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00" + "\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00" + "\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00" + "\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00" + "\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6" + "\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84" + "\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x99\xD6\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x08\x42" + "\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42" + "\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\xFF\xFF"; diff --git a/libfreerdp/core/activation.c b/libfreerdp/core/activation.c index c64c654dd..edc31a295 100644 --- a/libfreerdp/core/activation.c +++ b/libfreerdp/core/activation.c @@ -250,6 +250,7 @@ BOOL rdp_recv_server_font_map_pdu(rdpRdp* rdp, wStream* s) BOOL rdp_recv_client_font_map_pdu(rdpRdp* rdp, wStream* s) { rdp->finalize_sc_pdus |= FINALIZE_SC_FONT_MAP_PDU; + if(Stream_GetRemainingLength(s) >= 8) { Stream_Seek_UINT16(s); /* numberEntries (2 bytes) */ @@ -280,13 +281,10 @@ BOOL rdp_recv_deactivate_all(rdpRdp* rdp, wStream* s) UINT16 lengthSourceDescriptor; if (rdp->state == CONNECTION_STATE_ACTIVE) - { rdp->deactivation_reactivation = TRUE; - } else - { rdp->deactivation_reactivation = FALSE; - } + /* * Windows XP can send short DEACTIVATE_ALL PDU that doesn't contain * the following fields. @@ -313,7 +311,7 @@ BOOL rdp_recv_deactivate_all(rdpRdp* rdp, wStream* s) while(0); } - rdp->state = CONNECTION_STATE_CAPABILITY; + rdp_client_transition_to_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE); while (rdp->state != CONNECTION_STATE_ACTIVE) { @@ -370,6 +368,8 @@ BOOL rdp_server_accept_client_font_list_pdu(rdpRdp* rdp, wStream* s) if (!rdp_send_server_font_map_pdu(rdp)) return FALSE; + rdp_server_transition_to_state(rdp, CONNECTION_STATE_ACTIVE); + return TRUE; } diff --git a/libfreerdp/core/capabilities.c b/libfreerdp/core/capabilities.c index 4d69b4ed7..4da339677 100644 --- a/libfreerdp/core/capabilities.c +++ b/libfreerdp/core/capabilities.c @@ -185,6 +185,8 @@ BOOL rdp_read_general_capability_set(wStream* s, UINT16 length, rdpSettings* set Stream_Read_UINT8(s, refreshRectSupport); /* refreshRectSupport (1 byte) */ Stream_Read_UINT8(s, suppressOutputSupport); /* suppressOutputSupport (1 byte) */ + settings->NoBitmapCompressionHeader = (extraFlags & NO_BITMAP_COMPRESSION_HDR) ? TRUE : FALSE; + if (!(extraFlags & FASTPATH_OUTPUT_SUPPORTED)) settings->FastPathOutput = FALSE; @@ -213,7 +215,10 @@ void rdp_write_general_capability_set(wStream* s, rdpSettings* settings) header = rdp_capability_set_start(s); - extraFlags = LONG_CREDENTIALS_SUPPORTED | NO_BITMAP_COMPRESSION_HDR; + extraFlags = LONG_CREDENTIALS_SUPPORTED; + + if (settings->NoBitmapCompressionHeader) + extraFlags |= NO_BITMAP_COMPRESSION_HDR; if (settings->AutoReconnectionEnabled) extraFlags |= AUTORECONNECT_SUPPORTED; @@ -1209,7 +1214,7 @@ BOOL rdp_read_input_capability_set(wStream* s, UINT16 length, rdpSettings* setti Stream_Seek(s, 64); /* imeFileName (64 bytes) */ - if (settings->ServerMode != TRUE) + if (!settings->ServerMode) { if (inputFlags & INPUT_FLAG_FASTPATH_INPUT) { @@ -1217,7 +1222,7 @@ BOOL rdp_read_input_capability_set(wStream* s, UINT16 length, rdpSettings* setti } else if (inputFlags & INPUT_FLAG_FASTPATH_INPUT2) { - /* avertised by RDP 5.2, 6.0, 6.1 and 7.0 servers */ + /* advertised by RDP 5.2, 6.0, 6.1 and 7.0 servers */ } else { @@ -1440,17 +1445,25 @@ void rdp_write_cache_definition(wStream* s, GLYPH_CACHE_DEFINITION* cache_defini BOOL rdp_read_glyph_cache_capability_set(wStream* s, UINT16 length, rdpSettings* settings) { - UINT16 glyphSupportLevel; - if (length < 52) return FALSE; - Stream_Seek(s, 40); /* glyphCache (40 bytes) */ - Stream_Seek_UINT32(s); /* fragCache (4 bytes) */ - Stream_Read_UINT16(s, glyphSupportLevel); /* glyphSupportLevel (2 bytes) */ - Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */ + /* glyphCache (40 bytes) */ + rdp_read_cache_definition(s, &(settings->GlyphCache[0])); /* glyphCache0 (4 bytes) */ + rdp_read_cache_definition(s, &(settings->GlyphCache[1])); /* glyphCache1 (4 bytes) */ + rdp_read_cache_definition(s, &(settings->GlyphCache[2])); /* glyphCache2 (4 bytes) */ + rdp_read_cache_definition(s, &(settings->GlyphCache[3])); /* glyphCache3 (4 bytes) */ + rdp_read_cache_definition(s, &(settings->GlyphCache[4])); /* glyphCache4 (4 bytes) */ + rdp_read_cache_definition(s, &(settings->GlyphCache[5])); /* glyphCache5 (4 bytes) */ + rdp_read_cache_definition(s, &(settings->GlyphCache[6])); /* glyphCache6 (4 bytes) */ + rdp_read_cache_definition(s, &(settings->GlyphCache[7])); /* glyphCache7 (4 bytes) */ + rdp_read_cache_definition(s, &(settings->GlyphCache[8])); /* glyphCache8 (4 bytes) */ + rdp_read_cache_definition(s, &(settings->GlyphCache[9])); /* glyphCache9 (4 bytes) */ + rdp_read_cache_definition(s, settings->FragCache); /* fragCache (4 bytes) */ - settings->GlyphSupportLevel = glyphSupportLevel; + Stream_Read_UINT16(s, settings->GlyphSupportLevel); /* glyphSupportLevel (2 bytes) */ + + Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */ return TRUE; } @@ -2313,10 +2326,14 @@ BOOL rdp_print_multifragment_update_capability_set(wStream* s, UINT16 length) BOOL rdp_read_large_pointer_capability_set(wStream* s, UINT16 length, rdpSettings* settings) { + UINT16 largePointerSupportFlags; + if (length < 6) return FALSE; - Stream_Seek_UINT16(s); /* largePointerSupportFlags (2 bytes) */ + Stream_Read_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */ + + settings->LargePointerFlag = (largePointerSupportFlags & LARGE_POINTER_FLAG_96x96) ? 1 : 0; return TRUE; } @@ -2862,6 +2879,7 @@ BOOL rdp_read_frame_acknowledge_capability_set(wStream* s, UINT16 length, rdpSet { Stream_Seek_UINT32(s); /* (4 bytes) */ } + return TRUE; } @@ -2874,14 +2892,12 @@ BOOL rdp_read_frame_acknowledge_capability_set(wStream* s, UINT16 length, rdpSet void rdp_write_frame_acknowledge_capability_set(wStream* s, rdpSettings* settings) { int header; - UINT32 frame_acknowledge; Stream_EnsureRemainingCapacity(s, 32); header = rdp_capability_set_start(s); - frame_acknowledge = settings->FrameAcknowledge; - Stream_Write_UINT32(s, frame_acknowledge); /* (4 bytes) */ + Stream_Write_UINT32(s, settings->FrameAcknowledge); /* (4 bytes) */ rdp_capability_set_finish(s, header, CAPSET_TYPE_FRAME_ACKNOWLEDGE); } @@ -3501,24 +3517,13 @@ BOOL rdp_send_demand_active(rdpRdp* rdp) BOOL rdp_recv_confirm_active(rdpRdp* rdp, wStream* s) { - UINT16 channelId; - UINT16 pduType; - UINT16 pduLength; - UINT16 pduSource; + BOOL status; + rdpSettings* settings; UINT16 lengthSourceDescriptor; UINT16 lengthCombinedCapabilities; UINT16 numberCapabilities; - if (!rdp_recv_get_active_header(rdp, s, &channelId)) - return FALSE; - - if (!rdp_read_share_control_header(s, &pduLength, &pduType, &pduSource)) - return FALSE; - - rdp->settings->PduSource = pduSource; - - if (pduType != PDU_TYPE_CONFIRM_ACTIVE) - return FALSE; + settings = rdp->settings; if (Stream_GetRemainingLength(s) < 10) return FALSE; @@ -3535,7 +3540,46 @@ BOOL rdp_recv_confirm_active(rdpRdp* rdp, wStream* s) Stream_Read_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */ Stream_Seek(s, 2); /* pad2Octets (2 bytes) */ - return rdp_read_capability_sets(s, rdp->settings, numberCapabilities); + status = rdp_read_capability_sets(s, rdp->settings, numberCapabilities); + + if (!settings->ReceivedCapabilities[CAPSET_TYPE_SURFACE_COMMANDS]) + { + /* client does not support surface commands */ + } + + if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE]) + { + /* client does not support frame acks */ + settings->FrameAcknowledge = 0; + } + + if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID]) + { + /* client does not support bitmap cache v3 */ + settings->BitmapCacheV3Enabled = FALSE; + } + + if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CODECS]) + { + /* client does not support bitmap codecs */ + + settings->RemoteFxCodec = FALSE; + settings->NSCodec = FALSE; + settings->JpegCodec = FALSE; + } + + if (!settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE]) + { + /* client does not support multi fragment updates */ + } + + if (!settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER]) + { + /* client does not support large pointers */ + settings->LargePointerFlag = 0; + } + + return status; } void rdp_write_confirm_active(wStream* s, rdpSettings* settings) @@ -3628,17 +3672,13 @@ void rdp_write_confirm_active(wStream* s, rdpSettings* settings) rdp_write_bitmap_codecs_capability_set(s, settings); } - if (settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE]) - { - if (settings->FrameAcknowledge > 0) - { - numberCapabilities++; - rdp_write_frame_acknowledge_capability_set(s, settings); - } - } - else - { + if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE]) settings->FrameAcknowledge = 0; + + if (settings->FrameAcknowledge) + { + numberCapabilities++; + rdp_write_frame_acknowledge_capability_set(s, settings); } if (settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID]) diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index 247494e07..b42f23086 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -30,6 +30,7 @@ #include #include +#include /** * Connection Sequence\n @@ -61,6 +62,103 @@ * */ +/** + * + * Connection Sequence + * + * 1. Connection Initiation: The client initiates the connection by sending the server a + * Class 0 X.224 Connection Request PDU (section 2.2.1.1). The server responds with a + * Class 0 X.224 Connection Confirm PDU (section 2.2.1.2). From this point, all subsequent + * data sent between client and server is wrapped in an X.224 Data Protocol Data Unit (PDU). + * + * 2. Basic Settings Exchange: Basic settings are exchanged between the client and server by + * using the MCS Connect Initial PDU (section 2.2.1.3) and MCS Connect Response PDU (section 2.2.1.4). + * The Connect Initial PDU contains a Generic Conference Control (GCC) Conference Create Request, + * while the Connect Response PDU contains a GCC Conference Create Response. These two GCC packets + * contain concatenated blocks of settings data (such as core data, security data, and network data) + * which are read by client and server. + * + * 3. Channel Connection: The client sends an MCS Erect Domain Request PDU (section 2.2.1.5), + * followed by an MCS Attach User Request PDU (section 2.2.1.6) to attach the primary user identity + * to the MCS domain. The server responds with an MCS Attach User Confirm PDU (section 2.2.1.7) + * containing the User Channel ID. The client then proceeds to join the user channel, the + * input/output (I/O) channel, and all of the static virtual channels (the I/O and static virtual + * channel IDs are obtained from the data embedded in the GCC packets) by using multiple MCS Channel + * Join Request PDUs (section 2.2.1.8). The server confirms each channel with an MCS Channel Join + * Confirm PDU (section 2.2.1.9). (The client only sends a Channel Join Request after it has received + * the Channel Join Confirm for the previously sent request.) + * + * From this point, all subsequent data sent from the client to the server is wrapped in an MCS Send + * Data Request PDU, while data sent from the server to the client is wrapped in an MCS Send Data + * Indication PDU. This is in addition to the data being wrapped by an X.224 Data PDU. + * + * 4. RDP Security Commencement: If Standard RDP Security mechanisms (section 5.3) are being employed and + * encryption is in force (this is determined by examining the data embedded in the GCC Conference Create + * Response packet) then the client sends a Security Exchange PDU (section 2.2.1.10) containing an encrypted + * 32-byte random number to the server. This random number is encrypted with the public key of the server + * as described in section 5.3.4.1 (the server's public key, as well as a 32-byte server-generated random + * number, are both obtained from the data embedded in the GCC Conference Create Response packet). The client + * and server then utilize the two 32-byte random numbers to generate session keys which are used to encrypt + * and validate the integrity of subsequent RDP traffic. + * + * From this point, all subsequent RDP traffic can be encrypted and a security header is included with the + * data if encryption is in force. (The Client Info PDU (section 2.2.1.11) and licensing PDUs ([MS-RDPELE] + * section 2.2.2) are an exception in that they always have a security header). The Security Header follows + * the X.224 and MCS Headers and indicates whether the attached data is encrypted. Even if encryption is in + * force, server-to-client traffic may not always be encrypted, while client-to-server traffic must always be + * encrypted (encryption of licensing PDUs is optional, however). + * + * 5. Secure Settings Exchange: Secure client data (such as the username, password, and auto-reconnect cookie) + * is sent to the server by using the Client Info PDU (section 2.2.1.11). + * + * 6. Optional Connect-Time Auto-Detection: During the optional connect-time auto-detect phase the goal is to + * determine characteristics of the network, such as the round-trip latency time and the bandwidth of the link + * between the server and client. This is accomplished by exchanging a collection of PDUs (specified in section 2.2.1.4) + * over a predetermined period of time with enough data to ensure that the results are statistically relevant. + * + * 7. Licensing: The goal of the licensing exchange is to transfer a license from the server to the client. + * The client stores this license and on subsequent connections sends the license to the server for validation. + * However, in some situations the client may not be issued a license to store. In effect, the packets exchanged + * during this phase of the protocol depend on the licensing mechanisms employed by the server. Within the context + * of this document, it is assumed that the client will not be issued a license to store. For details regarding + * more advanced licensing scenarios that take place during the Licensing Phase, see [MS-RDPELE] section 1.3. + * + * 8. Optional Multitransport Bootstrapping: After the connection has been secured and the Licensing Phase has run + * to completion, the server can choose to initiate multitransport connections ([MS-RDPEMT] section 1.3). + * The Initiate Multitransport Request PDU (section 2.2.15.1) is sent by the server to the client and results + * in the out-of-band creation of a multitransport connection using messages from the RDP-UDP, TLS, DTLS, and + * multitransport protocols ([MS-RDPEMT] section 1.3.1). + * + * 9. Capabilities Exchange: The server sends the set of capabilities it supports to the client in a Demand Active PDU + * (section 2.2.1.13.1). The client responds with its capabilities by sending a Confirm Active PDU (section 2.2.1.13.2). + * + * 10. Connection Finalization: The client and server exchange PDUs to finalize the connection details. The client-to-server + * PDUs sent during this phase have no dependencies on any of the server-to-client PDUs; they may be sent as a single batch, + * provided that sequencing is maintained. + * + * - The Client Synchronize PDU (section 2.2.1.14) is sent after transmitting the Confirm Active PDU. + * - The Client Control (Cooperate) PDU (section 2.2.1.15) is sent after transmitting the Client Synchronize PDU. + * - The Client Control (Request Control) PDU (section 2.2.1.16) is sent after transmitting the Client Control (Cooperate) PDU. + * - The optional Persistent Key List PDUs (section 2.2.1.17) are sent after transmitting the Client Control (Request Control) PDU. + * - The Font List PDU (section 2.2.1.18) is sent after transmitting the Persistent Key List PDUs or, if the Persistent Key List + * PDUs were not sent, it is sent after transmitting the Client Control (Request Control) PDU (section 2.2.1.16). + * + * The server-to-client PDUs sent during the Connection Finalization Phase have dependencies on the client-to-server PDUs. + * + * - The optional Monitor Layout PDU (section 2.2.12.1) has no dependency on any client-to-server PDUs and is sent after the Demand Active PDU. + * - The Server Synchronize PDU (section 2.2.1.19) is sent in response to the Confirm Active PDU. + * - The Server Control (Cooperate) PDU (section 2.2.1.20) is sent after transmitting the Server Synchronize PDU. + * - The Server Control (Granted Control) PDU (section 2.2.1.21) is sent in response to the Client Control (Request Control) PDU. + * - The Font Map PDU (section 2.2.1.22) is sent in response to the Font List PDU. + * + * Once the client has sent the Confirm Active PDU, it can start sending mouse and keyboard input to the server, and upon receipt + * of the Font List PDU the server can start sending graphics output to the client. + * + * Besides input and graphics data, other data that can be exchanged between client and server after the connection has been + * finalized includes connection management information and virtual channel messages (exchanged between client-side plug-ins + * and server-side applications). + */ + /** * Establish RDP Connection based on the settings given in the 'rdp' parameter. * @msdn{cc240452} @@ -77,19 +175,18 @@ BOOL rdp_client_connect(rdpRdp* rdp) if (settings->GatewayEnabled) { - char* user; + char* user; char* domain; char* cookie; - int user_length = 0; + int user_length = 0; int domain_length; int cookie_length; - - if (settings->Username) - { - user = settings->Username; - user_length = strlen(settings->Username); - } + if (settings->Username) + { + user = settings->Username; + user_length = strlen(settings->Username); + } if (settings->Domain) domain = settings->Domain; @@ -105,10 +202,10 @@ BOOL rdp_client_connect(rdpRdp* rdp) CharUpperBuffA(cookie, domain_length); cookie[domain_length] = '\\'; - if (settings->Username) - CopyMemory(&cookie[domain_length + 1], user, user_length); + if (settings->Username) + CopyMemory(&cookie[domain_length + 1], user, user_length); - cookie[cookie_length] = '\0'; + cookie[cookie_length] = '\0'; nego_set_cookie(rdp->nego, cookie); free(cookie); @@ -159,7 +256,8 @@ BOOL rdp_client_connect(rdpRdp* rdp) } rdp_set_blocking_mode(rdp, FALSE); - rdp->state = CONNECTION_STATE_NEGO; + + rdp_client_transition_to_state(rdp, CONNECTION_STATE_NEGO); rdp->finalize_sc_pdus = 0; if (!mcs_send_connect_initial(rdp->mcs)) @@ -270,7 +368,7 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp) BYTE crypt_client_random[256 + 8]; BYTE client_random[CLIENT_RANDOM_LENGTH]; - if (rdp->settings->DisableEncryption == FALSE) + if (!rdp->settings->DisableEncryption) { /* no RDP encryption */ return TRUE; @@ -330,7 +428,7 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp) return TRUE; } -static BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s) +BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s) { BYTE client_random[64]; /* Should be only 32 after successful decryption, but on failure might take up to 64 bytes. */ BYTE crypt_client_random[256 + 8]; @@ -339,7 +437,7 @@ static BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s) BYTE* mod; BYTE* priv_exp; - if (rdp->settings->DisableEncryption == FALSE) + if (!rdp->settings->DisableEncryption) { /* No RDP Security. */ return TRUE; @@ -360,10 +458,12 @@ static BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s) return FALSE; } - if(Stream_GetRemainingLength(s) < 4) + if (Stream_GetRemainingLength(s) < 4) return FALSE; + Stream_Read_UINT32(s, rand_len); - if(Stream_GetRemainingLength(s) < rand_len + 8) /* include 8 bytes of padding */ + + if (Stream_GetRemainingLength(s) < rand_len + 8) /* include 8 bytes of padding */ return FALSE; key_len = rdp->settings->RdpServerRsaKey->ModulusLength; @@ -374,7 +474,7 @@ static BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s) return FALSE; } - memset(crypt_client_random, 0, sizeof(crypt_client_random)); + ZeroMemory(crypt_client_random, sizeof(crypt_client_random)); Stream_Read(s, crypt_client_random, rand_len); /* 8 zero bytes of padding */ Stream_Seek(s, 8); @@ -389,6 +489,7 @@ static BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s) } rdp->do_crypt = TRUE; + if (rdp->settings->SaltedChecksum) rdp->do_secure_checksum = TRUE; @@ -422,7 +523,7 @@ BOOL rdp_client_connect_mcs_connect_response(rdpRdp* rdp, wStream* s) if (!mcs_send_attach_user_request(rdp->mcs)) return FALSE; - rdp->state = CONNECTION_STATE_MCS_ATTACH_USER; + rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_ATTACH_USER); return TRUE; } @@ -435,7 +536,7 @@ BOOL rdp_client_connect_mcs_attach_user_confirm(rdpRdp* rdp, wStream* s) if (!mcs_send_channel_join_request(rdp->mcs, rdp->mcs->user_id)) return FALSE; - rdp->state = CONNECTION_STATE_MCS_CHANNEL_JOIN; + rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN); return TRUE; } @@ -505,7 +606,7 @@ BOOL rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, wStream* s) if (!rdp_send_client_info(rdp)) return FALSE; - rdp->state = CONNECTION_STATE_LICENSE; + rdp_client_transition_to_state(rdp, CONNECTION_STATE_LICENSING); } return TRUE; @@ -524,7 +625,7 @@ BOOL rdp_client_connect_license(rdpRdp* rdp, wStream* s) if (rdp->license->state == LICENSE_STATE_COMPLETED) { - rdp->state = CONNECTION_STATE_CAPABILITY; + rdp_client_transition_to_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE); } return TRUE; @@ -574,8 +675,7 @@ BOOL rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s) IFCALL(rdp->update->DesktopResize, rdp->update->context); } - rdp->state = CONNECTION_STATE_FINALIZATION; - update_reset_state(rdp->update); + rdp_client_transition_to_state(rdp, CONNECTION_STATE_FINALIZATION); return rdp_client_connect_finalize(rdp); } @@ -590,8 +690,10 @@ BOOL rdp_client_connect_finalize(rdpRdp* rdp) if (!rdp_send_client_synchronize_pdu(rdp)) return FALSE; + if (!rdp_send_client_control_pdu(rdp, CTRLACTION_COOPERATE)) return FALSE; + if (!rdp_send_client_control_pdu(rdp, CTRLACTION_REQUEST_CONTROL)) return FALSE; /** @@ -600,15 +702,91 @@ BOOL rdp_client_connect_finalize(rdpRdp* rdp) * stored in persistent bitmap cache or the server has advertised support for bitmap * host cache and a deactivation reactivation sequence is *not* in progress. */ + if (!rdp->deactivation_reactivation && rdp->settings->BitmapCachePersistEnabled) + { if (!rdp_send_client_persistent_key_list_pdu(rdp)) return FALSE; + } + if (!rdp_send_client_font_list_pdu(rdp, FONTLIST_FIRST | FONTLIST_LAST)) return FALSE; return TRUE; } +int rdp_client_transition_to_state(rdpRdp* rdp, int state) +{ + int status = 0; + + switch (state) + { + case CONNECTION_STATE_INITIAL: + rdp->state = CONNECTION_STATE_INITIAL; + break; + + case CONNECTION_STATE_NEGO: + rdp->state = CONNECTION_STATE_NEGO; + break; + + case CONNECTION_STATE_MCS_CONNECT: + rdp->state = CONNECTION_STATE_MCS_CONNECT; + break; + + case CONNECTION_STATE_MCS_ERECT_DOMAIN: + rdp->state = CONNECTION_STATE_MCS_ERECT_DOMAIN; + break; + + case CONNECTION_STATE_MCS_ATTACH_USER: + rdp->state = CONNECTION_STATE_MCS_ATTACH_USER; + break; + + case CONNECTION_STATE_MCS_CHANNEL_JOIN: + rdp->state = CONNECTION_STATE_MCS_CHANNEL_JOIN; + break; + + case CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT: + rdp->state = CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT; + break; + + case CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE: + rdp->state = CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE; + break; + + case CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT: + rdp->state = CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT; + break; + + case CONNECTION_STATE_LICENSING: + rdp->state = CONNECTION_STATE_LICENSING; + break; + + case CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING: + rdp->state = CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING; + break; + + case CONNECTION_STATE_CAPABILITIES_EXCHANGE: + rdp->state = CONNECTION_STATE_CAPABILITIES_EXCHANGE; + break; + + case CONNECTION_STATE_FINALIZATION: + rdp->state = CONNECTION_STATE_FINALIZATION; + update_reset_state(rdp->update); + rdp->finalize_sc_pdus = 0; + break; + + case CONNECTION_STATE_ACTIVE: + rdp->state = CONNECTION_STATE_ACTIVE; + break; + + default: + status = -1; + break; + } + + return status; +} + BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s) { BOOL status; @@ -623,8 +801,8 @@ BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s) fprintf(stderr, "Client Security: NLA:%d TLS:%d RDP:%d\n", (rdp->nego->requested_protocols & PROTOCOL_NLA) ? 1 : 0, - (rdp->nego->requested_protocols & PROTOCOL_TLS) ? 1 : 0, - (rdp->nego->requested_protocols == PROTOCOL_RDP) ? 1: 0); + (rdp->nego->requested_protocols & PROTOCOL_TLS) ? 1 : 0, + (rdp->nego->requested_protocols == PROTOCOL_RDP) ? 1: 0); fprintf(stderr, "Server Security: NLA:%d TLS:%d RDP:%d\n", settings->NlaSecurity, settings->TlsSecurity, settings->RdpSecurity); @@ -648,13 +826,14 @@ BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s) fprintf(stderr, "Negotiated Security: NLA:%d TLS:%d RDP:%d\n", (rdp->nego->selected_protocol & PROTOCOL_NLA) ? 1 : 0, - (rdp->nego->selected_protocol & PROTOCOL_TLS) ? 1 : 0, - (rdp->nego->selected_protocol == PROTOCOL_RDP) ? 1: 0); + (rdp->nego->selected_protocol & PROTOCOL_TLS) ? 1 : 0, + (rdp->nego->selected_protocol == PROTOCOL_RDP) ? 1: 0); if (!nego_send_negotiation_response(rdp->nego)) return FALSE; status = FALSE; + if (rdp->nego->selected_protocol & PROTOCOL_NLA) status = transport_accept_nla(rdp->transport); else if (rdp->nego->selected_protocol & PROTOCOL_TLS) @@ -667,7 +846,7 @@ BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s) transport_set_blocking_mode(rdp->transport, FALSE); - rdp->state = CONNECTION_STATE_NEGO; + rdp_server_transition_to_state(rdp, CONNECTION_STATE_NEGO); return TRUE; } @@ -691,7 +870,7 @@ BOOL rdp_server_accept_mcs_connect_initial(rdpRdp* rdp, wStream* s) if (!mcs_send_connect_response(rdp->mcs)) return FALSE; - rdp->state = CONNECTION_STATE_MCS_CONNECT; + rdp_server_transition_to_state(rdp, CONNECTION_STATE_MCS_CONNECT); return TRUE; } @@ -701,7 +880,7 @@ BOOL rdp_server_accept_mcs_erect_domain_request(rdpRdp* rdp, wStream* s) if (!mcs_recv_erect_domain_request(rdp->mcs, s)) return FALSE; - rdp->state = CONNECTION_STATE_MCS_ERECT_DOMAIN; + rdp_server_transition_to_state(rdp, CONNECTION_STATE_MCS_ERECT_DOMAIN); return TRUE; } @@ -714,7 +893,7 @@ BOOL rdp_server_accept_mcs_attach_user_request(rdpRdp* rdp, wStream* s) if (!mcs_send_attach_user_confirm(rdp->mcs)) return FALSE; - rdp->state = CONNECTION_STATE_MCS_ATTACH_USER; + rdp_server_transition_to_state(rdp, CONNECTION_STATE_MCS_ATTACH_USER); return TRUE; } @@ -745,44 +924,23 @@ BOOL rdp_server_accept_mcs_channel_join_request(rdpRdp* rdp, wStream* s) all_joined = FALSE; } - if (rdp->mcs->user_channel_joined && rdp->mcs->global_channel_joined && all_joined) - rdp->state = CONNECTION_STATE_MCS_CHANNEL_JOIN; - - return TRUE; -} - -BOOL rdp_server_accept_client_keys(rdpRdp* rdp, wStream* s) -{ - - if (!rdp_server_establish_keys(rdp, s)) - return FALSE; - - rdp->state = CONNECTION_STATE_ESTABLISH_KEYS; - - return TRUE; -} - -BOOL rdp_server_accept_client_info(rdpRdp* rdp, wStream* s) -{ - - if (!rdp_recv_client_info(rdp, s)) - return FALSE; - - if (!license_send_valid_client_error_packet(rdp->license)) - return FALSE; - - rdp->state = CONNECTION_STATE_LICENSE; + if ((rdp->mcs->user_channel_joined) && (rdp->mcs->global_channel_joined) && all_joined) + { + rdp_server_transition_to_state(rdp, CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT); + } return TRUE; } BOOL rdp_server_accept_confirm_active(rdpRdp* rdp, wStream* s) { + if (rdp->state != CONNECTION_STATE_CAPABILITIES_EXCHANGE) + return FALSE; + if (!rdp_recv_confirm_active(rdp, s)) return FALSE; - rdp->state = CONNECTION_STATE_ACTIVE; - update_reset_state(rdp->update); + rdp_server_transition_to_state(rdp, CONNECTION_STATE_FINALIZATION); if (!rdp_send_server_synchronize_pdu(rdp)) return FALSE; @@ -798,7 +956,7 @@ BOOL rdp_server_reactivate(rdpRdp* rdp) if (!rdp_send_deactivate_all(rdp)) return FALSE; - rdp->state = CONNECTION_STATE_LICENSE; + rdp_server_transition_to_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE); if (!rdp_send_demand_active(rdp)) return FALSE; @@ -806,3 +964,107 @@ BOOL rdp_server_reactivate(rdpRdp* rdp) return TRUE; } +int rdp_server_transition_to_state(rdpRdp* rdp, int state) +{ + int status = 0; + freerdp_peer* client = NULL; + + if (rdp->state >= CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT) + client = rdp->context->peer; + + if (rdp->state < CONNECTION_STATE_ACTIVE) + { + if (client) + client->activated = FALSE; + } + + switch (state) + { + case CONNECTION_STATE_INITIAL: + rdp->state = CONNECTION_STATE_INITIAL; + break; + + case CONNECTION_STATE_NEGO: + rdp->state = CONNECTION_STATE_NEGO; + break; + + case CONNECTION_STATE_MCS_CONNECT: + rdp->state = CONNECTION_STATE_MCS_CONNECT; + break; + + case CONNECTION_STATE_MCS_ERECT_DOMAIN: + rdp->state = CONNECTION_STATE_MCS_ERECT_DOMAIN; + break; + + case CONNECTION_STATE_MCS_ATTACH_USER: + rdp->state = CONNECTION_STATE_MCS_ATTACH_USER; + break; + + case CONNECTION_STATE_MCS_CHANNEL_JOIN: + rdp->state = CONNECTION_STATE_MCS_CHANNEL_JOIN; + break; + + case CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT: + rdp->state = CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT; + break; + + case CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE: + rdp->state = CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE; + break; + + case CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT: + rdp->state = CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT; + break; + + case CONNECTION_STATE_LICENSING: + rdp->state = CONNECTION_STATE_LICENSING; + break; + + case CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING: + rdp->state = CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING; + break; + + case CONNECTION_STATE_CAPABILITIES_EXCHANGE: + rdp->state = CONNECTION_STATE_CAPABILITIES_EXCHANGE; + rdp->AwaitCapabilities = FALSE; + break; + + case CONNECTION_STATE_FINALIZATION: + rdp->state = CONNECTION_STATE_FINALIZATION; + rdp->finalize_sc_pdus = 0; + break; + + case CONNECTION_STATE_ACTIVE: + rdp->state = CONNECTION_STATE_ACTIVE; + update_reset_state(rdp->update); + + if (client) + { + if (!client->connected) + { + /** + * PostConnect should only be called once and should not + * be called after a reactivation sequence. + */ + + IFCALLRET(client->PostConnect, client->connected, client); + + if (!client->connected) + return -1; + } + + IFCALLRET(client->Activate, client->activated, client); + + if (!client->activated) + return -1; + } + + break; + + default: + status = -1; + break; + } + + return status; +} diff --git a/libfreerdp/core/connection.h b/libfreerdp/core/connection.h index ec6f57415..b23e398cc 100644 --- a/libfreerdp/core/connection.h +++ b/libfreerdp/core/connection.h @@ -37,11 +37,14 @@ enum CONNECTION_STATE CONNECTION_STATE_MCS_ERECT_DOMAIN = 3, CONNECTION_STATE_MCS_ATTACH_USER = 4, CONNECTION_STATE_MCS_CHANNEL_JOIN = 5, - CONNECTION_STATE_ESTABLISH_KEYS = 6, - CONNECTION_STATE_LICENSE = 7, - CONNECTION_STATE_CAPABILITY = 8, - CONNECTION_STATE_FINALIZATION = 9, - CONNECTION_STATE_ACTIVE = 10 + CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT = 6, + CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE = 7, + CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT = 8, + CONNECTION_STATE_LICENSING = 9, + CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING = 10, + CONNECTION_STATE_CAPABILITIES_EXCHANGE = 11, + CONNECTION_STATE_FINALIZATION = 12, + CONNECTION_STATE_ACTIVE = 13 }; BOOL rdp_client_connect(rdpRdp* rdp); @@ -52,15 +55,16 @@ BOOL rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, wStream* s); BOOL rdp_client_connect_license(rdpRdp* rdp, wStream* s); BOOL rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s); BOOL rdp_client_connect_finalize(rdpRdp* rdp); +int rdp_client_transition_to_state(rdpRdp* rdp, int state); BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s); BOOL rdp_server_accept_mcs_connect_initial(rdpRdp* rdp, wStream* s); BOOL rdp_server_accept_mcs_erect_domain_request(rdpRdp* rdp, wStream* s); BOOL rdp_server_accept_mcs_attach_user_request(rdpRdp* rdp, wStream* s); BOOL rdp_server_accept_mcs_channel_join_request(rdpRdp* rdp, wStream* s); -BOOL rdp_server_accept_client_keys(rdpRdp* rdp, wStream* s); -BOOL rdp_server_accept_client_info(rdpRdp* rdp, wStream* s); BOOL rdp_server_accept_confirm_active(rdpRdp* rdp, wStream* s); +BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s); BOOL rdp_server_reactivate(rdpRdp* rdp); +int rdp_server_transition_to_state(rdpRdp* rdp, int state); #endif /* __CONNECTION_H */ diff --git a/libfreerdp/core/errinfo.c b/libfreerdp/core/errinfo.c index 2b78dbc51..da028318a 100644 --- a/libfreerdp/core/errinfo.c +++ b/libfreerdp/core/errinfo.c @@ -443,6 +443,44 @@ static const ERRINFO ERRINFO_CODES[] = ERRINFO_DEFINE(NONE) }; +const char* freerdp_get_error_info_string(UINT32 code) +{ + const ERRINFO* errInfo; + + errInfo = &ERRINFO_CODES[0]; + + while (errInfo->code != ERRINFO_NONE) + { + if (code == errInfo->code) + { + return errInfo->info; + } + + errInfo++; + } + + return "Unknown error."; +} + +const char* freerdp_get_error_info_name(UINT32 code) +{ + const ERRINFO* errInfo; + + errInfo = &ERRINFO_CODES[0]; + + while (errInfo->code != ERRINFO_NONE) + { + if (code == errInfo->code) + { + return errInfo->name; + } + + errInfo++; + } + + return "ERRINFO_UNKNOWN"; +} + void rdp_print_errinfo(UINT32 code) { const ERRINFO* errInfo; diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index 396750081..b447a8477 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -83,7 +83,8 @@ BOOL freerdp_connect(freerdp* instance) connectErrorCode = PREECONNECTERROR; } fprintf(stderr, "%s:%d: freerdp_pre_connect failed\n", __FILE__, __LINE__); - return FALSE; + + goto freerdp_connect_finally; } status = rdp_client_connect(rdp); @@ -92,7 +93,7 @@ BOOL freerdp_connect(freerdp* instance) if (instance->settings->AuthenticationOnly) { fprintf(stderr, "%s:%d: Authentication only, exit status %d\n", __FILE__, __LINE__, !status); - return status; + goto freerdp_connect_finally; } if (status) @@ -118,7 +119,7 @@ BOOL freerdp_connect(freerdp* instance) connectErrorCode = POSTCONNECTERROR; } - return FALSE; + goto freerdp_connect_finally; } if (instance->settings->PlayRemoteFx) @@ -132,9 +133,14 @@ BOOL freerdp_connect(freerdp* instance) update->pcap_rfx = pcap_open(settings->PlayRemoteFxFile, FALSE); if (!update->pcap_rfx) - return FALSE; + { + status = FALSE; + goto freerdp_connect_finally; + } else + { update->play_rfx = TRUE; + } while (pcap_has_next_record(update->pcap_rfx)) { @@ -154,7 +160,8 @@ BOOL freerdp_connect(freerdp* instance) Stream_Release(s); } - return TRUE; + status = TRUE; + goto freerdp_connect_finally; } } @@ -170,6 +177,8 @@ BOOL freerdp_connect(freerdp* instance) SetEvent(rdp->transport->connectedEvent); + freerdp_connect_finally: + EventArgsInit(&e, "freerdp"); e.result = status ? 0 : -1; PubSub_OnConnectionResult(instance->context->pubSub, instance->context, &e); @@ -328,18 +337,18 @@ void freerdp_get_version(int* major, int* minor, int* revision) static wEventType FreeRDP_Events[] = { - DEFINE_EVENT_ENTRY(WindowStateChange) - DEFINE_EVENT_ENTRY(ResizeWindow) - DEFINE_EVENT_ENTRY(LocalResizeWindow) - DEFINE_EVENT_ENTRY(EmbedWindow) - DEFINE_EVENT_ENTRY(PanningChange) - DEFINE_EVENT_ENTRY(ScalingFactorChange) - DEFINE_EVENT_ENTRY(ErrorInfo) - DEFINE_EVENT_ENTRY(ParamChange) - DEFINE_EVENT_ENTRY(Terminate) - DEFINE_EVENT_ENTRY(ConnectionResult) - DEFINE_EVENT_ENTRY(ChannelConnected) - DEFINE_EVENT_ENTRY(ChannelDisconnected) + DEFINE_EVENT_ENTRY(WindowStateChange) + DEFINE_EVENT_ENTRY(ResizeWindow) + DEFINE_EVENT_ENTRY(LocalResizeWindow) + DEFINE_EVENT_ENTRY(EmbedWindow) + DEFINE_EVENT_ENTRY(PanningChange) + DEFINE_EVENT_ENTRY(ScalingFactorChange) + DEFINE_EVENT_ENTRY(ErrorInfo) + DEFINE_EVENT_ENTRY(ParamChange) + DEFINE_EVENT_ENTRY(Terminate) + DEFINE_EVENT_ENTRY(ConnectionResult) + DEFINE_EVENT_ENTRY(ChannelConnected) + DEFINE_EVENT_ENTRY(ChannelDisconnected) }; /** Allocator function for a rdp context. @@ -357,18 +366,19 @@ int freerdp_context_new(freerdp* instance) instance->context = (rdpContext*) malloc(instance->ContextSize); ZeroMemory(instance->context, instance->ContextSize); + context = instance->context; + context->instance = instance; context->pubSub = PubSub_New(TRUE); PubSub_AddEventTypes(context->pubSub, FreeRDP_Events, sizeof(FreeRDP_Events) / sizeof(wEventType)); - rdp = rdp_new(instance); + rdp = rdp_new(context); instance->input = rdp->input; instance->update = rdp->update; instance->settings = rdp->settings; context->graphics = graphics_new(context); - context->instance = instance; context->rdp = rdp; context->input = instance->input; diff --git a/libfreerdp/core/input.c b/libfreerdp/core/input.c index 848a66505..64011b807 100644 --- a/libfreerdp/core/input.c +++ b/libfreerdp/core/input.c @@ -495,6 +495,8 @@ rdpInput* input_new(rdpRdp* rdp) if (input != NULL) { ZeroMemory(input, sizeof(rdpInput)); + + input->queue = MessageQueue_New(); } return input; @@ -507,6 +509,8 @@ void input_free(rdpInput* input) if (input->asynchronous) input_message_proxy_free(input->proxy); + MessageQueue_Free(input->queue); + free(input); } } diff --git a/libfreerdp/core/listener.c b/libfreerdp/core/listener.c index 2390542fb..b67703b1d 100644 --- a/libfreerdp/core/listener.c +++ b/libfreerdp/core/listener.c @@ -156,7 +156,9 @@ static BOOL freerdp_listener_open(freerdp_listener* instance, const char* bind_a continue; } - listener->sockfds[listener->num_sockfds++] = sockfd; + listener->sockfds[listener->num_sockfds] = sockfd; + listener->events[listener->num_sockfds] = CreateFileDescriptorEvent(NULL, FALSE, FALSE, sockfd); + listener->num_sockfds++; if (ai->ai_family == AF_INET) sin_addr = &(((struct sockaddr_in*) ai->ai_addr)->sin_addr); @@ -211,7 +213,9 @@ static BOOL freerdp_listener_open_local(freerdp_listener* instance, const char* return FALSE; } - listener->sockfds[listener->num_sockfds++] = sockfd; + listener->sockfds[listener->num_sockfds] = sockfd; + listener->events[listener->num_sockfds] = CreateFileDescriptorEvent(NULL, FALSE, FALSE, sockfd); + listener->num_sockfds++; fprintf(stderr, "Listening on socket %s.\n", addr.sun_path); @@ -237,21 +241,38 @@ static void freerdp_listener_close(freerdp_listener* instance) static BOOL freerdp_listener_get_fds(freerdp_listener* instance, void** rfds, int* rcount) { - int i; + int index; rdpListener* listener = (rdpListener*) instance->listener; if (listener->num_sockfds < 1) return FALSE; - for (i = 0; i < listener->num_sockfds; i++) + for (index = 0; index < listener->num_sockfds; index++) { - rfds[*rcount] = (void*)(long)(listener->sockfds[i]); + rfds[*rcount] = (void*)(long)(listener->sockfds[index]); (*rcount)++; } return TRUE; } +int freerdp_listener_get_event_handles(freerdp_listener* instance, HANDLE* events, DWORD* nCount) +{ + int index; + rdpListener* listener = (rdpListener*) instance->listener; + + if (listener->num_sockfds < 1) + return -1; + + for (index = 0; index < listener->num_sockfds; index++) + { + events[*nCount] = listener->events[index]; + (*nCount)++; + } + + return 0; +} + static BOOL freerdp_listener_check_fds(freerdp_listener* instance) { int i; @@ -327,6 +348,7 @@ freerdp_listener* freerdp_listener_new(void) instance->Open = freerdp_listener_open; instance->OpenLocal = freerdp_listener_open_local; instance->GetFileDescriptor = freerdp_listener_get_fds; + instance->GetEventHandles = freerdp_listener_get_event_handles; instance->CheckFileDescriptor = freerdp_listener_check_fds; instance->Close = freerdp_listener_close; diff --git a/libfreerdp/core/listener.h b/libfreerdp/core/listener.h index 51aa569e0..1474bf7db 100644 --- a/libfreerdp/core/listener.h +++ b/libfreerdp/core/listener.h @@ -23,14 +23,21 @@ typedef struct rdp_listener rdpListener; #include "rdp.h" + +#include +#include + #include +#define MAX_LISTENER_HANDLES 5 + struct rdp_listener { freerdp_listener* instance; - int sockfds[5]; int num_sockfds; + int sockfds[MAX_LISTENER_HANDLES]; + HANDLE events[MAX_LISTENER_HANDLES]; }; #endif diff --git a/libfreerdp/core/mcs.c b/libfreerdp/core/mcs.c index d5ea0899b..43a7a480c 100644 --- a/libfreerdp/core/mcs.c +++ b/libfreerdp/core/mcs.c @@ -356,15 +356,15 @@ BOOL mcs_recv_connect_initial(rdpMcs* mcs, wStream* s) return FALSE; /* targetParameters (DomainParameters) */ - if(!mcs_read_domain_parameters(s, &mcs->targetParameters)) + if (!mcs_read_domain_parameters(s, &mcs->targetParameters)) return FALSE; /* minimumParameters (DomainParameters) */ - if(!mcs_read_domain_parameters(s, &mcs->minimumParameters)) + if (!mcs_read_domain_parameters(s, &mcs->minimumParameters)) return FALSE; /* maximumParameters (DomainParameters) */ - if(!mcs_read_domain_parameters(s, &mcs->maximumParameters)) + if (!mcs_read_domain_parameters(s, &mcs->maximumParameters)) return FALSE; if (!ber_read_octet_string_tag(s, &length) || Stream_GetRemainingLength(s) < length) @@ -510,7 +510,7 @@ BOOL mcs_recv_connect_response(rdpMcs* mcs, wStream* s) if (!tpdu_read_data(s, &li)) return FALSE; - if(!ber_read_application_tag(s, MCS_TYPE_CONNECT_RESPONSE, &length) || + if (!ber_read_application_tag(s, MCS_TYPE_CONNECT_RESPONSE, &length) || !ber_read_enumerated(s, &result, MCS_Result_enum_length) || !ber_read_integer(s, &calledConnectId) || !mcs_read_domain_parameters(s, &(mcs->domainParameters)) || diff --git a/libfreerdp/core/message.c b/libfreerdp/core/message.c index 720b13797..f772e65fd 100644 --- a/libfreerdp/core/message.c +++ b/libfreerdp/core/message.c @@ -1741,7 +1741,6 @@ rdpUpdateProxy* update_message_proxy_new(rdpUpdate* update) ZeroMemory(message, sizeof(rdpUpdateProxy)); message->update = update; - update->queue = MessageQueue_New(); update_message_register_interface(message, update); } @@ -1752,7 +1751,6 @@ void update_message_proxy_free(rdpUpdateProxy* message) { if (message) { - MessageQueue_Free(message->update->queue); free(message); } } @@ -1940,7 +1938,6 @@ rdpInputProxy* input_message_proxy_new(rdpInput* input) ZeroMemory(proxy, sizeof(rdpInputProxy)); proxy->input = input; - input->queue = MessageQueue_New(); input_message_proxy_register(proxy, input); } @@ -1951,7 +1948,6 @@ void input_message_proxy_free(rdpInputProxy* proxy) { if (proxy) { - MessageQueue_Free(proxy->input->queue); free(proxy); } } diff --git a/libfreerdp/core/orders.c b/libfreerdp/core/orders.c index e5cc520b7..d0f5c9713 100644 --- a/libfreerdp/core/orders.c +++ b/libfreerdp/core/orders.c @@ -1364,7 +1364,7 @@ BOOL update_read_memblt_order(wStream* s, ORDER_INFO* orderInfo, MEMBLT_ORDER* m int update_approximate_memblt_order(ORDER_INFO* orderInfo, MEMBLT_ORDER* memblt) { - return 32; + return 64; } BOOL update_write_memblt_order(wStream* s, ORDER_INFO* orderInfo, MEMBLT_ORDER* memblt) @@ -2600,7 +2600,7 @@ BOOL update_read_create_offscreen_bitmap_order(wStream* s, CREATE_OFFSCREEN_BITM int update_approximate_create_offscreen_bitmap_order(CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap) { OFFSCREEN_DELETE_LIST* deleteList = &(create_offscreen_bitmap->deleteList); - return 8 + deleteList->cIndices * 2; + return 32 + deleteList->cIndices * 2; } BOOL update_write_create_offscreen_bitmap_order(wStream* s, CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap) diff --git a/libfreerdp/core/peer.c b/libfreerdp/core/peer.c index eb4ad60ea..5b38c905e 100644 --- a/libfreerdp/core/peer.c +++ b/libfreerdp/core/peer.c @@ -23,6 +23,7 @@ #include +#include "info.h" #include "certificate.h" #include @@ -53,6 +54,11 @@ static BOOL freerdp_peer_get_fds(freerdp_peer* client, void** rfds, int* rcount) return TRUE; } +static HANDLE freerdp_peer_get_event_handle(freerdp_peer* client) +{ + return client->context->rdp->transport->TcpIn->event; +} + static BOOL freerdp_peer_check_fds(freerdp_peer* client) { int status; @@ -105,29 +111,6 @@ static BOOL peer_recv_data_pdu(freerdp_peer* client, wStream* s) if (!rdp_server_accept_client_font_list_pdu(client->context->rdp, s)) return FALSE; - if (!client->connected) - { - /** - * PostConnect should only be called once and should not be called - * after a reactivation sequence. - */ - - IFCALLRET(client->PostConnect, client->connected, client); - - if (!client->connected) - return FALSE; - } - - if (!client->activated) - { - /* Activate will be called everytime after the client is activated/reactivated. */ - - IFCALLRET(client->Activate, client->activated, client); - - if (!client->activated) - return FALSE; - } - break; case DATA_PDU_TYPE_SHUTDOWN_REQUEST: @@ -135,7 +118,7 @@ static BOOL peer_recv_data_pdu(freerdp_peer* client, wStream* s) return FALSE; case DATA_PDU_TYPE_FRAME_ACKNOWLEDGE: - if(Stream_GetRemainingLength(s) < 4) + if (Stream_GetRemainingLength(s) < 4) return FALSE; Stream_Read_UINT32(s, client->ack_frame_id); IFCALL(client->update->SurfaceFrameAcknowledge, client->update->context, client->ack_frame_id); @@ -194,7 +177,7 @@ static int peer_recv_tpkt_pdu(freerdp_peer* client, wStream* s) if (channelId != MCS_GLOBAL_CHANNEL_ID) { - if(!freerdp_channel_peer_process(client, s, channelId)) + if (!freerdp_channel_peer_process(client, s, channelId)) return -1; } else @@ -211,6 +194,11 @@ static int peer_recv_tpkt_pdu(freerdp_peer* client, wStream* s) return -1; break; + case PDU_TYPE_CONFIRM_ACTIVE: + if (!rdp_server_accept_confirm_active(rdp, s)) + return -1; + break; + default: fprintf(stderr, "Client sent pduType %d\n", pduType); return -1; @@ -228,8 +216,6 @@ static int peer_recv_fastpath_pdu(freerdp_peer* client, wStream* s) rdp = client->context->rdp; fastpath = rdp->fastpath; - //if (!fastpath_read_header_rdp(fastpath, s, &length)) - // return -1; fastpath_read_header_rdp(fastpath, s, &length); @@ -301,36 +287,71 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) return -1; break; - case CONNECTION_STATE_MCS_CHANNEL_JOIN: + case CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT: if (rdp->settings->DisableEncryption) { - if (!rdp_server_accept_client_keys(rdp, s)) + if (!rdp_server_establish_keys(rdp, s)) return -1; - break; } - rdp->state = CONNECTION_STATE_ESTABLISH_KEYS; - /* FALLTHROUGH */ - case CONNECTION_STATE_ESTABLISH_KEYS: - if (!rdp_server_accept_client_info(rdp, s)) - return -1; + rdp_server_transition_to_state(rdp, CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE); + return peer_recv_callback(transport, s, extra); - IFCALL(client->Capabilities, client); - - if (!rdp_send_demand_active(rdp)) - return -1; break; - case CONNECTION_STATE_LICENSE: - if (!rdp_server_accept_confirm_active(rdp, s)) + case CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE: + + if (!rdp_recv_client_info(rdp, s)) + return -1; + + rdp_server_transition_to_state(rdp, CONNECTION_STATE_LICENSING); + return peer_recv_callback(transport, NULL, extra); + + break; + + case CONNECTION_STATE_LICENSING: + + if (!license_send_valid_client_error_packet(rdp->license)) + return FALSE; + + rdp_server_transition_to_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE); + return peer_recv_callback(transport, NULL, extra); + + break; + + case CONNECTION_STATE_CAPABILITIES_EXCHANGE: + + if (!rdp->AwaitCapabilities) + { + IFCALL(client->Capabilities, client); + + if (!rdp_send_demand_active(rdp)) + return -1; + + rdp->AwaitCapabilities = TRUE; + + if (s) + { + if (peer_recv_pdu(client, s) < 0) + return -1; + } + } + else { /** * During reactivation sequence the client might sent some input or channel data * before receiving the Deactivate All PDU. We need to process them as usual. */ - Stream_SetPosition(s, 0); - return peer_recv_pdu(client, s); + + if (peer_recv_pdu(client, s) < 0) + return -1; } + + break; + + case CONNECTION_STATE_FINALIZATION: + if (peer_recv_pdu(client, s) < 0) + return -1; break; case CONNECTION_STATE_ACTIVE: @@ -355,6 +376,7 @@ static BOOL freerdp_peer_close(freerdp_peer* client) */ if (!rdp_send_deactivate_all(client->context->rdp)) return FALSE; + return mcs_send_disconnect_provider_ultimatum(client->context->rdp->mcs); } @@ -372,14 +394,15 @@ void freerdp_peer_context_new(freerdp_peer* client) { rdpRdp* rdp; - rdp = rdp_new(NULL); + client->context = (rdpContext*) malloc(client->ContextSize); + ZeroMemory(client->context, client->ContextSize); + + rdp = rdp_new(client->context); + client->input = rdp->input; client->update = rdp->update; client->settings = rdp->settings; - client->context = (rdpContext*) malloc(client->ContextSize); - ZeroMemory(client->context, client->ContextSize); - client->context->rdp = rdp; client->context->peer = client; client->context->input = client->input; @@ -414,12 +437,13 @@ freerdp_peer* freerdp_peer_new(int sockfd) freerdp_tcp_set_no_delay(sockfd, TRUE); - if (client != NULL) + if (client) { client->sockfd = sockfd; client->ContextSize = sizeof(rdpContext); client->Initialize = freerdp_peer_initialize; client->GetFileDescriptor = freerdp_peer_get_fds; + client->GetEventHandle = freerdp_peer_get_event_handle; client->CheckFileDescriptor = freerdp_peer_check_fds; client->Close = freerdp_peer_close; client->Disconnect = freerdp_peer_disconnect; diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c index 1a4704d3c..867fd5c1b 100644 --- a/libfreerdp/core/rdp.c +++ b/libfreerdp/core/rdp.c @@ -236,8 +236,9 @@ wStream* rdp_data_pdu_init(rdpRdp* rdp) * @param channel_id channel id */ -BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channel_id) +BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channelId) { + BYTE byte; UINT16 initiator; enum DomainMCSPDU MCSPDU; @@ -274,8 +275,8 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channel_id return FALSE; per_read_integer16(s, &initiator, MCS_BASE_CHANNEL_ID); /* initiator (UserId) */ - per_read_integer16(s, channel_id, 0); /* channelId */ - Stream_Seek(s, 1); /* dataPriority + Segmentation (0x70) */ + per_read_integer16(s, channelId, 0); /* channelId */ + Stream_Read_UINT8(s, byte); /* dataPriority + Segmentation (0x70) */ if (!per_read_length(s, length)) /* userData (OCTET_STRING) */ return FALSE; @@ -294,7 +295,7 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channel_id * @param channel_id channel id */ -void rdp_write_header(rdpRdp* rdp, wStream* s, UINT16 length, UINT16 channel_id) +void rdp_write_header(rdpRdp* rdp, wStream* s, UINT16 length, UINT16 channelId) { int body_length; enum DomainMCSPDU MCSPDU; @@ -314,10 +315,10 @@ void rdp_write_header(rdpRdp* rdp, wStream* s, UINT16 length, UINT16 channel_id) mcs_write_domain_mcspdu_header(s, MCSPDU, length, 0); per_write_integer16(s, rdp->mcs->user_id, MCS_BASE_CHANNEL_ID); /* initiator */ - per_write_integer16(s, channel_id, 0); /* channelId */ + per_write_integer16(s, channelId, 0); /* channelId */ Stream_Write_UINT8(s, 0x70); /* dataPriority + segmentation */ /* - * We always encode length in two bytes, eventhough we could use + * We always encode length in two bytes, even though we could use * only one byte if length <= 0x7F. It is just easier that way, * because we can leave room for fixed-length header, store all * the data first and then store the header. @@ -926,20 +927,21 @@ static int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) status = -1; break; - case CONNECTION_STATE_LICENSE: + case CONNECTION_STATE_LICENSING: if (!rdp_client_connect_license(rdp, s)) status = -1; break; - case CONNECTION_STATE_CAPABILITY: + case CONNECTION_STATE_CAPABILITIES_EXCHANGE: if (!rdp_client_connect_demand_active(rdp, s)) status = -1; break; case CONNECTION_STATE_FINALIZATION: status = rdp_recv_pdu(rdp, s); + if ((status >= 0) && (rdp->finalize_sc_pdus == FINALIZE_SC_COMPLETE)) - rdp->state = CONNECTION_STATE_ACTIVE; + rdp_client_transition_to_state(rdp, CONNECTION_STATE_ACTIVE); break; case CONNECTION_STATE_ACTIVE: @@ -982,23 +984,25 @@ int rdp_check_fds(rdpRdp* rdp) * @return new RDP module */ -rdpRdp* rdp_new(freerdp* instance) +rdpRdp* rdp_new(rdpContext* context) { rdpRdp* rdp; rdp = (rdpRdp*) malloc(sizeof(rdpRdp)); - if (rdp != NULL) + if (rdp) { ZeroMemory(rdp, sizeof(rdpRdp)); - rdp->instance = instance; - rdp->settings = freerdp_settings_new((void*) instance); + rdp->context = context; - if (instance != NULL) - instance->settings = rdp->settings; + rdp->instance = context->instance; + rdp->settings = freerdp_settings_new((void*) context->instance); - rdp->extension = extension_new(instance); + if (context->instance) + context->instance->settings = rdp->settings; + + rdp->extension = extension_new(context->instance); rdp->transport = transport_new(rdp->settings); rdp->license = license_new(rdp); rdp->input = input_new(rdp); diff --git a/libfreerdp/core/rdp.h b/libfreerdp/core/rdp.h index fc730261e..aa43b988f 100644 --- a/libfreerdp/core/rdp.h +++ b/libfreerdp/core/rdp.h @@ -120,6 +120,7 @@ struct rdp_rdp { int state; freerdp* instance; + rdpContext* context; struct rdp_mcs* mcs; struct rdp_nego* nego; struct rdp_input* input; @@ -158,6 +159,7 @@ struct rdp_rdp BOOL disconnect; BOOL resendFocus; BOOL deactivation_reactivation; + BOOL AwaitCapabilities; }; BOOL rdp_read_security_header(wStream* s, UINT16* flags); @@ -193,7 +195,7 @@ BOOL rdp_recv_out_of_sequence_pdu(rdpRdp* rdp, wStream* s); void rdp_set_blocking_mode(rdpRdp* rdp, BOOL blocking); int rdp_check_fds(rdpRdp* rdp); -rdpRdp* rdp_new(freerdp* instance); +rdpRdp* rdp_new(rdpContext* context); void rdp_free(rdpRdp* rdp); #ifdef WITH_DEBUG_RDP diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index a02c80c7b..aaaaf99e9 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -334,6 +334,8 @@ rdpSettings* freerdp_settings_new(void* instance) settings->BitmapCacheV2CellInfo[4].numEntries = 2048; settings->BitmapCacheV2CellInfo[4].persistent = FALSE; + settings->NoBitmapCompressionHeader = TRUE; + settings->RefreshRect = TRUE; settings->SuppressOutput = TRUE; diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c index a0ad86406..908e06ae3 100644 --- a/libfreerdp/core/tcp.c +++ b/libfreerdp/core/tcp.c @@ -253,6 +253,13 @@ BOOL tcp_set_keep_alive_mode(rdpTcp* tcp) return TRUE; } +int tcp_attach(rdpTcp* tcp, int sockfd) +{ + tcp->sockfd = sockfd; + SetEventFileDescriptor(tcp->event, tcp->sockfd); + return 0; +} + HANDLE tcp_get_event_handle(rdpTcp* tcp) { #ifndef _WIN32 diff --git a/libfreerdp/core/tcp.h b/libfreerdp/core/tcp.h index 539d77673..c22e5da05 100644 --- a/libfreerdp/core/tcp.h +++ b/libfreerdp/core/tcp.h @@ -56,6 +56,7 @@ int tcp_wait_read(rdpTcp* tcp); int tcp_wait_write(rdpTcp* tcp); BOOL tcp_set_blocking_mode(rdpTcp* tcp, BOOL blocking); BOOL tcp_set_keep_alive_mode(rdpTcp* tcp); +int tcp_attach(rdpTcp* tcp, int sockfd); HANDLE tcp_get_event_handle(rdpTcp* tcp); rdpTcp* tcp_new(rdpSettings* settings); diff --git a/libfreerdp/core/tpdu.c b/libfreerdp/core/tpdu.c index a701c11d7..30a649c22 100644 --- a/libfreerdp/core/tpdu.c +++ b/libfreerdp/core/tpdu.c @@ -22,6 +22,7 @@ #endif #include +#include #include "tpdu.h" @@ -66,9 +67,9 @@ * @return TPDU length indicator (LI) */ -BOOL tpdu_read_header(wStream* s, BYTE* code, BYTE *li) +BOOL tpdu_read_header(wStream* s, BYTE* code, BYTE* li) { - if(Stream_GetRemainingLength(s) < 3) + if (Stream_GetRemainingLength(s) < 3) return FALSE; Stream_Read_UINT8(s, *li); /* LI */ @@ -86,6 +87,7 @@ BOOL tpdu_read_header(wStream* s, BYTE* code, BYTE *li) /* Class 0 (1 byte) */ return Stream_SafeSeek(s, 5); } + return TRUE; } @@ -205,16 +207,18 @@ void tpdu_write_data(wStream* s) * @param s stream */ -BOOL tpdu_read_data(wStream* s, UINT16 *LI) +BOOL tpdu_read_data(wStream* s, UINT16* LI) { BYTE code; BYTE li; - if(!tpdu_read_header(s, &code, &li)) + if (!tpdu_read_header(s, &code, &li)) return FALSE; if (code != X224_TPDU_DATA) return FALSE; + *LI = li; + return TRUE; } diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index 40885442b..03ffb2971 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -64,8 +64,7 @@ wStream* transport_send_stream_init(rdpTransport* transport, int size) void transport_attach(rdpTransport* transport, int sockfd) { - transport->TcpIn->sockfd = sockfd; - + tcp_attach(transport->TcpIn, sockfd); transport->SplitInputOutput = FALSE; transport->TcpOut = transport->TcpIn; } diff --git a/libfreerdp/core/update.c b/libfreerdp/core/update.c index c4eaedeec..442139d9a 100644 --- a/libfreerdp/core/update.c +++ b/libfreerdp/core/update.c @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -477,6 +478,7 @@ static void update_end_paint(rdpContext* context) if (update->numberOrders > 0) { + printf("Sending %d orders\n", update->numberOrders); fastpath_send_update_pdu(context->rdp->fastpath, FASTPATH_UPDATETYPE_ORDERS, s); } @@ -513,11 +515,16 @@ static BOOL update_check_flush(rdpContext* context, int size) { wStream* s; rdpUpdate* update = context->update; - rdpSettings* settings = context->settings; s = update->us; - if (Stream_GetPosition(s) + size + 256 >= settings->MultifragMaxRequestSize) + if (!update->us) + { + update->BeginPaint(context); + return FALSE; + } + + if (Stream_GetPosition(s) + size + 64 >= 0x3FFF) { update_flush(context); return TRUE; @@ -783,12 +790,13 @@ static void update_send_synchronize(rdpContext* context) static void update_send_desktop_resize(rdpContext* context) { - if (context->peer) - context->peer->activated = FALSE; - rdp_server_reactivate(context->rdp); } +/** + * Primary Drawing Orders + */ + static void update_send_dstblt(rdpContext* context, DSTBLT_ORDER* dstblt) { wStream* s; @@ -957,6 +965,10 @@ static void update_send_glyph_index(rdpContext* context, GLYPH_INDEX_ORDER* glyp update->numberOrders++; } +/* + * Secondary Drawing Orders + */ + static void update_send_cache_bitmap(rdpContext* context, CACHE_BITMAP_ORDER* cache_bitmap) { wStream* s; @@ -987,7 +999,7 @@ static void update_send_cache_bitmap(rdpContext* context, CACHE_BITMAP_ORDER* ca orderLength = (em - bm) - 13; Stream_SetPosition(s, bm); - Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY | ORDER_TYPE_CHANGE); /* controlFlags (1 byte) */ + Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */ Stream_Write_UINT16(s, orderLength); /* orderLength (2 bytes) */ Stream_Write_UINT16(s, extraFlags); /* extraFlags (2 bytes) */ Stream_Write_UINT8(s, orderType); /* orderType (1 byte) */ @@ -1006,14 +1018,15 @@ static void update_send_cache_bitmap_v2(rdpContext* context, CACHE_BITMAP_V2_ORD INT16 orderLength; rdpUpdate* update = context->update; - update_force_flush(context); - extraFlags = 0; headerLength = 6; orderType = cache_bitmap_v2->compressed ? ORDER_TYPE_BITMAP_COMPRESSED_V2 : ORDER_TYPE_BITMAP_UNCOMPRESSED_V2; + if (context->settings->NoBitmapCompressionHeader) + cache_bitmap_v2->flags |= CBR2_NO_BITMAP_COMPRESSION_HDR; + update_check_flush(context, headerLength + update_approximate_cache_bitmap_v2_order(cache_bitmap_v2, cache_bitmap_v2->compressed, &extraFlags)); s = update->us; @@ -1028,15 +1041,13 @@ static void update_send_cache_bitmap_v2(rdpContext* context, CACHE_BITMAP_V2_ORD orderLength = (em - bm) - 13; Stream_SetPosition(s, bm); - Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY | ORDER_TYPE_CHANGE); /* controlFlags (1 byte) */ + Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */ Stream_Write_UINT16(s, orderLength); /* orderLength (2 bytes) */ Stream_Write_UINT16(s, extraFlags); /* extraFlags (2 bytes) */ Stream_Write_UINT8(s, orderType); /* orderType (1 byte) */ Stream_SetPosition(s, em); update->numberOrders++; - - update_force_flush(context); } static void update_send_cache_bitmap_v3(rdpContext* context, CACHE_BITMAP_V3_ORDER* cache_bitmap_v3) @@ -1049,8 +1060,6 @@ static void update_send_cache_bitmap_v3(rdpContext* context, CACHE_BITMAP_V3_ORD INT16 orderLength; rdpUpdate* update = context->update; - update_force_flush(context); - extraFlags = 0; headerLength = 6; orderType = ORDER_TYPE_BITMAP_COMPRESSED_V3; @@ -1069,15 +1078,13 @@ static void update_send_cache_bitmap_v3(rdpContext* context, CACHE_BITMAP_V3_ORD orderLength = (em - bm) - 13; Stream_SetPosition(s, bm); - Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY | ORDER_TYPE_CHANGE); /* controlFlags (1 byte) */ + Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */ Stream_Write_UINT16(s, orderLength); /* orderLength (2 bytes) */ Stream_Write_UINT16(s, extraFlags); /* extraFlags (2 bytes) */ Stream_Write_UINT8(s, orderType); /* orderType (1 byte) */ Stream_SetPosition(s, em); update->numberOrders++; - - update_force_flush(context); } static void update_send_cache_color_table(rdpContext* context, CACHE_COLOR_TABLE_ORDER* cache_color_table) @@ -1089,8 +1096,6 @@ static void update_send_cache_color_table(rdpContext* context, CACHE_COLOR_TABLE INT16 orderLength; rdpUpdate* update = context->update; - update_force_flush(context); - flags = 0; headerLength = 6; @@ -1108,15 +1113,13 @@ static void update_send_cache_color_table(rdpContext* context, CACHE_COLOR_TABLE orderLength = (em - bm) - 13; Stream_SetPosition(s, bm); - Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY | ORDER_TYPE_CHANGE); /* controlFlags (1 byte) */ + Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */ Stream_Write_UINT16(s, orderLength); /* orderLength (2 bytes) */ Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */ Stream_Write_UINT8(s, ORDER_TYPE_CACHE_COLOR_TABLE); /* orderType (1 byte) */ Stream_SetPosition(s, em); update->numberOrders++; - - update_force_flush(context); } static void update_send_cache_glyph(rdpContext* context, CACHE_GLYPH_ORDER* cache_glyph) @@ -1128,8 +1131,6 @@ static void update_send_cache_glyph(rdpContext* context, CACHE_GLYPH_ORDER* cach INT16 orderLength; rdpUpdate* update = context->update; - update_force_flush(context); - flags = 0; headerLength = 6; @@ -1147,15 +1148,13 @@ static void update_send_cache_glyph(rdpContext* context, CACHE_GLYPH_ORDER* cach orderLength = (em - bm) - 13; Stream_SetPosition(s, bm); - Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY | ORDER_TYPE_CHANGE); /* controlFlags (1 byte) */ + Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */ Stream_Write_UINT16(s, orderLength); /* orderLength (2 bytes) */ Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */ Stream_Write_UINT8(s, ORDER_TYPE_CACHE_GLYPH); /* orderType (1 byte) */ Stream_SetPosition(s, em); update->numberOrders++; - - update_force_flush(context); } static void update_send_cache_glyph_v2(rdpContext* context, CACHE_GLYPH_V2_ORDER* cache_glyph_v2) @@ -1167,8 +1166,6 @@ static void update_send_cache_glyph_v2(rdpContext* context, CACHE_GLYPH_V2_ORDER INT16 orderLength; rdpUpdate* update = context->update; - update_force_flush(context); - flags = 0; headerLength = 6; @@ -1186,15 +1183,13 @@ static void update_send_cache_glyph_v2(rdpContext* context, CACHE_GLYPH_V2_ORDER orderLength = (em - bm) - 13; Stream_SetPosition(s, bm); - Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY | ORDER_TYPE_CHANGE); /* controlFlags (1 byte) */ + Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */ Stream_Write_UINT16(s, orderLength); /* orderLength (2 bytes) */ Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */ Stream_Write_UINT8(s, ORDER_TYPE_CACHE_GLYPH); /* orderType (1 byte) */ Stream_SetPosition(s, em); update->numberOrders++; - - update_force_flush(context); } static void update_send_cache_brush(rdpContext* context, CACHE_BRUSH_ORDER* cache_brush) @@ -1206,8 +1201,6 @@ static void update_send_cache_brush(rdpContext* context, CACHE_BRUSH_ORDER* cach INT16 orderLength; rdpUpdate* update = context->update; - update_force_flush(context); - flags = 0; headerLength = 6; @@ -1225,17 +1218,19 @@ static void update_send_cache_brush(rdpContext* context, CACHE_BRUSH_ORDER* cach orderLength = (em - bm) - 13; Stream_SetPosition(s, bm); - Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY | ORDER_TYPE_CHANGE); /* controlFlags (1 byte) */ + Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */ Stream_Write_UINT16(s, orderLength); /* orderLength (2 bytes) */ Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */ Stream_Write_UINT8(s, ORDER_TYPE_CACHE_BRUSH); /* orderType (1 byte) */ Stream_SetPosition(s, em); update->numberOrders++; - - update_force_flush(context); } +/** + * Alternate Secondary Drawing Orders + */ + static void update_send_create_offscreen_bitmap_order(rdpContext* context, CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap) { wStream* s; @@ -1245,8 +1240,6 @@ static void update_send_create_offscreen_bitmap_order(rdpContext* context, CREAT int headerLength; rdpUpdate* update = context->update; - update_force_flush(context); - headerLength = 1; orderType = ORDER_TYPE_CREATE_OFFSCREEN_BITMAP; controlFlags = ORDER_SECONDARY | (orderType << 2); @@ -1267,8 +1260,6 @@ static void update_send_create_offscreen_bitmap_order(rdpContext* context, CREAT Stream_SetPosition(s, em); update->numberOrders++; - - update_force_flush(context); } static void update_send_switch_surface_order(rdpContext* context, SWITCH_SURFACE_ORDER* switch_surface) @@ -1280,8 +1271,6 @@ static void update_send_switch_surface_order(rdpContext* context, SWITCH_SURFACE int headerLength; rdpUpdate* update = context->update; - update_force_flush(context); - headerLength = 1; orderType = ORDER_TYPE_SWITCH_SURFACE; controlFlags = ORDER_SECONDARY | (orderType << 2); @@ -1302,8 +1291,6 @@ static void update_send_switch_surface_order(rdpContext* context, SWITCH_SURFACE Stream_SetPosition(s, em); update->numberOrders++; - - update_force_flush(context); } static void update_send_pointer_system(rdpContext* context, POINTER_SYSTEM_UPDATE* pointer_system) @@ -1512,6 +1499,8 @@ rdpUpdate* update_new(rdpRdp* rdp) update->SuppressOutput = update_send_suppress_output; update->initialState = TRUE; + + update->queue = MessageQueue_New(); } return update; @@ -1545,6 +1534,8 @@ void update_free(rdpUpdate* update) if (update->asynchronous) update_message_proxy_free(update->proxy); + MessageQueue_Free(update->queue); + free(update); } } diff --git a/libfreerdp/locale/keyboard_layout.c b/libfreerdp/locale/keyboard_layout.c index 78e98cf5b..3869358cc 100644 --- a/libfreerdp/locale/keyboard_layout.c +++ b/libfreerdp/locale/keyboard_layout.c @@ -214,6 +214,11 @@ static const RDP_KEYBOARD_IME RDP_KEYBOARD_IME_TABLE[] = { KBD_CHINESE_TRADITIONAL_ALPHANUMERIC, "romanime.ime", "Chinese (Traditional) - Alphanumeric" } }; +void freerdp_keyboard_layouts_free(RDP_KEYBOARD_LAYOUT* layouts) +{ + free(layouts); +} + RDP_KEYBOARD_LAYOUT* freerdp_keyboard_get_layouts(DWORD types) { int num, length, i; diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 226291f57..9e265095e 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -69,7 +69,9 @@ endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/winpr/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/include/winpr/config.h) -add_subdirectory(include) +if(NOT WITH_WAYK) + add_subdirectory(include) +endif() add_subdirectory(libwinpr) diff --git a/winpr/include/winpr/collections.h b/winpr/include/winpr/collections.h index e6fc2bcf5..d493a59b2 100644 --- a/winpr/include/winpr/collections.h +++ b/winpr/include/winpr/collections.h @@ -204,6 +204,48 @@ WINPR_API BOOL ListDictionary_SetItemValue(wListDictionary* listDictionary, void WINPR_API wListDictionary* ListDictionary_New(BOOL synchronized); WINPR_API void ListDictionary_Free(wListDictionary* listDictionary); +/* System.Collections.Generic.LinkedList */ + +typedef struct _wLinkedListItem wLinkedListNode; + +struct _wLinkedListItem +{ + void* value; + wLinkedListNode* prev; + wLinkedListNode* next; +}; + +struct _wLinkedList +{ + int count; + int initial; + wLinkedListNode* head; + wLinkedListNode* tail; + wLinkedListNode* current; +}; +typedef struct _wLinkedList wLinkedList; + +WINPR_API int LinkedList_Count(wLinkedList* list); +WINPR_API void* LinkedList_First(wLinkedList* list); +WINPR_API void* LinkedList_Last(wLinkedList* list); + +WINPR_API BOOL LinkedList_Contains(wLinkedList* list, void* value); +WINPR_API void LinkedList_Clear(wLinkedList* list); + +WINPR_API void LinkedList_AddFirst(wLinkedList* list, void* value); +WINPR_API void LinkedList_AddLast(wLinkedList* list, void* value); + +WINPR_API void LinkedList_Remove(wLinkedList* list, void* value); +WINPR_API void LinkedList_RemoveFirst(wLinkedList* list); +WINPR_API void LinkedList_RemoveLast(wLinkedList* list); + +WINPR_API void LinkedList_Enumerator_Reset(wLinkedList* list); +WINPR_API void* LinkedList_Enumerator_Current(wLinkedList* list); +WINPR_API BOOL LinkedList_Enumerator_MoveNext(wLinkedList* list); + +WINPR_API wLinkedList* LinkedList_New(); +WINPR_API void LinkedList_Free(wLinkedList* list); + /* System.Collections.Generic.KeyValuePair */ struct _wKeyValuePair diff --git a/winpr/include/winpr/file.h b/winpr/include/winpr/file.h index b1dfe22f5..eac472bf2 100644 --- a/winpr/include/winpr/file.h +++ b/winpr/include/winpr/file.h @@ -302,6 +302,12 @@ extern "C" { WINPR_API BOOL FilePatternMatchA(LPCSTR lpFileName, LPCSTR lpPattern); WINPR_API LPSTR FilePatternFindNextWildcardA(LPCSTR lpPattern, DWORD* pFlags); +WINPR_API int UnixChangeFileMode(const char* filename, int flags); + +WINPR_API char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName); +WINPR_API char* GetNamedPipeUnixDomainSocketBaseFilePathA(); +WINPR_API char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName); + #ifdef __cplusplus } #endif diff --git a/winpr/include/winpr/io.h b/winpr/include/winpr/io.h index 3f4365b85..c182ea4ef 100644 --- a/winpr/include/winpr/io.h +++ b/winpr/include/winpr/io.h @@ -25,6 +25,25 @@ #ifndef _WIN32 +#define GENERIC_READ 0x80000000 +#define GENERIC_WRITE 0x40000000 +#define GENERIC_EXECUTE 0x20000000 +#define GENERIC_ALL 0x10000000 + +#define DELETE 0x00010000 +#define READ_CONTROL 0x00020000 +#define WRITE_DAC 0x00040000 +#define WRITE_OWNER 0x00080000 +#define SYNCHRONIZE 0x00100000 +#define STANDARD_RIGHTS_REQUIRED 0x000F0000 +#define STANDARD_RIGHTS_READ 0x00020000 +#define STANDARD_RIGHTS_WRITE 0x00020000 +#define STANDARD_RIGHTS_EXECUTE 0x00020000 +#define STANDARD_RIGHTS_ALL 0x001F0000 +#define SPECIFIC_RIGHTS_ALL 0x0000FFFF +#define ACCESS_SYSTEM_SECURITY 0x01000000 +#define MAXIMUM_ALLOWED 0x02000000 + typedef struct _OVERLAPPED { ULONG_PTR Internal; diff --git a/winpr/include/winpr/pipe.h b/winpr/include/winpr/pipe.h index 3875c4b6c..188adf859 100644 --- a/winpr/include/winpr/pipe.h +++ b/winpr/include/winpr/pipe.h @@ -28,12 +28,92 @@ #ifndef _WIN32 +#define PIPE_UNLIMITED_INSTANCES 0xFF + +#define PIPE_ACCESS_INBOUND 0x00000001 +#define PIPE_ACCESS_OUTBOUND 0x00000002 +#define PIPE_ACCESS_DUPLEX 0x00000003 + +#define FILE_FLAG_FIRST_PIPE_INSTANCE 0x00080000 +#define FILE_FLAG_WRITE_THROUGH 0x80000000 +#define FILE_FLAG_OVERLAPPED 0x40000000 + +#define PIPE_CLIENT_END 0x00000000 +#define PIPE_SERVER_END 0x00000001 + +#define PIPE_TYPE_BYTE 0x00000000 +#define PIPE_TYPE_MESSAGE 0x00000004 + +#define PIPE_READMODE_BYTE 0x00000000 +#define PIPE_READMODE_MESSAGE 0x00000002 + +#define PIPE_WAIT 0x00000000 +#define PIPE_NOWAIT 0x00000001 + +#define PIPE_ACCEPT_REMOTE_CLIENTS 0x00000000 +#define PIPE_REJECT_REMOTE_CLIENTS 0x00000008 + +#define NMPWAIT_USE_DEFAULT_WAIT 0x00000000 +#define NMPWAIT_NOWAIT 0x00000001 +#define NMPWAIT_WAIT_FOREVER 0xFFFFFFFF + #ifdef __cplusplus extern "C" { #endif +/** + * Unnamed pipe + */ + WINPR_API BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize); +/** + * Named pipe + */ + +WINPR_API HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, + DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes); +WINPR_API HANDLE CreateNamedPipeW(LPCWSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, + DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes); + +WINPR_API BOOL ConnectNamedPipe(HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped); + +WINPR_API BOOL DisconnectNamedPipe(HANDLE hNamedPipe); + +WINPR_API BOOL PeekNamedPipe(HANDLE hNamedPipe, LPVOID lpBuffer, DWORD nBufferSize, + LPDWORD lpBytesRead, LPDWORD lpTotalBytesAvail, LPDWORD lpBytesLeftThisMessage); + +WINPR_API BOOL TransactNamedPipe(HANDLE hNamedPipe, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, + DWORD nOutBufferSize, LPDWORD lpBytesRead, LPOVERLAPPED lpOverlapped); + +WINPR_API BOOL WaitNamedPipeA(LPCSTR lpNamedPipeName, DWORD nTimeOut); +WINPR_API BOOL WaitNamedPipeW(LPCWSTR lpNamedPipeName, DWORD nTimeOut); + +WINPR_API BOOL SetNamedPipeHandleState(HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout); + +WINPR_API BOOL ImpersonateNamedPipeClient(HANDLE hNamedPipe); + +WINPR_API BOOL GetNamedPipeClientComputerNameA(HANDLE Pipe, LPCSTR ClientComputerName, ULONG ClientComputerNameLength); +WINPR_API BOOL GetNamedPipeClientComputerNameW(HANDLE Pipe, LPCWSTR ClientComputerName, ULONG ClientComputerNameLength); + +#ifdef UNICODE +#define CreateNamedPipe CreateNamedPipeW +#define WaitNamedPipe WaitNamedPipeW +#define GetNamedPipeClientComputerName GetNamedPipeClientComputerNameW +#else +#define CreateNamedPipe CreateNamedPipeA +#define WaitNamedPipe WaitNamedPipeA +#define GetNamedPipeClientComputerName GetNamedPipeClientComputerNameA +#endif + +/** + * Extended API + */ + +WINPR_API char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName); +WINPR_API char* GetNamedPipeUnixDomainSocketBaseFilePathA(); +WINPR_API char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName); + #ifdef __cplusplus } #endif diff --git a/winpr/include/winpr/registry.h b/winpr/include/winpr/registry.h index a4021b360..53175ce28 100644 --- a/winpr/include/winpr/registry.h +++ b/winpr/include/winpr/registry.h @@ -35,22 +35,9 @@ extern "C" { #include #include +#include #include -#define DELETE 0x00010000 -#define READ_CONTROL 0x00020000 -#define WRITE_DAC 0x00040000 -#define WRITE_OWNER 0x00080000 -#define SYNCHRONIZE 0x00100000 -#define STANDARD_RIGHTS_REQUIRED 0x000f0000 - -#define STANDARD_RIGHTS_READ READ_CONTROL -#define STANDARD_RIGHTS_WRITE READ_CONTROL -#define STANDARD_RIGHTS_EXECUTE READ_CONTROL - -#define STANDARD_RIGHTS_ALL 0x001F0000 -#define SPECIFIC_RIGHTS_ALL 0x0000FFFF - #define OWNER_SECURITY_INFORMATION 0x00000001 #define GROUP_SECURITY_INFORMATION 0x00000002 #define DACL_SECURITY_INFORMATION 0x00000004 diff --git a/winpr/include/winpr/synch.h b/winpr/include/winpr/synch.h index fd083ae71..136c0877a 100644 --- a/winpr/include/winpr/synch.h +++ b/winpr/include/winpr/synch.h @@ -217,6 +217,8 @@ WINPR_API DWORD SignalObjectAndWait(HANDLE hObjectToSignal, HANDLE hObjectToWait /* Waitable Timer */ +#define CREATE_WAITABLE_TIMER_MANUAL_RESET 0x00000001 + typedef struct _REASON_CONTEXT { ULONG Version; @@ -238,6 +240,9 @@ typedef struct _REASON_CONTEXT typedef VOID (*PTIMERAPCROUTINE)(LPVOID lpArgToCompletionRoutine, DWORD dwTimerLowValue, DWORD dwTimerHighValue); +WINPR_API HANDLE CreateWaitableTimerA(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCSTR lpTimerName); +WINPR_API HANDLE CreateWaitableTimerW(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCWSTR lpTimerName); + WINPR_API HANDLE CreateWaitableTimerExA(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess); WINPR_API HANDLE CreateWaitableTimerExW(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess); @@ -253,9 +258,11 @@ WINPR_API HANDLE OpenWaitableTimerW(DWORD dwDesiredAccess, BOOL bInheritHandle, WINPR_API BOOL CancelWaitableTimer(HANDLE hTimer); #ifdef UNICODE +#define CreateWaitableTimer CreateWaitableTimerW #define CreateWaitableTimerEx CreateWaitableTimerExW #define OpenWaitableTimer OpenWaitableTimerW #else +#define CreateWaitableTimer CreateWaitableTimerA #define CreateWaitableTimerEx CreateWaitableTimerExA #define OpenWaitableTimer OpenWaitableTimerA #endif diff --git a/winpr/include/winpr/wtypes.h b/winpr/include/winpr/wtypes.h index 2aa8bb813..c05e1b86c 100644 --- a/winpr/include/winpr/wtypes.h +++ b/winpr/include/winpr/wtypes.h @@ -88,8 +88,8 @@ typedef DWORD HCALL; typedef int INT, *LPINT; typedef signed char INT8; typedef signed short INT16; -typedef signed int INT32; #ifndef XMD_H +typedef signed int INT32; typedef signed __int64 INT64; #endif typedef const WCHAR* LMCSTR; diff --git a/winpr/libwinpr/CMakeLists.txt b/winpr/libwinpr/CMakeLists.txt index fdb2bdac5..c5c2c6ece 100644 --- a/winpr/libwinpr/CMakeLists.txt +++ b/winpr/libwinpr/CMakeLists.txt @@ -54,7 +54,10 @@ if(MONOLITHIC_BUILD) set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") target_link_libraries(${MODULE_NAME} ${WINPR_LIBS}) + +if(NOT WITH_WAYK) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) +endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/libwinpr") endif() diff --git a/winpr/libwinpr/file/CMakeLists.txt b/winpr/libwinpr/file/CMakeLists.txt index c690d609a..7ab377c6d 100644 --- a/winpr/libwinpr/file/CMakeLists.txt +++ b/winpr/libwinpr/file/CMakeLists.txt @@ -31,7 +31,7 @@ set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SO set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL MODULE winpr - MODULES winpr-crt winpr-handle) + MODULES winpr-crt winpr-handle winpr-path) if(MONOLITHIC_BUILD) diff --git a/winpr/libwinpr/file/file.c b/winpr/libwinpr/file/file.c index b43cd215c..9fcb8db62 100644 --- a/winpr/libwinpr/file/file.c +++ b/winpr/libwinpr/file/file.c @@ -22,6 +22,7 @@ #endif #include +#include #include #include @@ -125,13 +126,21 @@ #ifndef _WIN32 +#ifdef HAVE_UNISTD_H +#include +#endif + #include #include #include #include #include #include + +#include +#include #include +#include #ifdef ANDROID #include @@ -146,7 +155,59 @@ HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { - return NULL; + char* name; + int status; + HANDLE hNamedPipe; + unsigned long flags; + struct sockaddr_un s; + WINPR_NAMED_PIPE* pNamedPipe; + + if (!lpFileName) + return INVALID_HANDLE_VALUE; + + name = GetNamedPipeNameWithoutPrefixA(lpFileName); + + if (!name) + return INVALID_HANDLE_VALUE; + + free(name); + + pNamedPipe = (WINPR_NAMED_PIPE*) malloc(sizeof(WINPR_NAMED_PIPE)); + hNamedPipe = (HANDLE) pNamedPipe; + + WINPR_HANDLE_SET_TYPE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE); + + pNamedPipe->name = _strdup(lpFileName); + pNamedPipe->dwOpenMode = 0; + pNamedPipe->dwPipeMode = 0; + pNamedPipe->nMaxInstances = 0; + pNamedPipe->nOutBufferSize = 0; + pNamedPipe->nInBufferSize = 0; + pNamedPipe->nDefaultTimeOut = 0; + + pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpFileName); + pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpFileName); + + pNamedPipe->clientfd = socket(PF_LOCAL, SOCK_STREAM, 0); + pNamedPipe->serverfd = -1; + + if (0) + { + flags = fcntl(pNamedPipe->clientfd, F_GETFL); + flags = flags | O_NONBLOCK; + fcntl(pNamedPipe->clientfd, F_SETFL, flags); + } + + ZeroMemory(&s, sizeof(struct sockaddr_un)); + s.sun_family = AF_UNIX; + strcpy(s.sun_path, pNamedPipe->lpFilePath); + + status = connect(pNamedPipe->clientfd, (struct sockaddr*) &s, sizeof(struct sockaddr_un)); + + if (status != 0) + return INVALID_HANDLE_VALUE; + + return hNamedPipe; } HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, @@ -170,7 +231,6 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, { ULONG Type; PVOID Object; - WINPR_PIPE* pipe; if (!winpr_Handle_GetInfo(hFile, &Type, &Object)) return FALSE; @@ -178,6 +238,7 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, if (Type == HANDLE_TYPE_ANONYMOUS_PIPE) { int status; + WINPR_PIPE* pipe; pipe = (WINPR_PIPE*) Object; @@ -187,6 +248,30 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, return TRUE; } + else if (Type == HANDLE_TYPE_NAMED_PIPE) + { + int status; + WINPR_NAMED_PIPE* pipe; + + pipe = (WINPR_NAMED_PIPE*) Object; + + status = nNumberOfBytesToRead; + + if (pipe->clientfd != -1) + status = read(pipe->clientfd, lpBuffer, nNumberOfBytesToRead); + else + return FALSE; + + if (status < 0) + { + *lpNumberOfBytesRead = 0; + return FALSE; + } + + *lpNumberOfBytesRead = status; + + return TRUE; + } return FALSE; } @@ -208,7 +293,6 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, { ULONG Type; PVOID Object; - WINPR_PIPE* pipe; if (!winpr_Handle_GetInfo(hFile, &Type, &Object)) return FALSE; @@ -216,6 +300,7 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, if (Type == HANDLE_TYPE_ANONYMOUS_PIPE) { int status; + WINPR_PIPE* pipe; pipe = (WINPR_PIPE*) Object; @@ -225,6 +310,30 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, return TRUE; } + else if (Type == HANDLE_TYPE_NAMED_PIPE) + { + int status; + WINPR_NAMED_PIPE* pipe; + + pipe = (WINPR_NAMED_PIPE*) Object; + + status = nNumberOfBytesToWrite; + + if (pipe->clientfd != -1) + status = write(pipe->clientfd, lpBuffer, nNumberOfBytesToWrite); + else + return FALSE; + + if (status < 0) + { + *lpNumberOfBytesWritten = 0; + return FALSE; + } + + *lpNumberOfBytesWritten = status; + + return TRUE; + } return FALSE; } @@ -445,3 +554,72 @@ BOOL CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttrib #endif +/* Extended API */ + +#define NAMED_PIPE_PREFIX_PATH "\\\\.\\pipe\\" + +char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName) +{ + char* lpFileName; + + if (!lpName) + return NULL; + + if (strncmp(lpName, NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH) - 1) != 0) + return NULL; + + lpFileName = _strdup(&lpName[strlen(NAMED_PIPE_PREFIX_PATH)]); + + return lpFileName; +} + +char* GetNamedPipeUnixDomainSocketBaseFilePathA() +{ + char* lpTempPath; + char* lpPipePath; + + lpTempPath = GetKnownPath(KNOWN_PATH_TEMP); + lpPipePath = GetCombinedPath(lpTempPath, ".pipe"); + + free(lpTempPath); + + return lpPipePath; +} + +char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName) +{ + char* lpPipePath; + char* lpFileName; + char* lpFilePath; + + lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA(); + + lpFileName = GetNamedPipeNameWithoutPrefixA(lpName); + lpFilePath = GetCombinedPath(lpPipePath, (char*) lpFileName); + + free(lpPipePath); + free(lpFileName); + + return lpFilePath; +} + +int UnixChangeFileMode(const char* filename, int flags) +{ + mode_t fl = 0; + + fl |= (flags & 0x4000) ? S_ISUID : 0; + fl |= (flags & 0x2000) ? S_ISGID : 0; + fl |= (flags & 0x1000) ? S_ISVTX : 0; + fl |= (flags & 0x0400) ? S_IRUSR : 0; + fl |= (flags & 0x0200) ? S_IWUSR : 0; + fl |= (flags & 0x0100) ? S_IXUSR : 0; + fl |= (flags & 0x0040) ? S_IRGRP : 0; + fl |= (flags & 0x0020) ? S_IWGRP : 0; + fl |= (flags & 0x0010) ? S_IXGRP : 0; + fl |= (flags & 0x0004) ? S_IROTH : 0; + fl |= (flags & 0x0002) ? S_IWOTH : 0; + fl |= (flags & 0x0001) ? S_IXOTH : 0; + + return chmod(filename, fl); +} + diff --git a/winpr/libwinpr/handle/handle.c b/winpr/libwinpr/handle/handle.c index d198a11a2..3031b032c 100644 --- a/winpr/libwinpr/handle/handle.c +++ b/winpr/libwinpr/handle/handle.c @@ -122,6 +122,21 @@ BOOL CloseHandle(HANDLE hObject) return TRUE; } + else if (Type == HANDLE_TYPE_TIMER) + { + WINPR_TIMER* timer; + + timer = (WINPR_TIMER*) Object; + +#ifdef __linux__ + if (timer->fd != -1) + close(timer->fd); +#endif + + free(Object); + + return TRUE; + } else if (Type == HANDLE_TYPE_ANONYMOUS_PIPE) { WINPR_PIPE* pipe; @@ -137,6 +152,22 @@ BOOL CloseHandle(HANDLE hObject) return TRUE; } + else if (Type == HANDLE_TYPE_NAMED_PIPE) + { + WINPR_NAMED_PIPE* pipe; + + pipe = (WINPR_NAMED_PIPE*) Object; + + if (pipe->clientfd != -1) + close(pipe->clientfd); + + if (pipe->serverfd != -1) + close(pipe->serverfd); + + free(Object); + + return TRUE; + } return FALSE; } diff --git a/winpr/libwinpr/pipe/pipe.c b/winpr/libwinpr/pipe/pipe.c index 1363763ee..241f131b9 100644 --- a/winpr/libwinpr/pipe/pipe.c +++ b/winpr/libwinpr/pipe/pipe.c @@ -22,6 +22,7 @@ #endif #include +#include #include #include @@ -34,8 +35,17 @@ #include "../handle/handle.h" +#include +#include +#include +#include + #include "pipe.h" +/* + * Unnamed pipe + */ + BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize) { int pipe_fd[2]; @@ -69,4 +79,169 @@ BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpP return TRUE; } +/** + * Named pipe + */ + +HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, + DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes) +{ + int status; + HANDLE hNamedPipe; + char* lpPipePath; + unsigned long flags; + struct sockaddr_un s; + WINPR_NAMED_PIPE* pNamedPipe; + + if (!lpName) + return INVALID_HANDLE_VALUE; + + pNamedPipe = (WINPR_NAMED_PIPE*) malloc(sizeof(WINPR_NAMED_PIPE)); + hNamedPipe = (HANDLE) pNamedPipe; + + WINPR_HANDLE_SET_TYPE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE); + + pNamedPipe->name = _strdup(lpName); + pNamedPipe->dwOpenMode = dwOpenMode; + pNamedPipe->dwPipeMode = dwPipeMode; + pNamedPipe->nMaxInstances = nMaxInstances; + pNamedPipe->nOutBufferSize = nOutBufferSize; + pNamedPipe->nInBufferSize = nInBufferSize; + pNamedPipe->nDefaultTimeOut = nDefaultTimeOut; + + pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpName); + pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpName); + + lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA(); + + if (!PathFileExistsA(lpPipePath)) + CreateDirectoryA(lpPipePath, 0); + + free(lpPipePath); + + pNamedPipe->clientfd = -1; + pNamedPipe->serverfd = socket(PF_LOCAL, SOCK_STREAM, 0); + + if (0) + { + flags = fcntl(pNamedPipe->serverfd, F_GETFL); + flags = flags | O_NONBLOCK; + fcntl(pNamedPipe->serverfd, F_SETFL, flags); + } + + ZeroMemory(&s, sizeof(struct sockaddr_un)); + s.sun_family = AF_UNIX; + strcpy(s.sun_path, pNamedPipe->lpFilePath); + unlink(s.sun_path); + + status = bind(pNamedPipe->serverfd, (struct sockaddr*) &s, sizeof(struct sockaddr_un)); + + if (status == 0) + { + status = listen(pNamedPipe->serverfd, 2); + + if (status == 0) + { + UnixChangeFileMode(pNamedPipe->lpFilePath, 0xFFFF); + } + } + + return hNamedPipe; +} + +HANDLE CreateNamedPipeW(LPCWSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, + DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes) +{ + return NULL; +} + +BOOL ConnectNamedPipe(HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped) +{ + int status; + socklen_t length; + struct sockaddr_un s; + WINPR_NAMED_PIPE* pNamedPipe; + + if (!hNamedPipe) + return FALSE; + + pNamedPipe = (WINPR_NAMED_PIPE*) hNamedPipe; + + length = sizeof(struct sockaddr_un); + ZeroMemory(&s, sizeof(struct sockaddr_un)); + + status = accept(pNamedPipe->serverfd, (struct sockaddr*) &s, &length); + + if (status < 0) + return FALSE; + + pNamedPipe->clientfd = status; + + return TRUE; +} + +BOOL DisconnectNamedPipe(HANDLE hNamedPipe) +{ + WINPR_NAMED_PIPE* pNamedPipe; + + pNamedPipe = (WINPR_NAMED_PIPE*) hNamedPipe; + + if (pNamedPipe->clientfd != -1) + { + close(pNamedPipe->clientfd); + pNamedPipe->clientfd = -1; + } + + return TRUE; +} + +BOOL PeekNamedPipe(HANDLE hNamedPipe, LPVOID lpBuffer, DWORD nBufferSize, + LPDWORD lpBytesRead, LPDWORD lpTotalBytesAvail, LPDWORD lpBytesLeftThisMessage) +{ + return TRUE; +} + +BOOL TransactNamedPipe(HANDLE hNamedPipe, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, + DWORD nOutBufferSize, LPDWORD lpBytesRead, LPOVERLAPPED lpOverlapped) +{ + return TRUE; +} + +BOOL WaitNamedPipeA(LPCSTR lpNamedPipeName, DWORD nTimeOut) +{ + return TRUE; +} + +BOOL WaitNamedPipeW(LPCWSTR lpNamedPipeName, DWORD nTimeOut) +{ + return TRUE; +} + +BOOL SetNamedPipeHandleState(HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout) +{ + WINPR_NAMED_PIPE* pNamedPipe; + + pNamedPipe = (WINPR_NAMED_PIPE*) hNamedPipe; + + if (lpMode) + pNamedPipe->dwPipeMode = *lpMode; + + return TRUE; +} + +BOOL ImpersonateNamedPipeClient(HANDLE hNamedPipe) +{ + return FALSE; +} + +BOOL GetNamedPipeClientComputerNameA(HANDLE Pipe, LPCSTR ClientComputerName, ULONG ClientComputerNameLength) +{ + return FALSE; +} + +BOOL GetNamedPipeClientComputerNameW(HANDLE Pipe, LPCWSTR ClientComputerName, ULONG ClientComputerNameLength) +{ + return FALSE; +} + #endif diff --git a/winpr/libwinpr/pipe/pipe.h b/winpr/libwinpr/pipe/pipe.h index f884fdc3f..2c326a771 100644 --- a/winpr/libwinpr/pipe/pipe.h +++ b/winpr/libwinpr/pipe/pipe.h @@ -34,6 +34,26 @@ struct winpr_pipe }; typedef struct winpr_pipe WINPR_PIPE; +struct winpr_named_pipe +{ + WINPR_HANDLE_DEF(); + + int clientfd; + int serverfd; + + const char* name; + const char* lpFileName; + const char* lpFilePath; + + DWORD dwOpenMode; + DWORD dwPipeMode; + DWORD nMaxInstances; + DWORD nOutBufferSize; + DWORD nInBufferSize; + DWORD nDefaultTimeOut; +}; +typedef struct winpr_named_pipe WINPR_NAMED_PIPE; + #endif #endif /* WINPR_PIPE_PRIVATE_H */ diff --git a/winpr/libwinpr/pipe/test/CMakeLists.txt b/winpr/libwinpr/pipe/test/CMakeLists.txt index 57abdc91e..c7b9b5a3d 100644 --- a/winpr/libwinpr/pipe/test/CMakeLists.txt +++ b/winpr/libwinpr/pipe/test/CMakeLists.txt @@ -5,7 +5,9 @@ set(MODULE_PREFIX "TEST_PIPE") set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) set(${MODULE_PREFIX}_TESTS - TestPipeCreatePipe.c) + TestPipeCreatePipe.c + TestPipeCreateNamedPipe.c + TestPipeCreateNamedPipeOverlapped.c) create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} @@ -16,7 +18,7 @@ add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} MODULE winpr - MODULES winpr-pipe) + MODULES winpr-pipe winpr-io winpr-synch winpr-thread winpr-error winpr-utils) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c new file mode 100644 index 000000000..5204217fa --- /dev/null +++ b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c @@ -0,0 +1,181 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PIPE_BUFFER_SIZE 32 + +static HANDLE ReadyEvent; + +static LPTSTR lpszPipeName = _T("\\\\.\\pipe\\winpr_test_pipe"); + +static void* named_pipe_client_thread(void* arg) +{ + HANDLE hNamedPipe; + BYTE* lpReadBuffer; + BYTE* lpWriteBuffer; + BOOL fSuccess = FALSE; + DWORD nNumberOfBytesToRead; + DWORD nNumberOfBytesToWrite; + DWORD lpNumberOfBytesRead; + DWORD lpNumberOfBytesWritten; + + WaitForSingleObject(ReadyEvent, INFINITE); + + hNamedPipe = CreateFile(lpszPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + + if (!hNamedPipe) + { + printf("Named Pipe CreateFile failure: NULL handle\n"); + return NULL; + } + + if (hNamedPipe == INVALID_HANDLE_VALUE) + { + printf("Named Pipe CreateFile failure: INVALID_HANDLE_VALUE\n"); + return NULL; + } + + lpReadBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE); + lpWriteBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE); + + lpNumberOfBytesWritten = 0; + nNumberOfBytesToWrite = PIPE_BUFFER_SIZE; + + FillMemory(lpWriteBuffer, PIPE_BUFFER_SIZE, 0x59); + + fSuccess = WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, &lpNumberOfBytesWritten, NULL); + + if (!fSuccess || (lpNumberOfBytesWritten == 0)) + { + printf("Client NamedPipe WriteFile failure\n"); + return NULL; + } + + lpNumberOfBytesRead = 0; + nNumberOfBytesToRead = PIPE_BUFFER_SIZE; + + ZeroMemory(lpReadBuffer, PIPE_BUFFER_SIZE); + + fSuccess = ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, &lpNumberOfBytesRead, NULL); + + if (!fSuccess || (lpNumberOfBytesRead == 0)) + { + printf("Client NamedPipe ReadFile failure\n"); + return NULL; + } + + printf("Client ReadFile (%d):\n", lpNumberOfBytesRead); + winpr_HexDump(lpReadBuffer, lpNumberOfBytesRead); + + free(lpReadBuffer); + free(lpWriteBuffer); + + CloseHandle(hNamedPipe); + + return NULL; +} + +static void* named_pipe_server_thread(void* arg) +{ + HANDLE hNamedPipe; + BYTE* lpReadBuffer; + BYTE* lpWriteBuffer; + BOOL fSuccess = FALSE; + BOOL fConnected = FALSE; + DWORD nNumberOfBytesToRead; + DWORD nNumberOfBytesToWrite; + DWORD lpNumberOfBytesRead; + DWORD lpNumberOfBytesWritten; + + hNamedPipe = CreateNamedPipe(lpszPipeName, + PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 0, NULL); + + if (!hNamedPipe) + { + printf("CreateNamedPipe failure: NULL handle\n"); + return NULL; + } + + if (hNamedPipe == INVALID_HANDLE_VALUE) + { + printf("CreateNamedPipe failure: INVALID_HANDLE_VALUE\n"); + return NULL; + } + + SetEvent(ReadyEvent); + + fConnected = ConnectNamedPipe(hNamedPipe, NULL); + + if (!fConnected) + fConnected = (GetLastError() == ERROR_PIPE_CONNECTED); + + if (!fConnected) + { + printf("ConnectNamedPipe failure\n"); + return NULL; + } + + lpReadBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE); + lpWriteBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE); + + lpNumberOfBytesRead = 0; + nNumberOfBytesToRead = PIPE_BUFFER_SIZE; + + ZeroMemory(lpReadBuffer, PIPE_BUFFER_SIZE); + + fSuccess = ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, &lpNumberOfBytesRead, NULL); + + if (!fSuccess || (lpNumberOfBytesRead == 0)) + { + printf("Server NamedPipe ReadFile failure\n"); + return NULL; + } + + printf("Server ReadFile (%d):\n", lpNumberOfBytesRead); + winpr_HexDump(lpReadBuffer, lpNumberOfBytesRead); + + lpNumberOfBytesWritten = 0; + nNumberOfBytesToWrite = PIPE_BUFFER_SIZE; + + FillMemory(lpWriteBuffer, PIPE_BUFFER_SIZE, 0x45); + + fSuccess = WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, &lpNumberOfBytesWritten, NULL); + + if (!fSuccess || (lpNumberOfBytesWritten == 0)) + { + printf("Server NamedPipe WriteFile failure\n"); + return NULL; + } + + free(lpReadBuffer); + free(lpWriteBuffer); + + CloseHandle(hNamedPipe); + + return NULL; +} + +int TestPipeCreateNamedPipe(int argc, char* argv[]) +{ + HANDLE ClientThread; + HANDLE ServerThread; + + ReadyEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + ClientThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) named_pipe_client_thread, NULL, 0, NULL); + ServerThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) named_pipe_server_thread, NULL, 0, NULL); + + WaitForSingleObject(ClientThread, INFINITE); + WaitForSingleObject(ServerThread, INFINITE); + + return 0; +} + diff --git a/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c new file mode 100644 index 000000000..f5524c3f8 --- /dev/null +++ b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c @@ -0,0 +1,240 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PIPE_BUFFER_SIZE 32 + +static HANDLE ReadyEvent; + +static LPTSTR lpszPipeName = _T("\\\\.\\pipe\\winpr_test_pipe_overlapped"); + +static void* named_pipe_client_thread(void* arg) +{ + DWORD status; + HANDLE hEvent; + HANDLE hNamedPipe; + BYTE* lpReadBuffer; + BYTE* lpWriteBuffer; + BOOL fSuccess = FALSE; + OVERLAPPED overlapped; + DWORD nNumberOfBytesToRead; + DWORD nNumberOfBytesToWrite; + DWORD NumberOfBytesTransferred; + + WaitForSingleObject(ReadyEvent, INFINITE); + + hNamedPipe = CreateFile(lpszPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + + if (!hNamedPipe) + { + printf("Named Pipe CreateFile failure: NULL handle\n"); + return NULL; + } + + if (hNamedPipe == INVALID_HANDLE_VALUE) + { + printf("Named Pipe CreateFile failure: INVALID_HANDLE_VALUE\n"); + return NULL; + } + + lpReadBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE); + lpWriteBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE); + + ZeroMemory(&overlapped, sizeof(OVERLAPPED)); + hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + overlapped.hEvent = hEvent; + + nNumberOfBytesToWrite = PIPE_BUFFER_SIZE; + + FillMemory(lpWriteBuffer, PIPE_BUFFER_SIZE, 0x59); + + fSuccess = WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, NULL, &overlapped); + + if (!fSuccess) + fSuccess = (GetLastError() == ERROR_IO_PENDING); + + if (!fSuccess) + { + printf("Client NamedPipe WriteFile failure: %d\n", GetLastError()); + return NULL; + } + + status = WaitForMultipleObjects(1, &hEvent, FALSE, INFINITE); + + NumberOfBytesTransferred = 0; + fSuccess = GetOverlappedResult(hNamedPipe, &overlapped, &NumberOfBytesTransferred, TRUE); + + printf("Client GetOverlappedResult: fSuccess: %d NumberOfBytesTransferred: %d\n", fSuccess, NumberOfBytesTransferred); + + nNumberOfBytesToRead = PIPE_BUFFER_SIZE; + + ZeroMemory(lpReadBuffer, PIPE_BUFFER_SIZE); + + fSuccess = ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, NULL, &overlapped); + + if (!fSuccess) + fSuccess = (GetLastError() == ERROR_IO_PENDING); + + if (!fSuccess) + { + printf("Client NamedPipe ReadFile failure: %d\n", GetLastError()); + return NULL; + } + + status = WaitForMultipleObjects(1, &hEvent, FALSE, INFINITE); + + NumberOfBytesTransferred = 0; + fSuccess = GetOverlappedResult(hNamedPipe, &overlapped, &NumberOfBytesTransferred, TRUE); + + printf("Client GetOverlappedResult: fSuccess: %d NumberOfBytesTransferred: %d\n", fSuccess, NumberOfBytesTransferred); + + printf("Client ReadFile (%d):\n", NumberOfBytesTransferred); + winpr_HexDump(lpReadBuffer, NumberOfBytesTransferred); + + free(lpReadBuffer); + free(lpWriteBuffer); + + CloseHandle(hNamedPipe); + CloseHandle(hEvent); + + return NULL; +} + +static void* named_pipe_server_thread(void* arg) +{ + DWORD status; + HANDLE hEvent; + HANDLE hNamedPipe; + BYTE* lpReadBuffer; + BYTE* lpWriteBuffer; + OVERLAPPED overlapped; + BOOL fSuccess = FALSE; + BOOL fConnected = FALSE; + DWORD nNumberOfBytesToRead; + DWORD nNumberOfBytesToWrite; + DWORD NumberOfBytesTransferred; + + hNamedPipe = CreateNamedPipe(lpszPipeName, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 0, NULL); + + if (!hNamedPipe) + { + printf("CreateNamedPipe failure: NULL handle\n"); + return NULL; + } + + if (hNamedPipe == INVALID_HANDLE_VALUE) + { + printf("CreateNamedPipe failure: INVALID_HANDLE_VALUE (%d)\n", GetLastError()); + return NULL; + } + + SetEvent(ReadyEvent); + + ZeroMemory(&overlapped, sizeof(OVERLAPPED)); + hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + overlapped.hEvent = hEvent; + + fConnected = ConnectNamedPipe(hNamedPipe, &overlapped); + + printf("ConnectNamedPipe status: %d\n", GetLastError()); + + if (!fConnected) + fConnected = (GetLastError() == ERROR_IO_PENDING); + + status = WaitForMultipleObjects(1, &hEvent, FALSE, INFINITE); + + NumberOfBytesTransferred = 0; + fSuccess = GetOverlappedResult(hNamedPipe, &overlapped, &NumberOfBytesTransferred, TRUE); + + printf("Server GetOverlappedResult: fSuccess: %d NumberOfBytesTransferred: %d\n", fSuccess, NumberOfBytesTransferred); + + if (!fConnected) + { + printf("ConnectNamedPipe failure: %d\n", GetLastError()); + return NULL; + } + + lpReadBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE); + lpWriteBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE); + + nNumberOfBytesToRead = PIPE_BUFFER_SIZE; + + ZeroMemory(lpReadBuffer, PIPE_BUFFER_SIZE); + + fSuccess = ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, NULL, &overlapped); + + if (!fSuccess) + fSuccess = (GetLastError() == ERROR_IO_PENDING); + + if (!fSuccess) + { + printf("Server NamedPipe ReadFile failure: %d\n", GetLastError()); + return NULL; + } + + status = WaitForMultipleObjects(1, &hEvent, FALSE, INFINITE); + + NumberOfBytesTransferred = 0; + fSuccess = GetOverlappedResult(hNamedPipe, &overlapped, &NumberOfBytesTransferred, TRUE); + + printf("Server GetOverlappedResult: fSuccess: %d NumberOfBytesTransferred: %d\n", fSuccess, NumberOfBytesTransferred); + + printf("Server ReadFile (%d):\n", NumberOfBytesTransferred); + winpr_HexDump(lpReadBuffer, NumberOfBytesTransferred); + + nNumberOfBytesToWrite = PIPE_BUFFER_SIZE; + + FillMemory(lpWriteBuffer, PIPE_BUFFER_SIZE, 0x45); + + fSuccess = WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, NULL, &overlapped); + + if (!fSuccess) + fSuccess = (GetLastError() == ERROR_IO_PENDING); + + if (!fSuccess) + { + printf("Server NamedPipe WriteFile failure: %d\n", GetLastError()); + return NULL; + } + + status = WaitForMultipleObjects(1, &hEvent, FALSE, INFINITE); + + NumberOfBytesTransferred = 0; + fSuccess = GetOverlappedResult(hNamedPipe, &overlapped, &NumberOfBytesTransferred, TRUE); + + printf("Server GetOverlappedResult: fSuccess: %d NumberOfBytesTransferred: %d\n", fSuccess, NumberOfBytesTransferred); + + free(lpReadBuffer); + free(lpWriteBuffer); + + CloseHandle(hNamedPipe); + CloseHandle(hEvent); + + return NULL; +} + +int TestPipeCreateNamedPipeOverlapped(int argc, char* argv[]) +{ + HANDLE ClientThread; + HANDLE ServerThread; + + ReadyEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + ClientThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) named_pipe_client_thread, NULL, 0, NULL); + ServerThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) named_pipe_server_thread, NULL, 0, NULL); + + WaitForSingleObject(ClientThread, INFINITE); + WaitForSingleObject(ServerThread, INFINITE); + + return 0; +} + diff --git a/winpr/libwinpr/synch/event.c b/winpr/libwinpr/synch/event.c index 173afafb7..ece585cbf 100644 --- a/winpr/libwinpr/synch/event.c +++ b/winpr/libwinpr/synch/event.c @@ -82,6 +82,9 @@ HANDLE CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, WINPR_HANDLE_SET_TYPE(event, HANDLE_TYPE_EVENT); handle = (HANDLE) event; + + if (bInitialState) + SetEvent(handle); } if (!cs.LockSemaphore) diff --git a/winpr/libwinpr/synch/mutex.c b/winpr/libwinpr/synch/mutex.c index bc0e3f02b..89e6eaaf1 100644 --- a/winpr/libwinpr/synch/mutex.c +++ b/winpr/libwinpr/synch/mutex.c @@ -25,16 +25,6 @@ #include "synch.h" -/** - * CreateMutexA - * CreateMutexW - * CreateMutexExA - * CreateMutexExW - * OpenMutexA - * OpenMutexW - * ReleaseMutex - */ - #ifndef _WIN32 #include "../handle/handle.h" diff --git a/winpr/libwinpr/synch/synch.h b/winpr/libwinpr/synch/synch.h index 158f3bcea..f3593c536 100644 --- a/winpr/libwinpr/synch/synch.h +++ b/winpr/libwinpr/synch/synch.h @@ -20,6 +20,12 @@ #ifndef WINPR_SYNCH_PRIVATE_H #define WINPR_SYNCH_PRIVATE_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + #include #ifndef _WIN32 @@ -68,6 +74,29 @@ struct winpr_event }; typedef struct winpr_event WINPR_EVENT; +#ifdef HAVE_TIMERFD_H +#include +#include +#include +#include +#endif + +struct winpr_timer +{ + WINPR_HANDLE_DEF(); + + int fd; + LONG lPeriod; + BOOL bManualReset; + PTIMERAPCROUTINE pfnCompletionRoutine; + LPVOID lpArgToCompletionRoutine; + +#ifdef HAVE_TIMERFD_H + struct itimerspec timeout; +#endif +}; +typedef struct winpr_timer WINPR_TIMER; + #endif #endif /* WINPR_SYNCH_PRIVATE_H */ diff --git a/winpr/libwinpr/synch/test/CMakeLists.txt b/winpr/libwinpr/synch/test/CMakeLists.txt index d26d32935..a00169ccd 100644 --- a/winpr/libwinpr/synch/test/CMakeLists.txt +++ b/winpr/libwinpr/synch/test/CMakeLists.txt @@ -5,7 +5,11 @@ set(MODULE_PREFIX "TEST_SYNCH") set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) set(${MODULE_PREFIX}_TESTS - TestSynchCritical.c) + TestSynchEvent.c + TestSynchMutex.c + TestSynchCritical.c + TestSynchSemaphore.c + TestSynchWaitableTimer.c) create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} diff --git a/winpr/libwinpr/synch/test/TestSynchEvent.c b/winpr/libwinpr/synch/test/TestSynchEvent.c new file mode 100644 index 000000000..1262613e9 --- /dev/null +++ b/winpr/libwinpr/synch/test/TestSynchEvent.c @@ -0,0 +1,42 @@ + +#include +#include + +int TestSynchEvent(int argc, char* argv[]) +{ + HANDLE event; + + event = CreateEvent(NULL, TRUE, TRUE, NULL); + + if (!event) + { + printf("CreateEvent failure\n"); + return -1; + } + + if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0) + { + printf("WaitForSingleObject(event, INFINITE) failure\n"); + return -1; + } + + ResetEvent(event); + + if (WaitForSingleObject(event, 0) != WAIT_TIMEOUT) + { + printf("WaitForSingleObject(event, 0) failure\n"); + return -1; + } + + SetEvent(event); + + if (WaitForSingleObject(event, 0) != WAIT_OBJECT_0) + { + printf("WaitForSingleObject(event, 0) failure\n"); + return -1; + } + + CloseHandle(event); + + return 0; +} diff --git a/winpr/libwinpr/synch/test/TestSynchMutex.c b/winpr/libwinpr/synch/test/TestSynchMutex.c new file mode 100644 index 000000000..6d2a5df43 --- /dev/null +++ b/winpr/libwinpr/synch/test/TestSynchMutex.c @@ -0,0 +1,21 @@ + +#include +#include + +int TestSynchMutex(int argc, char* argv[]) +{ + HANDLE mutex; + + mutex = CreateMutex(NULL, FALSE, NULL); + + if (!mutex) + { + printf("CreateMutex failure\n"); + return -1; + } + + CloseHandle(mutex); + + return 0; +} + diff --git a/winpr/libwinpr/synch/test/TestSynchSemaphore.c b/winpr/libwinpr/synch/test/TestSynchSemaphore.c new file mode 100644 index 000000000..3a9fa161c --- /dev/null +++ b/winpr/libwinpr/synch/test/TestSynchSemaphore.c @@ -0,0 +1,21 @@ + +#include +#include + +int TestSynchSemaphore(int argc, char* argv[]) +{ + HANDLE semaphore; + + semaphore = CreateSemaphore(NULL, 0, 1, NULL); + + if (!semaphore) + { + printf("CreateSemaphore failure\n"); + return -1; + } + + CloseHandle(semaphore); + + return 0; +} + diff --git a/winpr/libwinpr/synch/test/TestSynchWaitableTimer.c b/winpr/libwinpr/synch/test/TestSynchWaitableTimer.c new file mode 100644 index 000000000..472a412e1 --- /dev/null +++ b/winpr/libwinpr/synch/test/TestSynchWaitableTimer.c @@ -0,0 +1,71 @@ + +#include +#include + +int TestSynchWaitableTimer(int argc, char* argv[]) +{ + HANDLE timer; + LONG period; + LARGE_INTEGER due; + + timer = CreateWaitableTimer(NULL, TRUE, NULL); + + if (!timer) + { + printf("CreateWaitableTimer failure\n"); + return -1; + } + + due.QuadPart = -15000000LL; /* 1.5 seconds */ + + if (!SetWaitableTimer(timer, &due, 0, NULL, NULL, 0)) + { + printf("SetWaitableTimer failure\n"); + return -1; + } + + if (WaitForSingleObject(timer, INFINITE) != WAIT_OBJECT_0) + { + printf("WaitForSingleObject(timer, INFINITE) failure\n"); + return -1; + } + + printf("Timer Signaled\n"); + + if (WaitForSingleObject(timer, 2000) != WAIT_TIMEOUT) + { + printf("WaitForSingleObject(timer, 2000) failure\n"); + return -1; + } + + due.QuadPart = 0; + + period = 1200; /* 1.2 seconds */ + + if (!SetWaitableTimer(timer, &due, period, NULL, NULL, 0)) + { + printf("SetWaitableTimer failure\n"); + return -1; + } + + if (WaitForSingleObject(timer, INFINITE) != WAIT_OBJECT_0) + { + printf("WaitForSingleObject(timer, INFINITE) failure\n"); + return -1; + } + + printf("Timer Signaled\n"); + + if (WaitForMultipleObjects(1, &timer, FALSE, INFINITE) != WAIT_OBJECT_0) + { + printf("WaitForMultipleObjects(timer, INFINITE) failure\n"); + return -1; + } + + printf("Timer Signaled\n"); + + CloseHandle(timer); + + return 0; +} + diff --git a/winpr/libwinpr/synch/timer.c b/winpr/libwinpr/synch/timer.c index 2753ae563..bc32ffcdb 100644 --- a/winpr/libwinpr/synch/timer.c +++ b/winpr/libwinpr/synch/timer.c @@ -21,23 +21,66 @@ #include "config.h" #endif +#include + #include -/** - * CreateWaitableTimerExW - * OpenWaitableTimerW - * SetWaitableTimer - * SetWaitableTimerEx - * CancelWaitableTimer - */ +#include "synch.h" #ifndef _WIN32 -HANDLE CreateWaitableTimerExA(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess) +#include "../handle/handle.h" + +HANDLE CreateWaitableTimerA(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCSTR lpTimerName) +{ + HANDLE handle = NULL; + WINPR_TIMER* timer; + + timer = (WINPR_TIMER*) malloc(sizeof(WINPR_TIMER)); + + if (timer) + { + int status = 0; + + WINPR_HANDLE_SET_TYPE(timer, HANDLE_TYPE_TIMER); + handle = (HANDLE) timer; + + timer->fd = -1; + timer->lPeriod = 0; + timer->bManualReset = bManualReset; + timer->pfnCompletionRoutine = NULL; + timer->lpArgToCompletionRoutine = NULL; + +#ifdef HAVE_TIMERFD_H + timer->fd = timerfd_create(CLOCK_MONOTONIC, 0); + + if (timer->fd <= 0) + return NULL; + + status = fcntl(timer->fd, F_SETFL, O_NONBLOCK); + + if (status) + return NULL; +#endif + } + + return handle; +} + +HANDLE CreateWaitableTimerW(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCWSTR lpTimerName) { return NULL; } +HANDLE CreateWaitableTimerExA(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess) +{ + BOOL bManualReset; + + bManualReset = (dwFlags & CREATE_WAITABLE_TIMER_MANUAL_RESET) ? TRUE : FALSE; + + return CreateWaitableTimerA(lpTimerAttributes, bManualReset, lpTimerName); +} + HANDLE CreateWaitableTimerExW(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess) { return NULL; @@ -46,12 +89,98 @@ HANDLE CreateWaitableTimerExW(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR l BOOL SetWaitableTimer(HANDLE hTimer, const LARGE_INTEGER* lpDueTime, LONG lPeriod, PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, BOOL fResume) { + ULONG Type; + PVOID Object; + int status = 0; + WINPR_TIMER* timer; + LONGLONG seconds = 0; + LONGLONG nanoseconds = 0; + + if (!winpr_Handle_GetInfo(hTimer, &Type, &Object)) + return FALSE; + + if (Type != HANDLE_TYPE_TIMER) + return FALSE; + + if (!lpDueTime) + return FALSE; + + if (lPeriod < 0) + return FALSE; + + timer = (WINPR_TIMER*) Object; + + timer->lPeriod = lPeriod; /* milliseconds */ + timer->pfnCompletionRoutine = pfnCompletionRoutine; + timer->lpArgToCompletionRoutine = lpArgToCompletionRoutine; + +#ifdef HAVE_TIMERFD_H + ZeroMemory(&(timer->timeout), sizeof(struct itimerspec)); + + if (lpDueTime->QuadPart < 0) + { + LONGLONG due = lpDueTime->QuadPart * (-1); + + /* due time is in 100 nanosecond intervals */ + + seconds = (due / 10000000); + nanoseconds = ((due % 10000000) * 100); + } + else if (lpDueTime->QuadPart == 0) + { + seconds = nanoseconds = 0; + } + else + { + printf("SetWaitableTimer: implement absolute time\n"); + return FALSE; + } + + if (lPeriod > 0) + { + timer->timeout.it_interval.tv_sec = (lPeriod / 1000); /* seconds */ + timer->timeout.it_interval.tv_nsec = ((lPeriod % 1000) * 1000000); /* nanoseconds */ + } + + if (lpDueTime->QuadPart != 0) + { + timer->timeout.it_value.tv_sec = seconds; /* seconds */ + timer->timeout.it_value.tv_nsec = nanoseconds; /* nanoseconds */ + } + else + { + timer->timeout.it_value.tv_sec = timer->timeout.it_interval.tv_sec; /* seconds */ + timer->timeout.it_value.tv_nsec = timer->timeout.it_interval.tv_nsec; /* nanoseconds */ + } + + status = timerfd_settime(timer->fd, 0, &(timer->timeout), NULL); + + if (status) + { + printf("SetWaitableTimer timerfd_settime failure: %d\n", status); + return FALSE; + } +#endif + return TRUE; } BOOL SetWaitableTimerEx(HANDLE hTimer, const LARGE_INTEGER* lpDueTime, LONG lPeriod, PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, PREASON_CONTEXT WakeContext, ULONG TolerableDelay) { + ULONG Type; + PVOID Object; + WINPR_TIMER* timer; + + if (!winpr_Handle_GetInfo(hTimer, &Type, &Object)) + return FALSE; + + if (Type == HANDLE_TYPE_TIMER) + { + timer = (WINPR_TIMER*) Object; + return TRUE; + } + return TRUE; } diff --git a/winpr/libwinpr/synch/wait.c b/winpr/libwinpr/synch/wait.c index 8060aa8ed..d488b0eea 100644 --- a/winpr/libwinpr/synch/wait.c +++ b/winpr/libwinpr/synch/wait.c @@ -62,13 +62,16 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) thread = (WINPR_THREAD*) Object; - status = pthread_join(thread->thread, &thread_status); + if (thread->started) + { + status = pthread_join(thread->thread, &thread_status); - if (status != 0) - fprintf(stderr, "WaitForSingleObject: pthread_join failure: %d\n", status); + if (status != 0) + fprintf(stderr, "WaitForSingleObject: pthread_join failure: %d\n", status); - if (thread_status) - thread->dwExitCode = ((DWORD) (size_t) thread_status); + if (thread_status) + thread->dwExitCode = ((DWORD) (size_t) thread_status); + } } else if (Type == HANDLE_TYPE_MUTEX) { @@ -143,7 +146,7 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) length = read(semaphore->pipe_fd[0], &length, 1); if (length != 1) - return FALSE; + return WAIT_FAILED; } #else @@ -153,6 +156,51 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) sem_wait((winpr_sem_t*) semaphore->sem); #endif +#endif + } + else if (Type == HANDLE_TYPE_TIMER) + { + WINPR_TIMER* timer; + + timer = (WINPR_TIMER*) Object; + +#ifdef HAVE_EVENTFD_H + if (timer->fd != -1) + { + int status; + fd_set rfds; + UINT64 expirations; + struct timeval timeout; + + FD_ZERO(&rfds); + FD_SET(timer->fd, &rfds); + ZeroMemory(&timeout, sizeof(timeout)); + + if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0)) + { + timeout.tv_usec = dwMilliseconds * 1000; + } + + status = select(timer->fd + 1, &rfds, 0, 0, + (dwMilliseconds == INFINITE) ? NULL : &timeout); + + if (status < 0) + return WAIT_FAILED; + + if (status != 1) + return WAIT_TIMEOUT; + + status = read(timer->fd, (void*) &expirations, sizeof(UINT64)); + + if (status != 8) + return WAIT_TIMEOUT; + } + else + { + return WAIT_FAILED; + } +#else + return WAIT_FAILED; #endif } else @@ -181,6 +229,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl if (!nCount) return WAIT_FAILED; + maxfd = 0; FD_ZERO(&fds); ZeroMemory(&timeout, sizeof(timeout)); @@ -205,13 +254,18 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl return WAIT_FAILED; #endif } + else if (Type == HANDLE_TYPE_TIMER) + { + WINPR_TIMER* timer = (WINPR_TIMER*) Object; + fd = timer->fd; + } else { return WAIT_FAILED; } - if (fd == -1) - return WAIT_FAILED; + if (fd == -1) + return WAIT_FAILED; FD_SET(fd, &fds); @@ -238,19 +292,40 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl winpr_Handle_GetInfo(lpHandles[index], &Type, &Object); if (Type == HANDLE_TYPE_EVENT) + { fd = ((WINPR_EVENT*) Object)->pipe_fd[0]; + } else if (Type == HANDLE_TYPE_SEMAPHORE) + { fd = ((WINPR_SEMAPHORE*) Object)->pipe_fd[0]; + } + else if (Type == HANDLE_TYPE_TIMER) + { + WINPR_TIMER* timer = (WINPR_TIMER*) Object; + fd = timer->fd; + } if (FD_ISSET(fd, &fds)) { if (Type == HANDLE_TYPE_SEMAPHORE) { - int length = read(fd, &length, 1); + int length; + + length = read(fd, &length, 1); if (length != 1) return WAIT_FAILED; } + else if (Type == HANDLE_TYPE_TIMER) + { + int length; + UINT64 expirations; + + length = read(fd, (void*) &expirations, sizeof(UINT64)); + + if (length != 8) + return WAIT_FAILED; + } return (WAIT_OBJECT_0 + index); } diff --git a/winpr/libwinpr/utils/CMakeLists.txt b/winpr/libwinpr/utils/CMakeLists.txt index 2a8c53afe..d7db7b6d6 100644 --- a/winpr/libwinpr/utils/CMakeLists.txt +++ b/winpr/libwinpr/utils/CMakeLists.txt @@ -25,6 +25,7 @@ set(${MODULE_PREFIX}_COLLECTIONS_SRCS collections/Reference.c collections/ArrayList.c collections/Dictionary.c + collections/LinkedList.c collections/ListDictionary.c collections/KeyValuePair.c collections/CountdownEvent.c diff --git a/winpr/libwinpr/utils/collections/LinkedList.c b/winpr/libwinpr/utils/collections/LinkedList.c new file mode 100644 index 000000000..f96f9d7c0 --- /dev/null +++ b/winpr/libwinpr/utils/collections/LinkedList.c @@ -0,0 +1,339 @@ +/** + * WinPR: Windows Portable Runtime + * System.Collections.Generic.LinkedList + * + * Copyright 2013 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +/** + * C equivalent of the C# LinkedList Class: + * http://msdn.microsoft.com/en-us/library/he2s3bh7.aspx + * + * Internal implementation uses a doubly-linked list + */ + +/** + * Properties + */ + +/** + * Gets the number of nodes actually contained in the LinkedList. + */ + +int LinkedList_Count(wLinkedList* list) +{ + return list->count; +} + +/** + * Gets the first node of the LinkedList. + */ + +void* LinkedList_First(wLinkedList* list) +{ + if (list->head) + return list->head->value; + else + return NULL; +} + +/** + * Gets the last node of the LinkedList. + */ + +void* LinkedList_Last(wLinkedList* list) +{ + if (list->tail) + return list->tail->value; + else + return NULL; +} + +/** + * Methods + */ + +/** + * Determines whether the LinkedList contains a specific value. + */ + +BOOL LinkedList_Contains(wLinkedList* list, void* value) +{ + wLinkedListNode* item; + + if (!list->head) + return FALSE; + + item = list->head; + + while (item) + { + if (item->value == value) + break; + + item = item->next; + } + + return (item) ? TRUE : FALSE; +} + +/** + * Removes all entries from the LinkedList. + */ + +void LinkedList_Clear(wLinkedList* list) +{ + wLinkedListNode* node; + wLinkedListNode* nextNode; + + if (!list->head) + return; + + node = list->head; + + while (node) + { + nextNode = node->next; + free(node); + node = nextNode; + } + + list->head = list->tail = NULL; + list->count = 0; +} + +/** + * Adds a new node containing the specified value at the start of the LinkedList. + */ + +void LinkedList_AddFirst(wLinkedList* list, void* value) +{ + wLinkedListNode* node; + + node = (wLinkedListNode*) malloc(sizeof(wLinkedListNode)); + node->prev = node->next = NULL; + node->value = value; + + if (!list->head) + { + list->tail = list->head = node; + } + else + { + list->head->prev = node; + node->next = list->head; + list->head = node; + } + + list->count++; +} + +/** + * Adds a new node containing the specified value at the end of the LinkedList. + */ + +void LinkedList_AddLast(wLinkedList* list, void* value) +{ + wLinkedListNode* node; + + node = (wLinkedListNode*) malloc(sizeof(wLinkedListNode)); + node->prev = node->next = NULL; + node->value = value; + + if (!list->tail) + { + list->head = list->tail = node; + } + else + { + list->tail->next = node; + node->prev = list->tail; + list->tail = node; + } + + list->count++; +} + +/** + * Removes the first occurrence of the specified value from the LinkedList. + */ + +void LinkedList_Remove(wLinkedList* list, void* value) +{ + wLinkedListNode* node; + + node = list->head; + + while (node) + { + if (node->value == value) + { + if (node->prev) + node->prev->next = node->next; + + if (node->next) + node->next->prev = node->prev; + + if ((!node->prev) && (!node->next)) + list->head = list->tail = NULL; + + free(node); + + list->count--; + + break; + } + + node = node->next; + } +} + +/** + * Removes the node at the start of the LinkedList. + */ + +void LinkedList_RemoveFirst(wLinkedList* list) +{ + wLinkedListNode* node; + + if (list->head) + { + node = list->head; + + list->head = list->head->next; + + if (!list->head) + { + list->tail = NULL; + } + else + { + list->head->prev = NULL; + } + + free(node); + + list->count--; + } +} + +/** + * Removes the node at the end of the LinkedList. + */ + +void LinkedList_RemoveLast(wLinkedList* list) +{ + wLinkedListNode* node; + + if (list->tail) + { + node = list->tail; + + list->tail = list->tail->prev; + + if (!list->tail) + { + list->head = NULL; + } + else + { + list->tail->next = NULL; + } + + free(node); + + list->count--; + } +} + +/** + * Sets the enumerator to its initial position, which is before the first element in the collection. + */ + +void LinkedList_Enumerator_Reset(wLinkedList* list) +{ + list->initial = 1; + list->current = list->head; +} + +/* + * Gets the element at the current position of the enumerator. + */ + +void* LinkedList_Enumerator_Current(wLinkedList* list) +{ + if (list->initial) + return NULL; + + if (list->current) + return list->current->value; + else + return NULL; +} + +/* + * Advances the enumerator to the next element of the LinkedList. + */ + +BOOL LinkedList_Enumerator_MoveNext(wLinkedList* list) +{ + if (list->initial) + list->initial = 0; + else + list->current = list->current->next; + + if (!list->current) + return FALSE; + + return TRUE; +} + +/** + * Construction, Destruction + */ + +wLinkedList* LinkedList_New() +{ + wLinkedList* list = NULL; + + list = (wLinkedList*) malloc(sizeof(wLinkedList)); + + if (list) + { + list->count = 0; + list->initial = 0; + list->head = NULL; + list->tail = NULL; + list->current = NULL; + } + + return list; +} + +void LinkedList_Free(wLinkedList* list) +{ + if (list) + { + LinkedList_Clear(list); + free(list); + } +} + diff --git a/winpr/libwinpr/utils/test/CMakeLists.txt b/winpr/libwinpr/utils/test/CMakeLists.txt index 1455779ef..46af971bf 100644 --- a/winpr/libwinpr/utils/test/CMakeLists.txt +++ b/winpr/libwinpr/utils/test/CMakeLists.txt @@ -9,6 +9,7 @@ set(${MODULE_PREFIX}_TESTS TestPrint.c TestPubSub.c TestArrayList.c + TestLinkedList.c TestListDictionary.c TestCmdLine.c TestStreamPool.c diff --git a/winpr/libwinpr/utils/test/TestLinkedList.c b/winpr/libwinpr/utils/test/TestLinkedList.c new file mode 100644 index 000000000..555d617e7 --- /dev/null +++ b/winpr/libwinpr/utils/test/TestLinkedList.c @@ -0,0 +1,114 @@ + +#include +#include +#include + +int TestLinkedList(int argc, char* argv[]) +{ + int count; + int number; + wLinkedList* list; + + list = LinkedList_New(); + + LinkedList_AddFirst(list, (void*) (size_t) 1); + LinkedList_AddLast(list, (void*) (size_t) 2); + LinkedList_AddLast(list, (void*) (size_t) 3); + + count = LinkedList_Count(list); + + if (count != 3) + { + printf("LinkedList_Count: expected %d, actual: %d\n", 3, count); + return -1; + } + + LinkedList_Enumerator_Reset(list); + + while (LinkedList_Enumerator_MoveNext(list)) + { + number = (int) (size_t) LinkedList_Enumerator_Current(list); + printf("\t%d\n", number); + } + printf("\n"); + + printf("LinkedList First: %d Last: %d\n", + (int) (size_t) LinkedList_First(list), (int) (size_t) LinkedList_Last(list)); + + LinkedList_RemoveFirst(list); + LinkedList_RemoveLast(list); + + count = LinkedList_Count(list); + + if (count != 1) + { + printf("LinkedList_Count: expected %d, actual: %d\n", 1, count); + return -1; + } + + LinkedList_Enumerator_Reset(list); + + while (LinkedList_Enumerator_MoveNext(list)) + { + number = (int) (size_t) LinkedList_Enumerator_Current(list); + printf("\t%d\n", number); + } + printf("\n"); + + printf("LinkedList First: %d Last: %d\n", + (int) (size_t) LinkedList_First(list), (int) (size_t) LinkedList_Last(list)); + + LinkedList_RemoveFirst(list); + LinkedList_RemoveLast(list); + + count = LinkedList_Count(list); + + if (count != 0) + { + printf("LinkedList_Count: expected %d, actual: %d\n", 0, count); + return -1; + } + + LinkedList_AddFirst(list, (void*) (size_t) 4); + LinkedList_AddLast(list, (void*) (size_t) 5); + LinkedList_AddLast(list, (void*) (size_t) 6); + + count = LinkedList_Count(list); + + if (count != 3) + { + printf("LinkedList_Count: expected %d, actual: %d\n", 3, count); + return -1; + } + + LinkedList_Enumerator_Reset(list); + + while (LinkedList_Enumerator_MoveNext(list)) + { + number = (int) (size_t) LinkedList_Enumerator_Current(list); + printf("\t%d\n", number); + } + printf("\n"); + + printf("LinkedList First: %d Last: %d\n", + (int) (size_t) LinkedList_First(list), (int) (size_t) LinkedList_Last(list)); + + LinkedList_Remove(list, (void*) (size_t) 5); + + LinkedList_Enumerator_Reset(list); + + while (LinkedList_Enumerator_MoveNext(list)) + { + number = (int) (size_t) LinkedList_Enumerator_Current(list); + printf("\t%d\n", number); + } + printf("\n"); + + printf("LinkedList First: %d Last: %d\n", + (int) (size_t) LinkedList_First(list), (int) (size_t) LinkedList_Last(list)); + + LinkedList_Free(list); + + return 0; +} + diff --git a/winpr/tools/makecert/CMakeLists.txt b/winpr/tools/makecert/CMakeLists.txt index 7663caa18..c31d08cef 100644 --- a/winpr/tools/makecert/CMakeLists.txt +++ b/winpr/tools/makecert/CMakeLists.txt @@ -38,8 +38,10 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) -install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) -add_subdirectory(cli) +if(NOT WITH_WAYK) + install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) + add_subdirectory(cli) +endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Tools")