Merge pull request from awakecoding/master

Server-side core fixes, WinPR waitable timers & named pipes, Multitouch fixes
This commit is contained in:
Marc-André Moreau 2013-08-07 13:39:29 -07:00
commit 0e8dfb9e77
83 changed files with 3166 additions and 633 deletions

View File

@ -142,7 +142,7 @@ if(CMAKE_COMPILER_IS_GNUCC)
endif() endif()
endif() endif()
if(CMAKE_BUILD_TYPE STREQUAL "Release") 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") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
else() else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g")
@ -160,10 +160,10 @@ endif()
if(MSVC) if(MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Gd") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Gd")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MT") #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MD")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /O2") #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /O2")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Ob2") #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Ob2")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W2") #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W2")
if(CMAKE_SIZEOF_VOID_P EQUAL 8) if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_AMD64_") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_AMD64_")
else() else()
@ -171,6 +171,13 @@ if(MSVC)
endif() endif()
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}) SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR})
SET(LIBRARY_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() endif()
if(WIN32) if(WIN32)
@ -261,6 +268,7 @@ endif()
if(UNIX OR CYGWIN) if(UNIX OR CYGWIN)
check_include_files(sys/eventfd.h HAVE_EVENTFD_H) check_include_files(sys/eventfd.h HAVE_EVENTFD_H)
check_include_files(sys/timerfd.h HAVE_TIMERFD_H)
set(X11_FEATURE_TYPE "RECOMMENDED") set(X11_FEATURE_TYPE "RECOMMENDED")
else() else()
set(X11_FEATURE_TYPE "DISABLED") set(X11_FEATURE_TYPE "DISABLED")
@ -461,7 +469,9 @@ if(WITH_THIRD_PARTY)
endif() endif()
endif() endif()
add_subdirectory(include) if (NOT WITH_WAYK)
add_subdirectory(include)
endif()
add_subdirectory(libfreerdp) add_subdirectory(libfreerdp)
@ -486,6 +496,8 @@ endif()
SET(CPACK_BINARY_ZIP "ON") SET(CPACK_BINARY_ZIP "ON")
if(NOT WITH_WAYK)
set(CPACK_SOURCE_IGNORE_FILES "/\\\\.git/;/\\\\.gitignore;/CMakeCache.txt") set(CPACK_SOURCE_IGNORE_FILES "/\\\\.git/;/\\\\.gitignore;/CMakeCache.txt")
if(NOT WIN32) if(NOT WIN32)
@ -541,9 +553,12 @@ if(MSVC)
if(MSVC_RUNTIME STREQUAL "dynamic") if(MSVC_RUNTIME STREQUAL "dynamic")
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE) set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
include(InstallRequiredSystemLibraries) include(InstallRequiredSystemLibraries)
if(NOT WITH_WAYK)
install(PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} install(PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS}
DESTINATION ${CMAKE_INSTALL_BINDIR} DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT libraries) COMPONENT libraries)
endif()
endif() endif()
set(EXTRA_DATA_DIR "extra/") set(EXTRA_DATA_DIR "extra/")
@ -589,3 +604,4 @@ endif()
include(CPack) include(CPack)
endif()

View File

@ -96,9 +96,10 @@ struct _RDPEI_PLUGIN
RDPINPUT_CONTACT_DATA contacts[MAX_CONTACTS]; RDPINPUT_CONTACT_DATA contacts[MAX_CONTACTS];
RDPINPUT_CONTACT_POINT* contactPoints; RDPINPUT_CONTACT_POINT* contactPoints;
HANDLE mutex;
HANDLE event; HANDLE event;
HANDLE thread; HANDLE thread;
CRITICAL_SECTION lock;
}; };
typedef struct _RDPEI_PLUGIN RDPEI_PLUGIN; typedef struct _RDPEI_PLUGIN RDPEI_PLUGIN;
@ -160,7 +161,7 @@ static void* rdpei_schedule_thread(void* arg)
{ {
status = WaitForSingleObject(rdpei->event, 20); status = WaitForSingleObject(rdpei->event, 20);
WaitForSingleObject(rdpei->mutex, INFINITE); EnterCriticalSection(&rdpei->lock);
rdpei_add_frame(context); rdpei_add_frame(context);
@ -170,7 +171,7 @@ static void* rdpei_schedule_thread(void* arg)
if (status == WAIT_OBJECT_0) if (status == WAIT_OBJECT_0)
ResetEvent(rdpei->event); ResetEvent(rdpei->event);
ReleaseMutex(rdpei->mutex); LeaveCriticalSection(&rdpei->lock);
} }
return NULL; return NULL;
@ -219,7 +220,7 @@ int rdpei_send_cs_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback)
if (!rdpei->thread) if (!rdpei->thread)
{ {
rdpei->mutex = CreateMutex(NULL, FALSE, NULL); InitializeCriticalSection(&rdpei->lock);
rdpei->event = CreateEvent(NULL, TRUE, FALSE, NULL); rdpei->event = CreateEvent(NULL, TRUE, FALSE, NULL);
rdpei->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) rdpei_schedule_thread, (void*) rdpei, 0, 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; RDPINPUT_CONTACT_POINT* contactPoint;
RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) context->handle; RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) context->handle;
WaitForSingleObject(rdpei->mutex, INFINITE); EnterCriticalSection(&rdpei->lock);
contactPoint = (RDPINPUT_CONTACT_POINT*) &rdpei->contactPoints[contact->contactId]; contactPoint = (RDPINPUT_CONTACT_POINT*) &rdpei->contactPoints[contact->contactId];
CopyMemory(&(contactPoint->data), contact, sizeof(RDPINPUT_CONTACT_DATA)); 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); SetEvent(rdpei->event);
ReleaseMutex(rdpei->mutex); LeaveCriticalSection(&rdpei->lock);
return 1; return 1;
} }

View File

@ -57,4 +57,4 @@ endif()
if (WITH_DOTNET) if (WITH_DOTNET)
add_subdirectory(DotNetClient) add_subdirectory(DotNetClient)
endif() endif()

View File

@ -66,8 +66,8 @@ set_target_properties(${MODULE_NAME} PROPERTIES
MACOSX_FRAMEWORK_IDENTIFIER com.awakecoding.${MODULE_NAME} MACOSX_FRAMEWORK_IDENTIFIER com.awakecoding.${MODULE_NAME}
FRAMEWORK_VERSION 1.1.0 FRAMEWORK_VERSION 1.1.0
MACOSX_FRAMEWORK_SHORT_VERSION_STRING 1.1.0 MACOSX_FRAMEWORK_SHORT_VERSION_STRING 1.1.0
MACOSX_FRAMEWORK_BUNDLE_VERSION 1.1.0 MACOSX_FRAMEWORK_BUNDLE_BUNDLE_VERSION 1.1.0
INSTALL_NAME_DIR "@executable_path/../../Frameworks" INSTALL_NAME_DIR "@executable_path/../Frameworks"
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/Info.plist MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/Info.plist
BUILD_WITH_INSTALL_RPATH 1) BUILD_WITH_INSTALL_RPATH 1)
@ -132,7 +132,7 @@ if (${BUILD_SHARED_LIBS})
endif() endif()
# Add post-build NIB file generation in unix makefiles. XCode handles this implicitly. # 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}") 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 # 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} --compile ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/Versions/${MACOSX_BUNDLE_SHORT_VERSION_STRING}/Resources/${XIB_WE}.nib ${xib}
COMMENT "Compiling ${xib}") COMMENT "Compiling ${xib}")
endforeach() endforeach()
endif() # endif()
# Copy the public header files into the framework # Copy the public header files into the framework
foreach(HEADER ${${MODULE_NAME}_HEADERS}) foreach(HEADER ${${MODULE_NAME}_HEADERS})
@ -169,6 +169,7 @@ endforeach()
# Copy the FreeRDP header files into the framework # Copy the FreeRDP header files into the framework
add_custom_command(TARGET ${MODULE_NAME} POST_BUILD 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}/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}) COMMENT Copying FreeRDP header files to ${MODULE_NAME})
add_subdirectory(cli) add_subdirectory(cli)

View File

@ -41,14 +41,11 @@
@interface MRDPView : NSView @interface MRDPView : NSView
{ {
CFRunLoopSourceRef run_loop_src_channels;
CFRunLoopSourceRef run_loop_src_update;
CFRunLoopSourceRef run_loop_src_input;
NSBitmapImageRep* bmiRep; NSBitmapImageRep* bmiRep;
NSMutableArray* cursors; NSMutableArray* cursors;
NSMutableArray* windows; NSMutableArray* windows;
NSTimer* pasteboard_timer; NSTimer* pasteboard_timer;
NSCursor* currentCursor;
NSRect prevWinPosition; NSRect prevWinPosition;
int titleBarHeight; int titleBarHeight;
freerdp* instance; freerdp* instance;
@ -61,7 +58,6 @@
char** argv; char** argv;
NSPoint savedDragLocation; NSPoint savedDragLocation;
BOOL mouseInClientArea;
BOOL firstCreateWindow; BOOL firstCreateWindow;
BOOL isMoveSizeInProgress; BOOL isMoveSizeInProgress;
BOOL skipResizeOnce; BOOL skipResizeOnce;
@ -80,6 +76,8 @@
int kdcapslock; int kdcapslock;
BOOL initialized; BOOL initialized;
NSImageView* imageView;
@public @public
NSPasteboard* pasteboard_rd; /* for reading from clipboard */ NSPasteboard* pasteboard_rd; /* for reading from clipboard */
@ -90,11 +88,11 @@
} }
- (int) rdpStart :(rdpContext*) rdp_context; - (int) rdpStart :(rdpContext*) rdp_context;
- (void) rdpConnectError; - (void) setCursor: (NSCursor*) cursor;
- (void) rdpRemoteAppError;
- (void) onPasteboardTimerFired :(NSTimer *) timer; - (void) onPasteboardTimerFired :(NSTimer *) timer;
- (void) releaseResources; - (void) releaseResources;
- (void) setViewSize : (int) width : (int) height; - (void) setViewSize : (int) w : (int) h;
@property (assign) int is_connected; @property (assign) int is_connected;
@ -114,3 +112,4 @@ BOOL mac_pre_connect(freerdp* instance);
BOOL mac_post_connect(freerdp* instance); BOOL mac_post_connect(freerdp* instance);
BOOL mac_authenticate(freerdp* instance, char** username, char** password, char** domain); 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); 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);

View File

@ -42,6 +42,8 @@
* - * -
*/ */
#include <winpr/windows.h>
#include "mf_client.h" #include "mf_client.h"
#import "mfreerdp.h" #import "mfreerdp.h"
#import "MRDPView.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_begin_paint(rdpContext* context);
void mac_end_paint(rdpContext* context); void mac_end_paint(rdpContext* context);
void mac_save_state_info(freerdp* instance, rdpContext* context); void mac_save_state_info(freerdp* instance, rdpContext* context);
static void update_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info); static void update_activity_cb(freerdp* instance);
static void input_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info); static void input_activity_cb(freerdp* instance);
static void channel_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info); static void channel_activity_cb(freerdp* instance);
int register_update_fds(freerdp* instance);
int register_input_fds(freerdp* instance);
int invoke_draw_rect(rdpContext* context); int invoke_draw_rect(rdpContext* context);
int process_plugin_args(rdpSettings* settings, const char* name, RDP_PLUGIN_DATA* plugin_data, void* user_data); 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); 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); void cliprdr_send_supported_format_list(freerdp* instance);
int register_channel_fds(int* fds, int count, freerdp* instance); int register_channel_fds(int* fds, int count, freerdp* instance);
DWORD mac_client_thread(void* param);
struct cursor struct cursor
{ {
rdpPointer* pointer; rdpPointer* pointer;
@ -121,7 +124,6 @@ struct rgba_data
- (int) rdpStart:(rdpContext*) rdp_context - (int) rdpStart:(rdpContext*) rdp_context
{ {
int status;
mfContext* mfc; mfContext* mfc;
rdpSettings* settings; rdpSettings* settings;
EmbedWindowEventArgs e; EmbedWindowEventArgs e;
@ -137,32 +139,97 @@ struct rgba_data
e.embed = TRUE; e.embed = TRUE;
e.handle = (void*) self; e.handle = (void*) self;
PubSub_OnEmbedWindow(context->pubSub, context, &e); 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; 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 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]; NSTrackingArea * trackingArea = [[NSTrackingArea alloc] initWithRect:[self visibleRect] options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingCursorUpdate | NSTrackingEnabledDuringMouseDrag | NSTrackingActiveWhenFirstResponder owner:self userInfo:nil];
[self addTrackingArea:trackingArea]; [self addTrackingArea:trackingArea];
mouseInClientArea = YES; // Set the default cursor
currentCursor = [NSCursor arrowCursor];
initialized = YES; 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 * become first responder so we can get keyboard and mouse events
***********************************************************************/ ***********************************************************************/
@ -594,7 +677,8 @@ struct rgba_data
- (void) releaseResources - (void) releaseResources
{ {
int i; int i;
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
{ {
if (argv[i]) if (argv[i])
@ -608,15 +692,6 @@ struct rgba_data
if (pixel_data) if (pixel_data)
free(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 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 - (void) onPasteboardTimerFired :(NSTimer*) timer
{ {
int i; int i;
@ -870,7 +857,6 @@ BOOL mac_pre_connect(freerdp* instance)
settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE; settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE;
settings->OrderSupport[NEG_ELLIPSE_CB_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); freerdp_channels_pre_connect(instance->context->channels, instance);
return TRUE; return TRUE;
@ -975,7 +961,7 @@ void mf_Pointer_New(rdpContext* context, rdpPointer* pointer)
MRDPCursor* mrdpCursor = [[MRDPCursor alloc] init]; MRDPCursor* mrdpCursor = [[MRDPCursor alloc] init];
mfContext* mfc = (mfContext*) context; mfContext* mfc = (mfContext*) context;
MRDPView* view = (MRDPView*) mfc->view; MRDPView* view = (MRDPView*) mfc->view;
rect.size.width = pointer->width; rect.size.width = pointer->width;
rect.size.height = pointer->height; rect.size.height = pointer->height;
rect.origin.x = pointer->xPos; 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); cursor_data = (BYTE*) malloc(rect.size.width * rect.size.height * 4);
mrdpCursor->cursor_data = cursor_data; 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, freerdp_alpha_cursor_convert(cursor_data, pointer->xorMaskData, pointer->andMaskData,
pointer->width, pointer->height, pointer->xorBpp, context->gdi->clrconv); 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 */ /* store cursor bitmap image in representation - required by NSImage */
bmiRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **) &cursor_data bmiRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **) &cursor_data
pixelsWide:rect.size.width pixelsWide:rect.size.width
@ -1054,18 +1048,17 @@ void mf_Pointer_Set(rdpContext* context, rdpPointer* pointer)
MRDPView* view = (MRDPView*) mfc->view; MRDPView* view = (MRDPView*) mfc->view;
NSMutableArray* ma = view->cursors; NSMutableArray* ma = view->cursors;
if (!view->mouseInClientArea)
return;
for (MRDPCursor* cursor in ma) for (MRDPCursor* cursor in ma)
{ {
if (cursor->pointer == pointer) if (cursor->pointer == pointer)
{ {
[cursor->nsCursor set]; [view setCursor:cursor->nsCursor];
return; return;
} }
} }
NSLog(@"Cursor not found");
} }
/** ********************************************************************* /** *********************************************************************
@ -1083,7 +1076,9 @@ void mf_Pointer_SetNull(rdpContext* context)
void mf_Pointer_SetDefault(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 * 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; int status;
wMessage message; wMessage message;
wMessageQueue* queue; wMessageQueue* queue;
freerdp* instance = (freerdp*) info;
status = 1; status = 1;
queue = freerdp_get_message_queue(instance, FREERDP_UPDATE_MESSAGE_QUEUE); queue = freerdp_get_message_queue(instance, FREERDP_UPDATE_MESSAGE_QUEUE);
if (queue) if (queue)
{ {
while (MessageQueue_Peek(queue, &message, TRUE)) while (MessageQueue_Peek(queue, &message, TRUE))
@ -1175,21 +1169,21 @@ static void update_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBack
break; break;
} }
} }
else
CFRelease(fdref); {
register_update_fds(instance); fprintf(stderr, "update_activity_cb: No queue!\n");
}
} }
/** ********************************************************************* /** *********************************************************************
* called when input data is available * 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; int status;
wMessage message; wMessage message;
wMessageQueue* queue; wMessageQueue* queue;
freerdp* instance = (freerdp*) info;
status = 1; status = 1;
queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE); 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)) 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); status = freerdp_message_queue_process_message(instance, FREERDP_INPUT_MESSAGE_QUEUE, &message);
if (!status) if (!status)
break; break;
} }
} }
else
CFRelease(fdref); {
register_input_fds(instance); fprintf(stderr, "input_activity_cb: No queue!\n");
}
} }
/** ********************************************************************* /** *********************************************************************
* called when data is available on a virtual channel * 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; wMessage* event;
freerdp* instance = (freerdp*) info;
freerdp_channels_process_pending_messages(instance); freerdp_channels_process_pending_messages(instance);
event = freerdp_channels_pop_event(instance->context->channels); event = freerdp_channels_pop_event(instance->context->channels);
if (event) if (event)
{ {
switch (GetMessageClass(event->id)) fprintf(stderr, "channel_activity_cb: message %d\n", event->id);
switch (GetMessageClass(event->id))
{ {
case CliprdrChannel_Class: case CliprdrChannel_Class:
process_cliprdr_event(instance, event); process_cliprdr_event(instance, event);
@ -1234,90 +1226,6 @@ static void channel_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBac
freerdp_event_free(event); 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); 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) * 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) * 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) void windows_to_apple_cords(MRDPView* view, NSRect* r)

View File

@ -18,6 +18,8 @@
MRDPView* mrdpView; MRDPView* mrdpView;
} }
- (void) rdpConnectError: (NSString*) customMessage;
@property (assign) IBOutlet NSWindow *window; @property (assign) IBOutlet NSWindow *window;
@property (assign) rdpContext *context; @property (assign) rdpContext *context;

View File

@ -11,8 +11,9 @@
#import "MacFreeRDP/mf_client.h" #import "MacFreeRDP/mf_client.h"
static AppDelegate* _singleDelegate = nil; 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 @implementation AppDelegate
@ -45,7 +46,10 @@ void AppDelegate_EmbedWindowEventHandler(rdpContext* context, EmbedWindowEventAr
} }
else 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); 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 @end
void AppDelegate_EmbedWindowEventHandler(rdpContext* context, EmbedWindowEventArgs* e) void AppDelegate_EmbedWindowEventHandler(void* ctx, EmbedWindowEventArgs* e)
{ {
rdpContext* context = (rdpContext*) ctx;
if (_singleDelegate) if (_singleDelegate)
{ {
mfContext* mfc = (mfContext*) context; mfContext* mfc = (mfContext*) context;
@ -124,4 +157,48 @@ void AppDelegate_EmbedWindowEventHandler(rdpContext* context, EmbedWindowEventAr
[[_singleDelegate->window contentView] addSubview:mfc->view]; [[_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];
}
} }

View File

@ -86,7 +86,7 @@ set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/Mac")
add_custom_command(TARGET ${MODULE_NAME} POST_BUILD add_custom_command(TARGET ${MODULE_NAME} POST_BUILD
COMMAND mkdir ARGS -p ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.app/Contents/Frameworks 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 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" "@executable_path/../Frameworks/MacFreeRDP.framework/Versions/Current/MacFreeRDP"
"${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.app/Contents/MacOS/${MODULE_NAME}" "${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.app/Contents/MacOS/${MODULE_NAME}"
COMMENT Setting install name for MacFreeRDP) COMMENT Setting install name for MacFreeRDP)

View File

@ -73,8 +73,7 @@ int mfreerdp_client_stop(rdpContext* context)
MessageQueue_PostQuit(queue, 0); MessageQueue_PostQuit(queue, 0);
} }
} }
else if (context->settings->AsyncInput)
if (context->settings->AsyncInput)
{ {
wMessageQueue* queue; wMessageQueue* queue;
queue = freerdp_get_message_queue(context->instance, FREERDP_INPUT_MESSAGE_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; mfc->disconnect = TRUE;
} }
if (mfc->thread)
{
SetEvent(mfc->stopEvent);
WaitForSingleObject(mfc->thread, INFINITE);
CloseHandle(mfc->thread);
mfc->thread = NULL;
}
if (mfc->view_ownership) if (mfc->view_ownership)
{ {
@ -106,6 +113,8 @@ int mfreerdp_client_new(freerdp* instance, rdpContext* context)
mfc = (mfContext*) instance->context; mfc = (mfContext*) instance->context;
mfc->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
context->instance->PreConnect = mac_pre_connect; context->instance->PreConnect = mac_pre_connect;
context->instance->PostConnect = mac_post_connect; context->instance->PostConnect = mac_post_connect;
context->instance->ReceiveChannelData = mac_receive_channel_data; context->instance->ReceiveChannelData = mac_receive_channel_data;
@ -115,8 +124,8 @@ int mfreerdp_client_new(freerdp* instance, rdpContext* context)
settings = instance->settings; settings = instance->settings;
settings->AsyncUpdate = TRUE; settings->AsyncUpdate = TRUE;
// TODO settings->AsyncInput = TRUE; settings->AsyncInput = TRUE;
settings->AsyncChannels = TRUE; settings->AsyncChannels = TRUE;
settings->AsyncTransport = TRUE; settings->AsyncTransport = TRUE;
settings->RedirectClipboard = TRUE; settings->RedirectClipboard = TRUE;

View File

@ -44,6 +44,7 @@ struct mf_context
int client_height; int client_height;
HANDLE keyboardThread; HANDLE keyboardThread;
HANDLE stopEvent;
HGDI_DC hdc; HGDI_DC hdc;
UINT16 srcBpp; UINT16 srcBpp;

View File

@ -63,8 +63,10 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
if(WITH_CLIENT_INTERFACE) if(WITH_CLIENT_INTERFACE)
if (NOT WITH_WAYK)
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries)
add_subdirectory(cli) add_subdirectory(cli)
endif()
else() else()
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT client) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT client)
endif() endif()

View File

@ -664,8 +664,8 @@ void wf_gdi_register_update_callbacks(rdpUpdate* update)
{ {
rdpPrimaryUpdate* primary = update->primary; rdpPrimaryUpdate* primary = update->primary;
update->Palette = wf_gdi_palette_update; update->Palette = (pPalette) wf_gdi_palette_update;
update->SetBounds = wf_gdi_set_bounds; update->SetBounds = (pSetBounds) wf_gdi_set_bounds;
primary->DstBlt = (pDstBlt) wf_gdi_dstblt; primary->DstBlt = (pDstBlt) wf_gdi_dstblt;
primary->PatBlt = (pPatBlt) wf_gdi_patblt; primary->PatBlt = (pPatBlt) wf_gdi_patblt;
@ -690,8 +690,8 @@ void wf_gdi_register_update_callbacks(rdpUpdate* update)
primary->EllipseSC = NULL; primary->EllipseSC = NULL;
primary->EllipseCB = NULL; primary->EllipseCB = NULL;
update->SurfaceBits = wf_gdi_surface_bits; update->SurfaceBits = (pSurfaceBits) wf_gdi_surface_bits;
update->SurfaceFrameMarker = wf_gdi_surface_frame_marker; update->SurfaceFrameMarker = (pSurfaceFrameMarker) wf_gdi_surface_frame_marker;
} }
void wf_update_canvas_diff(wfContext* wfc) void wf_update_canvas_diff(wfContext* wfc)

View File

@ -101,13 +101,15 @@ static BOOL xf_event_Expose(xfContext* xfc, XEvent* event, BOOL app)
{ {
xf_draw_screen_scaled(xfc, x - xfc->offset_x, xf_draw_screen_scaled(xfc, x - xfc->offset_x,
y - xfc->offset_y, w, h, FALSE); y - xfc->offset_y, w, h, FALSE);
} else }
else
{ {
XCopyArea(xfc->display, xfc->primary, XCopyArea(xfc->display, xfc->primary,
xfc->window->handle, xfc->gc, x, y, w, xfc->window->handle, xfc->gc, x, y, w,
h, x, y); h, x, y);
} }
} else }
else
{ {
xfWindow* xfw; xfWindow* xfw;
rdpWindow* window; 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, window = window_list_get_by_extra_id(rail->list,
(void*) event->xexpose.window); (void*) event->xexpose.window);
if (window != NULL ) if (window)
{ {
xfw = (xfWindow*) window->extra; xfw = (xfWindow*) window->extra;
xf_UpdateWindowArea(xfc, xfw, x, y, w, h); xf_UpdateWindowArea(xfc, xfw, x, y, w, h);

View File

@ -255,7 +255,7 @@ void xf_Pointer_Free(rdpContext* context, rdpPointer* pointer)
xf_lock_x11(xfc, FALSE); xf_lock_x11(xfc, FALSE);
if (((xfPointer*) pointer)->cursor != 0) if (((xfPointer*) pointer)->cursor)
XFreeCursor(xfc->display, ((xfPointer*) pointer)->cursor); XFreeCursor(xfc->display, ((xfPointer*) pointer)->cursor);
xf_unlock_x11(xfc, FALSE); xf_unlock_x11(xfc, FALSE);
@ -269,10 +269,12 @@ void xf_Pointer_Set(rdpContext* context, rdpPointer* pointer)
xf_lock_x11(xfc, FALSE); xf_lock_x11(xfc, FALSE);
xfc->pointer = (xfPointer*) pointer;
/* in RemoteApp mode, window can be null if none has had focus */ /* in RemoteApp mode, window can be null if none has had focus */
if (xfc->window != NULL) if (xfc->window)
XDefineCursor(xfc->display, xfc->window->handle, ((xfPointer*) pointer)->cursor); XDefineCursor(xfc->display, xfc->window->handle, xfc->pointer->cursor);
xf_unlock_x11(xfc, FALSE); xf_unlock_x11(xfc, FALSE);
#endif #endif
@ -299,7 +301,9 @@ void xf_Pointer_SetNull(rdpContext* context)
nullcursor = XcursorImageLoadCursor(xfc->display, &ci); 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); XDefineCursor(xfc->display, xfc->window->handle, nullcursor);
xf_unlock_x11(xfc, FALSE); xf_unlock_x11(xfc, FALSE);
@ -313,7 +317,9 @@ void xf_Pointer_SetDefault(rdpContext* context)
xf_lock_x11(xfc, FALSE); xf_lock_x11(xfc, FALSE);
if (xfc->window != NULL) xfc->pointer = NULL;
if (xfc->window)
XUndefineCursor(xfc->display, xfc->window->handle); XUndefineCursor(xfc->display, xfc->window->handle);
xf_unlock_x11(xfc, FALSE); xf_unlock_x11(xfc, FALSE);

View File

@ -21,6 +21,13 @@
#include "config.h" #include "config.h"
#endif #endif
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#ifdef WITH_XCURSOR
#include <X11/Xcursor/Xcursor.h>
#endif
#ifdef WITH_XI #ifdef WITH_XI
#include <X11/extensions/XInput2.h> #include <X11/extensions/XInput2.h>
#endif #endif
@ -551,6 +558,57 @@ char* xf_input_touch_state_string(DWORD flags)
return "TouchUnknown"; 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 xf_input_touch_remote(xfContext* xfc, XIDeviceEvent* event, int evtype)
{ {
int x, y; int x, y;
@ -561,6 +619,8 @@ int xf_input_touch_remote(xfContext* xfc, XIDeviceEvent* event, int evtype)
if (!rdpei) if (!rdpei)
return 0; return 0;
xf_input_hide_cursor(xfc);
touchId = event->detail; touchId = event->detail;
x = (int) event->event_x; x = (int) event->event_x;
y = (int) event->event_y; 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) int xf_input_event(xfContext* xfc, XIDeviceEvent* event, int evtype)
{ {
xf_input_show_cursor(xfc);
switch (evtype) switch (evtype)
{ {
case XI_ButtonPress: case XI_ButtonPress:

View File

@ -89,6 +89,7 @@ struct xf_context
BOOL unobscured; BOOL unobscured;
BOOL debug; BOOL debug;
xfWindow* window; xfWindow* window;
xfPointer* pointer;
xfWorkArea workArea; xfWorkArea workArea;
int current_desktop; int current_desktop;
BOOL remote_app; BOOL remote_app;
@ -96,6 +97,7 @@ struct xf_context
HCLRCONV clrconv; HCLRCONV clrconv;
HANDLE mutex; HANDLE mutex;
BOOL UseXThreads; BOOL UseXThreads;
BOOL cursorHidden;
HGDI_DC hdc; HGDI_DC hdc;
BYTE* primary_buffer; BYTE* primary_buffer;
@ -106,7 +108,6 @@ struct xf_context
UINT16 frame_x2; UINT16 frame_x2;
UINT16 frame_y2; UINT16 frame_y2;
//double scale;
int originalWidth; int originalWidth;
int originalHeight; int originalHeight;
int currentWidth; int currentWidth;

View File

@ -53,7 +53,9 @@ target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
set_target_properties(${MODULE_NAME} PROPERTIES LINK_INTERFACE_LIBRARIES "") 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") set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/Common")

View File

@ -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); 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(_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 #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 \ #define WRITE_RDP_FILE_VALUE_RETURN \
return __required_size; 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) size_t freerdp_client_write_rdp_file_buffer(rdpFile* file, char* buffer, size_t size)
{ {
WRITE_RDP_FILE_DECLARE(file, buffer, size) WRITE_RDP_FILE_DECLARE(file, buffer, size)

40
cmake/FindPixman.cmake Normal file
View File

@ -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 <marcandre.moreau@gmail.com>
#
# 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)

View File

@ -5,17 +5,20 @@ macro(configure_msvc_runtime)
if("${MSVC_RUNTIME}" STREQUAL "") if("${MSVC_RUNTIME}" STREQUAL "")
set(MSVC_RUNTIME "dynamic") set(MSVC_RUNTIME "dynamic")
endif() endif()
# Set compiler options. # Set compiler options.
set(variables set(variables
CMAKE_C_FLAGS
CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_DEBUG
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_MINSIZEREL
CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS_RELWITHDEBINFO
CMAKE_CXX_FLAGS
CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_MINSIZEREL
CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS_RELWITHDEBINFO)
)
if(${MSVC_RUNTIME} STREQUAL "static") if(${MSVC_RUNTIME} STREQUAL "static")
message(STATUS "MSVC: using statically-linked runtime (/MT and /MTd).") message(STATUS "MSVC: using statically-linked runtime (/MT and /MTd).")
foreach(variable ${variables}) foreach(variable ${variables})
@ -31,6 +34,25 @@ macro(configure_msvc_runtime)
endif() endif()
endforeach() endforeach()
endif() 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}) foreach(variable ${variables})
set(${variable} "${${variable}}" CACHE STRING "MSVC_${variable}" FORCE) set(${variable} "${${variable}}" CACHE STRING "MSVC_${variable}" FORCE)
endforeach() endforeach()

View File

@ -30,6 +30,7 @@
#cmakedefine HAVE_SYS_SELECT_H #cmakedefine HAVE_SYS_SELECT_H
#cmakedefine HAVE_SYS_STRTIO_H #cmakedefine HAVE_SYS_STRTIO_H
#cmakedefine HAVE_EVENTFD_H #cmakedefine HAVE_EVENTFD_H
#cmakedefine HAVE_TIMERFD_H
#cmakedefine HAVE_TM_GMTOFF #cmakedefine HAVE_TM_GMTOFF

View File

@ -138,17 +138,7 @@ enum FILE_CREATE_OPTION
#define FILE_WRITE_ATTRIBUTES 0x00000100 #define FILE_WRITE_ATTRIBUTES 0x00000100
#endif #endif
#define DELETE 0x00010000 #include <winpr/io.h>
#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
#endif #endif

9
include/freerdp/error.h Normal file → Executable file
View File

@ -20,6 +20,10 @@
#ifndef FREERDP_ERROR_H #ifndef FREERDP_ERROR_H
#define FREERDP_ERROR_H #define FREERDP_ERROR_H
#include <winpr/crt.h>
#include <freerdp/api.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -128,6 +132,9 @@ extern "C" {
#define ERRINFO_SUCCESS 0x00000000 #define ERRINFO_SUCCESS 0x00000000
#define ERRINFO_NONE 0xFFFFFFFF #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 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. * 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 * 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 ERRORSTART 10000
#define PREECONNECTERROR ERRORSTART + 1 #define PREECONNECTERROR ERRORSTART + 1

View File

@ -34,6 +34,7 @@ extern "C" {
typedef BOOL (*psListenerOpen)(freerdp_listener* instance, const char* bind_address, UINT16 port); typedef BOOL (*psListenerOpen)(freerdp_listener* instance, const char* bind_address, UINT16 port);
typedef BOOL (*psListenerOpenLocal)(freerdp_listener* instance, const char* path); typedef BOOL (*psListenerOpenLocal)(freerdp_listener* instance, const char* path);
typedef BOOL (*psListenerGetFileDescriptor)(freerdp_listener* instance, void** rfds, int* rcount); 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 BOOL (*psListenerCheckFileDescriptor)(freerdp_listener* instance);
typedef void (*psListenerClose)(freerdp_listener* instance); typedef void (*psListenerClose)(freerdp_listener* instance);
typedef void (*psPeerAccepted)(freerdp_listener* instance, freerdp_peer* client); typedef void (*psPeerAccepted)(freerdp_listener* instance, freerdp_peer* client);
@ -50,6 +51,7 @@ struct rdp_freerdp_listener
psListenerOpen Open; psListenerOpen Open;
psListenerOpenLocal OpenLocal; psListenerOpenLocal OpenLocal;
psListenerGetFileDescriptor GetFileDescriptor; psListenerGetFileDescriptor GetFileDescriptor;
psListenerGetEventHandles GetEventHandles;
psListenerCheckFileDescriptor CheckFileDescriptor; psListenerCheckFileDescriptor CheckFileDescriptor;
psListenerClose Close; psListenerClose Close;

View File

@ -205,6 +205,7 @@ extern "C" {
FREERDP_API DWORD freerdp_keyboard_init(DWORD keyboardLayoutId); FREERDP_API DWORD freerdp_keyboard_init(DWORD keyboardLayoutId);
FREERDP_API RDP_KEYBOARD_LAYOUT* freerdp_keyboard_get_layouts(DWORD types); 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 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_layout_id_from_name(const char* name);
FREERDP_API DWORD freerdp_keyboard_get_rdp_scancode_from_x11_keycode(DWORD keycode); FREERDP_API DWORD freerdp_keyboard_get_rdp_scancode_from_x11_keycode(DWORD keycode);

View File

@ -33,6 +33,7 @@ typedef void (*psPeerContextFree)(freerdp_peer* client, rdpContext* context);
typedef BOOL (*psPeerInitialize)(freerdp_peer* client); typedef BOOL (*psPeerInitialize)(freerdp_peer* client);
typedef BOOL (*psPeerGetFileDescriptor)(freerdp_peer* client, void** rfds, int* rcount); typedef BOOL (*psPeerGetFileDescriptor)(freerdp_peer* client, void** rfds, int* rcount);
typedef HANDLE (*psPeerGetEventHandle)(freerdp_peer* client);
typedef BOOL (*psPeerCheckFileDescriptor)(freerdp_peer* client); typedef BOOL (*psPeerCheckFileDescriptor)(freerdp_peer* client);
typedef BOOL (*psPeerClose)(freerdp_peer* client); typedef BOOL (*psPeerClose)(freerdp_peer* client);
typedef void (*psPeerDisconnect)(freerdp_peer* client); typedef void (*psPeerDisconnect)(freerdp_peer* client);
@ -60,6 +61,7 @@ struct rdp_freerdp_peer
psPeerInitialize Initialize; psPeerInitialize Initialize;
psPeerGetFileDescriptor GetFileDescriptor; psPeerGetFileDescriptor GetFileDescriptor;
psPeerGetEventHandle GetEventHandle;
psPeerCheckFileDescriptor CheckFileDescriptor; psPeerCheckFileDescriptor CheckFileDescriptor;
psPeerClose Close; psPeerClose Close;
psPeerDisconnect Disconnect; psPeerDisconnect Disconnect;

View File

@ -59,9 +59,11 @@ if(MONOLITHIC_BUILD)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
install(TARGETS ${MODULE_NAME} if(NOT WITH_WAYK)
DESTINATION ${CMAKE_INSTALL_LIBDIR} install(TARGETS ${MODULE_NAME}
COMPONENT libraries) DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT libraries)
endif()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp") set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp")
endif() endif()

View File

@ -1572,3 +1572,153 @@ int freerdp_bitmap_compress(char* in_data, int width, int height,
return lines_sent; 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";

View File

@ -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) BOOL rdp_recv_client_font_map_pdu(rdpRdp* rdp, wStream* s)
{ {
rdp->finalize_sc_pdus |= FINALIZE_SC_FONT_MAP_PDU; rdp->finalize_sc_pdus |= FINALIZE_SC_FONT_MAP_PDU;
if(Stream_GetRemainingLength(s) >= 8) if(Stream_GetRemainingLength(s) >= 8)
{ {
Stream_Seek_UINT16(s); /* numberEntries (2 bytes) */ Stream_Seek_UINT16(s); /* numberEntries (2 bytes) */
@ -280,13 +281,10 @@ BOOL rdp_recv_deactivate_all(rdpRdp* rdp, wStream* s)
UINT16 lengthSourceDescriptor; UINT16 lengthSourceDescriptor;
if (rdp->state == CONNECTION_STATE_ACTIVE) if (rdp->state == CONNECTION_STATE_ACTIVE)
{
rdp->deactivation_reactivation = TRUE; rdp->deactivation_reactivation = TRUE;
}
else else
{
rdp->deactivation_reactivation = FALSE; rdp->deactivation_reactivation = FALSE;
}
/* /*
* Windows XP can send short DEACTIVATE_ALL PDU that doesn't contain * Windows XP can send short DEACTIVATE_ALL PDU that doesn't contain
* the following fields. * the following fields.
@ -313,7 +311,7 @@ BOOL rdp_recv_deactivate_all(rdpRdp* rdp, wStream* s)
while(0); while(0);
} }
rdp->state = CONNECTION_STATE_CAPABILITY; rdp_client_transition_to_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE);
while (rdp->state != CONNECTION_STATE_ACTIVE) 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)) if (!rdp_send_server_font_map_pdu(rdp))
return FALSE; return FALSE;
rdp_server_transition_to_state(rdp, CONNECTION_STATE_ACTIVE);
return TRUE; return TRUE;
} }

View File

@ -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, refreshRectSupport); /* refreshRectSupport (1 byte) */
Stream_Read_UINT8(s, suppressOutputSupport); /* suppressOutputSupport (1 byte) */ Stream_Read_UINT8(s, suppressOutputSupport); /* suppressOutputSupport (1 byte) */
settings->NoBitmapCompressionHeader = (extraFlags & NO_BITMAP_COMPRESSION_HDR) ? TRUE : FALSE;
if (!(extraFlags & FASTPATH_OUTPUT_SUPPORTED)) if (!(extraFlags & FASTPATH_OUTPUT_SUPPORTED))
settings->FastPathOutput = FALSE; settings->FastPathOutput = FALSE;
@ -213,7 +215,10 @@ void rdp_write_general_capability_set(wStream* s, rdpSettings* settings)
header = rdp_capability_set_start(s); 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) if (settings->AutoReconnectionEnabled)
extraFlags |= AUTORECONNECT_SUPPORTED; 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) */ Stream_Seek(s, 64); /* imeFileName (64 bytes) */
if (settings->ServerMode != TRUE) if (!settings->ServerMode)
{ {
if (inputFlags & INPUT_FLAG_FASTPATH_INPUT) 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) 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 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) BOOL rdp_read_glyph_cache_capability_set(wStream* s, UINT16 length, rdpSettings* settings)
{ {
UINT16 glyphSupportLevel;
if (length < 52) if (length < 52)
return FALSE; return FALSE;
Stream_Seek(s, 40); /* glyphCache (40 bytes) */ /* glyphCache (40 bytes) */
Stream_Seek_UINT32(s); /* fragCache (4 bytes) */ rdp_read_cache_definition(s, &(settings->GlyphCache[0])); /* glyphCache0 (4 bytes) */
Stream_Read_UINT16(s, glyphSupportLevel); /* glyphSupportLevel (2 bytes) */ rdp_read_cache_definition(s, &(settings->GlyphCache[1])); /* glyphCache1 (4 bytes) */
Stream_Seek_UINT16(s); /* pad2Octets (2 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; 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) BOOL rdp_read_large_pointer_capability_set(wStream* s, UINT16 length, rdpSettings* settings)
{ {
UINT16 largePointerSupportFlags;
if (length < 6) if (length < 6)
return FALSE; 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; return TRUE;
} }
@ -2862,6 +2879,7 @@ BOOL rdp_read_frame_acknowledge_capability_set(wStream* s, UINT16 length, rdpSet
{ {
Stream_Seek_UINT32(s); /* (4 bytes) */ Stream_Seek_UINT32(s); /* (4 bytes) */
} }
return TRUE; 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) void rdp_write_frame_acknowledge_capability_set(wStream* s, rdpSettings* settings)
{ {
int header; int header;
UINT32 frame_acknowledge;
Stream_EnsureRemainingCapacity(s, 32); Stream_EnsureRemainingCapacity(s, 32);
header = rdp_capability_set_start(s); header = rdp_capability_set_start(s);
frame_acknowledge = settings->FrameAcknowledge; Stream_Write_UINT32(s, settings->FrameAcknowledge); /* (4 bytes) */
Stream_Write_UINT32(s, frame_acknowledge); /* (4 bytes) */
rdp_capability_set_finish(s, header, CAPSET_TYPE_FRAME_ACKNOWLEDGE); 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) BOOL rdp_recv_confirm_active(rdpRdp* rdp, wStream* s)
{ {
UINT16 channelId; BOOL status;
UINT16 pduType; rdpSettings* settings;
UINT16 pduLength;
UINT16 pduSource;
UINT16 lengthSourceDescriptor; UINT16 lengthSourceDescriptor;
UINT16 lengthCombinedCapabilities; UINT16 lengthCombinedCapabilities;
UINT16 numberCapabilities; UINT16 numberCapabilities;
if (!rdp_recv_get_active_header(rdp, s, &channelId)) settings = rdp->settings;
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;
if (Stream_GetRemainingLength(s) < 10) if (Stream_GetRemainingLength(s) < 10)
return FALSE; return FALSE;
@ -3535,7 +3540,46 @@ BOOL rdp_recv_confirm_active(rdpRdp* rdp, wStream* s)
Stream_Read_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */ Stream_Read_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
Stream_Seek(s, 2); /* pad2Octets (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) 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); rdp_write_bitmap_codecs_capability_set(s, settings);
} }
if (settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE]) if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
{
if (settings->FrameAcknowledge > 0)
{
numberCapabilities++;
rdp_write_frame_acknowledge_capability_set(s, settings);
}
}
else
{
settings->FrameAcknowledge = 0; 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]) if (settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID])

View File

@ -30,6 +30,7 @@
#include <winpr/crt.h> #include <winpr/crt.h>
#include <freerdp/error.h> #include <freerdp/error.h>
#include <freerdp/listener.h>
/** /**
* Connection Sequence\n * 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. * Establish RDP Connection based on the settings given in the 'rdp' parameter.
* @msdn{cc240452} * @msdn{cc240452}
@ -77,19 +175,18 @@ BOOL rdp_client_connect(rdpRdp* rdp)
if (settings->GatewayEnabled) if (settings->GatewayEnabled)
{ {
char* user; char* user;
char* domain; char* domain;
char* cookie; char* cookie;
int user_length = 0; int user_length = 0;
int domain_length; int domain_length;
int cookie_length; int cookie_length;
if (settings->Username)
if (settings->Username) {
{ user = settings->Username;
user = settings->Username; user_length = strlen(settings->Username);
user_length = strlen(settings->Username); }
}
if (settings->Domain) if (settings->Domain)
domain = settings->Domain; domain = settings->Domain;
@ -105,10 +202,10 @@ BOOL rdp_client_connect(rdpRdp* rdp)
CharUpperBuffA(cookie, domain_length); CharUpperBuffA(cookie, domain_length);
cookie[domain_length] = '\\'; cookie[domain_length] = '\\';
if (settings->Username) if (settings->Username)
CopyMemory(&cookie[domain_length + 1], user, user_length); CopyMemory(&cookie[domain_length + 1], user, user_length);
cookie[cookie_length] = '\0'; cookie[cookie_length] = '\0';
nego_set_cookie(rdp->nego, cookie); nego_set_cookie(rdp->nego, cookie);
free(cookie); free(cookie);
@ -159,7 +256,8 @@ BOOL rdp_client_connect(rdpRdp* rdp)
} }
rdp_set_blocking_mode(rdp, FALSE); 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; rdp->finalize_sc_pdus = 0;
if (!mcs_send_connect_initial(rdp->mcs)) 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 crypt_client_random[256 + 8];
BYTE client_random[CLIENT_RANDOM_LENGTH]; BYTE client_random[CLIENT_RANDOM_LENGTH];
if (rdp->settings->DisableEncryption == FALSE) if (!rdp->settings->DisableEncryption)
{ {
/* no RDP encryption */ /* no RDP encryption */
return TRUE; return TRUE;
@ -330,7 +428,7 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp)
return TRUE; 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 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]; BYTE crypt_client_random[256 + 8];
@ -339,7 +437,7 @@ static BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
BYTE* mod; BYTE* mod;
BYTE* priv_exp; BYTE* priv_exp;
if (rdp->settings->DisableEncryption == FALSE) if (!rdp->settings->DisableEncryption)
{ {
/* No RDP Security. */ /* No RDP Security. */
return TRUE; return TRUE;
@ -360,10 +458,12 @@ static BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
return FALSE; return FALSE;
} }
if(Stream_GetRemainingLength(s) < 4) if (Stream_GetRemainingLength(s) < 4)
return FALSE; return FALSE;
Stream_Read_UINT32(s, rand_len); 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; return FALSE;
key_len = rdp->settings->RdpServerRsaKey->ModulusLength; key_len = rdp->settings->RdpServerRsaKey->ModulusLength;
@ -374,7 +474,7 @@ static BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
return FALSE; 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); Stream_Read(s, crypt_client_random, rand_len);
/* 8 zero bytes of padding */ /* 8 zero bytes of padding */
Stream_Seek(s, 8); Stream_Seek(s, 8);
@ -389,6 +489,7 @@ static BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
} }
rdp->do_crypt = TRUE; rdp->do_crypt = TRUE;
if (rdp->settings->SaltedChecksum) if (rdp->settings->SaltedChecksum)
rdp->do_secure_checksum = TRUE; 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)) if (!mcs_send_attach_user_request(rdp->mcs))
return FALSE; return FALSE;
rdp->state = CONNECTION_STATE_MCS_ATTACH_USER; rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_ATTACH_USER);
return TRUE; 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)) if (!mcs_send_channel_join_request(rdp->mcs, rdp->mcs->user_id))
return FALSE; return FALSE;
rdp->state = CONNECTION_STATE_MCS_CHANNEL_JOIN; rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN);
return TRUE; return TRUE;
} }
@ -505,7 +606,7 @@ BOOL rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, wStream* s)
if (!rdp_send_client_info(rdp)) if (!rdp_send_client_info(rdp))
return FALSE; return FALSE;
rdp->state = CONNECTION_STATE_LICENSE; rdp_client_transition_to_state(rdp, CONNECTION_STATE_LICENSING);
} }
return TRUE; return TRUE;
@ -524,7 +625,7 @@ BOOL rdp_client_connect_license(rdpRdp* rdp, wStream* s)
if (rdp->license->state == LICENSE_STATE_COMPLETED) if (rdp->license->state == LICENSE_STATE_COMPLETED)
{ {
rdp->state = CONNECTION_STATE_CAPABILITY; rdp_client_transition_to_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE);
} }
return TRUE; return TRUE;
@ -574,8 +675,7 @@ BOOL rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s)
IFCALL(rdp->update->DesktopResize, rdp->update->context); IFCALL(rdp->update->DesktopResize, rdp->update->context);
} }
rdp->state = CONNECTION_STATE_FINALIZATION; rdp_client_transition_to_state(rdp, CONNECTION_STATE_FINALIZATION);
update_reset_state(rdp->update);
return rdp_client_connect_finalize(rdp); return rdp_client_connect_finalize(rdp);
} }
@ -590,8 +690,10 @@ BOOL rdp_client_connect_finalize(rdpRdp* rdp)
if (!rdp_send_client_synchronize_pdu(rdp)) if (!rdp_send_client_synchronize_pdu(rdp))
return FALSE; return FALSE;
if (!rdp_send_client_control_pdu(rdp, CTRLACTION_COOPERATE)) if (!rdp_send_client_control_pdu(rdp, CTRLACTION_COOPERATE))
return FALSE; return FALSE;
if (!rdp_send_client_control_pdu(rdp, CTRLACTION_REQUEST_CONTROL)) if (!rdp_send_client_control_pdu(rdp, CTRLACTION_REQUEST_CONTROL))
return FALSE; 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 * stored in persistent bitmap cache or the server has advertised support for bitmap
* host cache and a deactivation reactivation sequence is *not* in progress. * host cache and a deactivation reactivation sequence is *not* in progress.
*/ */
if (!rdp->deactivation_reactivation && rdp->settings->BitmapCachePersistEnabled) if (!rdp->deactivation_reactivation && rdp->settings->BitmapCachePersistEnabled)
{
if (!rdp_send_client_persistent_key_list_pdu(rdp)) if (!rdp_send_client_persistent_key_list_pdu(rdp))
return FALSE; return FALSE;
}
if (!rdp_send_client_font_list_pdu(rdp, FONTLIST_FIRST | FONTLIST_LAST)) if (!rdp_send_client_font_list_pdu(rdp, FONTLIST_FIRST | FONTLIST_LAST))
return FALSE; return FALSE;
return TRUE; 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 rdp_server_accept_nego(rdpRdp* rdp, wStream* s)
{ {
BOOL status; 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", fprintf(stderr, "Client Security: NLA:%d TLS:%d RDP:%d\n",
(rdp->nego->requested_protocols & PROTOCOL_NLA) ? 1 : 0, (rdp->nego->requested_protocols & PROTOCOL_NLA) ? 1 : 0,
(rdp->nego->requested_protocols & PROTOCOL_TLS) ? 1 : 0, (rdp->nego->requested_protocols & PROTOCOL_TLS) ? 1 : 0,
(rdp->nego->requested_protocols == PROTOCOL_RDP) ? 1: 0); (rdp->nego->requested_protocols == PROTOCOL_RDP) ? 1: 0);
fprintf(stderr, "Server Security: NLA:%d TLS:%d RDP:%d\n", fprintf(stderr, "Server Security: NLA:%d TLS:%d RDP:%d\n",
settings->NlaSecurity, settings->TlsSecurity, settings->RdpSecurity); 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", fprintf(stderr, "Negotiated Security: NLA:%d TLS:%d RDP:%d\n",
(rdp->nego->selected_protocol & PROTOCOL_NLA) ? 1 : 0, (rdp->nego->selected_protocol & PROTOCOL_NLA) ? 1 : 0,
(rdp->nego->selected_protocol & PROTOCOL_TLS) ? 1 : 0, (rdp->nego->selected_protocol & PROTOCOL_TLS) ? 1 : 0,
(rdp->nego->selected_protocol == PROTOCOL_RDP) ? 1: 0); (rdp->nego->selected_protocol == PROTOCOL_RDP) ? 1: 0);
if (!nego_send_negotiation_response(rdp->nego)) if (!nego_send_negotiation_response(rdp->nego))
return FALSE; return FALSE;
status = FALSE; status = FALSE;
if (rdp->nego->selected_protocol & PROTOCOL_NLA) if (rdp->nego->selected_protocol & PROTOCOL_NLA)
status = transport_accept_nla(rdp->transport); status = transport_accept_nla(rdp->transport);
else if (rdp->nego->selected_protocol & PROTOCOL_TLS) 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); transport_set_blocking_mode(rdp->transport, FALSE);
rdp->state = CONNECTION_STATE_NEGO; rdp_server_transition_to_state(rdp, CONNECTION_STATE_NEGO);
return TRUE; return TRUE;
} }
@ -691,7 +870,7 @@ BOOL rdp_server_accept_mcs_connect_initial(rdpRdp* rdp, wStream* s)
if (!mcs_send_connect_response(rdp->mcs)) if (!mcs_send_connect_response(rdp->mcs))
return FALSE; return FALSE;
rdp->state = CONNECTION_STATE_MCS_CONNECT; rdp_server_transition_to_state(rdp, CONNECTION_STATE_MCS_CONNECT);
return TRUE; 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)) if (!mcs_recv_erect_domain_request(rdp->mcs, s))
return FALSE; return FALSE;
rdp->state = CONNECTION_STATE_MCS_ERECT_DOMAIN; rdp_server_transition_to_state(rdp, CONNECTION_STATE_MCS_ERECT_DOMAIN);
return TRUE; 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)) if (!mcs_send_attach_user_confirm(rdp->mcs))
return FALSE; return FALSE;
rdp->state = CONNECTION_STATE_MCS_ATTACH_USER; rdp_server_transition_to_state(rdp, CONNECTION_STATE_MCS_ATTACH_USER);
return TRUE; return TRUE;
} }
@ -745,44 +924,23 @@ BOOL rdp_server_accept_mcs_channel_join_request(rdpRdp* rdp, wStream* s)
all_joined = FALSE; all_joined = FALSE;
} }
if (rdp->mcs->user_channel_joined && rdp->mcs->global_channel_joined && all_joined) if ((rdp->mcs->user_channel_joined) && (rdp->mcs->global_channel_joined) && all_joined)
rdp->state = CONNECTION_STATE_MCS_CHANNEL_JOIN; {
rdp_server_transition_to_state(rdp, CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT);
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;
return TRUE; return TRUE;
} }
BOOL rdp_server_accept_confirm_active(rdpRdp* rdp, wStream* s) 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)) if (!rdp_recv_confirm_active(rdp, s))
return FALSE; return FALSE;
rdp->state = CONNECTION_STATE_ACTIVE; rdp_server_transition_to_state(rdp, CONNECTION_STATE_FINALIZATION);
update_reset_state(rdp->update);
if (!rdp_send_server_synchronize_pdu(rdp)) if (!rdp_send_server_synchronize_pdu(rdp))
return FALSE; return FALSE;
@ -798,7 +956,7 @@ BOOL rdp_server_reactivate(rdpRdp* rdp)
if (!rdp_send_deactivate_all(rdp)) if (!rdp_send_deactivate_all(rdp))
return FALSE; return FALSE;
rdp->state = CONNECTION_STATE_LICENSE; rdp_server_transition_to_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE);
if (!rdp_send_demand_active(rdp)) if (!rdp_send_demand_active(rdp))
return FALSE; return FALSE;
@ -806,3 +964,107 @@ BOOL rdp_server_reactivate(rdpRdp* rdp)
return TRUE; 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;
}

View File

@ -37,11 +37,14 @@ enum CONNECTION_STATE
CONNECTION_STATE_MCS_ERECT_DOMAIN = 3, CONNECTION_STATE_MCS_ERECT_DOMAIN = 3,
CONNECTION_STATE_MCS_ATTACH_USER = 4, CONNECTION_STATE_MCS_ATTACH_USER = 4,
CONNECTION_STATE_MCS_CHANNEL_JOIN = 5, CONNECTION_STATE_MCS_CHANNEL_JOIN = 5,
CONNECTION_STATE_ESTABLISH_KEYS = 6, CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT = 6,
CONNECTION_STATE_LICENSE = 7, CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE = 7,
CONNECTION_STATE_CAPABILITY = 8, CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT = 8,
CONNECTION_STATE_FINALIZATION = 9, CONNECTION_STATE_LICENSING = 9,
CONNECTION_STATE_ACTIVE = 10 CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING = 10,
CONNECTION_STATE_CAPABILITIES_EXCHANGE = 11,
CONNECTION_STATE_FINALIZATION = 12,
CONNECTION_STATE_ACTIVE = 13
}; };
BOOL rdp_client_connect(rdpRdp* rdp); 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_license(rdpRdp* rdp, wStream* s);
BOOL rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s); BOOL rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s);
BOOL rdp_client_connect_finalize(rdpRdp* rdp); 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_nego(rdpRdp* rdp, wStream* s);
BOOL rdp_server_accept_mcs_connect_initial(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_erect_domain_request(rdpRdp* rdp, wStream* s);
BOOL rdp_server_accept_mcs_attach_user_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_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_accept_confirm_active(rdpRdp* rdp, wStream* s);
BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s);
BOOL rdp_server_reactivate(rdpRdp* rdp); BOOL rdp_server_reactivate(rdpRdp* rdp);
int rdp_server_transition_to_state(rdpRdp* rdp, int state);
#endif /* __CONNECTION_H */ #endif /* __CONNECTION_H */

View File

@ -443,6 +443,44 @@ static const ERRINFO ERRINFO_CODES[] =
ERRINFO_DEFINE(NONE) 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) void rdp_print_errinfo(UINT32 code)
{ {
const ERRINFO* errInfo; const ERRINFO* errInfo;

View File

@ -83,7 +83,8 @@ BOOL freerdp_connect(freerdp* instance)
connectErrorCode = PREECONNECTERROR; connectErrorCode = PREECONNECTERROR;
} }
fprintf(stderr, "%s:%d: freerdp_pre_connect failed\n", __FILE__, __LINE__); fprintf(stderr, "%s:%d: freerdp_pre_connect failed\n", __FILE__, __LINE__);
return FALSE;
goto freerdp_connect_finally;
} }
status = rdp_client_connect(rdp); status = rdp_client_connect(rdp);
@ -92,7 +93,7 @@ BOOL freerdp_connect(freerdp* instance)
if (instance->settings->AuthenticationOnly) if (instance->settings->AuthenticationOnly)
{ {
fprintf(stderr, "%s:%d: Authentication only, exit status %d\n", __FILE__, __LINE__, !status); fprintf(stderr, "%s:%d: Authentication only, exit status %d\n", __FILE__, __LINE__, !status);
return status; goto freerdp_connect_finally;
} }
if (status) if (status)
@ -118,7 +119,7 @@ BOOL freerdp_connect(freerdp* instance)
connectErrorCode = POSTCONNECTERROR; connectErrorCode = POSTCONNECTERROR;
} }
return FALSE; goto freerdp_connect_finally;
} }
if (instance->settings->PlayRemoteFx) if (instance->settings->PlayRemoteFx)
@ -132,9 +133,14 @@ BOOL freerdp_connect(freerdp* instance)
update->pcap_rfx = pcap_open(settings->PlayRemoteFxFile, FALSE); update->pcap_rfx = pcap_open(settings->PlayRemoteFxFile, FALSE);
if (!update->pcap_rfx) if (!update->pcap_rfx)
return FALSE; {
status = FALSE;
goto freerdp_connect_finally;
}
else else
{
update->play_rfx = TRUE; update->play_rfx = TRUE;
}
while (pcap_has_next_record(update->pcap_rfx)) while (pcap_has_next_record(update->pcap_rfx))
{ {
@ -154,7 +160,8 @@ BOOL freerdp_connect(freerdp* instance)
Stream_Release(s); Stream_Release(s);
} }
return TRUE; status = TRUE;
goto freerdp_connect_finally;
} }
} }
@ -170,6 +177,8 @@ BOOL freerdp_connect(freerdp* instance)
SetEvent(rdp->transport->connectedEvent); SetEvent(rdp->transport->connectedEvent);
freerdp_connect_finally:
EventArgsInit(&e, "freerdp"); EventArgsInit(&e, "freerdp");
e.result = status ? 0 : -1; e.result = status ? 0 : -1;
PubSub_OnConnectionResult(instance->context->pubSub, instance->context, &e); 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[] = static wEventType FreeRDP_Events[] =
{ {
DEFINE_EVENT_ENTRY(WindowStateChange) DEFINE_EVENT_ENTRY(WindowStateChange)
DEFINE_EVENT_ENTRY(ResizeWindow) DEFINE_EVENT_ENTRY(ResizeWindow)
DEFINE_EVENT_ENTRY(LocalResizeWindow) DEFINE_EVENT_ENTRY(LocalResizeWindow)
DEFINE_EVENT_ENTRY(EmbedWindow) DEFINE_EVENT_ENTRY(EmbedWindow)
DEFINE_EVENT_ENTRY(PanningChange) DEFINE_EVENT_ENTRY(PanningChange)
DEFINE_EVENT_ENTRY(ScalingFactorChange) DEFINE_EVENT_ENTRY(ScalingFactorChange)
DEFINE_EVENT_ENTRY(ErrorInfo) DEFINE_EVENT_ENTRY(ErrorInfo)
DEFINE_EVENT_ENTRY(ParamChange) DEFINE_EVENT_ENTRY(ParamChange)
DEFINE_EVENT_ENTRY(Terminate) DEFINE_EVENT_ENTRY(Terminate)
DEFINE_EVENT_ENTRY(ConnectionResult) DEFINE_EVENT_ENTRY(ConnectionResult)
DEFINE_EVENT_ENTRY(ChannelConnected) DEFINE_EVENT_ENTRY(ChannelConnected)
DEFINE_EVENT_ENTRY(ChannelDisconnected) DEFINE_EVENT_ENTRY(ChannelDisconnected)
}; };
/** Allocator function for a rdp context. /** Allocator function for a rdp context.
@ -357,18 +366,19 @@ int freerdp_context_new(freerdp* instance)
instance->context = (rdpContext*) malloc(instance->ContextSize); instance->context = (rdpContext*) malloc(instance->ContextSize);
ZeroMemory(instance->context, instance->ContextSize); ZeroMemory(instance->context, instance->ContextSize);
context = instance->context; context = instance->context;
context->instance = instance;
context->pubSub = PubSub_New(TRUE); context->pubSub = PubSub_New(TRUE);
PubSub_AddEventTypes(context->pubSub, FreeRDP_Events, sizeof(FreeRDP_Events) / sizeof(wEventType)); PubSub_AddEventTypes(context->pubSub, FreeRDP_Events, sizeof(FreeRDP_Events) / sizeof(wEventType));
rdp = rdp_new(instance); rdp = rdp_new(context);
instance->input = rdp->input; instance->input = rdp->input;
instance->update = rdp->update; instance->update = rdp->update;
instance->settings = rdp->settings; instance->settings = rdp->settings;
context->graphics = graphics_new(context); context->graphics = graphics_new(context);
context->instance = instance;
context->rdp = rdp; context->rdp = rdp;
context->input = instance->input; context->input = instance->input;

View File

@ -495,6 +495,8 @@ rdpInput* input_new(rdpRdp* rdp)
if (input != NULL) if (input != NULL)
{ {
ZeroMemory(input, sizeof(rdpInput)); ZeroMemory(input, sizeof(rdpInput));
input->queue = MessageQueue_New();
} }
return input; return input;
@ -507,6 +509,8 @@ void input_free(rdpInput* input)
if (input->asynchronous) if (input->asynchronous)
input_message_proxy_free(input->proxy); input_message_proxy_free(input->proxy);
MessageQueue_Free(input->queue);
free(input); free(input);
} }
} }

View File

@ -156,7 +156,9 @@ static BOOL freerdp_listener_open(freerdp_listener* instance, const char* bind_a
continue; 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) if (ai->ai_family == AF_INET)
sin_addr = &(((struct sockaddr_in*) ai->ai_addr)->sin_addr); 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; 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); 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) static BOOL freerdp_listener_get_fds(freerdp_listener* instance, void** rfds, int* rcount)
{ {
int i; int index;
rdpListener* listener = (rdpListener*) instance->listener; rdpListener* listener = (rdpListener*) instance->listener;
if (listener->num_sockfds < 1) if (listener->num_sockfds < 1)
return FALSE; 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)++; (*rcount)++;
} }
return TRUE; 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) static BOOL freerdp_listener_check_fds(freerdp_listener* instance)
{ {
int i; int i;
@ -327,6 +348,7 @@ freerdp_listener* freerdp_listener_new(void)
instance->Open = freerdp_listener_open; instance->Open = freerdp_listener_open;
instance->OpenLocal = freerdp_listener_open_local; instance->OpenLocal = freerdp_listener_open_local;
instance->GetFileDescriptor = freerdp_listener_get_fds; instance->GetFileDescriptor = freerdp_listener_get_fds;
instance->GetEventHandles = freerdp_listener_get_event_handles;
instance->CheckFileDescriptor = freerdp_listener_check_fds; instance->CheckFileDescriptor = freerdp_listener_check_fds;
instance->Close = freerdp_listener_close; instance->Close = freerdp_listener_close;

View File

@ -23,14 +23,21 @@
typedef struct rdp_listener rdpListener; typedef struct rdp_listener rdpListener;
#include "rdp.h" #include "rdp.h"
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <freerdp/listener.h> #include <freerdp/listener.h>
#define MAX_LISTENER_HANDLES 5
struct rdp_listener struct rdp_listener
{ {
freerdp_listener* instance; freerdp_listener* instance;
int sockfds[5];
int num_sockfds; int num_sockfds;
int sockfds[MAX_LISTENER_HANDLES];
HANDLE events[MAX_LISTENER_HANDLES];
}; };
#endif #endif

View File

@ -356,15 +356,15 @@ BOOL mcs_recv_connect_initial(rdpMcs* mcs, wStream* s)
return FALSE; return FALSE;
/* targetParameters (DomainParameters) */ /* targetParameters (DomainParameters) */
if(!mcs_read_domain_parameters(s, &mcs->targetParameters)) if (!mcs_read_domain_parameters(s, &mcs->targetParameters))
return FALSE; return FALSE;
/* minimumParameters (DomainParameters) */ /* minimumParameters (DomainParameters) */
if(!mcs_read_domain_parameters(s, &mcs->minimumParameters)) if (!mcs_read_domain_parameters(s, &mcs->minimumParameters))
return FALSE; return FALSE;
/* maximumParameters (DomainParameters) */ /* maximumParameters (DomainParameters) */
if(!mcs_read_domain_parameters(s, &mcs->maximumParameters)) if (!mcs_read_domain_parameters(s, &mcs->maximumParameters))
return FALSE; return FALSE;
if (!ber_read_octet_string_tag(s, &length) || Stream_GetRemainingLength(s) < length) 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)) if (!tpdu_read_data(s, &li))
return FALSE; 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_enumerated(s, &result, MCS_Result_enum_length) ||
!ber_read_integer(s, &calledConnectId) || !ber_read_integer(s, &calledConnectId) ||
!mcs_read_domain_parameters(s, &(mcs->domainParameters)) || !mcs_read_domain_parameters(s, &(mcs->domainParameters)) ||

View File

@ -1741,7 +1741,6 @@ rdpUpdateProxy* update_message_proxy_new(rdpUpdate* update)
ZeroMemory(message, sizeof(rdpUpdateProxy)); ZeroMemory(message, sizeof(rdpUpdateProxy));
message->update = update; message->update = update;
update->queue = MessageQueue_New();
update_message_register_interface(message, update); update_message_register_interface(message, update);
} }
@ -1752,7 +1751,6 @@ void update_message_proxy_free(rdpUpdateProxy* message)
{ {
if (message) if (message)
{ {
MessageQueue_Free(message->update->queue);
free(message); free(message);
} }
} }
@ -1940,7 +1938,6 @@ rdpInputProxy* input_message_proxy_new(rdpInput* input)
ZeroMemory(proxy, sizeof(rdpInputProxy)); ZeroMemory(proxy, sizeof(rdpInputProxy));
proxy->input = input; proxy->input = input;
input->queue = MessageQueue_New();
input_message_proxy_register(proxy, input); input_message_proxy_register(proxy, input);
} }
@ -1951,7 +1948,6 @@ void input_message_proxy_free(rdpInputProxy* proxy)
{ {
if (proxy) if (proxy)
{ {
MessageQueue_Free(proxy->input->queue);
free(proxy); free(proxy);
} }
} }

View File

@ -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) 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) 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) int update_approximate_create_offscreen_bitmap_order(CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap)
{ {
OFFSCREEN_DELETE_LIST* deleteList = &(create_offscreen_bitmap->deleteList); 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) BOOL update_write_create_offscreen_bitmap_order(wStream* s, CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap)

View File

@ -23,6 +23,7 @@
#include <winpr/crt.h> #include <winpr/crt.h>
#include "info.h"
#include "certificate.h" #include "certificate.h"
#include <freerdp/utils/tcp.h> #include <freerdp/utils/tcp.h>
@ -53,6 +54,11 @@ static BOOL freerdp_peer_get_fds(freerdp_peer* client, void** rfds, int* rcount)
return TRUE; 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) static BOOL freerdp_peer_check_fds(freerdp_peer* client)
{ {
int status; 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)) if (!rdp_server_accept_client_font_list_pdu(client->context->rdp, s))
return FALSE; 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; break;
case DATA_PDU_TYPE_SHUTDOWN_REQUEST: case DATA_PDU_TYPE_SHUTDOWN_REQUEST:
@ -135,7 +118,7 @@ static BOOL peer_recv_data_pdu(freerdp_peer* client, wStream* s)
return FALSE; return FALSE;
case DATA_PDU_TYPE_FRAME_ACKNOWLEDGE: case DATA_PDU_TYPE_FRAME_ACKNOWLEDGE:
if(Stream_GetRemainingLength(s) < 4) if (Stream_GetRemainingLength(s) < 4)
return FALSE; return FALSE;
Stream_Read_UINT32(s, client->ack_frame_id); Stream_Read_UINT32(s, client->ack_frame_id);
IFCALL(client->update->SurfaceFrameAcknowledge, client->update->context, 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 (channelId != MCS_GLOBAL_CHANNEL_ID)
{ {
if(!freerdp_channel_peer_process(client, s, channelId)) if (!freerdp_channel_peer_process(client, s, channelId))
return -1; return -1;
} }
else else
@ -211,6 +194,11 @@ static int peer_recv_tpkt_pdu(freerdp_peer* client, wStream* s)
return -1; return -1;
break; break;
case PDU_TYPE_CONFIRM_ACTIVE:
if (!rdp_server_accept_confirm_active(rdp, s))
return -1;
break;
default: default:
fprintf(stderr, "Client sent pduType %d\n", pduType); fprintf(stderr, "Client sent pduType %d\n", pduType);
return -1; return -1;
@ -228,8 +216,6 @@ static int peer_recv_fastpath_pdu(freerdp_peer* client, wStream* s)
rdp = client->context->rdp; rdp = client->context->rdp;
fastpath = rdp->fastpath; fastpath = rdp->fastpath;
//if (!fastpath_read_header_rdp(fastpath, s, &length))
// return -1;
fastpath_read_header_rdp(fastpath, s, &length); fastpath_read_header_rdp(fastpath, s, &length);
@ -301,36 +287,71 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra)
return -1; return -1;
break; break;
case CONNECTION_STATE_MCS_CHANNEL_JOIN: case CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT:
if (rdp->settings->DisableEncryption) if (rdp->settings->DisableEncryption)
{ {
if (!rdp_server_accept_client_keys(rdp, s)) if (!rdp_server_establish_keys(rdp, s))
return -1; return -1;
break;
} }
rdp->state = CONNECTION_STATE_ESTABLISH_KEYS;
/* FALLTHROUGH */
case CONNECTION_STATE_ESTABLISH_KEYS: rdp_server_transition_to_state(rdp, CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE);
if (!rdp_server_accept_client_info(rdp, s)) return peer_recv_callback(transport, s, extra);
return -1;
IFCALL(client->Capabilities, client);
if (!rdp_send_demand_active(rdp))
return -1;
break; break;
case CONNECTION_STATE_LICENSE: case CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE:
if (!rdp_server_accept_confirm_active(rdp, s))
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 * 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. * 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; break;
case CONNECTION_STATE_ACTIVE: case CONNECTION_STATE_ACTIVE:
@ -355,6 +376,7 @@ static BOOL freerdp_peer_close(freerdp_peer* client)
*/ */
if (!rdp_send_deactivate_all(client->context->rdp)) if (!rdp_send_deactivate_all(client->context->rdp))
return FALSE; return FALSE;
return mcs_send_disconnect_provider_ultimatum(client->context->rdp->mcs); return mcs_send_disconnect_provider_ultimatum(client->context->rdp->mcs);
} }
@ -372,14 +394,15 @@ void freerdp_peer_context_new(freerdp_peer* client)
{ {
rdpRdp* rdp; 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->input = rdp->input;
client->update = rdp->update; client->update = rdp->update;
client->settings = rdp->settings; client->settings = rdp->settings;
client->context = (rdpContext*) malloc(client->ContextSize);
ZeroMemory(client->context, client->ContextSize);
client->context->rdp = rdp; client->context->rdp = rdp;
client->context->peer = client; client->context->peer = client;
client->context->input = client->input; client->context->input = client->input;
@ -414,12 +437,13 @@ freerdp_peer* freerdp_peer_new(int sockfd)
freerdp_tcp_set_no_delay(sockfd, TRUE); freerdp_tcp_set_no_delay(sockfd, TRUE);
if (client != NULL) if (client)
{ {
client->sockfd = sockfd; client->sockfd = sockfd;
client->ContextSize = sizeof(rdpContext); client->ContextSize = sizeof(rdpContext);
client->Initialize = freerdp_peer_initialize; client->Initialize = freerdp_peer_initialize;
client->GetFileDescriptor = freerdp_peer_get_fds; client->GetFileDescriptor = freerdp_peer_get_fds;
client->GetEventHandle = freerdp_peer_get_event_handle;
client->CheckFileDescriptor = freerdp_peer_check_fds; client->CheckFileDescriptor = freerdp_peer_check_fds;
client->Close = freerdp_peer_close; client->Close = freerdp_peer_close;
client->Disconnect = freerdp_peer_disconnect; client->Disconnect = freerdp_peer_disconnect;

View File

@ -236,8 +236,9 @@ wStream* rdp_data_pdu_init(rdpRdp* rdp)
* @param channel_id channel id * @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; UINT16 initiator;
enum DomainMCSPDU MCSPDU; enum DomainMCSPDU MCSPDU;
@ -274,8 +275,8 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channel_id
return FALSE; return FALSE;
per_read_integer16(s, &initiator, MCS_BASE_CHANNEL_ID); /* initiator (UserId) */ per_read_integer16(s, &initiator, MCS_BASE_CHANNEL_ID); /* initiator (UserId) */
per_read_integer16(s, channel_id, 0); /* channelId */ per_read_integer16(s, channelId, 0); /* channelId */
Stream_Seek(s, 1); /* dataPriority + Segmentation (0x70) */ Stream_Read_UINT8(s, byte); /* dataPriority + Segmentation (0x70) */
if (!per_read_length(s, length)) /* userData (OCTET_STRING) */ if (!per_read_length(s, length)) /* userData (OCTET_STRING) */
return FALSE; return FALSE;
@ -294,7 +295,7 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channel_id
* @param channel_id 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; int body_length;
enum DomainMCSPDU MCSPDU; 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); 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, 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 */ 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, * only one byte if length <= 0x7F. It is just easier that way,
* because we can leave room for fixed-length header, store all * because we can leave room for fixed-length header, store all
* the data first and then store the header. * 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; status = -1;
break; break;
case CONNECTION_STATE_LICENSE: case CONNECTION_STATE_LICENSING:
if (!rdp_client_connect_license(rdp, s)) if (!rdp_client_connect_license(rdp, s))
status = -1; status = -1;
break; break;
case CONNECTION_STATE_CAPABILITY: case CONNECTION_STATE_CAPABILITIES_EXCHANGE:
if (!rdp_client_connect_demand_active(rdp, s)) if (!rdp_client_connect_demand_active(rdp, s))
status = -1; status = -1;
break; break;
case CONNECTION_STATE_FINALIZATION: case CONNECTION_STATE_FINALIZATION:
status = rdp_recv_pdu(rdp, s); status = rdp_recv_pdu(rdp, s);
if ((status >= 0) && (rdp->finalize_sc_pdus == FINALIZE_SC_COMPLETE)) 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; break;
case CONNECTION_STATE_ACTIVE: case CONNECTION_STATE_ACTIVE:
@ -982,23 +984,25 @@ int rdp_check_fds(rdpRdp* rdp)
* @return new RDP module * @return new RDP module
*/ */
rdpRdp* rdp_new(freerdp* instance) rdpRdp* rdp_new(rdpContext* context)
{ {
rdpRdp* rdp; rdpRdp* rdp;
rdp = (rdpRdp*) malloc(sizeof(rdpRdp)); rdp = (rdpRdp*) malloc(sizeof(rdpRdp));
if (rdp != NULL) if (rdp)
{ {
ZeroMemory(rdp, sizeof(rdpRdp)); ZeroMemory(rdp, sizeof(rdpRdp));
rdp->instance = instance; rdp->context = context;
rdp->settings = freerdp_settings_new((void*) instance);
if (instance != NULL) rdp->instance = context->instance;
instance->settings = rdp->settings; 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->transport = transport_new(rdp->settings);
rdp->license = license_new(rdp); rdp->license = license_new(rdp);
rdp->input = input_new(rdp); rdp->input = input_new(rdp);

View File

@ -120,6 +120,7 @@ struct rdp_rdp
{ {
int state; int state;
freerdp* instance; freerdp* instance;
rdpContext* context;
struct rdp_mcs* mcs; struct rdp_mcs* mcs;
struct rdp_nego* nego; struct rdp_nego* nego;
struct rdp_input* input; struct rdp_input* input;
@ -158,6 +159,7 @@ struct rdp_rdp
BOOL disconnect; BOOL disconnect;
BOOL resendFocus; BOOL resendFocus;
BOOL deactivation_reactivation; BOOL deactivation_reactivation;
BOOL AwaitCapabilities;
}; };
BOOL rdp_read_security_header(wStream* s, UINT16* flags); 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); void rdp_set_blocking_mode(rdpRdp* rdp, BOOL blocking);
int rdp_check_fds(rdpRdp* rdp); int rdp_check_fds(rdpRdp* rdp);
rdpRdp* rdp_new(freerdp* instance); rdpRdp* rdp_new(rdpContext* context);
void rdp_free(rdpRdp* rdp); void rdp_free(rdpRdp* rdp);
#ifdef WITH_DEBUG_RDP #ifdef WITH_DEBUG_RDP

View File

@ -334,6 +334,8 @@ rdpSettings* freerdp_settings_new(void* instance)
settings->BitmapCacheV2CellInfo[4].numEntries = 2048; settings->BitmapCacheV2CellInfo[4].numEntries = 2048;
settings->BitmapCacheV2CellInfo[4].persistent = FALSE; settings->BitmapCacheV2CellInfo[4].persistent = FALSE;
settings->NoBitmapCompressionHeader = TRUE;
settings->RefreshRect = TRUE; settings->RefreshRect = TRUE;
settings->SuppressOutput = TRUE; settings->SuppressOutput = TRUE;

View File

@ -253,6 +253,13 @@ BOOL tcp_set_keep_alive_mode(rdpTcp* tcp)
return TRUE; 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) HANDLE tcp_get_event_handle(rdpTcp* tcp)
{ {
#ifndef _WIN32 #ifndef _WIN32

View File

@ -56,6 +56,7 @@ int tcp_wait_read(rdpTcp* tcp);
int tcp_wait_write(rdpTcp* tcp); int tcp_wait_write(rdpTcp* tcp);
BOOL tcp_set_blocking_mode(rdpTcp* tcp, BOOL blocking); BOOL tcp_set_blocking_mode(rdpTcp* tcp, BOOL blocking);
BOOL tcp_set_keep_alive_mode(rdpTcp* tcp); BOOL tcp_set_keep_alive_mode(rdpTcp* tcp);
int tcp_attach(rdpTcp* tcp, int sockfd);
HANDLE tcp_get_event_handle(rdpTcp* tcp); HANDLE tcp_get_event_handle(rdpTcp* tcp);
rdpTcp* tcp_new(rdpSettings* settings); rdpTcp* tcp_new(rdpSettings* settings);

View File

@ -22,6 +22,7 @@
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <winpr/print.h>
#include "tpdu.h" #include "tpdu.h"
@ -66,9 +67,9 @@
* @return TPDU length indicator (LI) * @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; return FALSE;
Stream_Read_UINT8(s, *li); /* LI */ Stream_Read_UINT8(s, *li); /* LI */
@ -86,6 +87,7 @@ BOOL tpdu_read_header(wStream* s, BYTE* code, BYTE *li)
/* Class 0 (1 byte) */ /* Class 0 (1 byte) */
return Stream_SafeSeek(s, 5); return Stream_SafeSeek(s, 5);
} }
return TRUE; return TRUE;
} }
@ -205,16 +207,18 @@ void tpdu_write_data(wStream* s)
* @param s stream * @param s stream
*/ */
BOOL tpdu_read_data(wStream* s, UINT16 *LI) BOOL tpdu_read_data(wStream* s, UINT16* LI)
{ {
BYTE code; BYTE code;
BYTE li; BYTE li;
if(!tpdu_read_header(s, &code, &li)) if (!tpdu_read_header(s, &code, &li))
return FALSE; return FALSE;
if (code != X224_TPDU_DATA) if (code != X224_TPDU_DATA)
return FALSE; return FALSE;
*LI = li; *LI = li;
return TRUE; return TRUE;
} }

View File

@ -64,8 +64,7 @@ wStream* transport_send_stream_init(rdpTransport* transport, int size)
void transport_attach(rdpTransport* transport, int sockfd) void transport_attach(rdpTransport* transport, int sockfd)
{ {
transport->TcpIn->sockfd = sockfd; tcp_attach(transport->TcpIn, sockfd);
transport->SplitInputOutput = FALSE; transport->SplitInputOutput = FALSE;
transport->TcpOut = transport->TcpIn; transport->TcpOut = transport->TcpIn;
} }

View File

@ -23,6 +23,7 @@
#include <winpr/crt.h> #include <winpr/crt.h>
#include <winpr/print.h> #include <winpr/print.h>
#include <winpr/synch.h>
#include <winpr/thread.h> #include <winpr/thread.h>
#include <winpr/collections.h> #include <winpr/collections.h>
@ -477,6 +478,7 @@ static void update_end_paint(rdpContext* context)
if (update->numberOrders > 0) if (update->numberOrders > 0)
{ {
printf("Sending %d orders\n", update->numberOrders);
fastpath_send_update_pdu(context->rdp->fastpath, FASTPATH_UPDATETYPE_ORDERS, s); 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; wStream* s;
rdpUpdate* update = context->update; rdpUpdate* update = context->update;
rdpSettings* settings = context->settings;
s = update->us; 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); update_flush(context);
return TRUE; return TRUE;
@ -783,12 +790,13 @@ static void update_send_synchronize(rdpContext* context)
static void update_send_desktop_resize(rdpContext* context) static void update_send_desktop_resize(rdpContext* context)
{ {
if (context->peer)
context->peer->activated = FALSE;
rdp_server_reactivate(context->rdp); rdp_server_reactivate(context->rdp);
} }
/**
* Primary Drawing Orders
*/
static void update_send_dstblt(rdpContext* context, DSTBLT_ORDER* dstblt) static void update_send_dstblt(rdpContext* context, DSTBLT_ORDER* dstblt)
{ {
wStream* s; wStream* s;
@ -957,6 +965,10 @@ static void update_send_glyph_index(rdpContext* context, GLYPH_INDEX_ORDER* glyp
update->numberOrders++; update->numberOrders++;
} }
/*
* Secondary Drawing Orders
*/
static void update_send_cache_bitmap(rdpContext* context, CACHE_BITMAP_ORDER* cache_bitmap) static void update_send_cache_bitmap(rdpContext* context, CACHE_BITMAP_ORDER* cache_bitmap)
{ {
wStream* s; wStream* s;
@ -987,7 +999,7 @@ static void update_send_cache_bitmap(rdpContext* context, CACHE_BITMAP_ORDER* ca
orderLength = (em - bm) - 13; orderLength = (em - bm) - 13;
Stream_SetPosition(s, bm); 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, orderLength); /* orderLength (2 bytes) */
Stream_Write_UINT16(s, extraFlags); /* extraFlags (2 bytes) */ Stream_Write_UINT16(s, extraFlags); /* extraFlags (2 bytes) */
Stream_Write_UINT8(s, orderType); /* orderType (1 byte) */ 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; INT16 orderLength;
rdpUpdate* update = context->update; rdpUpdate* update = context->update;
update_force_flush(context);
extraFlags = 0; extraFlags = 0;
headerLength = 6; headerLength = 6;
orderType = cache_bitmap_v2->compressed ? orderType = cache_bitmap_v2->compressed ?
ORDER_TYPE_BITMAP_COMPRESSED_V2 : ORDER_TYPE_BITMAP_UNCOMPRESSED_V2; 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)); update_check_flush(context, headerLength + update_approximate_cache_bitmap_v2_order(cache_bitmap_v2, cache_bitmap_v2->compressed, &extraFlags));
s = update->us; s = update->us;
@ -1028,15 +1041,13 @@ static void update_send_cache_bitmap_v2(rdpContext* context, CACHE_BITMAP_V2_ORD
orderLength = (em - bm) - 13; orderLength = (em - bm) - 13;
Stream_SetPosition(s, bm); 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, orderLength); /* orderLength (2 bytes) */
Stream_Write_UINT16(s, extraFlags); /* extraFlags (2 bytes) */ Stream_Write_UINT16(s, extraFlags); /* extraFlags (2 bytes) */
Stream_Write_UINT8(s, orderType); /* orderType (1 byte) */ Stream_Write_UINT8(s, orderType); /* orderType (1 byte) */
Stream_SetPosition(s, em); Stream_SetPosition(s, em);
update->numberOrders++; update->numberOrders++;
update_force_flush(context);
} }
static void update_send_cache_bitmap_v3(rdpContext* context, CACHE_BITMAP_V3_ORDER* cache_bitmap_v3) 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; INT16 orderLength;
rdpUpdate* update = context->update; rdpUpdate* update = context->update;
update_force_flush(context);
extraFlags = 0; extraFlags = 0;
headerLength = 6; headerLength = 6;
orderType = ORDER_TYPE_BITMAP_COMPRESSED_V3; 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; orderLength = (em - bm) - 13;
Stream_SetPosition(s, bm); 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, orderLength); /* orderLength (2 bytes) */
Stream_Write_UINT16(s, extraFlags); /* extraFlags (2 bytes) */ Stream_Write_UINT16(s, extraFlags); /* extraFlags (2 bytes) */
Stream_Write_UINT8(s, orderType); /* orderType (1 byte) */ Stream_Write_UINT8(s, orderType); /* orderType (1 byte) */
Stream_SetPosition(s, em); Stream_SetPosition(s, em);
update->numberOrders++; update->numberOrders++;
update_force_flush(context);
} }
static void update_send_cache_color_table(rdpContext* context, CACHE_COLOR_TABLE_ORDER* cache_color_table) 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; INT16 orderLength;
rdpUpdate* update = context->update; rdpUpdate* update = context->update;
update_force_flush(context);
flags = 0; flags = 0;
headerLength = 6; headerLength = 6;
@ -1108,15 +1113,13 @@ static void update_send_cache_color_table(rdpContext* context, CACHE_COLOR_TABLE
orderLength = (em - bm) - 13; orderLength = (em - bm) - 13;
Stream_SetPosition(s, bm); 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, orderLength); /* orderLength (2 bytes) */
Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */ Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */
Stream_Write_UINT8(s, ORDER_TYPE_CACHE_COLOR_TABLE); /* orderType (1 byte) */ Stream_Write_UINT8(s, ORDER_TYPE_CACHE_COLOR_TABLE); /* orderType (1 byte) */
Stream_SetPosition(s, em); Stream_SetPosition(s, em);
update->numberOrders++; update->numberOrders++;
update_force_flush(context);
} }
static void update_send_cache_glyph(rdpContext* context, CACHE_GLYPH_ORDER* cache_glyph) 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; INT16 orderLength;
rdpUpdate* update = context->update; rdpUpdate* update = context->update;
update_force_flush(context);
flags = 0; flags = 0;
headerLength = 6; headerLength = 6;
@ -1147,15 +1148,13 @@ static void update_send_cache_glyph(rdpContext* context, CACHE_GLYPH_ORDER* cach
orderLength = (em - bm) - 13; orderLength = (em - bm) - 13;
Stream_SetPosition(s, bm); 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, orderLength); /* orderLength (2 bytes) */
Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */ Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */
Stream_Write_UINT8(s, ORDER_TYPE_CACHE_GLYPH); /* orderType (1 byte) */ Stream_Write_UINT8(s, ORDER_TYPE_CACHE_GLYPH); /* orderType (1 byte) */
Stream_SetPosition(s, em); Stream_SetPosition(s, em);
update->numberOrders++; update->numberOrders++;
update_force_flush(context);
} }
static void update_send_cache_glyph_v2(rdpContext* context, CACHE_GLYPH_V2_ORDER* cache_glyph_v2) 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; INT16 orderLength;
rdpUpdate* update = context->update; rdpUpdate* update = context->update;
update_force_flush(context);
flags = 0; flags = 0;
headerLength = 6; headerLength = 6;
@ -1186,15 +1183,13 @@ static void update_send_cache_glyph_v2(rdpContext* context, CACHE_GLYPH_V2_ORDER
orderLength = (em - bm) - 13; orderLength = (em - bm) - 13;
Stream_SetPosition(s, bm); 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, orderLength); /* orderLength (2 bytes) */
Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */ Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */
Stream_Write_UINT8(s, ORDER_TYPE_CACHE_GLYPH); /* orderType (1 byte) */ Stream_Write_UINT8(s, ORDER_TYPE_CACHE_GLYPH); /* orderType (1 byte) */
Stream_SetPosition(s, em); Stream_SetPosition(s, em);
update->numberOrders++; update->numberOrders++;
update_force_flush(context);
} }
static void update_send_cache_brush(rdpContext* context, CACHE_BRUSH_ORDER* cache_brush) 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; INT16 orderLength;
rdpUpdate* update = context->update; rdpUpdate* update = context->update;
update_force_flush(context);
flags = 0; flags = 0;
headerLength = 6; headerLength = 6;
@ -1225,17 +1218,19 @@ static void update_send_cache_brush(rdpContext* context, CACHE_BRUSH_ORDER* cach
orderLength = (em - bm) - 13; orderLength = (em - bm) - 13;
Stream_SetPosition(s, bm); 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, orderLength); /* orderLength (2 bytes) */
Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */ Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */
Stream_Write_UINT8(s, ORDER_TYPE_CACHE_BRUSH); /* orderType (1 byte) */ Stream_Write_UINT8(s, ORDER_TYPE_CACHE_BRUSH); /* orderType (1 byte) */
Stream_SetPosition(s, em); Stream_SetPosition(s, em);
update->numberOrders++; 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) static void update_send_create_offscreen_bitmap_order(rdpContext* context, CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap)
{ {
wStream* s; wStream* s;
@ -1245,8 +1240,6 @@ static void update_send_create_offscreen_bitmap_order(rdpContext* context, CREAT
int headerLength; int headerLength;
rdpUpdate* update = context->update; rdpUpdate* update = context->update;
update_force_flush(context);
headerLength = 1; headerLength = 1;
orderType = ORDER_TYPE_CREATE_OFFSCREEN_BITMAP; orderType = ORDER_TYPE_CREATE_OFFSCREEN_BITMAP;
controlFlags = ORDER_SECONDARY | (orderType << 2); controlFlags = ORDER_SECONDARY | (orderType << 2);
@ -1267,8 +1260,6 @@ static void update_send_create_offscreen_bitmap_order(rdpContext* context, CREAT
Stream_SetPosition(s, em); Stream_SetPosition(s, em);
update->numberOrders++; update->numberOrders++;
update_force_flush(context);
} }
static void update_send_switch_surface_order(rdpContext* context, SWITCH_SURFACE_ORDER* switch_surface) 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; int headerLength;
rdpUpdate* update = context->update; rdpUpdate* update = context->update;
update_force_flush(context);
headerLength = 1; headerLength = 1;
orderType = ORDER_TYPE_SWITCH_SURFACE; orderType = ORDER_TYPE_SWITCH_SURFACE;
controlFlags = ORDER_SECONDARY | (orderType << 2); controlFlags = ORDER_SECONDARY | (orderType << 2);
@ -1302,8 +1291,6 @@ static void update_send_switch_surface_order(rdpContext* context, SWITCH_SURFACE
Stream_SetPosition(s, em); Stream_SetPosition(s, em);
update->numberOrders++; update->numberOrders++;
update_force_flush(context);
} }
static void update_send_pointer_system(rdpContext* context, POINTER_SYSTEM_UPDATE* pointer_system) 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->SuppressOutput = update_send_suppress_output;
update->initialState = TRUE; update->initialState = TRUE;
update->queue = MessageQueue_New();
} }
return update; return update;
@ -1545,6 +1534,8 @@ void update_free(rdpUpdate* update)
if (update->asynchronous) if (update->asynchronous)
update_message_proxy_free(update->proxy); update_message_proxy_free(update->proxy);
MessageQueue_Free(update->queue);
free(update); free(update);
} }
} }

View File

@ -214,6 +214,11 @@ static const RDP_KEYBOARD_IME RDP_KEYBOARD_IME_TABLE[] =
{ KBD_CHINESE_TRADITIONAL_ALPHANUMERIC, "romanime.ime", "Chinese (Traditional) - Alphanumeric" } { 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) RDP_KEYBOARD_LAYOUT* freerdp_keyboard_get_layouts(DWORD types)
{ {
int num, length, i; int num, length, i;

View File

@ -69,7 +69,9 @@ endif()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/winpr/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/include/winpr/config.h) 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) add_subdirectory(libwinpr)

View File

@ -204,6 +204,48 @@ WINPR_API BOOL ListDictionary_SetItemValue(wListDictionary* listDictionary, void
WINPR_API wListDictionary* ListDictionary_New(BOOL synchronized); WINPR_API wListDictionary* ListDictionary_New(BOOL synchronized);
WINPR_API void ListDictionary_Free(wListDictionary* listDictionary); WINPR_API void ListDictionary_Free(wListDictionary* listDictionary);
/* System.Collections.Generic.LinkedList<T> */
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<TKey,TValue> */ /* System.Collections.Generic.KeyValuePair<TKey,TValue> */
struct _wKeyValuePair struct _wKeyValuePair

View File

@ -302,6 +302,12 @@ extern "C" {
WINPR_API BOOL FilePatternMatchA(LPCSTR lpFileName, LPCSTR lpPattern); WINPR_API BOOL FilePatternMatchA(LPCSTR lpFileName, LPCSTR lpPattern);
WINPR_API LPSTR FilePatternFindNextWildcardA(LPCSTR lpPattern, DWORD* pFlags); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -25,6 +25,25 @@
#ifndef _WIN32 #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 typedef struct _OVERLAPPED
{ {
ULONG_PTR Internal; ULONG_PTR Internal;

View File

@ -28,12 +28,92 @@
#ifndef _WIN32 #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 #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/**
* Unnamed pipe
*/
WINPR_API BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -35,22 +35,9 @@ extern "C" {
#include <winpr/winpr.h> #include <winpr/winpr.h>
#include <winpr/wtypes.h> #include <winpr/wtypes.h>
#include <winpr/io.h>
#include <winpr/error.h> #include <winpr/error.h>
#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 OWNER_SECURITY_INFORMATION 0x00000001
#define GROUP_SECURITY_INFORMATION 0x00000002 #define GROUP_SECURITY_INFORMATION 0x00000002
#define DACL_SECURITY_INFORMATION 0x00000004 #define DACL_SECURITY_INFORMATION 0x00000004

View File

@ -217,6 +217,8 @@ WINPR_API DWORD SignalObjectAndWait(HANDLE hObjectToSignal, HANDLE hObjectToWait
/* Waitable Timer */ /* Waitable Timer */
#define CREATE_WAITABLE_TIMER_MANUAL_RESET 0x00000001
typedef struct _REASON_CONTEXT typedef struct _REASON_CONTEXT
{ {
ULONG Version; ULONG Version;
@ -238,6 +240,9 @@ typedef struct _REASON_CONTEXT
typedef VOID (*PTIMERAPCROUTINE)(LPVOID lpArgToCompletionRoutine, DWORD dwTimerLowValue, DWORD dwTimerHighValue); 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 CreateWaitableTimerExA(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess);
WINPR_API HANDLE CreateWaitableTimerExW(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR 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); WINPR_API BOOL CancelWaitableTimer(HANDLE hTimer);
#ifdef UNICODE #ifdef UNICODE
#define CreateWaitableTimer CreateWaitableTimerW
#define CreateWaitableTimerEx CreateWaitableTimerExW #define CreateWaitableTimerEx CreateWaitableTimerExW
#define OpenWaitableTimer OpenWaitableTimerW #define OpenWaitableTimer OpenWaitableTimerW
#else #else
#define CreateWaitableTimer CreateWaitableTimerA
#define CreateWaitableTimerEx CreateWaitableTimerExA #define CreateWaitableTimerEx CreateWaitableTimerExA
#define OpenWaitableTimer OpenWaitableTimerA #define OpenWaitableTimer OpenWaitableTimerA
#endif #endif

View File

@ -88,8 +88,8 @@ typedef DWORD HCALL;
typedef int INT, *LPINT; typedef int INT, *LPINT;
typedef signed char INT8; typedef signed char INT8;
typedef signed short INT16; typedef signed short INT16;
typedef signed int INT32;
#ifndef XMD_H #ifndef XMD_H
typedef signed int INT32;
typedef signed __int64 INT64; typedef signed __int64 INT64;
#endif #endif
typedef const WCHAR* LMCSTR; typedef const WCHAR* LMCSTR;

View File

@ -54,7 +54,10 @@ if(MONOLITHIC_BUILD)
set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib")
target_link_libraries(${MODULE_NAME} ${WINPR_LIBS}) target_link_libraries(${MODULE_NAME} ${WINPR_LIBS})
if(NOT WITH_WAYK)
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries)
endif()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/libwinpr") set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/libwinpr")
endif() endif()

View File

@ -31,7 +31,7 @@ set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SO
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL
MODULE winpr MODULE winpr
MODULES winpr-crt winpr-handle) MODULES winpr-crt winpr-handle winpr-path)
if(MONOLITHIC_BUILD) if(MONOLITHIC_BUILD)

View File

@ -22,6 +22,7 @@
#endif #endif
#include <winpr/crt.h> #include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/handle.h> #include <winpr/handle.h>
#include <winpr/file.h> #include <winpr/file.h>
@ -125,13 +126,21 @@
#ifndef _WIN32 #ifndef _WIN32
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <time.h> #include <time.h>
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <dirent.h> #include <dirent.h>
#include <fcntl.h>
#include <sys/un.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/socket.h>
#ifdef ANDROID #ifdef ANDROID
#include <sys/vfs.h> #include <sys/vfs.h>
@ -146,7 +155,59 @@
HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) 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, 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; ULONG Type;
PVOID Object; PVOID Object;
WINPR_PIPE* pipe;
if (!winpr_Handle_GetInfo(hFile, &Type, &Object)) if (!winpr_Handle_GetInfo(hFile, &Type, &Object))
return FALSE; return FALSE;
@ -178,6 +238,7 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
if (Type == HANDLE_TYPE_ANONYMOUS_PIPE) if (Type == HANDLE_TYPE_ANONYMOUS_PIPE)
{ {
int status; int status;
WINPR_PIPE* pipe;
pipe = (WINPR_PIPE*) Object; pipe = (WINPR_PIPE*) Object;
@ -187,6 +248,30 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
return TRUE; 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; return FALSE;
} }
@ -208,7 +293,6 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
{ {
ULONG Type; ULONG Type;
PVOID Object; PVOID Object;
WINPR_PIPE* pipe;
if (!winpr_Handle_GetInfo(hFile, &Type, &Object)) if (!winpr_Handle_GetInfo(hFile, &Type, &Object))
return FALSE; return FALSE;
@ -216,6 +300,7 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
if (Type == HANDLE_TYPE_ANONYMOUS_PIPE) if (Type == HANDLE_TYPE_ANONYMOUS_PIPE)
{ {
int status; int status;
WINPR_PIPE* pipe;
pipe = (WINPR_PIPE*) Object; pipe = (WINPR_PIPE*) Object;
@ -225,6 +310,30 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
return TRUE; 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; return FALSE;
} }
@ -445,3 +554,72 @@ BOOL CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttrib
#endif #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);
}

View File

@ -122,6 +122,21 @@ BOOL CloseHandle(HANDLE hObject)
return TRUE; 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) else if (Type == HANDLE_TYPE_ANONYMOUS_PIPE)
{ {
WINPR_PIPE* pipe; WINPR_PIPE* pipe;
@ -137,6 +152,22 @@ BOOL CloseHandle(HANDLE hObject)
return TRUE; 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; return FALSE;
} }

View File

@ -22,6 +22,7 @@
#endif #endif
#include <winpr/crt.h> #include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/handle.h> #include <winpr/handle.h>
#include <winpr/pipe.h> #include <winpr/pipe.h>
@ -34,8 +35,17 @@
#include "../handle/handle.h" #include "../handle/handle.h"
#include <fcntl.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include "pipe.h" #include "pipe.h"
/*
* Unnamed pipe
*/
BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize) BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize)
{ {
int pipe_fd[2]; int pipe_fd[2];
@ -69,4 +79,169 @@ BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpP
return TRUE; 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 #endif

View File

@ -34,6 +34,26 @@ struct winpr_pipe
}; };
typedef struct winpr_pipe 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
#endif /* WINPR_PIPE_PRIVATE_H */ #endif /* WINPR_PIPE_PRIVATE_H */

View File

@ -5,7 +5,9 @@ set(MODULE_PREFIX "TEST_PIPE")
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS set(${MODULE_PREFIX}_TESTS
TestPipeCreatePipe.c) TestPipeCreatePipe.c
TestPipeCreateNamedPipe.c
TestPipeCreateNamedPipeOverlapped.c)
create_test_sourcelist(${MODULE_PREFIX}_SRCS create_test_sourcelist(${MODULE_PREFIX}_SRCS
${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_DRIVER}
@ -16,7 +18,7 @@ add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD} MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr 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}) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})

View File

@ -0,0 +1,181 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/pipe.h>
#include <winpr/file.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
#include <winpr/print.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#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;
}

View File

@ -0,0 +1,240 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/pipe.h>
#include <winpr/file.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
#include <winpr/print.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#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;
}

View File

@ -82,6 +82,9 @@ HANDLE CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset,
WINPR_HANDLE_SET_TYPE(event, HANDLE_TYPE_EVENT); WINPR_HANDLE_SET_TYPE(event, HANDLE_TYPE_EVENT);
handle = (HANDLE) event; handle = (HANDLE) event;
if (bInitialState)
SetEvent(handle);
} }
if (!cs.LockSemaphore) if (!cs.LockSemaphore)

View File

@ -25,16 +25,6 @@
#include "synch.h" #include "synch.h"
/**
* CreateMutexA
* CreateMutexW
* CreateMutexExA
* CreateMutexExW
* OpenMutexA
* OpenMutexW
* ReleaseMutex
*/
#ifndef _WIN32 #ifndef _WIN32
#include "../handle/handle.h" #include "../handle/handle.h"

View File

@ -20,6 +20,12 @@
#ifndef WINPR_SYNCH_PRIVATE_H #ifndef WINPR_SYNCH_PRIVATE_H
#define WINPR_SYNCH_PRIVATE_H #define WINPR_SYNCH_PRIVATE_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <winpr/platform.h>
#include <winpr/synch.h> #include <winpr/synch.h>
#ifndef _WIN32 #ifndef _WIN32
@ -68,6 +74,29 @@ struct winpr_event
}; };
typedef struct winpr_event WINPR_EVENT; typedef struct winpr_event WINPR_EVENT;
#ifdef HAVE_TIMERFD_H
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/timerfd.h>
#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
#endif /* WINPR_SYNCH_PRIVATE_H */ #endif /* WINPR_SYNCH_PRIVATE_H */

View File

@ -5,7 +5,11 @@ set(MODULE_PREFIX "TEST_SYNCH")
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS set(${MODULE_PREFIX}_TESTS
TestSynchCritical.c) TestSynchEvent.c
TestSynchMutex.c
TestSynchCritical.c
TestSynchSemaphore.c
TestSynchWaitableTimer.c)
create_test_sourcelist(${MODULE_PREFIX}_SRCS create_test_sourcelist(${MODULE_PREFIX}_SRCS
${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_DRIVER}

View File

@ -0,0 +1,42 @@
#include <winpr/crt.h>
#include <winpr/synch.h>
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;
}

View File

@ -0,0 +1,21 @@
#include <winpr/crt.h>
#include <winpr/synch.h>
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;
}

View File

@ -0,0 +1,21 @@
#include <winpr/crt.h>
#include <winpr/synch.h>
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;
}

View File

@ -0,0 +1,71 @@
#include <winpr/crt.h>
#include <winpr/synch.h>
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;
}

View File

@ -21,23 +21,66 @@
#include "config.h" #include "config.h"
#endif #endif
#include <winpr/crt.h>
#include <winpr/synch.h> #include <winpr/synch.h>
/** #include "synch.h"
* CreateWaitableTimerExW
* OpenWaitableTimerW
* SetWaitableTimer
* SetWaitableTimerEx
* CancelWaitableTimer
*/
#ifndef _WIN32 #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; 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) HANDLE CreateWaitableTimerExW(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess)
{ {
return NULL; return NULL;
@ -46,12 +89,98 @@ HANDLE CreateWaitableTimerExW(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR l
BOOL SetWaitableTimer(HANDLE hTimer, const LARGE_INTEGER* lpDueTime, LONG lPeriod, BOOL SetWaitableTimer(HANDLE hTimer, const LARGE_INTEGER* lpDueTime, LONG lPeriod,
PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, BOOL fResume) 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; return TRUE;
} }
BOOL SetWaitableTimerEx(HANDLE hTimer, const LARGE_INTEGER* lpDueTime, LONG lPeriod, BOOL SetWaitableTimerEx(HANDLE hTimer, const LARGE_INTEGER* lpDueTime, LONG lPeriod,
PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, PREASON_CONTEXT WakeContext, ULONG TolerableDelay) 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; return TRUE;
} }

View File

@ -62,13 +62,16 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
thread = (WINPR_THREAD*) Object; thread = (WINPR_THREAD*) Object;
status = pthread_join(thread->thread, &thread_status); if (thread->started)
{
status = pthread_join(thread->thread, &thread_status);
if (status != 0) if (status != 0)
fprintf(stderr, "WaitForSingleObject: pthread_join failure: %d\n", status); fprintf(stderr, "WaitForSingleObject: pthread_join failure: %d\n", status);
if (thread_status) if (thread_status)
thread->dwExitCode = ((DWORD) (size_t) thread_status); thread->dwExitCode = ((DWORD) (size_t) thread_status);
}
} }
else if (Type == HANDLE_TYPE_MUTEX) else if (Type == HANDLE_TYPE_MUTEX)
{ {
@ -143,7 +146,7 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
length = read(semaphore->pipe_fd[0], &length, 1); length = read(semaphore->pipe_fd[0], &length, 1);
if (length != 1) if (length != 1)
return FALSE; return WAIT_FAILED;
} }
#else #else
@ -153,6 +156,51 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
sem_wait((winpr_sem_t*) semaphore->sem); sem_wait((winpr_sem_t*) semaphore->sem);
#endif #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 #endif
} }
else else
@ -181,6 +229,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl
if (!nCount) if (!nCount)
return WAIT_FAILED; return WAIT_FAILED;
maxfd = 0; maxfd = 0;
FD_ZERO(&fds); FD_ZERO(&fds);
ZeroMemory(&timeout, sizeof(timeout)); ZeroMemory(&timeout, sizeof(timeout));
@ -205,13 +254,18 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl
return WAIT_FAILED; return WAIT_FAILED;
#endif #endif
} }
else if (Type == HANDLE_TYPE_TIMER)
{
WINPR_TIMER* timer = (WINPR_TIMER*) Object;
fd = timer->fd;
}
else else
{ {
return WAIT_FAILED; return WAIT_FAILED;
} }
if (fd == -1) if (fd == -1)
return WAIT_FAILED; return WAIT_FAILED;
FD_SET(fd, &fds); FD_SET(fd, &fds);
@ -238,19 +292,40 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl
winpr_Handle_GetInfo(lpHandles[index], &Type, &Object); winpr_Handle_GetInfo(lpHandles[index], &Type, &Object);
if (Type == HANDLE_TYPE_EVENT) if (Type == HANDLE_TYPE_EVENT)
{
fd = ((WINPR_EVENT*) Object)->pipe_fd[0]; fd = ((WINPR_EVENT*) Object)->pipe_fd[0];
}
else if (Type == HANDLE_TYPE_SEMAPHORE) else if (Type == HANDLE_TYPE_SEMAPHORE)
{
fd = ((WINPR_SEMAPHORE*) Object)->pipe_fd[0]; 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 (FD_ISSET(fd, &fds))
{ {
if (Type == HANDLE_TYPE_SEMAPHORE) if (Type == HANDLE_TYPE_SEMAPHORE)
{ {
int length = read(fd, &length, 1); int length;
length = read(fd, &length, 1);
if (length != 1) if (length != 1)
return WAIT_FAILED; 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); return (WAIT_OBJECT_0 + index);
} }

View File

@ -25,6 +25,7 @@ set(${MODULE_PREFIX}_COLLECTIONS_SRCS
collections/Reference.c collections/Reference.c
collections/ArrayList.c collections/ArrayList.c
collections/Dictionary.c collections/Dictionary.c
collections/LinkedList.c
collections/ListDictionary.c collections/ListDictionary.c
collections/KeyValuePair.c collections/KeyValuePair.c
collections/CountdownEvent.c collections/CountdownEvent.c

View File

@ -0,0 +1,339 @@
/**
* WinPR: Windows Portable Runtime
* System.Collections.Generic.LinkedList<T>
*
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* 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 <winpr/collections.h>
/**
* C equivalent of the C# LinkedList<T> 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);
}
}

View File

@ -9,6 +9,7 @@ set(${MODULE_PREFIX}_TESTS
TestPrint.c TestPrint.c
TestPubSub.c TestPubSub.c
TestArrayList.c TestArrayList.c
TestLinkedList.c
TestListDictionary.c TestListDictionary.c
TestCmdLine.c TestCmdLine.c
TestStreamPool.c TestStreamPool.c

View File

@ -0,0 +1,114 @@
#include <winpr/crt.h>
#include <winpr/tchar.h>
#include <winpr/collections.h>
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;
}

View File

@ -38,8 +38,10 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) if(NOT WITH_WAYK)
add_subdirectory(cli) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries)
add_subdirectory(cli)
endif()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Tools") set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Tools")