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

View File

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

View File

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

View File

@ -66,8 +66,8 @@ set_target_properties(${MODULE_NAME} PROPERTIES
MACOSX_FRAMEWORK_IDENTIFIER com.awakecoding.${MODULE_NAME}
FRAMEWORK_VERSION 1.1.0
MACOSX_FRAMEWORK_SHORT_VERSION_STRING 1.1.0
MACOSX_FRAMEWORK_BUNDLE_VERSION 1.1.0
INSTALL_NAME_DIR "@executable_path/../../Frameworks"
MACOSX_FRAMEWORK_BUNDLE_BUNDLE_VERSION 1.1.0
INSTALL_NAME_DIR "@executable_path/../Frameworks"
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/Info.plist
BUILD_WITH_INSTALL_RPATH 1)
@ -132,7 +132,7 @@ if (${BUILD_SHARED_LIBS})
endif()
# Add post-build NIB file generation in unix makefiles. XCode handles this implicitly.
if("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles")
# if("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles")
message(STATUS "Adding post-build NIB file generation event for ${MODULE_NAME}")
# Make sure we can find the 'ibtool' program. If we can NOT find it we
@ -156,7 +156,7 @@ if("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles")
--compile ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/Versions/${MACOSX_BUNDLE_SHORT_VERSION_STRING}/Resources/${XIB_WE}.nib ${xib}
COMMENT "Compiling ${xib}")
endforeach()
endif()
# endif()
# Copy the public header files into the framework
foreach(HEADER ${${MODULE_NAME}_HEADERS})
@ -169,6 +169,7 @@ endforeach()
# Copy the FreeRDP header files into the framework
add_custom_command(TARGET ${MODULE_NAME} POST_BUILD
COMMAND ditto ${CMAKE_SOURCE_DIR}/include/freerdp ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/Headers/freerdp
COMMAND ditto ${CMAKE_SOURCE_DIR}/winpr/include/winpr ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/Headers/winpr
COMMENT Copying FreeRDP header files to ${MODULE_NAME})
add_subdirectory(cli)

View File

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

View File

@ -42,6 +42,8 @@
* -
*/
#include <winpr/windows.h>
#include "mf_client.h"
#import "mfreerdp.h"
#import "MRDPView.h"
@ -80,11 +82,9 @@ void mac_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmap);
void mac_begin_paint(rdpContext* context);
void mac_end_paint(rdpContext* context);
void mac_save_state_info(freerdp* instance, rdpContext* context);
static void update_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info);
static void input_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info);
static void channel_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info);
int register_update_fds(freerdp* instance);
int register_input_fds(freerdp* instance);
static void update_activity_cb(freerdp* instance);
static void input_activity_cb(freerdp* instance);
static void channel_activity_cb(freerdp* instance);
int invoke_draw_rect(rdpContext* context);
int process_plugin_args(rdpSettings* settings, const char* name, RDP_PLUGIN_DATA* plugin_data, void* user_data);
int receive_channel_data(freerdp* instance, int chan_id, BYTE* data, int size, int flags, int total_size);
@ -98,6 +98,9 @@ void cliprdr_process_text(freerdp* instance, BYTE* data, int len);
void cliprdr_send_supported_format_list(freerdp* instance);
int register_channel_fds(int* fds, int count, freerdp* instance);
DWORD mac_client_thread(void* param);
struct cursor
{
rdpPointer* pointer;
@ -121,7 +124,6 @@ struct rgba_data
- (int) rdpStart:(rdpContext*) rdp_context
{
int status;
mfContext* mfc;
rdpSettings* settings;
EmbedWindowEventArgs e;
@ -137,32 +139,97 @@ struct rgba_data
e.embed = TRUE;
e.handle = (void*) self;
PubSub_OnEmbedWindow(context->pubSub, context, &e);
[self setViewSize :instance->settings->DesktopWidth :instance->settings->DesktopHeight];
status = freerdp_connect(context->instance);
mfc->thread = CreateThread(NULL, 0, mac_client_thread, (void*) context, 0, &mfc->mainThreadId);
if (!status)
{
[self setIs_connected:0];
[self rdpConnectError];
return 1;
}
/* register update message queue with the RunLoop */
register_update_fds(context->instance);
/* register update message queue with the RunLoop */
register_input_fds(context->instance);
/* register channel events with the RunLoop */
register_channels_fds(context->instance);
freerdp_check_fds(context->instance);
[self setIs_connected:1];
return 0;
}
DWORD mac_client_thread(void* param)
{
@autoreleasepool
{
int status;
HANDLE events[4];
HANDLE input_event;
HANDLE update_event;
HANDLE channels_event;
DWORD nCount;
rdpContext* context = (rdpContext*) param;
mfContext* mfc = (mfContext*) context;
freerdp* instance = context->instance;
MRDPView* view = mfc->view;
status = freerdp_connect(context->instance);
if (!status)
{
[view setIs_connected:0];
return 0;
}
[view setIs_connected:1];
nCount = 0;
events[nCount++] = mfc->stopEvent;
if (instance->settings->AsyncUpdate)
{
events[nCount++] = update_event = freerdp_get_message_queue_event_handle(instance, FREERDP_UPDATE_MESSAGE_QUEUE);
}
if (instance->settings->AsyncInput)
{
events[nCount++] = input_event = freerdp_get_message_queue_event_handle(instance, FREERDP_INPUT_MESSAGE_QUEUE);
}
if (instance->settings->AsyncChannels)
{
events[nCount++] = channels_event = freerdp_channels_get_event_handle(instance);
}
while (1)
{
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
if (WaitForSingleObject(mfc->stopEvent, 0) == WAIT_OBJECT_0)
{
break;
}
if (instance->settings->AsyncUpdate)
{
if (WaitForSingleObject(update_event, 0) == WAIT_OBJECT_0)
{
update_activity_cb(instance);
}
}
if (instance->settings->AsyncInput)
{
if (WaitForSingleObject(input_event, 0) == WAIT_OBJECT_0)
{
input_activity_cb(instance);
}
}
if (instance->settings->AsyncChannels)
{
if (WaitForSingleObject(channels_event, 0) == WAIT_OBJECT_0)
{
channel_activity_cb(instance);
}
}
}
ExitThread(0);
return 0;
}
}
/************************************************************************
methods we override
************************************************************************/
@ -212,13 +279,29 @@ struct rgba_data
NSTrackingArea * trackingArea = [[NSTrackingArea alloc] initWithRect:[self visibleRect] options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingCursorUpdate | NSTrackingEnabledDuringMouseDrag | NSTrackingActiveWhenFirstResponder owner:self userInfo:nil];
[self addTrackingArea:trackingArea];
mouseInClientArea = YES;
// Set the default cursor
currentCursor = [NSCursor arrowCursor];
initialized = YES;
}
}
- (void) setCursor: (NSCursor*) cursor
{
self->currentCursor = cursor;
[[self window] invalidateCursorRectsForView:self];
[imageView setImage:[currentCursor image]];
}
// Set the current cursor
- (void) resetCursorRects
{
[self addCursorRect:[self visibleRect] cursor:currentCursor];
}
/** *********************************************************************
* become first responder so we can get keyboard and mouse events
***********************************************************************/
@ -594,7 +677,8 @@ struct rgba_data
- (void) releaseResources
{
int i;
for (i = 0; i < argc; i++)
{
if (argv[i])
@ -608,15 +692,6 @@ struct rgba_data
if (pixel_data)
free(pixel_data);
if (run_loop_src_update != 0)
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_src_update, kCFRunLoopDefaultMode);
if (run_loop_src_input != 0)
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_src_input, kCFRunLoopDefaultMode);
if (run_loop_src_channels != 0)
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_src_channels, kCFRunLoopDefaultMode);
}
/** *********************************************************************
@ -650,94 +725,6 @@ struct rgba_data
instance methods
************************************************************************/
/** *********************************************************************
* double check that a mouse event occurred in our client view
***********************************************************************/
- (BOOL) eventIsInClientArea :(NSEvent *) event :(int *) xptr :(int *) yptr
{
NSPoint loc = [event locationInWindow];
int x = (int) loc.x;
int y = (int) loc.y;
if ((x < 0) || (y < 0))
{
if (mouseInClientArea)
{
// set default cursor before leaving client area
mouseInClientArea = NO;
NSCursor *cur = [NSCursor arrowCursor];
[cur set];
}
return NO;
}
if ((x > width) || (y > height))
{
if (mouseInClientArea)
{
// set default cursor before leaving client area
mouseInClientArea = NO;
NSCursor *cur = [NSCursor arrowCursor];
[cur set];
}
return NO;
}
// on Mac origin is at lower left, but we want it on upper left
y = height - y;
*xptr = x;
*yptr = y;
mouseInClientArea = YES;
return YES;
}
/** *********************************************************************
* called when we fail to connect to a RDP server
***********************************************************************/
- (void) rdpConnectError
{
NSString* message = @"Error connecting to server";
if (connectErrorCode == AUTHENTICATIONERROR)
{
message = [NSString stringWithFormat:@"%@:\n%@", message, @"Authentication failure, check credentials."];
}
NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:message];
[alert beginSheetModalForWindow:[self window]
modalDelegate:self
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
contextInfo:nil];
}
/** *********************************************************************
* called when we fail to launch remote app on RDP server
***********************************************************************/
- (void) rdpRemoteAppError
{
NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:@"Error starting remote app on specified server"];
[alert beginSheetModalForWindow:[self window]
modalDelegate:self
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
contextInfo:nil];
}
/** *********************************************************************
* just a terminate selector for above call
***********************************************************************/
- (void) alertDidEnd:(NSAlert *)a returnCode:(NSInteger)rc contextInfo:(void *)ci
{
[NSApp terminate:nil];
}
- (void) onPasteboardTimerFired :(NSTimer*) timer
{
int i;
@ -870,7 +857,6 @@ BOOL mac_pre_connect(freerdp* instance)
settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE;
settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE;
[view setViewSize :instance->settings->DesktopWidth :instance->settings->DesktopHeight];
freerdp_channels_pre_connect(instance->context->channels, instance);
return TRUE;
@ -975,7 +961,7 @@ void mf_Pointer_New(rdpContext* context, rdpPointer* pointer)
MRDPCursor* mrdpCursor = [[MRDPCursor alloc] init];
mfContext* mfc = (mfContext*) context;
MRDPView* view = (MRDPView*) mfc->view;
rect.size.width = pointer->width;
rect.size.height = pointer->height;
rect.origin.x = pointer->xPos;
@ -984,9 +970,17 @@ void mf_Pointer_New(rdpContext* context, rdpPointer* pointer)
cursor_data = (BYTE*) malloc(rect.size.width * rect.size.height * 4);
mrdpCursor->cursor_data = cursor_data;
if (pointer->xorBpp > 24)
{
freerdp_image_swap_color_order(pointer->xorMaskData, pointer->width, pointer->height);
}
freerdp_alpha_cursor_convert(cursor_data, pointer->xorMaskData, pointer->andMaskData,
pointer->width, pointer->height, pointer->xorBpp, context->gdi->clrconv);
// TODO if xorBpp is > 24 need to call freerdp_image_swap_color_order
// see file df_graphics.c
/* store cursor bitmap image in representation - required by NSImage */
bmiRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **) &cursor_data
pixelsWide:rect.size.width
@ -1054,18 +1048,17 @@ void mf_Pointer_Set(rdpContext* context, rdpPointer* pointer)
MRDPView* view = (MRDPView*) mfc->view;
NSMutableArray* ma = view->cursors;
if (!view->mouseInClientArea)
return;
for (MRDPCursor* cursor in ma)
{
if (cursor->pointer == pointer)
{
[cursor->nsCursor set];
[view setCursor:cursor->nsCursor];
return;
}
}
NSLog(@"Cursor not found");
}
/** *********************************************************************
@ -1083,7 +1076,9 @@ void mf_Pointer_SetNull(rdpContext* context)
void mf_Pointer_SetDefault(rdpContext* context)
{
mfContext* mfc = (mfContext*) context;
MRDPView* view = (MRDPView*) mfc->view;
[view setCursor:[NSCursor arrowCursor]];
}
/** *********************************************************************
@ -1155,16 +1150,15 @@ void mac_end_paint(rdpContext* context)
* called when update data is available
***********************************************************************/
static void update_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info)
static void update_activity_cb(freerdp* instance)
{
int status;
wMessage message;
wMessageQueue* queue;
freerdp* instance = (freerdp*) info;
status = 1;
queue = freerdp_get_message_queue(instance, FREERDP_UPDATE_MESSAGE_QUEUE);
if (queue)
{
while (MessageQueue_Peek(queue, &message, TRUE))
@ -1175,21 +1169,21 @@ static void update_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBack
break;
}
}
CFRelease(fdref);
register_update_fds(instance);
else
{
fprintf(stderr, "update_activity_cb: No queue!\n");
}
}
/** *********************************************************************
* called when input data is available
***********************************************************************/
static void input_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info)
static void input_activity_cb(freerdp* instance)
{
int status;
wMessage message;
wMessageQueue* queue;
freerdp* instance = (freerdp*) info;
wMessageQueue* queue;
status = 1;
queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE);
@ -1198,34 +1192,32 @@ static void input_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackT
{
while (MessageQueue_Peek(queue, &message, TRUE))
{
fprintf(stderr, "input_activity_cb: message %d\n", message.id);
status = freerdp_message_queue_process_message(instance, FREERDP_INPUT_MESSAGE_QUEUE, &message);
if (!status)
break;
}
}
CFRelease(fdref);
register_input_fds(instance);
else
{
fprintf(stderr, "input_activity_cb: No queue!\n");
}
}
/** *********************************************************************
* called when data is available on a virtual channel
***********************************************************************/
static void channel_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info)
static void channel_activity_cb(freerdp* instance)
{
wMessage* event;
freerdp* instance = (freerdp*) info;
wMessage* event;
freerdp_channels_process_pending_messages(instance);
event = freerdp_channels_pop_event(instance->context->channels);
if (event)
{
switch (GetMessageClass(event->id))
fprintf(stderr, "channel_activity_cb: message %d\n", event->id);
switch (GetMessageClass(event->id))
{
case CliprdrChannel_Class:
process_cliprdr_event(instance, event);
@ -1234,90 +1226,6 @@ static void channel_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBac
freerdp_event_free(event);
}
CFRelease(fdref);
register_channels_fds(instance);
}
/** *********************************************************************
* setup callbacks for data availability on update message queue
***********************************************************************/
int register_update_fds(freerdp* instance)
{
int fd_update_event;
HANDLE update_event;
CFFileDescriptorRef fdref;
CFFileDescriptorContext fd_context = { 0, instance, NULL, NULL, NULL };
mfContext* mfc = (mfContext*) instance->context;
MRDPView* view = (MRDPView*) mfc->view;
if (instance->settings->AsyncUpdate)
{
update_event = freerdp_get_message_queue_event_handle(instance, FREERDP_UPDATE_MESSAGE_QUEUE);
fd_update_event = GetEventFileDescriptor(update_event);
fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd_update_event, true, update_activity_cb, &fd_context);
CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
view->run_loop_src_update = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), view->run_loop_src_update, kCFRunLoopDefaultMode);
}
return 0;
}
/** *********************************************************************
* setup callbacks for data availability on input message queue
***********************************************************************/
int register_input_fds(freerdp* instance)
{
int fd_input_event;
HANDLE input_event;
CFFileDescriptorRef fdref;
CFFileDescriptorContext fd_context = { 0, instance, NULL, NULL, NULL };
mfContext* mfc = (mfContext*) instance->context;
MRDPView* view = (MRDPView*) mfc->view;
if (instance->settings->AsyncInput)
{
input_event = freerdp_get_message_queue_event_handle(instance, FREERDP_INPUT_MESSAGE_QUEUE);
fd_input_event = GetEventFileDescriptor(input_event);
fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd_input_event, true, input_activity_cb, &fd_context);
CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
view->run_loop_src_input = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), view->run_loop_src_input, kCFRunLoopDefaultMode);
}
return 0;
}
/** *********************************************************************
* setup callbacks for data availability on channels
***********************************************************************/
int register_channels_fds(freerdp* instance)
{
int fd_channel_event;
HANDLE channel_event;
CFFileDescriptorRef fdref;
CFFileDescriptorContext fd_context = { 0, instance, NULL, NULL, NULL };
mfContext* mfc = (mfContext*) instance->context;
MRDPView* view = (MRDPView*) mfc->view;
if (instance->settings->AsyncChannels)
{
channel_event = freerdp_channels_get_event_handle(instance);
fd_channel_event = GetEventFileDescriptor(channel_event);
fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd_channel_event, true, channel_activity_cb, &fd_context);
CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
view->run_loop_src_channels = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), view->run_loop_src_channels, kCFRunLoopDefaultMode);
}
return 0;
}
/** *********************************************************************
@ -1555,20 +1463,12 @@ void cliprdr_send_supported_format_list(freerdp* instance)
freerdp_channels_send_event(instance->context->channels, (wMessage*) event);
}
/**
* given a rect with 0,0 at the bottom left (apple cords)
* convert it to a rect with 0,0 at the top left (windows cords)
*/
void apple_to_windows_cords(MRDPView* view, NSRect* r)
{
r->origin.y = view->height - (r->origin.y + r->size.height);
}
/**
* given a rect with 0,0 at the top left (windows cords)
* convert it to a rect with 0,0 at the bottom left (apple cords)
*
* Note: the formula works for conversions in both directions.
*
*/
void windows_to_apple_cords(MRDPView* view, NSRect* r)

View File

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

View File

@ -11,8 +11,9 @@
#import "MacFreeRDP/mf_client.h"
static AppDelegate* _singleDelegate = nil;
void AppDelegate_EmbedWindowEventHandler(rdpContext* context, EmbedWindowEventArgs* e);
void AppDelegate_EmbedWindowEventHandler(void* context, EmbedWindowEventArgs* e);
void AppDelegate_ConnectionResultEventHandler(void* context, ConnectionResultEventArgs* e);
void AppDelegate_ErrorInfoEventHandler(void* ctx, ErrorInfoEventArgs* e);
@implementation AppDelegate
@ -45,7 +46,10 @@ void AppDelegate_EmbedWindowEventHandler(rdpContext* context, EmbedWindowEventAr
}
else
{
PubSub_Subscribe(context->pubSub, "EmbedWindow", (pEventHandler) AppDelegate_EmbedWindowEventHandler);
PubSub_SubscribeConnectionResult(context->pubSub, AppDelegate_ConnectionResultEventHandler);
PubSub_SubscribeErrorInfo(context->pubSub, AppDelegate_ErrorInfoEventHandler);
PubSub_SubscribeEmbedWindow(context->pubSub, AppDelegate_EmbedWindowEventHandler);
freerdp_client_start(context);
}
}
@ -110,10 +114,39 @@ void AppDelegate_EmbedWindowEventHandler(rdpContext* context, EmbedWindowEventAr
}
/** *********************************************************************
* called when we fail to connect to a RDP server - Make sure this is called from the main thread.
***********************************************************************/
- (void) rdpConnectError : (NSString*) withMessage
{
NSString* message = withMessage ? withMessage : @"Error connecting to server";
NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:message];
[alert beginSheetModalForWindow:[self window]
modalDelegate:self
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
contextInfo:nil];
}
/** *********************************************************************
* just a terminate selector for above call
***********************************************************************/
- (void) alertDidEnd:(NSAlert *)a returnCode:(NSInteger)rc contextInfo:(void *)ci
{
[NSApp terminate:nil];
}
@end
void AppDelegate_EmbedWindowEventHandler(rdpContext* context, EmbedWindowEventArgs* e)
void AppDelegate_EmbedWindowEventHandler(void* ctx, EmbedWindowEventArgs* e)
{
rdpContext* context = (rdpContext*) ctx;
if (_singleDelegate)
{
mfContext* mfc = (mfContext*) context;
@ -124,4 +157,48 @@ void AppDelegate_EmbedWindowEventHandler(rdpContext* context, EmbedWindowEventAr
[[_singleDelegate->window contentView] addSubview:mfc->view];
}
}
}
/** *********************************************************************
* On connection error, display message and quit application
***********************************************************************/
void AppDelegate_ConnectionResultEventHandler(void* ctx, ConnectionResultEventArgs* e)
{
NSLog(@"ConnectionResult event result:%d\n", e->result);
if (_singleDelegate)
{
if (e->result != 0)
{
NSString* message = nil;
if (connectErrorCode == AUTHENTICATIONERROR)
{
message = [NSString stringWithFormat:@"%@:\n%@", message, @"Authentication failure, check credentials."];
}
// Making sure this should be invoked on the main UI thread.
[_singleDelegate performSelectorOnMainThread:@selector(rdpConnectError:) withObject:message waitUntilDone:FALSE];
[message release];
}
}
}
void AppDelegate_ErrorInfoEventHandler(void* ctx, ErrorInfoEventArgs* e)
{
NSLog(@"ErrorInfo event code:%d\n", e->code);
if (_singleDelegate)
{
// Retrieve error message associated with error code
NSString* message = nil;
if (e->code != ERRINFO_NONE)
{
const char* errorMessage = freerdp_get_error_info_string(e->code);
message = [[NSString alloc] initWithUTF8String:errorMessage];
}
// Making sure this should be invoked on the main UI thread.
[_singleDelegate performSelectorOnMainThread:@selector(rdpConnectError:) withObject:message waitUntilDone:TRUE];
[message release];
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

@ -21,6 +21,13 @@
#include "config.h"
#endif
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#ifdef WITH_XCURSOR
#include <X11/Xcursor/Xcursor.h>
#endif
#ifdef WITH_XI
#include <X11/extensions/XInput2.h>
#endif
@ -551,6 +558,57 @@ char* xf_input_touch_state_string(DWORD flags)
return "TouchUnknown";
}
void xf_input_hide_cursor(xfContext* xfc)
{
#ifdef WITH_XCURSOR
if (!xfc->cursorHidden)
{
XcursorImage ci;
XcursorPixel xp = 0;
static Cursor nullcursor = None;
xf_lock_x11(xfc, FALSE);
ZeroMemory(&ci, sizeof(ci));
ci.version = XCURSOR_IMAGE_VERSION;
ci.size = sizeof(ci);
ci.width = ci.height = 1;
ci.xhot = ci.yhot = 0;
ci.pixels = &xp;
nullcursor = XcursorImageLoadCursor(xfc->display, &ci);
if ((xfc->window) && (nullcursor != None))
XDefineCursor(xfc->display, xfc->window->handle, nullcursor);
xfc->cursorHidden = TRUE;
xf_unlock_x11(xfc, FALSE);
}
#endif
}
void xf_input_show_cursor(xfContext* xfc)
{
#ifdef WITH_XCURSOR
xf_lock_x11(xfc, FALSE);
if (xfc->cursorHidden)
{
if (xfc->window)
{
if (!xfc->pointer)
XUndefineCursor(xfc->display, xfc->window->handle);
else
XDefineCursor(xfc->display, xfc->window->handle, xfc->pointer->cursor);
}
xfc->cursorHidden = FALSE;
}
xf_unlock_x11(xfc, FALSE);
#endif
}
int xf_input_touch_remote(xfContext* xfc, XIDeviceEvent* event, int evtype)
{
int x, y;
@ -561,6 +619,8 @@ int xf_input_touch_remote(xfContext* xfc, XIDeviceEvent* event, int evtype)
if (!rdpei)
return 0;
xf_input_hide_cursor(xfc);
touchId = event->detail;
x = (int) event->event_x;
y = (int) event->event_y;
@ -586,7 +646,8 @@ int xf_input_touch_remote(xfContext* xfc, XIDeviceEvent* event, int evtype)
int xf_input_event(xfContext* xfc, XIDeviceEvent* event, int evtype)
{
xf_input_show_cursor(xfc);
switch (evtype)
{
case XI_ButtonPress:

View File

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

View File

@ -53,7 +53,9 @@ target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
set_target_properties(${MODULE_NAME} PROPERTIES LINK_INTERFACE_LIBRARIES "")
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries)
if (NOT WITH_WAYK)
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries)
endif()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/Common")

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);
}
#define WRITE_ALL_SETTINGS TRUE
#define WRITE_ALL_SETTINGS FALSE
#define SETTING_MODIFIED(_settings, _field) (WRITE_ALL_SETTINGS || _settings->settings_modified[FreeRDP_##_field])
#define SETTING_MODIFIED_SET(_target, _settings, _field) if SETTING_MODIFIED(_settings, _field) _target = _settings->_field
@ -605,7 +605,6 @@ if (~__rdpFile->_field) \
#define WRITE_RDP_FILE_VALUE_RETURN \
return __required_size;
// TODO: Optimize by only writing the fields that have a value i.e ~((size_t) file->FieldName) != 0
size_t freerdp_client_write_rdp_file_buffer(rdpFile* file, char* buffer, size_t size)
{
WRITE_RDP_FILE_DECLARE(file, buffer, size)

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

View File

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

View File

@ -138,17 +138,7 @@ enum FILE_CREATE_OPTION
#define FILE_WRITE_ATTRIBUTES 0x00000100
#endif
#define DELETE 0x00010000
#define READ_CONTROL 0x00020000
#define WRITE_DAC 0x00040000
#define WRITE_OWNER 0x00080000
#define SYNCHRONIZE 0x00100000
#define ACCESS_SYSTEM_SECURITY 0x01000000
#define MAXIMUM_ALLOWED 0x02000000
#define GENERIC_ALL 0x10000000
#define GENERIC_EXECUTE 0x20000000
#define GENERIC_WRITE 0x40000000
#define GENERIC_READ 0x80000000
#include <winpr/io.h>
#endif

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

@ -20,6 +20,10 @@
#ifndef FREERDP_ERROR_H
#define FREERDP_ERROR_H
#include <winpr/crt.h>
#include <freerdp/api.h>
#ifdef __cplusplus
extern "C" {
#endif
@ -128,6 +132,9 @@ extern "C" {
#define ERRINFO_SUCCESS 0x00000000
#define ERRINFO_NONE 0xFFFFFFFF
FREERDP_API const char* freerdp_get_error_info_string(UINT32 code);
FREERDP_API const char* freerdp_get_error_info_name(UINT32 code);
/**
* This static variable holds an error code if the return value from connect is FALSE.
* This variable is always set to 0 in the beginning of the connect sequence.
@ -135,7 +142,7 @@ extern "C" {
* The value can hold one of the defined error codes below OR an error according to errno
*/
extern int connectErrorCode;
FREERDP_API extern int connectErrorCode;
#define ERRORSTART 10000
#define PREECONNECTERROR ERRORSTART + 1

View File

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

View File

@ -205,6 +205,7 @@ extern "C" {
FREERDP_API DWORD freerdp_keyboard_init(DWORD keyboardLayoutId);
FREERDP_API RDP_KEYBOARD_LAYOUT* freerdp_keyboard_get_layouts(DWORD types);
FREERDP_API void freerdp_keyboard_layouts_free(RDP_KEYBOARD_LAYOUT* layouts);
FREERDP_API const char* freerdp_keyboard_get_layout_name_from_id(DWORD keyboardLayoutId);
FREERDP_API DWORD freerdp_keyboard_get_layout_id_from_name(const char* name);
FREERDP_API DWORD freerdp_keyboard_get_rdp_scancode_from_x11_keycode(DWORD keycode);

View File

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

View File

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

View File

@ -1572,3 +1572,153 @@ int freerdp_bitmap_compress(char* in_data, int width, int height,
return lines_sent;
}
/**
* RDP6 Bitmap Test Case ([MS-RDPEGDI])
*/
const BYTE TEST_RDP6_COMPRESSED_BITMAP[220] =
"\x85\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x06\x8B\x99\xD6\x99"
"\xD6\x99\xD6\x10\x84\x08\x42\x08\x42\x10\x84\x99\xD6\x99\xD6\x99"
"\xD6\x99\xD6\x06\x84\x99\xD6\x99\xD6\x99\xD6\xFF\xFF\x16\x69\x99"
"\xD6\x06\x69\x99\xD6\x04\xCC\x89\x52\x03\x6E\xFF\xFF\x02\x6E\x08"
"\x42\x01\x70\x08\x42\x71\xFF\xFF\xCE\x18\xC6\x01\x81\x08\x42\xCE"
"\x66\x29\x02\xCD\x89\x52\x03\x88\x10\x84\x99\xD6\x99\xD6\x99\xD6"
"\x00\x00\x00\x00\x00\x00\x00\x00\xD8\x99\xD6\x03\xF8\x01\x00\x00"
"\x00\x00\xF0\x66\x99\xD6\x05\x6A\x99\xD6\x00\xC4\xCC\x89\x52\x03"
"\x6E\xFF\xFF\x02\x6E\x08\x42\x01\x70\x08\x42\x71\xFF\xFF\xCE\x18"
"\xC6\x01\x81\x08\x42\xCE\x66\x29\x02\xCD\x89\x52\x03\x00\x04\xD6"
"\x99\xD6\xC3\x80\x61\x00\xA5\x80\x40\xEC\x52\x00\x5A\x00\x2D\x00"
"\x24\x00\x12\x00\x24\x00\x12\x00\x5A\x00\x2D\x00\xA5\x80\x52\x00"
"\xC3\x80\x61\x00\x00\x00\x00\x00\xCC\x89\x52\x03\x6E\xFF\xFF\x02"
"\xCB\x18\xC6\x84\x08\x42\x08\x42\x08\x42\xFF\xFF";
const BYTE TEST_RDP6_UNCOMPRESSED_BITMAP[2048] =
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84"
"\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x99\xD6\xFF\xFF"
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x08\x42"
"\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42"
"\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\xFF\xFF"
"\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42"
"\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42"
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
"\xFF\xFF\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84"
"\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x08\x42"
"\x08\x42\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84"
"\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x99\xD6\xFF\xFF"
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x08\x42"
"\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42"
"\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\xFF\xFF"
"\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42"
"\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42"
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
"\xFF\xFF\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84"
"\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x08\x42"
"\x08\x42\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00"
"\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6"
"\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00"
"\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00"
"\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00"
"\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00"
"\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00"
"\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00"
"\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6"
"\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84"
"\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x99\xD6\xFF\xFF"
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x08\x42"
"\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42"
"\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\xFF\xFF";

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

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, suppressOutputSupport); /* suppressOutputSupport (1 byte) */
settings->NoBitmapCompressionHeader = (extraFlags & NO_BITMAP_COMPRESSION_HDR) ? TRUE : FALSE;
if (!(extraFlags & FASTPATH_OUTPUT_SUPPORTED))
settings->FastPathOutput = FALSE;
@ -213,7 +215,10 @@ void rdp_write_general_capability_set(wStream* s, rdpSettings* settings)
header = rdp_capability_set_start(s);
extraFlags = LONG_CREDENTIALS_SUPPORTED | NO_BITMAP_COMPRESSION_HDR;
extraFlags = LONG_CREDENTIALS_SUPPORTED;
if (settings->NoBitmapCompressionHeader)
extraFlags |= NO_BITMAP_COMPRESSION_HDR;
if (settings->AutoReconnectionEnabled)
extraFlags |= AUTORECONNECT_SUPPORTED;
@ -1209,7 +1214,7 @@ BOOL rdp_read_input_capability_set(wStream* s, UINT16 length, rdpSettings* setti
Stream_Seek(s, 64); /* imeFileName (64 bytes) */
if (settings->ServerMode != TRUE)
if (!settings->ServerMode)
{
if (inputFlags & INPUT_FLAG_FASTPATH_INPUT)
{
@ -1217,7 +1222,7 @@ BOOL rdp_read_input_capability_set(wStream* s, UINT16 length, rdpSettings* setti
}
else if (inputFlags & INPUT_FLAG_FASTPATH_INPUT2)
{
/* avertised by RDP 5.2, 6.0, 6.1 and 7.0 servers */
/* advertised by RDP 5.2, 6.0, 6.1 and 7.0 servers */
}
else
{
@ -1440,17 +1445,25 @@ void rdp_write_cache_definition(wStream* s, GLYPH_CACHE_DEFINITION* cache_defini
BOOL rdp_read_glyph_cache_capability_set(wStream* s, UINT16 length, rdpSettings* settings)
{
UINT16 glyphSupportLevel;
if (length < 52)
return FALSE;
Stream_Seek(s, 40); /* glyphCache (40 bytes) */
Stream_Seek_UINT32(s); /* fragCache (4 bytes) */
Stream_Read_UINT16(s, glyphSupportLevel); /* glyphSupportLevel (2 bytes) */
Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
/* glyphCache (40 bytes) */
rdp_read_cache_definition(s, &(settings->GlyphCache[0])); /* glyphCache0 (4 bytes) */
rdp_read_cache_definition(s, &(settings->GlyphCache[1])); /* glyphCache1 (4 bytes) */
rdp_read_cache_definition(s, &(settings->GlyphCache[2])); /* glyphCache2 (4 bytes) */
rdp_read_cache_definition(s, &(settings->GlyphCache[3])); /* glyphCache3 (4 bytes) */
rdp_read_cache_definition(s, &(settings->GlyphCache[4])); /* glyphCache4 (4 bytes) */
rdp_read_cache_definition(s, &(settings->GlyphCache[5])); /* glyphCache5 (4 bytes) */
rdp_read_cache_definition(s, &(settings->GlyphCache[6])); /* glyphCache6 (4 bytes) */
rdp_read_cache_definition(s, &(settings->GlyphCache[7])); /* glyphCache7 (4 bytes) */
rdp_read_cache_definition(s, &(settings->GlyphCache[8])); /* glyphCache8 (4 bytes) */
rdp_read_cache_definition(s, &(settings->GlyphCache[9])); /* glyphCache9 (4 bytes) */
rdp_read_cache_definition(s, settings->FragCache); /* fragCache (4 bytes) */
settings->GlyphSupportLevel = glyphSupportLevel;
Stream_Read_UINT16(s, settings->GlyphSupportLevel); /* glyphSupportLevel (2 bytes) */
Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
return TRUE;
}
@ -2313,10 +2326,14 @@ BOOL rdp_print_multifragment_update_capability_set(wStream* s, UINT16 length)
BOOL rdp_read_large_pointer_capability_set(wStream* s, UINT16 length, rdpSettings* settings)
{
UINT16 largePointerSupportFlags;
if (length < 6)
return FALSE;
Stream_Seek_UINT16(s); /* largePointerSupportFlags (2 bytes) */
Stream_Read_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
settings->LargePointerFlag = (largePointerSupportFlags & LARGE_POINTER_FLAG_96x96) ? 1 : 0;
return TRUE;
}
@ -2862,6 +2879,7 @@ BOOL rdp_read_frame_acknowledge_capability_set(wStream* s, UINT16 length, rdpSet
{
Stream_Seek_UINT32(s); /* (4 bytes) */
}
return TRUE;
}
@ -2874,14 +2892,12 @@ BOOL rdp_read_frame_acknowledge_capability_set(wStream* s, UINT16 length, rdpSet
void rdp_write_frame_acknowledge_capability_set(wStream* s, rdpSettings* settings)
{
int header;
UINT32 frame_acknowledge;
Stream_EnsureRemainingCapacity(s, 32);
header = rdp_capability_set_start(s);
frame_acknowledge = settings->FrameAcknowledge;
Stream_Write_UINT32(s, frame_acknowledge); /* (4 bytes) */
Stream_Write_UINT32(s, settings->FrameAcknowledge); /* (4 bytes) */
rdp_capability_set_finish(s, header, CAPSET_TYPE_FRAME_ACKNOWLEDGE);
}
@ -3501,24 +3517,13 @@ BOOL rdp_send_demand_active(rdpRdp* rdp)
BOOL rdp_recv_confirm_active(rdpRdp* rdp, wStream* s)
{
UINT16 channelId;
UINT16 pduType;
UINT16 pduLength;
UINT16 pduSource;
BOOL status;
rdpSettings* settings;
UINT16 lengthSourceDescriptor;
UINT16 lengthCombinedCapabilities;
UINT16 numberCapabilities;
if (!rdp_recv_get_active_header(rdp, s, &channelId))
return FALSE;
if (!rdp_read_share_control_header(s, &pduLength, &pduType, &pduSource))
return FALSE;
rdp->settings->PduSource = pduSource;
if (pduType != PDU_TYPE_CONFIRM_ACTIVE)
return FALSE;
settings = rdp->settings;
if (Stream_GetRemainingLength(s) < 10)
return FALSE;
@ -3535,7 +3540,46 @@ BOOL rdp_recv_confirm_active(rdpRdp* rdp, wStream* s)
Stream_Read_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
Stream_Seek(s, 2); /* pad2Octets (2 bytes) */
return rdp_read_capability_sets(s, rdp->settings, numberCapabilities);
status = rdp_read_capability_sets(s, rdp->settings, numberCapabilities);
if (!settings->ReceivedCapabilities[CAPSET_TYPE_SURFACE_COMMANDS])
{
/* client does not support surface commands */
}
if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
{
/* client does not support frame acks */
settings->FrameAcknowledge = 0;
}
if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID])
{
/* client does not support bitmap cache v3 */
settings->BitmapCacheV3Enabled = FALSE;
}
if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CODECS])
{
/* client does not support bitmap codecs */
settings->RemoteFxCodec = FALSE;
settings->NSCodec = FALSE;
settings->JpegCodec = FALSE;
}
if (!settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE])
{
/* client does not support multi fragment updates */
}
if (!settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER])
{
/* client does not support large pointers */
settings->LargePointerFlag = 0;
}
return status;
}
void rdp_write_confirm_active(wStream* s, rdpSettings* settings)
@ -3628,17 +3672,13 @@ void rdp_write_confirm_active(wStream* s, rdpSettings* settings)
rdp_write_bitmap_codecs_capability_set(s, settings);
}
if (settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
{
if (settings->FrameAcknowledge > 0)
{
numberCapabilities++;
rdp_write_frame_acknowledge_capability_set(s, settings);
}
}
else
{
if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
settings->FrameAcknowledge = 0;
if (settings->FrameAcknowledge)
{
numberCapabilities++;
rdp_write_frame_acknowledge_capability_set(s, settings);
}
if (settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID])

View File

@ -30,6 +30,7 @@
#include <winpr/crt.h>
#include <freerdp/error.h>
#include <freerdp/listener.h>
/**
* Connection Sequence\n
@ -61,6 +62,103 @@
*
*/
/**
*
* Connection Sequence
*
* 1. Connection Initiation: The client initiates the connection by sending the server a
* Class 0 X.224 Connection Request PDU (section 2.2.1.1). The server responds with a
* Class 0 X.224 Connection Confirm PDU (section 2.2.1.2). From this point, all subsequent
* data sent between client and server is wrapped in an X.224 Data Protocol Data Unit (PDU).
*
* 2. Basic Settings Exchange: Basic settings are exchanged between the client and server by
* using the MCS Connect Initial PDU (section 2.2.1.3) and MCS Connect Response PDU (section 2.2.1.4).
* The Connect Initial PDU contains a Generic Conference Control (GCC) Conference Create Request,
* while the Connect Response PDU contains a GCC Conference Create Response. These two GCC packets
* contain concatenated blocks of settings data (such as core data, security data, and network data)
* which are read by client and server.
*
* 3. Channel Connection: The client sends an MCS Erect Domain Request PDU (section 2.2.1.5),
* followed by an MCS Attach User Request PDU (section 2.2.1.6) to attach the primary user identity
* to the MCS domain. The server responds with an MCS Attach User Confirm PDU (section 2.2.1.7)
* containing the User Channel ID. The client then proceeds to join the user channel, the
* input/output (I/O) channel, and all of the static virtual channels (the I/O and static virtual
* channel IDs are obtained from the data embedded in the GCC packets) by using multiple MCS Channel
* Join Request PDUs (section 2.2.1.8). The server confirms each channel with an MCS Channel Join
* Confirm PDU (section 2.2.1.9). (The client only sends a Channel Join Request after it has received
* the Channel Join Confirm for the previously sent request.)
*
* From this point, all subsequent data sent from the client to the server is wrapped in an MCS Send
* Data Request PDU, while data sent from the server to the client is wrapped in an MCS Send Data
* Indication PDU. This is in addition to the data being wrapped by an X.224 Data PDU.
*
* 4. RDP Security Commencement: If Standard RDP Security mechanisms (section 5.3) are being employed and
* encryption is in force (this is determined by examining the data embedded in the GCC Conference Create
* Response packet) then the client sends a Security Exchange PDU (section 2.2.1.10) containing an encrypted
* 32-byte random number to the server. This random number is encrypted with the public key of the server
* as described in section 5.3.4.1 (the server's public key, as well as a 32-byte server-generated random
* number, are both obtained from the data embedded in the GCC Conference Create Response packet). The client
* and server then utilize the two 32-byte random numbers to generate session keys which are used to encrypt
* and validate the integrity of subsequent RDP traffic.
*
* From this point, all subsequent RDP traffic can be encrypted and a security header is included with the
* data if encryption is in force. (The Client Info PDU (section 2.2.1.11) and licensing PDUs ([MS-RDPELE]
* section 2.2.2) are an exception in that they always have a security header). The Security Header follows
* the X.224 and MCS Headers and indicates whether the attached data is encrypted. Even if encryption is in
* force, server-to-client traffic may not always be encrypted, while client-to-server traffic must always be
* encrypted (encryption of licensing PDUs is optional, however).
*
* 5. Secure Settings Exchange: Secure client data (such as the username, password, and auto-reconnect cookie)
* is sent to the server by using the Client Info PDU (section 2.2.1.11).
*
* 6. Optional Connect-Time Auto-Detection: During the optional connect-time auto-detect phase the goal is to
* determine characteristics of the network, such as the round-trip latency time and the bandwidth of the link
* between the server and client. This is accomplished by exchanging a collection of PDUs (specified in section 2.2.1.4)
* over a predetermined period of time with enough data to ensure that the results are statistically relevant.
*
* 7. Licensing: The goal of the licensing exchange is to transfer a license from the server to the client.
* The client stores this license and on subsequent connections sends the license to the server for validation.
* However, in some situations the client may not be issued a license to store. In effect, the packets exchanged
* during this phase of the protocol depend on the licensing mechanisms employed by the server. Within the context
* of this document, it is assumed that the client will not be issued a license to store. For details regarding
* more advanced licensing scenarios that take place during the Licensing Phase, see [MS-RDPELE] section 1.3.
*
* 8. Optional Multitransport Bootstrapping: After the connection has been secured and the Licensing Phase has run
* to completion, the server can choose to initiate multitransport connections ([MS-RDPEMT] section 1.3).
* The Initiate Multitransport Request PDU (section 2.2.15.1) is sent by the server to the client and results
* in the out-of-band creation of a multitransport connection using messages from the RDP-UDP, TLS, DTLS, and
* multitransport protocols ([MS-RDPEMT] section 1.3.1).
*
* 9. Capabilities Exchange: The server sends the set of capabilities it supports to the client in a Demand Active PDU
* (section 2.2.1.13.1). The client responds with its capabilities by sending a Confirm Active PDU (section 2.2.1.13.2).
*
* 10. Connection Finalization: The client and server exchange PDUs to finalize the connection details. The client-to-server
* PDUs sent during this phase have no dependencies on any of the server-to-client PDUs; they may be sent as a single batch,
* provided that sequencing is maintained.
*
* - The Client Synchronize PDU (section 2.2.1.14) is sent after transmitting the Confirm Active PDU.
* - The Client Control (Cooperate) PDU (section 2.2.1.15) is sent after transmitting the Client Synchronize PDU.
* - The Client Control (Request Control) PDU (section 2.2.1.16) is sent after transmitting the Client Control (Cooperate) PDU.
* - The optional Persistent Key List PDUs (section 2.2.1.17) are sent after transmitting the Client Control (Request Control) PDU.
* - The Font List PDU (section 2.2.1.18) is sent after transmitting the Persistent Key List PDUs or, if the Persistent Key List
* PDUs were not sent, it is sent after transmitting the Client Control (Request Control) PDU (section 2.2.1.16).
*
* The server-to-client PDUs sent during the Connection Finalization Phase have dependencies on the client-to-server PDUs.
*
* - The optional Monitor Layout PDU (section 2.2.12.1) has no dependency on any client-to-server PDUs and is sent after the Demand Active PDU.
* - The Server Synchronize PDU (section 2.2.1.19) is sent in response to the Confirm Active PDU.
* - The Server Control (Cooperate) PDU (section 2.2.1.20) is sent after transmitting the Server Synchronize PDU.
* - The Server Control (Granted Control) PDU (section 2.2.1.21) is sent in response to the Client Control (Request Control) PDU.
* - The Font Map PDU (section 2.2.1.22) is sent in response to the Font List PDU.
*
* Once the client has sent the Confirm Active PDU, it can start sending mouse and keyboard input to the server, and upon receipt
* of the Font List PDU the server can start sending graphics output to the client.
*
* Besides input and graphics data, other data that can be exchanged between client and server after the connection has been
* finalized includes connection management information and virtual channel messages (exchanged between client-side plug-ins
* and server-side applications).
*/
/**
* Establish RDP Connection based on the settings given in the 'rdp' parameter.
* @msdn{cc240452}
@ -77,19 +175,18 @@ BOOL rdp_client_connect(rdpRdp* rdp)
if (settings->GatewayEnabled)
{
char* user;
char* user;
char* domain;
char* cookie;
int user_length = 0;
int user_length = 0;
int domain_length;
int cookie_length;
if (settings->Username)
{
user = settings->Username;
user_length = strlen(settings->Username);
}
if (settings->Username)
{
user = settings->Username;
user_length = strlen(settings->Username);
}
if (settings->Domain)
domain = settings->Domain;
@ -105,10 +202,10 @@ BOOL rdp_client_connect(rdpRdp* rdp)
CharUpperBuffA(cookie, domain_length);
cookie[domain_length] = '\\';
if (settings->Username)
CopyMemory(&cookie[domain_length + 1], user, user_length);
if (settings->Username)
CopyMemory(&cookie[domain_length + 1], user, user_length);
cookie[cookie_length] = '\0';
cookie[cookie_length] = '\0';
nego_set_cookie(rdp->nego, cookie);
free(cookie);
@ -159,7 +256,8 @@ BOOL rdp_client_connect(rdpRdp* rdp)
}
rdp_set_blocking_mode(rdp, FALSE);
rdp->state = CONNECTION_STATE_NEGO;
rdp_client_transition_to_state(rdp, CONNECTION_STATE_NEGO);
rdp->finalize_sc_pdus = 0;
if (!mcs_send_connect_initial(rdp->mcs))
@ -270,7 +368,7 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp)
BYTE crypt_client_random[256 + 8];
BYTE client_random[CLIENT_RANDOM_LENGTH];
if (rdp->settings->DisableEncryption == FALSE)
if (!rdp->settings->DisableEncryption)
{
/* no RDP encryption */
return TRUE;
@ -330,7 +428,7 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp)
return TRUE;
}
static BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
{
BYTE client_random[64]; /* Should be only 32 after successful decryption, but on failure might take up to 64 bytes. */
BYTE crypt_client_random[256 + 8];
@ -339,7 +437,7 @@ static BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
BYTE* mod;
BYTE* priv_exp;
if (rdp->settings->DisableEncryption == FALSE)
if (!rdp->settings->DisableEncryption)
{
/* No RDP Security. */
return TRUE;
@ -360,10 +458,12 @@ static BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
return FALSE;
}
if(Stream_GetRemainingLength(s) < 4)
if (Stream_GetRemainingLength(s) < 4)
return FALSE;
Stream_Read_UINT32(s, rand_len);
if(Stream_GetRemainingLength(s) < rand_len + 8) /* include 8 bytes of padding */
if (Stream_GetRemainingLength(s) < rand_len + 8) /* include 8 bytes of padding */
return FALSE;
key_len = rdp->settings->RdpServerRsaKey->ModulusLength;
@ -374,7 +474,7 @@ static BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
return FALSE;
}
memset(crypt_client_random, 0, sizeof(crypt_client_random));
ZeroMemory(crypt_client_random, sizeof(crypt_client_random));
Stream_Read(s, crypt_client_random, rand_len);
/* 8 zero bytes of padding */
Stream_Seek(s, 8);
@ -389,6 +489,7 @@ static BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
}
rdp->do_crypt = TRUE;
if (rdp->settings->SaltedChecksum)
rdp->do_secure_checksum = TRUE;
@ -422,7 +523,7 @@ BOOL rdp_client_connect_mcs_connect_response(rdpRdp* rdp, wStream* s)
if (!mcs_send_attach_user_request(rdp->mcs))
return FALSE;
rdp->state = CONNECTION_STATE_MCS_ATTACH_USER;
rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_ATTACH_USER);
return TRUE;
}
@ -435,7 +536,7 @@ BOOL rdp_client_connect_mcs_attach_user_confirm(rdpRdp* rdp, wStream* s)
if (!mcs_send_channel_join_request(rdp->mcs, rdp->mcs->user_id))
return FALSE;
rdp->state = CONNECTION_STATE_MCS_CHANNEL_JOIN;
rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN);
return TRUE;
}
@ -505,7 +606,7 @@ BOOL rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, wStream* s)
if (!rdp_send_client_info(rdp))
return FALSE;
rdp->state = CONNECTION_STATE_LICENSE;
rdp_client_transition_to_state(rdp, CONNECTION_STATE_LICENSING);
}
return TRUE;
@ -524,7 +625,7 @@ BOOL rdp_client_connect_license(rdpRdp* rdp, wStream* s)
if (rdp->license->state == LICENSE_STATE_COMPLETED)
{
rdp->state = CONNECTION_STATE_CAPABILITY;
rdp_client_transition_to_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE);
}
return TRUE;
@ -574,8 +675,7 @@ BOOL rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s)
IFCALL(rdp->update->DesktopResize, rdp->update->context);
}
rdp->state = CONNECTION_STATE_FINALIZATION;
update_reset_state(rdp->update);
rdp_client_transition_to_state(rdp, CONNECTION_STATE_FINALIZATION);
return rdp_client_connect_finalize(rdp);
}
@ -590,8 +690,10 @@ BOOL rdp_client_connect_finalize(rdpRdp* rdp)
if (!rdp_send_client_synchronize_pdu(rdp))
return FALSE;
if (!rdp_send_client_control_pdu(rdp, CTRLACTION_COOPERATE))
return FALSE;
if (!rdp_send_client_control_pdu(rdp, CTRLACTION_REQUEST_CONTROL))
return FALSE;
/**
@ -600,15 +702,91 @@ BOOL rdp_client_connect_finalize(rdpRdp* rdp)
* stored in persistent bitmap cache or the server has advertised support for bitmap
* host cache and a deactivation reactivation sequence is *not* in progress.
*/
if (!rdp->deactivation_reactivation && rdp->settings->BitmapCachePersistEnabled)
{
if (!rdp_send_client_persistent_key_list_pdu(rdp))
return FALSE;
}
if (!rdp_send_client_font_list_pdu(rdp, FONTLIST_FIRST | FONTLIST_LAST))
return FALSE;
return TRUE;
}
int rdp_client_transition_to_state(rdpRdp* rdp, int state)
{
int status = 0;
switch (state)
{
case CONNECTION_STATE_INITIAL:
rdp->state = CONNECTION_STATE_INITIAL;
break;
case CONNECTION_STATE_NEGO:
rdp->state = CONNECTION_STATE_NEGO;
break;
case CONNECTION_STATE_MCS_CONNECT:
rdp->state = CONNECTION_STATE_MCS_CONNECT;
break;
case CONNECTION_STATE_MCS_ERECT_DOMAIN:
rdp->state = CONNECTION_STATE_MCS_ERECT_DOMAIN;
break;
case CONNECTION_STATE_MCS_ATTACH_USER:
rdp->state = CONNECTION_STATE_MCS_ATTACH_USER;
break;
case CONNECTION_STATE_MCS_CHANNEL_JOIN:
rdp->state = CONNECTION_STATE_MCS_CHANNEL_JOIN;
break;
case CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT:
rdp->state = CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT;
break;
case CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE:
rdp->state = CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE;
break;
case CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT:
rdp->state = CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT;
break;
case CONNECTION_STATE_LICENSING:
rdp->state = CONNECTION_STATE_LICENSING;
break;
case CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING:
rdp->state = CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING;
break;
case CONNECTION_STATE_CAPABILITIES_EXCHANGE:
rdp->state = CONNECTION_STATE_CAPABILITIES_EXCHANGE;
break;
case CONNECTION_STATE_FINALIZATION:
rdp->state = CONNECTION_STATE_FINALIZATION;
update_reset_state(rdp->update);
rdp->finalize_sc_pdus = 0;
break;
case CONNECTION_STATE_ACTIVE:
rdp->state = CONNECTION_STATE_ACTIVE;
break;
default:
status = -1;
break;
}
return status;
}
BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s)
{
BOOL status;
@ -623,8 +801,8 @@ BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s)
fprintf(stderr, "Client Security: NLA:%d TLS:%d RDP:%d\n",
(rdp->nego->requested_protocols & PROTOCOL_NLA) ? 1 : 0,
(rdp->nego->requested_protocols & PROTOCOL_TLS) ? 1 : 0,
(rdp->nego->requested_protocols == PROTOCOL_RDP) ? 1: 0);
(rdp->nego->requested_protocols & PROTOCOL_TLS) ? 1 : 0,
(rdp->nego->requested_protocols == PROTOCOL_RDP) ? 1: 0);
fprintf(stderr, "Server Security: NLA:%d TLS:%d RDP:%d\n",
settings->NlaSecurity, settings->TlsSecurity, settings->RdpSecurity);
@ -648,13 +826,14 @@ BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s)
fprintf(stderr, "Negotiated Security: NLA:%d TLS:%d RDP:%d\n",
(rdp->nego->selected_protocol & PROTOCOL_NLA) ? 1 : 0,
(rdp->nego->selected_protocol & PROTOCOL_TLS) ? 1 : 0,
(rdp->nego->selected_protocol == PROTOCOL_RDP) ? 1: 0);
(rdp->nego->selected_protocol & PROTOCOL_TLS) ? 1 : 0,
(rdp->nego->selected_protocol == PROTOCOL_RDP) ? 1: 0);
if (!nego_send_negotiation_response(rdp->nego))
return FALSE;
status = FALSE;
if (rdp->nego->selected_protocol & PROTOCOL_NLA)
status = transport_accept_nla(rdp->transport);
else if (rdp->nego->selected_protocol & PROTOCOL_TLS)
@ -667,7 +846,7 @@ BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s)
transport_set_blocking_mode(rdp->transport, FALSE);
rdp->state = CONNECTION_STATE_NEGO;
rdp_server_transition_to_state(rdp, CONNECTION_STATE_NEGO);
return TRUE;
}
@ -691,7 +870,7 @@ BOOL rdp_server_accept_mcs_connect_initial(rdpRdp* rdp, wStream* s)
if (!mcs_send_connect_response(rdp->mcs))
return FALSE;
rdp->state = CONNECTION_STATE_MCS_CONNECT;
rdp_server_transition_to_state(rdp, CONNECTION_STATE_MCS_CONNECT);
return TRUE;
}
@ -701,7 +880,7 @@ BOOL rdp_server_accept_mcs_erect_domain_request(rdpRdp* rdp, wStream* s)
if (!mcs_recv_erect_domain_request(rdp->mcs, s))
return FALSE;
rdp->state = CONNECTION_STATE_MCS_ERECT_DOMAIN;
rdp_server_transition_to_state(rdp, CONNECTION_STATE_MCS_ERECT_DOMAIN);
return TRUE;
}
@ -714,7 +893,7 @@ BOOL rdp_server_accept_mcs_attach_user_request(rdpRdp* rdp, wStream* s)
if (!mcs_send_attach_user_confirm(rdp->mcs))
return FALSE;
rdp->state = CONNECTION_STATE_MCS_ATTACH_USER;
rdp_server_transition_to_state(rdp, CONNECTION_STATE_MCS_ATTACH_USER);
return TRUE;
}
@ -745,44 +924,23 @@ BOOL rdp_server_accept_mcs_channel_join_request(rdpRdp* rdp, wStream* s)
all_joined = FALSE;
}
if (rdp->mcs->user_channel_joined && rdp->mcs->global_channel_joined && all_joined)
rdp->state = CONNECTION_STATE_MCS_CHANNEL_JOIN;
return TRUE;
}
BOOL rdp_server_accept_client_keys(rdpRdp* rdp, wStream* s)
{
if (!rdp_server_establish_keys(rdp, s))
return FALSE;
rdp->state = CONNECTION_STATE_ESTABLISH_KEYS;
return TRUE;
}
BOOL rdp_server_accept_client_info(rdpRdp* rdp, wStream* s)
{
if (!rdp_recv_client_info(rdp, s))
return FALSE;
if (!license_send_valid_client_error_packet(rdp->license))
return FALSE;
rdp->state = CONNECTION_STATE_LICENSE;
if ((rdp->mcs->user_channel_joined) && (rdp->mcs->global_channel_joined) && all_joined)
{
rdp_server_transition_to_state(rdp, CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT);
}
return TRUE;
}
BOOL rdp_server_accept_confirm_active(rdpRdp* rdp, wStream* s)
{
if (rdp->state != CONNECTION_STATE_CAPABILITIES_EXCHANGE)
return FALSE;
if (!rdp_recv_confirm_active(rdp, s))
return FALSE;
rdp->state = CONNECTION_STATE_ACTIVE;
update_reset_state(rdp->update);
rdp_server_transition_to_state(rdp, CONNECTION_STATE_FINALIZATION);
if (!rdp_send_server_synchronize_pdu(rdp))
return FALSE;
@ -798,7 +956,7 @@ BOOL rdp_server_reactivate(rdpRdp* rdp)
if (!rdp_send_deactivate_all(rdp))
return FALSE;
rdp->state = CONNECTION_STATE_LICENSE;
rdp_server_transition_to_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE);
if (!rdp_send_demand_active(rdp))
return FALSE;
@ -806,3 +964,107 @@ BOOL rdp_server_reactivate(rdpRdp* rdp)
return TRUE;
}
int rdp_server_transition_to_state(rdpRdp* rdp, int state)
{
int status = 0;
freerdp_peer* client = NULL;
if (rdp->state >= CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT)
client = rdp->context->peer;
if (rdp->state < CONNECTION_STATE_ACTIVE)
{
if (client)
client->activated = FALSE;
}
switch (state)
{
case CONNECTION_STATE_INITIAL:
rdp->state = CONNECTION_STATE_INITIAL;
break;
case CONNECTION_STATE_NEGO:
rdp->state = CONNECTION_STATE_NEGO;
break;
case CONNECTION_STATE_MCS_CONNECT:
rdp->state = CONNECTION_STATE_MCS_CONNECT;
break;
case CONNECTION_STATE_MCS_ERECT_DOMAIN:
rdp->state = CONNECTION_STATE_MCS_ERECT_DOMAIN;
break;
case CONNECTION_STATE_MCS_ATTACH_USER:
rdp->state = CONNECTION_STATE_MCS_ATTACH_USER;
break;
case CONNECTION_STATE_MCS_CHANNEL_JOIN:
rdp->state = CONNECTION_STATE_MCS_CHANNEL_JOIN;
break;
case CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT:
rdp->state = CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT;
break;
case CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE:
rdp->state = CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE;
break;
case CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT:
rdp->state = CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT;
break;
case CONNECTION_STATE_LICENSING:
rdp->state = CONNECTION_STATE_LICENSING;
break;
case CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING:
rdp->state = CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING;
break;
case CONNECTION_STATE_CAPABILITIES_EXCHANGE:
rdp->state = CONNECTION_STATE_CAPABILITIES_EXCHANGE;
rdp->AwaitCapabilities = FALSE;
break;
case CONNECTION_STATE_FINALIZATION:
rdp->state = CONNECTION_STATE_FINALIZATION;
rdp->finalize_sc_pdus = 0;
break;
case CONNECTION_STATE_ACTIVE:
rdp->state = CONNECTION_STATE_ACTIVE;
update_reset_state(rdp->update);
if (client)
{
if (!client->connected)
{
/**
* PostConnect should only be called once and should not
* be called after a reactivation sequence.
*/
IFCALLRET(client->PostConnect, client->connected, client);
if (!client->connected)
return -1;
}
IFCALLRET(client->Activate, client->activated, client);
if (!client->activated)
return -1;
}
break;
default:
status = -1;
break;
}
return status;
}

View File

@ -37,11 +37,14 @@ enum CONNECTION_STATE
CONNECTION_STATE_MCS_ERECT_DOMAIN = 3,
CONNECTION_STATE_MCS_ATTACH_USER = 4,
CONNECTION_STATE_MCS_CHANNEL_JOIN = 5,
CONNECTION_STATE_ESTABLISH_KEYS = 6,
CONNECTION_STATE_LICENSE = 7,
CONNECTION_STATE_CAPABILITY = 8,
CONNECTION_STATE_FINALIZATION = 9,
CONNECTION_STATE_ACTIVE = 10
CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT = 6,
CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE = 7,
CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT = 8,
CONNECTION_STATE_LICENSING = 9,
CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING = 10,
CONNECTION_STATE_CAPABILITIES_EXCHANGE = 11,
CONNECTION_STATE_FINALIZATION = 12,
CONNECTION_STATE_ACTIVE = 13
};
BOOL rdp_client_connect(rdpRdp* rdp);
@ -52,15 +55,16 @@ BOOL rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, wStream* s);
BOOL rdp_client_connect_license(rdpRdp* rdp, wStream* s);
BOOL rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s);
BOOL rdp_client_connect_finalize(rdpRdp* rdp);
int rdp_client_transition_to_state(rdpRdp* rdp, int state);
BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s);
BOOL rdp_server_accept_mcs_connect_initial(rdpRdp* rdp, wStream* s);
BOOL rdp_server_accept_mcs_erect_domain_request(rdpRdp* rdp, wStream* s);
BOOL rdp_server_accept_mcs_attach_user_request(rdpRdp* rdp, wStream* s);
BOOL rdp_server_accept_mcs_channel_join_request(rdpRdp* rdp, wStream* s);
BOOL rdp_server_accept_client_keys(rdpRdp* rdp, wStream* s);
BOOL rdp_server_accept_client_info(rdpRdp* rdp, wStream* s);
BOOL rdp_server_accept_confirm_active(rdpRdp* rdp, wStream* s);
BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s);
BOOL rdp_server_reactivate(rdpRdp* rdp);
int rdp_server_transition_to_state(rdpRdp* rdp, int state);
#endif /* __CONNECTION_H */

View File

@ -443,6 +443,44 @@ static const ERRINFO ERRINFO_CODES[] =
ERRINFO_DEFINE(NONE)
};
const char* freerdp_get_error_info_string(UINT32 code)
{
const ERRINFO* errInfo;
errInfo = &ERRINFO_CODES[0];
while (errInfo->code != ERRINFO_NONE)
{
if (code == errInfo->code)
{
return errInfo->info;
}
errInfo++;
}
return "Unknown error.";
}
const char* freerdp_get_error_info_name(UINT32 code)
{
const ERRINFO* errInfo;
errInfo = &ERRINFO_CODES[0];
while (errInfo->code != ERRINFO_NONE)
{
if (code == errInfo->code)
{
return errInfo->name;
}
errInfo++;
}
return "ERRINFO_UNKNOWN";
}
void rdp_print_errinfo(UINT32 code)
{
const ERRINFO* errInfo;

View File

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

View File

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

View File

@ -156,7 +156,9 @@ static BOOL freerdp_listener_open(freerdp_listener* instance, const char* bind_a
continue;
}
listener->sockfds[listener->num_sockfds++] = sockfd;
listener->sockfds[listener->num_sockfds] = sockfd;
listener->events[listener->num_sockfds] = CreateFileDescriptorEvent(NULL, FALSE, FALSE, sockfd);
listener->num_sockfds++;
if (ai->ai_family == AF_INET)
sin_addr = &(((struct sockaddr_in*) ai->ai_addr)->sin_addr);
@ -211,7 +213,9 @@ static BOOL freerdp_listener_open_local(freerdp_listener* instance, const char*
return FALSE;
}
listener->sockfds[listener->num_sockfds++] = sockfd;
listener->sockfds[listener->num_sockfds] = sockfd;
listener->events[listener->num_sockfds] = CreateFileDescriptorEvent(NULL, FALSE, FALSE, sockfd);
listener->num_sockfds++;
fprintf(stderr, "Listening on socket %s.\n", addr.sun_path);
@ -237,21 +241,38 @@ static void freerdp_listener_close(freerdp_listener* instance)
static BOOL freerdp_listener_get_fds(freerdp_listener* instance, void** rfds, int* rcount)
{
int i;
int index;
rdpListener* listener = (rdpListener*) instance->listener;
if (listener->num_sockfds < 1)
return FALSE;
for (i = 0; i < listener->num_sockfds; i++)
for (index = 0; index < listener->num_sockfds; index++)
{
rfds[*rcount] = (void*)(long)(listener->sockfds[i]);
rfds[*rcount] = (void*)(long)(listener->sockfds[index]);
(*rcount)++;
}
return TRUE;
}
int freerdp_listener_get_event_handles(freerdp_listener* instance, HANDLE* events, DWORD* nCount)
{
int index;
rdpListener* listener = (rdpListener*) instance->listener;
if (listener->num_sockfds < 1)
return -1;
for (index = 0; index < listener->num_sockfds; index++)
{
events[*nCount] = listener->events[index];
(*nCount)++;
}
return 0;
}
static BOOL freerdp_listener_check_fds(freerdp_listener* instance)
{
int i;
@ -327,6 +348,7 @@ freerdp_listener* freerdp_listener_new(void)
instance->Open = freerdp_listener_open;
instance->OpenLocal = freerdp_listener_open_local;
instance->GetFileDescriptor = freerdp_listener_get_fds;
instance->GetEventHandles = freerdp_listener_get_event_handles;
instance->CheckFileDescriptor = freerdp_listener_check_fds;
instance->Close = freerdp_listener_close;

View File

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

View File

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

View File

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

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)
{
return 32;
return 64;
}
BOOL update_write_memblt_order(wStream* s, ORDER_INFO* orderInfo, MEMBLT_ORDER* memblt)
@ -2600,7 +2600,7 @@ BOOL update_read_create_offscreen_bitmap_order(wStream* s, CREATE_OFFSCREEN_BITM
int update_approximate_create_offscreen_bitmap_order(CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap)
{
OFFSCREEN_DELETE_LIST* deleteList = &(create_offscreen_bitmap->deleteList);
return 8 + deleteList->cIndices * 2;
return 32 + deleteList->cIndices * 2;
}
BOOL update_write_create_offscreen_bitmap_order(wStream* s, CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap)

View File

@ -23,6 +23,7 @@
#include <winpr/crt.h>
#include "info.h"
#include "certificate.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;
}
static HANDLE freerdp_peer_get_event_handle(freerdp_peer* client)
{
return client->context->rdp->transport->TcpIn->event;
}
static BOOL freerdp_peer_check_fds(freerdp_peer* client)
{
int status;
@ -105,29 +111,6 @@ static BOOL peer_recv_data_pdu(freerdp_peer* client, wStream* s)
if (!rdp_server_accept_client_font_list_pdu(client->context->rdp, s))
return FALSE;
if (!client->connected)
{
/**
* PostConnect should only be called once and should not be called
* after a reactivation sequence.
*/
IFCALLRET(client->PostConnect, client->connected, client);
if (!client->connected)
return FALSE;
}
if (!client->activated)
{
/* Activate will be called everytime after the client is activated/reactivated. */
IFCALLRET(client->Activate, client->activated, client);
if (!client->activated)
return FALSE;
}
break;
case DATA_PDU_TYPE_SHUTDOWN_REQUEST:
@ -135,7 +118,7 @@ static BOOL peer_recv_data_pdu(freerdp_peer* client, wStream* s)
return FALSE;
case DATA_PDU_TYPE_FRAME_ACKNOWLEDGE:
if(Stream_GetRemainingLength(s) < 4)
if (Stream_GetRemainingLength(s) < 4)
return FALSE;
Stream_Read_UINT32(s, client->ack_frame_id);
IFCALL(client->update->SurfaceFrameAcknowledge, client->update->context, client->ack_frame_id);
@ -194,7 +177,7 @@ static int peer_recv_tpkt_pdu(freerdp_peer* client, wStream* s)
if (channelId != MCS_GLOBAL_CHANNEL_ID)
{
if(!freerdp_channel_peer_process(client, s, channelId))
if (!freerdp_channel_peer_process(client, s, channelId))
return -1;
}
else
@ -211,6 +194,11 @@ static int peer_recv_tpkt_pdu(freerdp_peer* client, wStream* s)
return -1;
break;
case PDU_TYPE_CONFIRM_ACTIVE:
if (!rdp_server_accept_confirm_active(rdp, s))
return -1;
break;
default:
fprintf(stderr, "Client sent pduType %d\n", pduType);
return -1;
@ -228,8 +216,6 @@ static int peer_recv_fastpath_pdu(freerdp_peer* client, wStream* s)
rdp = client->context->rdp;
fastpath = rdp->fastpath;
//if (!fastpath_read_header_rdp(fastpath, s, &length))
// return -1;
fastpath_read_header_rdp(fastpath, s, &length);
@ -301,36 +287,71 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra)
return -1;
break;
case CONNECTION_STATE_MCS_CHANNEL_JOIN:
case CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT:
if (rdp->settings->DisableEncryption)
{
if (!rdp_server_accept_client_keys(rdp, s))
if (!rdp_server_establish_keys(rdp, s))
return -1;
break;
}
rdp->state = CONNECTION_STATE_ESTABLISH_KEYS;
/* FALLTHROUGH */
case CONNECTION_STATE_ESTABLISH_KEYS:
if (!rdp_server_accept_client_info(rdp, s))
return -1;
rdp_server_transition_to_state(rdp, CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE);
return peer_recv_callback(transport, s, extra);
IFCALL(client->Capabilities, client);
if (!rdp_send_demand_active(rdp))
return -1;
break;
case CONNECTION_STATE_LICENSE:
if (!rdp_server_accept_confirm_active(rdp, s))
case CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE:
if (!rdp_recv_client_info(rdp, s))
return -1;
rdp_server_transition_to_state(rdp, CONNECTION_STATE_LICENSING);
return peer_recv_callback(transport, NULL, extra);
break;
case CONNECTION_STATE_LICENSING:
if (!license_send_valid_client_error_packet(rdp->license))
return FALSE;
rdp_server_transition_to_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE);
return peer_recv_callback(transport, NULL, extra);
break;
case CONNECTION_STATE_CAPABILITIES_EXCHANGE:
if (!rdp->AwaitCapabilities)
{
IFCALL(client->Capabilities, client);
if (!rdp_send_demand_active(rdp))
return -1;
rdp->AwaitCapabilities = TRUE;
if (s)
{
if (peer_recv_pdu(client, s) < 0)
return -1;
}
}
else
{
/**
* During reactivation sequence the client might sent some input or channel data
* before receiving the Deactivate All PDU. We need to process them as usual.
*/
Stream_SetPosition(s, 0);
return peer_recv_pdu(client, s);
if (peer_recv_pdu(client, s) < 0)
return -1;
}
break;
case CONNECTION_STATE_FINALIZATION:
if (peer_recv_pdu(client, s) < 0)
return -1;
break;
case CONNECTION_STATE_ACTIVE:
@ -355,6 +376,7 @@ static BOOL freerdp_peer_close(freerdp_peer* client)
*/
if (!rdp_send_deactivate_all(client->context->rdp))
return FALSE;
return mcs_send_disconnect_provider_ultimatum(client->context->rdp->mcs);
}
@ -372,14 +394,15 @@ void freerdp_peer_context_new(freerdp_peer* client)
{
rdpRdp* rdp;
rdp = rdp_new(NULL);
client->context = (rdpContext*) malloc(client->ContextSize);
ZeroMemory(client->context, client->ContextSize);
rdp = rdp_new(client->context);
client->input = rdp->input;
client->update = rdp->update;
client->settings = rdp->settings;
client->context = (rdpContext*) malloc(client->ContextSize);
ZeroMemory(client->context, client->ContextSize);
client->context->rdp = rdp;
client->context->peer = client;
client->context->input = client->input;
@ -414,12 +437,13 @@ freerdp_peer* freerdp_peer_new(int sockfd)
freerdp_tcp_set_no_delay(sockfd, TRUE);
if (client != NULL)
if (client)
{
client->sockfd = sockfd;
client->ContextSize = sizeof(rdpContext);
client->Initialize = freerdp_peer_initialize;
client->GetFileDescriptor = freerdp_peer_get_fds;
client->GetEventHandle = freerdp_peer_get_event_handle;
client->CheckFileDescriptor = freerdp_peer_check_fds;
client->Close = freerdp_peer_close;
client->Disconnect = freerdp_peer_disconnect;

View File

@ -236,8 +236,9 @@ wStream* rdp_data_pdu_init(rdpRdp* rdp)
* @param channel_id channel id
*/
BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channel_id)
BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channelId)
{
BYTE byte;
UINT16 initiator;
enum DomainMCSPDU MCSPDU;
@ -274,8 +275,8 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channel_id
return FALSE;
per_read_integer16(s, &initiator, MCS_BASE_CHANNEL_ID); /* initiator (UserId) */
per_read_integer16(s, channel_id, 0); /* channelId */
Stream_Seek(s, 1); /* dataPriority + Segmentation (0x70) */
per_read_integer16(s, channelId, 0); /* channelId */
Stream_Read_UINT8(s, byte); /* dataPriority + Segmentation (0x70) */
if (!per_read_length(s, length)) /* userData (OCTET_STRING) */
return FALSE;
@ -294,7 +295,7 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channel_id
* @param channel_id channel id
*/
void rdp_write_header(rdpRdp* rdp, wStream* s, UINT16 length, UINT16 channel_id)
void rdp_write_header(rdpRdp* rdp, wStream* s, UINT16 length, UINT16 channelId)
{
int body_length;
enum DomainMCSPDU MCSPDU;
@ -314,10 +315,10 @@ void rdp_write_header(rdpRdp* rdp, wStream* s, UINT16 length, UINT16 channel_id)
mcs_write_domain_mcspdu_header(s, MCSPDU, length, 0);
per_write_integer16(s, rdp->mcs->user_id, MCS_BASE_CHANNEL_ID); /* initiator */
per_write_integer16(s, channel_id, 0); /* channelId */
per_write_integer16(s, channelId, 0); /* channelId */
Stream_Write_UINT8(s, 0x70); /* dataPriority + segmentation */
/*
* We always encode length in two bytes, eventhough we could use
* We always encode length in two bytes, even though we could use
* only one byte if length <= 0x7F. It is just easier that way,
* because we can leave room for fixed-length header, store all
* the data first and then store the header.
@ -926,20 +927,21 @@ static int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra)
status = -1;
break;
case CONNECTION_STATE_LICENSE:
case CONNECTION_STATE_LICENSING:
if (!rdp_client_connect_license(rdp, s))
status = -1;
break;
case CONNECTION_STATE_CAPABILITY:
case CONNECTION_STATE_CAPABILITIES_EXCHANGE:
if (!rdp_client_connect_demand_active(rdp, s))
status = -1;
break;
case CONNECTION_STATE_FINALIZATION:
status = rdp_recv_pdu(rdp, s);
if ((status >= 0) && (rdp->finalize_sc_pdus == FINALIZE_SC_COMPLETE))
rdp->state = CONNECTION_STATE_ACTIVE;
rdp_client_transition_to_state(rdp, CONNECTION_STATE_ACTIVE);
break;
case CONNECTION_STATE_ACTIVE:
@ -982,23 +984,25 @@ int rdp_check_fds(rdpRdp* rdp)
* @return new RDP module
*/
rdpRdp* rdp_new(freerdp* instance)
rdpRdp* rdp_new(rdpContext* context)
{
rdpRdp* rdp;
rdp = (rdpRdp*) malloc(sizeof(rdpRdp));
if (rdp != NULL)
if (rdp)
{
ZeroMemory(rdp, sizeof(rdpRdp));
rdp->instance = instance;
rdp->settings = freerdp_settings_new((void*) instance);
rdp->context = context;
if (instance != NULL)
instance->settings = rdp->settings;
rdp->instance = context->instance;
rdp->settings = freerdp_settings_new((void*) context->instance);
rdp->extension = extension_new(instance);
if (context->instance)
context->instance->settings = rdp->settings;
rdp->extension = extension_new(context->instance);
rdp->transport = transport_new(rdp->settings);
rdp->license = license_new(rdp);
rdp->input = input_new(rdp);

View File

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

View File

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

View File

@ -253,6 +253,13 @@ BOOL tcp_set_keep_alive_mode(rdpTcp* tcp)
return TRUE;
}
int tcp_attach(rdpTcp* tcp, int sockfd)
{
tcp->sockfd = sockfd;
SetEventFileDescriptor(tcp->event, tcp->sockfd);
return 0;
}
HANDLE tcp_get_event_handle(rdpTcp* tcp)
{
#ifndef _WIN32

View File

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

View File

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

View File

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

View File

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

View File

@ -214,6 +214,11 @@ static const RDP_KEYBOARD_IME RDP_KEYBOARD_IME_TABLE[] =
{ KBD_CHINESE_TRADITIONAL_ALPHANUMERIC, "romanime.ime", "Chinese (Traditional) - Alphanumeric" }
};
void freerdp_keyboard_layouts_free(RDP_KEYBOARD_LAYOUT* layouts)
{
free(layouts);
}
RDP_KEYBOARD_LAYOUT* freerdp_keyboard_get_layouts(DWORD types)
{
int num, length, i;

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)
add_subdirectory(include)
if(NOT WITH_WAYK)
add_subdirectory(include)
endif()
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 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> */
struct _wKeyValuePair

View File

@ -302,6 +302,12 @@ extern "C" {
WINPR_API BOOL FilePatternMatchA(LPCSTR lpFileName, LPCSTR lpPattern);
WINPR_API LPSTR FilePatternFindNextWildcardA(LPCSTR lpPattern, DWORD* pFlags);
WINPR_API int UnixChangeFileMode(const char* filename, int flags);
WINPR_API char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName);
WINPR_API char* GetNamedPipeUnixDomainSocketBaseFilePathA();
WINPR_API char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName);
#ifdef __cplusplus
}
#endif

View File

@ -25,6 +25,25 @@
#ifndef _WIN32
#define GENERIC_READ 0x80000000
#define GENERIC_WRITE 0x40000000
#define GENERIC_EXECUTE 0x20000000
#define GENERIC_ALL 0x10000000
#define DELETE 0x00010000
#define READ_CONTROL 0x00020000
#define WRITE_DAC 0x00040000
#define WRITE_OWNER 0x00080000
#define SYNCHRONIZE 0x00100000
#define STANDARD_RIGHTS_REQUIRED 0x000F0000
#define STANDARD_RIGHTS_READ 0x00020000
#define STANDARD_RIGHTS_WRITE 0x00020000
#define STANDARD_RIGHTS_EXECUTE 0x00020000
#define STANDARD_RIGHTS_ALL 0x001F0000
#define SPECIFIC_RIGHTS_ALL 0x0000FFFF
#define ACCESS_SYSTEM_SECURITY 0x01000000
#define MAXIMUM_ALLOWED 0x02000000
typedef struct _OVERLAPPED
{
ULONG_PTR Internal;

View File

@ -28,12 +28,92 @@
#ifndef _WIN32
#define PIPE_UNLIMITED_INSTANCES 0xFF
#define PIPE_ACCESS_INBOUND 0x00000001
#define PIPE_ACCESS_OUTBOUND 0x00000002
#define PIPE_ACCESS_DUPLEX 0x00000003
#define FILE_FLAG_FIRST_PIPE_INSTANCE 0x00080000
#define FILE_FLAG_WRITE_THROUGH 0x80000000
#define FILE_FLAG_OVERLAPPED 0x40000000
#define PIPE_CLIENT_END 0x00000000
#define PIPE_SERVER_END 0x00000001
#define PIPE_TYPE_BYTE 0x00000000
#define PIPE_TYPE_MESSAGE 0x00000004
#define PIPE_READMODE_BYTE 0x00000000
#define PIPE_READMODE_MESSAGE 0x00000002
#define PIPE_WAIT 0x00000000
#define PIPE_NOWAIT 0x00000001
#define PIPE_ACCEPT_REMOTE_CLIENTS 0x00000000
#define PIPE_REJECT_REMOTE_CLIENTS 0x00000008
#define NMPWAIT_USE_DEFAULT_WAIT 0x00000000
#define NMPWAIT_NOWAIT 0x00000001
#define NMPWAIT_WAIT_FOREVER 0xFFFFFFFF
#ifdef __cplusplus
extern "C" {
#endif
/**
* Unnamed pipe
*/
WINPR_API BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize);
/**
* Named pipe
*/
WINPR_API HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances,
DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes);
WINPR_API HANDLE CreateNamedPipeW(LPCWSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances,
DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes);
WINPR_API BOOL ConnectNamedPipe(HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped);
WINPR_API BOOL DisconnectNamedPipe(HANDLE hNamedPipe);
WINPR_API BOOL PeekNamedPipe(HANDLE hNamedPipe, LPVOID lpBuffer, DWORD nBufferSize,
LPDWORD lpBytesRead, LPDWORD lpTotalBytesAvail, LPDWORD lpBytesLeftThisMessage);
WINPR_API BOOL TransactNamedPipe(HANDLE hNamedPipe, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize, LPDWORD lpBytesRead, LPOVERLAPPED lpOverlapped);
WINPR_API BOOL WaitNamedPipeA(LPCSTR lpNamedPipeName, DWORD nTimeOut);
WINPR_API BOOL WaitNamedPipeW(LPCWSTR lpNamedPipeName, DWORD nTimeOut);
WINPR_API BOOL SetNamedPipeHandleState(HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout);
WINPR_API BOOL ImpersonateNamedPipeClient(HANDLE hNamedPipe);
WINPR_API BOOL GetNamedPipeClientComputerNameA(HANDLE Pipe, LPCSTR ClientComputerName, ULONG ClientComputerNameLength);
WINPR_API BOOL GetNamedPipeClientComputerNameW(HANDLE Pipe, LPCWSTR ClientComputerName, ULONG ClientComputerNameLength);
#ifdef UNICODE
#define CreateNamedPipe CreateNamedPipeW
#define WaitNamedPipe WaitNamedPipeW
#define GetNamedPipeClientComputerName GetNamedPipeClientComputerNameW
#else
#define CreateNamedPipe CreateNamedPipeA
#define WaitNamedPipe WaitNamedPipeA
#define GetNamedPipeClientComputerName GetNamedPipeClientComputerNameA
#endif
/**
* Extended API
*/
WINPR_API char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName);
WINPR_API char* GetNamedPipeUnixDomainSocketBaseFilePathA();
WINPR_API char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName);
#ifdef __cplusplus
}
#endif

View File

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

View File

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

View File

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

View File

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

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
MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL
MODULE winpr
MODULES winpr-crt winpr-handle)
MODULES winpr-crt winpr-handle winpr-path)
if(MONOLITHIC_BUILD)

View File

@ -22,6 +22,7 @@
#endif
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/handle.h>
#include <winpr/file.h>
@ -125,13 +126,21 @@
#ifndef _WIN32
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <sys/socket.h>
#ifdef ANDROID
#include <sys/vfs.h>
@ -146,7 +155,59 @@
HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
{
return NULL;
char* name;
int status;
HANDLE hNamedPipe;
unsigned long flags;
struct sockaddr_un s;
WINPR_NAMED_PIPE* pNamedPipe;
if (!lpFileName)
return INVALID_HANDLE_VALUE;
name = GetNamedPipeNameWithoutPrefixA(lpFileName);
if (!name)
return INVALID_HANDLE_VALUE;
free(name);
pNamedPipe = (WINPR_NAMED_PIPE*) malloc(sizeof(WINPR_NAMED_PIPE));
hNamedPipe = (HANDLE) pNamedPipe;
WINPR_HANDLE_SET_TYPE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE);
pNamedPipe->name = _strdup(lpFileName);
pNamedPipe->dwOpenMode = 0;
pNamedPipe->dwPipeMode = 0;
pNamedPipe->nMaxInstances = 0;
pNamedPipe->nOutBufferSize = 0;
pNamedPipe->nInBufferSize = 0;
pNamedPipe->nDefaultTimeOut = 0;
pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpFileName);
pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpFileName);
pNamedPipe->clientfd = socket(PF_LOCAL, SOCK_STREAM, 0);
pNamedPipe->serverfd = -1;
if (0)
{
flags = fcntl(pNamedPipe->clientfd, F_GETFL);
flags = flags | O_NONBLOCK;
fcntl(pNamedPipe->clientfd, F_SETFL, flags);
}
ZeroMemory(&s, sizeof(struct sockaddr_un));
s.sun_family = AF_UNIX;
strcpy(s.sun_path, pNamedPipe->lpFilePath);
status = connect(pNamedPipe->clientfd, (struct sockaddr*) &s, sizeof(struct sockaddr_un));
if (status != 0)
return INVALID_HANDLE_VALUE;
return hNamedPipe;
}
HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
@ -170,7 +231,6 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
{
ULONG Type;
PVOID Object;
WINPR_PIPE* pipe;
if (!winpr_Handle_GetInfo(hFile, &Type, &Object))
return FALSE;
@ -178,6 +238,7 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
if (Type == HANDLE_TYPE_ANONYMOUS_PIPE)
{
int status;
WINPR_PIPE* pipe;
pipe = (WINPR_PIPE*) Object;
@ -187,6 +248,30 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
return TRUE;
}
else if (Type == HANDLE_TYPE_NAMED_PIPE)
{
int status;
WINPR_NAMED_PIPE* pipe;
pipe = (WINPR_NAMED_PIPE*) Object;
status = nNumberOfBytesToRead;
if (pipe->clientfd != -1)
status = read(pipe->clientfd, lpBuffer, nNumberOfBytesToRead);
else
return FALSE;
if (status < 0)
{
*lpNumberOfBytesRead = 0;
return FALSE;
}
*lpNumberOfBytesRead = status;
return TRUE;
}
return FALSE;
}
@ -208,7 +293,6 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
{
ULONG Type;
PVOID Object;
WINPR_PIPE* pipe;
if (!winpr_Handle_GetInfo(hFile, &Type, &Object))
return FALSE;
@ -216,6 +300,7 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
if (Type == HANDLE_TYPE_ANONYMOUS_PIPE)
{
int status;
WINPR_PIPE* pipe;
pipe = (WINPR_PIPE*) Object;
@ -225,6 +310,30 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
return TRUE;
}
else if (Type == HANDLE_TYPE_NAMED_PIPE)
{
int status;
WINPR_NAMED_PIPE* pipe;
pipe = (WINPR_NAMED_PIPE*) Object;
status = nNumberOfBytesToWrite;
if (pipe->clientfd != -1)
status = write(pipe->clientfd, lpBuffer, nNumberOfBytesToWrite);
else
return FALSE;
if (status < 0)
{
*lpNumberOfBytesWritten = 0;
return FALSE;
}
*lpNumberOfBytesWritten = status;
return TRUE;
}
return FALSE;
}
@ -445,3 +554,72 @@ BOOL CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttrib
#endif
/* Extended API */
#define NAMED_PIPE_PREFIX_PATH "\\\\.\\pipe\\"
char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName)
{
char* lpFileName;
if (!lpName)
return NULL;
if (strncmp(lpName, NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH) - 1) != 0)
return NULL;
lpFileName = _strdup(&lpName[strlen(NAMED_PIPE_PREFIX_PATH)]);
return lpFileName;
}
char* GetNamedPipeUnixDomainSocketBaseFilePathA()
{
char* lpTempPath;
char* lpPipePath;
lpTempPath = GetKnownPath(KNOWN_PATH_TEMP);
lpPipePath = GetCombinedPath(lpTempPath, ".pipe");
free(lpTempPath);
return lpPipePath;
}
char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName)
{
char* lpPipePath;
char* lpFileName;
char* lpFilePath;
lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA();
lpFileName = GetNamedPipeNameWithoutPrefixA(lpName);
lpFilePath = GetCombinedPath(lpPipePath, (char*) lpFileName);
free(lpPipePath);
free(lpFileName);
return lpFilePath;
}
int UnixChangeFileMode(const char* filename, int flags)
{
mode_t fl = 0;
fl |= (flags & 0x4000) ? S_ISUID : 0;
fl |= (flags & 0x2000) ? S_ISGID : 0;
fl |= (flags & 0x1000) ? S_ISVTX : 0;
fl |= (flags & 0x0400) ? S_IRUSR : 0;
fl |= (flags & 0x0200) ? S_IWUSR : 0;
fl |= (flags & 0x0100) ? S_IXUSR : 0;
fl |= (flags & 0x0040) ? S_IRGRP : 0;
fl |= (flags & 0x0020) ? S_IWGRP : 0;
fl |= (flags & 0x0010) ? S_IXGRP : 0;
fl |= (flags & 0x0004) ? S_IROTH : 0;
fl |= (flags & 0x0002) ? S_IWOTH : 0;
fl |= (flags & 0x0001) ? S_IXOTH : 0;
return chmod(filename, fl);
}

View File

@ -122,6 +122,21 @@ BOOL CloseHandle(HANDLE hObject)
return TRUE;
}
else if (Type == HANDLE_TYPE_TIMER)
{
WINPR_TIMER* timer;
timer = (WINPR_TIMER*) Object;
#ifdef __linux__
if (timer->fd != -1)
close(timer->fd);
#endif
free(Object);
return TRUE;
}
else if (Type == HANDLE_TYPE_ANONYMOUS_PIPE)
{
WINPR_PIPE* pipe;
@ -137,6 +152,22 @@ BOOL CloseHandle(HANDLE hObject)
return TRUE;
}
else if (Type == HANDLE_TYPE_NAMED_PIPE)
{
WINPR_NAMED_PIPE* pipe;
pipe = (WINPR_NAMED_PIPE*) Object;
if (pipe->clientfd != -1)
close(pipe->clientfd);
if (pipe->serverfd != -1)
close(pipe->serverfd);
free(Object);
return TRUE;
}
return FALSE;
}

View File

@ -22,6 +22,7 @@
#endif
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/handle.h>
#include <winpr/pipe.h>
@ -34,8 +35,17 @@
#include "../handle/handle.h"
#include <fcntl.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include "pipe.h"
/*
* Unnamed pipe
*/
BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize)
{
int pipe_fd[2];
@ -69,4 +79,169 @@ BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpP
return TRUE;
}
/**
* Named pipe
*/
HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances,
DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
{
int status;
HANDLE hNamedPipe;
char* lpPipePath;
unsigned long flags;
struct sockaddr_un s;
WINPR_NAMED_PIPE* pNamedPipe;
if (!lpName)
return INVALID_HANDLE_VALUE;
pNamedPipe = (WINPR_NAMED_PIPE*) malloc(sizeof(WINPR_NAMED_PIPE));
hNamedPipe = (HANDLE) pNamedPipe;
WINPR_HANDLE_SET_TYPE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE);
pNamedPipe->name = _strdup(lpName);
pNamedPipe->dwOpenMode = dwOpenMode;
pNamedPipe->dwPipeMode = dwPipeMode;
pNamedPipe->nMaxInstances = nMaxInstances;
pNamedPipe->nOutBufferSize = nOutBufferSize;
pNamedPipe->nInBufferSize = nInBufferSize;
pNamedPipe->nDefaultTimeOut = nDefaultTimeOut;
pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpName);
pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpName);
lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA();
if (!PathFileExistsA(lpPipePath))
CreateDirectoryA(lpPipePath, 0);
free(lpPipePath);
pNamedPipe->clientfd = -1;
pNamedPipe->serverfd = socket(PF_LOCAL, SOCK_STREAM, 0);
if (0)
{
flags = fcntl(pNamedPipe->serverfd, F_GETFL);
flags = flags | O_NONBLOCK;
fcntl(pNamedPipe->serverfd, F_SETFL, flags);
}
ZeroMemory(&s, sizeof(struct sockaddr_un));
s.sun_family = AF_UNIX;
strcpy(s.sun_path, pNamedPipe->lpFilePath);
unlink(s.sun_path);
status = bind(pNamedPipe->serverfd, (struct sockaddr*) &s, sizeof(struct sockaddr_un));
if (status == 0)
{
status = listen(pNamedPipe->serverfd, 2);
if (status == 0)
{
UnixChangeFileMode(pNamedPipe->lpFilePath, 0xFFFF);
}
}
return hNamedPipe;
}
HANDLE CreateNamedPipeW(LPCWSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances,
DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
{
return NULL;
}
BOOL ConnectNamedPipe(HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped)
{
int status;
socklen_t length;
struct sockaddr_un s;
WINPR_NAMED_PIPE* pNamedPipe;
if (!hNamedPipe)
return FALSE;
pNamedPipe = (WINPR_NAMED_PIPE*) hNamedPipe;
length = sizeof(struct sockaddr_un);
ZeroMemory(&s, sizeof(struct sockaddr_un));
status = accept(pNamedPipe->serverfd, (struct sockaddr*) &s, &length);
if (status < 0)
return FALSE;
pNamedPipe->clientfd = status;
return TRUE;
}
BOOL DisconnectNamedPipe(HANDLE hNamedPipe)
{
WINPR_NAMED_PIPE* pNamedPipe;
pNamedPipe = (WINPR_NAMED_PIPE*) hNamedPipe;
if (pNamedPipe->clientfd != -1)
{
close(pNamedPipe->clientfd);
pNamedPipe->clientfd = -1;
}
return TRUE;
}
BOOL PeekNamedPipe(HANDLE hNamedPipe, LPVOID lpBuffer, DWORD nBufferSize,
LPDWORD lpBytesRead, LPDWORD lpTotalBytesAvail, LPDWORD lpBytesLeftThisMessage)
{
return TRUE;
}
BOOL TransactNamedPipe(HANDLE hNamedPipe, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize, LPDWORD lpBytesRead, LPOVERLAPPED lpOverlapped)
{
return TRUE;
}
BOOL WaitNamedPipeA(LPCSTR lpNamedPipeName, DWORD nTimeOut)
{
return TRUE;
}
BOOL WaitNamedPipeW(LPCWSTR lpNamedPipeName, DWORD nTimeOut)
{
return TRUE;
}
BOOL SetNamedPipeHandleState(HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout)
{
WINPR_NAMED_PIPE* pNamedPipe;
pNamedPipe = (WINPR_NAMED_PIPE*) hNamedPipe;
if (lpMode)
pNamedPipe->dwPipeMode = *lpMode;
return TRUE;
}
BOOL ImpersonateNamedPipeClient(HANDLE hNamedPipe)
{
return FALSE;
}
BOOL GetNamedPipeClientComputerNameA(HANDLE Pipe, LPCSTR ClientComputerName, ULONG ClientComputerNameLength)
{
return FALSE;
}
BOOL GetNamedPipeClientComputerNameW(HANDLE Pipe, LPCWSTR ClientComputerName, ULONG ClientComputerNameLength)
{
return FALSE;
}
#endif

View File

@ -34,6 +34,26 @@ struct winpr_pipe
};
typedef struct winpr_pipe WINPR_PIPE;
struct winpr_named_pipe
{
WINPR_HANDLE_DEF();
int clientfd;
int serverfd;
const char* name;
const char* lpFileName;
const char* lpFilePath;
DWORD dwOpenMode;
DWORD dwPipeMode;
DWORD nMaxInstances;
DWORD nOutBufferSize;
DWORD nInBufferSize;
DWORD nDefaultTimeOut;
};
typedef struct winpr_named_pipe WINPR_NAMED_PIPE;
#endif
#endif /* WINPR_PIPE_PRIVATE_H */

View File

@ -5,7 +5,9 @@ set(MODULE_PREFIX "TEST_PIPE")
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS
TestPipeCreatePipe.c)
TestPipeCreatePipe.c
TestPipeCreateNamedPipe.c
TestPipeCreateNamedPipeOverlapped.c)
create_test_sourcelist(${MODULE_PREFIX}_SRCS
${${MODULE_PREFIX}_DRIVER}
@ -16,7 +18,7 @@ add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-pipe)
MODULES winpr-pipe winpr-io winpr-synch winpr-thread winpr-error winpr-utils)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})

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);
handle = (HANDLE) event;
if (bInitialState)
SetEvent(handle);
}
if (!cs.LockSemaphore)

View File

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

View File

@ -20,6 +20,12 @@
#ifndef 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>
#ifndef _WIN32
@ -68,6 +74,29 @@ struct 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 /* 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}_TESTS
TestSynchCritical.c)
TestSynchEvent.c
TestSynchMutex.c
TestSynchCritical.c
TestSynchSemaphore.c
TestSynchWaitableTimer.c)
create_test_sourcelist(${MODULE_PREFIX}_SRCS
${${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"
#endif
#include <winpr/crt.h>
#include <winpr/synch.h>
/**
* CreateWaitableTimerExW
* OpenWaitableTimerW
* SetWaitableTimer
* SetWaitableTimerEx
* CancelWaitableTimer
*/
#include "synch.h"
#ifndef _WIN32
HANDLE CreateWaitableTimerExA(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess)
#include "../handle/handle.h"
HANDLE CreateWaitableTimerA(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCSTR lpTimerName)
{
HANDLE handle = NULL;
WINPR_TIMER* timer;
timer = (WINPR_TIMER*) malloc(sizeof(WINPR_TIMER));
if (timer)
{
int status = 0;
WINPR_HANDLE_SET_TYPE(timer, HANDLE_TYPE_TIMER);
handle = (HANDLE) timer;
timer->fd = -1;
timer->lPeriod = 0;
timer->bManualReset = bManualReset;
timer->pfnCompletionRoutine = NULL;
timer->lpArgToCompletionRoutine = NULL;
#ifdef HAVE_TIMERFD_H
timer->fd = timerfd_create(CLOCK_MONOTONIC, 0);
if (timer->fd <= 0)
return NULL;
status = fcntl(timer->fd, F_SETFL, O_NONBLOCK);
if (status)
return NULL;
#endif
}
return handle;
}
HANDLE CreateWaitableTimerW(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCWSTR lpTimerName)
{
return NULL;
}
HANDLE CreateWaitableTimerExA(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess)
{
BOOL bManualReset;
bManualReset = (dwFlags & CREATE_WAITABLE_TIMER_MANUAL_RESET) ? TRUE : FALSE;
return CreateWaitableTimerA(lpTimerAttributes, bManualReset, lpTimerName);
}
HANDLE CreateWaitableTimerExW(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess)
{
return NULL;
@ -46,12 +89,98 @@ HANDLE CreateWaitableTimerExW(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR l
BOOL SetWaitableTimer(HANDLE hTimer, const LARGE_INTEGER* lpDueTime, LONG lPeriod,
PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, BOOL fResume)
{
ULONG Type;
PVOID Object;
int status = 0;
WINPR_TIMER* timer;
LONGLONG seconds = 0;
LONGLONG nanoseconds = 0;
if (!winpr_Handle_GetInfo(hTimer, &Type, &Object))
return FALSE;
if (Type != HANDLE_TYPE_TIMER)
return FALSE;
if (!lpDueTime)
return FALSE;
if (lPeriod < 0)
return FALSE;
timer = (WINPR_TIMER*) Object;
timer->lPeriod = lPeriod; /* milliseconds */
timer->pfnCompletionRoutine = pfnCompletionRoutine;
timer->lpArgToCompletionRoutine = lpArgToCompletionRoutine;
#ifdef HAVE_TIMERFD_H
ZeroMemory(&(timer->timeout), sizeof(struct itimerspec));
if (lpDueTime->QuadPart < 0)
{
LONGLONG due = lpDueTime->QuadPart * (-1);
/* due time is in 100 nanosecond intervals */
seconds = (due / 10000000);
nanoseconds = ((due % 10000000) * 100);
}
else if (lpDueTime->QuadPart == 0)
{
seconds = nanoseconds = 0;
}
else
{
printf("SetWaitableTimer: implement absolute time\n");
return FALSE;
}
if (lPeriod > 0)
{
timer->timeout.it_interval.tv_sec = (lPeriod / 1000); /* seconds */
timer->timeout.it_interval.tv_nsec = ((lPeriod % 1000) * 1000000); /* nanoseconds */
}
if (lpDueTime->QuadPart != 0)
{
timer->timeout.it_value.tv_sec = seconds; /* seconds */
timer->timeout.it_value.tv_nsec = nanoseconds; /* nanoseconds */
}
else
{
timer->timeout.it_value.tv_sec = timer->timeout.it_interval.tv_sec; /* seconds */
timer->timeout.it_value.tv_nsec = timer->timeout.it_interval.tv_nsec; /* nanoseconds */
}
status = timerfd_settime(timer->fd, 0, &(timer->timeout), NULL);
if (status)
{
printf("SetWaitableTimer timerfd_settime failure: %d\n", status);
return FALSE;
}
#endif
return TRUE;
}
BOOL SetWaitableTimerEx(HANDLE hTimer, const LARGE_INTEGER* lpDueTime, LONG lPeriod,
PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, PREASON_CONTEXT WakeContext, ULONG TolerableDelay)
{
ULONG Type;
PVOID Object;
WINPR_TIMER* timer;
if (!winpr_Handle_GetInfo(hTimer, &Type, &Object))
return FALSE;
if (Type == HANDLE_TYPE_TIMER)
{
timer = (WINPR_TIMER*) Object;
return TRUE;
}
return TRUE;
}

View File

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

View File

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

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
TestPubSub.c
TestArrayList.c
TestLinkedList.c
TestListDictionary.c
TestCmdLine.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})
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries)
add_subdirectory(cli)
if(NOT WITH_WAYK)
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries)
add_subdirectory(cli)
endif()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Tools")