Merge pull request #1390 from awakecoding/master
Server-side core fixes, WinPR waitable timers & named pipes, Multitouch fixes
This commit is contained in:
commit
0e8dfb9e77
@ -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()
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -57,4 +57,4 @@ endif()
|
||||
|
||||
if (WITH_DOTNET)
|
||||
add_subdirectory(DotNetClient)
|
||||
endif()
|
||||
endif()
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -18,6 +18,8 @@
|
||||
MRDPView* mrdpView;
|
||||
}
|
||||
|
||||
- (void) rdpConnectError: (NSString*) customMessage;
|
||||
|
||||
@property (assign) IBOutlet NSWindow *window;
|
||||
@property (assign) rdpContext *context;
|
||||
|
||||
|
@ -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];
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -44,6 +44,7 @@ struct mf_context
|
||||
int client_height;
|
||||
|
||||
HANDLE keyboardThread;
|
||||
HANDLE stopEvent;
|
||||
|
||||
HGDI_DC hdc;
|
||||
UINT16 srcBpp;
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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")
|
||||
|
||||
|
@ -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
40
cmake/FindPixman.cmake
Normal 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)
|
@ -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()
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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
9
include/freerdp/error.h
Normal file → Executable 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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
@ -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";
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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])
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)) ||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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})
|
||||
|
||||
|
181
winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c
Normal file
181
winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c
Normal 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;
|
||||
}
|
||||
|
240
winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c
Normal file
240
winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c
Normal 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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -25,16 +25,6 @@
|
||||
|
||||
#include "synch.h"
|
||||
|
||||
/**
|
||||
* CreateMutexA
|
||||
* CreateMutexW
|
||||
* CreateMutexExA
|
||||
* CreateMutexExW
|
||||
* OpenMutexA
|
||||
* OpenMutexW
|
||||
* ReleaseMutex
|
||||
*/
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include "../handle/handle.h"
|
||||
|
@ -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 */
|
||||
|
@ -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}
|
||||
|
42
winpr/libwinpr/synch/test/TestSynchEvent.c
Normal file
42
winpr/libwinpr/synch/test/TestSynchEvent.c
Normal 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;
|
||||
}
|
21
winpr/libwinpr/synch/test/TestSynchMutex.c
Normal file
21
winpr/libwinpr/synch/test/TestSynchMutex.c
Normal 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;
|
||||
}
|
||||
|
21
winpr/libwinpr/synch/test/TestSynchSemaphore.c
Normal file
21
winpr/libwinpr/synch/test/TestSynchSemaphore.c
Normal 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;
|
||||
}
|
||||
|
71
winpr/libwinpr/synch/test/TestSynchWaitableTimer.c
Normal file
71
winpr/libwinpr/synch/test/TestSynchWaitableTimer.c
Normal 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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
339
winpr/libwinpr/utils/collections/LinkedList.c
Normal file
339
winpr/libwinpr/utils/collections/LinkedList.c
Normal 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);
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ set(${MODULE_PREFIX}_TESTS
|
||||
TestPrint.c
|
||||
TestPubSub.c
|
||||
TestArrayList.c
|
||||
TestLinkedList.c
|
||||
TestListDictionary.c
|
||||
TestCmdLine.c
|
||||
TestStreamPool.c
|
||||
|
114
winpr/libwinpr/utils/test/TestLinkedList.c
Normal file
114
winpr/libwinpr/utils/test/TestLinkedList.c
Normal 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;
|
||||
}
|
||||
|
@ -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")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user