rail server: implement channel code for rail server

* Split common functionality from client code
* Clean up client code and use proper defines for constants
* Implements the channel code to read/write server side
  messages.
This commit is contained in:
Mati Shabtay 2019-07-04 10:58:08 +03:00 committed by akallabeth
parent 8298728663
commit 4dacb57f6f
16 changed files with 2487 additions and 645 deletions

View File

@ -20,3 +20,7 @@ define_channel("rail")
if(WITH_CLIENT_CHANNELS)
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()
if(WITH_SERVER_CHANNELS)
add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()

View File

@ -129,11 +129,11 @@ static UINT rail_client_execute(RailClientContext* context, const RAIL_EXEC_ORDE
if (!exeOrFile)
return ERROR_INVALID_PARAMETER;
if (!rail_string_to_unicode_string(exec->RemoteApplicationProgram,
if (!utf8_string_to_rail_string(exec->RemoteApplicationProgram,
&ruExeOrFile) || /* RemoteApplicationProgram */
!rail_string_to_unicode_string(exec->RemoteApplicationWorkingDir,
!utf8_string_to_rail_string(exec->RemoteApplicationWorkingDir,
&ruWorkingDir) || /* ShellWorkingDirectory */
!rail_string_to_unicode_string(exec->RemoteApplicationArguments,
!utf8_string_to_rail_string(exec->RemoteApplicationArguments,
&ruArguments)) /* RemoteApplicationCmdLine */
error = ERROR_INTERNAL_ERROR;
else
@ -219,7 +219,9 @@ static UINT rail_send_client_sysparam(RailClientContext* context, RAIL_SYSPARAM_
return CHANNEL_RC_NO_MEMORY;
}
if ((error = rail_write_client_sysparam_order(rail, s, sysparam)))
if ((error = rail_write_sysparam_order(
s, sysparam,
(rail->channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED) != 0)))
{
WLog_ERR(TAG, "rail_write_client_sysparam_order failed with error %" PRIu32 "!", error);
Stream_Free(s, TRUE);
@ -331,20 +333,6 @@ static UINT rail_client_system_param(RailClientContext* context,
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_server_system_param(RailClientContext* context,
const RAIL_SYSPARAM_ORDER* sysparam)
{
if (!context || !sysparam)
return ERROR_INVALID_PARAMETER;
return CHANNEL_RC_OK; /* stub - should be registered by client */
}
/**
* Function description
*
@ -378,36 +366,6 @@ static UINT rail_client_handshake(RailClientContext* context, const RAIL_HANDSHA
return rail_send_handshake_order(rail, handshake);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_server_handshake(RailClientContext* context, const RAIL_HANDSHAKE_ORDER* handshake)
{
if (!context || !handshake)
return ERROR_INVALID_PARAMETER;
return CHANNEL_RC_OK; /* stub - should be registered by client */
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_server_handshake_ex(RailClientContext* context,
const RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
{
railPlugin* rail;
if (!context || !handshakeEx)
return ERROR_INVALID_PARAMETER;
rail = (railPlugin*)context->handle;
return CHANNEL_RC_OK;
}
/**
* Function description
*
@ -442,34 +400,6 @@ static UINT rail_client_window_move(RailClientContext* context,
return rail_send_client_window_move_order(rail, windowMove);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_server_local_move_size(RailClientContext* context,
const RAIL_LOCALMOVESIZE_ORDER* localMoveSize)
{
if (!context || !localMoveSize)
return ERROR_INVALID_PARAMETER;
return CHANNEL_RC_OK; /* stub - should be registered by client */
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_server_min_max_info(RailClientContext* context,
const RAIL_MINMAXINFO_ORDER* minMaxInfo)
{
if (!context || !minMaxInfo)
return ERROR_INVALID_PARAMETER;
return CHANNEL_RC_OK; /* stub - should be registered by client */
}
/**
* Function description
*
@ -520,20 +450,6 @@ static UINT rail_client_language_bar_info(RailClientContext* context,
return rail_send_client_langbar_info_order(rail, langBarInfo);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_server_language_bar_info(RailClientContext* context,
const RAIL_LANGBAR_INFO_ORDER* langBarInfo)
{
if (!context || !langBarInfo)
return ERROR_INVALID_PARAMETER;
return CHANNEL_RC_OK; /* stub - should be registered by client */
}
static UINT rail_client_language_ime_info(RailClientContext* context,
const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo)
{
@ -546,20 +462,6 @@ static UINT rail_client_language_ime_info(RailClientContext* context,
return rail_send_client_languageime_info_order(rail, langImeInfo);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_server_execute_result(RailClientContext* context,
const RAIL_EXEC_RESULT_ORDER* execResult)
{
if (!context || !execResult)
return ERROR_INVALID_PARAMETER;
return CHANNEL_RC_OK; /* stub - should be registered by client */
}
/**
* Function description
*
@ -577,6 +479,18 @@ static UINT rail_client_get_appid_request(RailClientContext* context,
return rail_send_client_get_appid_req_order(rail, getAppIdReq);
}
static UINT rail_client_compartment_info(RailClientContext* context,
const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
{
railPlugin* rail;
if (!context || !compartmentInfo || !context->handle)
return ERROR_INVALID_PARAMETER;
rail = (railPlugin*)context->handle;
return rail_send_client_compartment_info_order(rail, compartmentInfo);
}
static UINT rail_client_cloak(RailClientContext* context, const RAIL_CLOAK* cloak)
{
railPlugin* rail;
@ -585,7 +499,7 @@ static UINT rail_client_cloak(RailClientContext* context, const RAIL_CLOAK* cloa
return ERROR_INVALID_PARAMETER;
rail = (railPlugin*)context->handle;
return rail_send_client_order_cloak_order(rail, cloak);
return rail_send_client_cloak_order(rail, cloak);
}
static UINT rail_client_snap_arrange(RailClientContext* context, const RAIL_SNAP_ARRANGE* snap)
@ -596,21 +510,7 @@ static UINT rail_client_snap_arrange(RailClientContext* context, const RAIL_SNAP
return ERROR_INVALID_PARAMETER;
rail = (railPlugin*)context->handle;
return rail_send_client_order_snap_arrange_order(rail, snap);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_server_get_appid_response(RailClientContext* context,
const RAIL_GET_APPID_RESP_ORDER* getAppIdResp)
{
if (!context || !getAppIdResp)
return ERROR_INVALID_PARAMETER;
return CHANNEL_RC_OK; /* stub - should be registered by client */
return rail_send_client_snap_arrange_order(rail, snap);
}
/**
@ -645,7 +545,7 @@ static UINT rail_virtual_channel_event_data_received(railPlugin* rail, void* pDa
data_in = rail->data_in;
if (!Stream_EnsureRemainingCapacity(data_in, (int)dataLength))
if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
{
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
return CHANNEL_RC_NO_MEMORY;
@ -774,6 +674,7 @@ static DWORD WINAPI rail_virtual_channel_client_thread(LPVOID arg)
*/
static UINT rail_virtual_channel_event_connected(railPlugin* rail, LPVOID pData, UINT32 dataLength)
{
RailClientContext* context = rail_get_client_interface(rail);
UINT status;
status = rail->channelEntryPoints.pVirtualChannelOpenEx(rail->InitHandle, &rail->OpenHandle,
rail->channelDef.name,
@ -786,6 +687,15 @@ static UINT rail_virtual_channel_event_connected(railPlugin* rail, LPVOID pData,
return status;
}
if (context)
{
IFCALLRET(context->OnOpen, status, context, &rail->sendHandshake);
if (status != CHANNEL_RC_OK)
WLog_ERR(TAG, "context->OnOpen failed with %s [%08" PRIX32 "]",
WTSErrorToString(status), status);
}
rail->queue = MessageQueue_New(NULL);
if (!rail->queue)
@ -919,9 +829,11 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p
return FALSE;
}
/* Default to automatically replying to server handshakes */
rail->sendHandshake = TRUE;
rail->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
sprintf_s(rail->channelDef.name, ARRAYSIZE(rail->channelDef.name), "rail");
sprintf_s(rail->channelDef.name, ARRAYSIZE(rail->channelDef.name), RAIL_SVC_CHANNEL_NAME);
pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) &&
@ -941,25 +853,18 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p
context->ClientExecute = rail_client_execute;
context->ClientActivate = rail_client_activate;
context->ClientSystemParam = rail_client_system_param;
context->ServerSystemParam = rail_server_system_param;
context->ClientSystemCommand = rail_client_system_command;
context->ClientHandshake = rail_client_handshake;
context->ServerHandshake = rail_server_handshake;
context->ServerHandshakeEx = rail_server_handshake_ex;
context->ClientNotifyEvent = rail_client_notify_event;
context->ClientWindowMove = rail_client_window_move;
context->ServerLocalMoveSize = rail_server_local_move_size;
context->ServerMinMaxInfo = rail_server_min_max_info;
context->ClientInformation = rail_client_information;
context->ClientSystemMenu = rail_client_system_menu;
context->ClientLanguageBarInfo = rail_client_language_bar_info;
context->ServerLanguageBarInfo = rail_server_language_bar_info;
context->ClientLanguageIMEInfo = rail_client_language_ime_info;
context->ServerExecuteResult = rail_server_execute_result;
context->ClientGetAppIdRequest = rail_client_get_appid_request;
context->ServerGetAppIdResponse = rail_server_get_appid_response;
context->ClientSnapArrange = rail_client_snap_arrange;
context->ClientCloak = rail_client_cloak;
context->ClientCompartmentInfo = rail_client_compartment_info;
rail->rdpcontext = pEntryPointsEx->context;
rail->context = context;
isFreerdp = TRUE;

View File

@ -53,6 +53,7 @@ struct rail_plugin
DWORD channelBuildNumber;
DWORD channelFlags;
RAIL_CLIENT_STATUS_ORDER clientStatus;
BOOL sendHandshake;
};
typedef struct rail_plugin railPlugin;

View File

@ -32,55 +32,6 @@
#include "rail_orders.h"
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_write_unicode_string(wStream* s, const RAIL_UNICODE_STRING* unicode_string)
{
if (!s || !unicode_string)
return ERROR_INVALID_PARAMETER;
if (!Stream_EnsureRemainingCapacity(s, 2 + unicode_string->length))
{
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
return CHANNEL_RC_NO_MEMORY;
}
Stream_Write_UINT16(s, unicode_string->length); /* cbString (2 bytes) */
Stream_Write(s, unicode_string->string, unicode_string->length); /* string */
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_write_unicode_string_value(wStream* s, const RAIL_UNICODE_STRING* unicode_string)
{
size_t length;
if (!s || !unicode_string)
return ERROR_INVALID_PARAMETER;
length = unicode_string->length;
if (length > 0)
{
if (!Stream_EnsureRemainingCapacity(s, length))
{
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
return CHANNEL_RC_NO_MEMORY;
}
Stream_Write(s, unicode_string->string, length); /* string */
}
return CHANNEL_RC_OK;
}
/**
* Function description
*
@ -103,37 +54,6 @@ UINT rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType)
return rail_send_channel_data(rail, s);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_write_high_contrast(wStream* s, const RAIL_HIGH_CONTRAST* highContrast)
{
UINT32 colorSchemeLength;
if (!s || !highContrast)
return ERROR_INVALID_PARAMETER;
colorSchemeLength = highContrast->colorScheme.length + 2;
Stream_Write_UINT32(s, highContrast->flags); /* flags (4 bytes) */
Stream_Write_UINT32(s, colorSchemeLength); /* colorSchemeLength (4 bytes) */
return rail_write_unicode_string(s, &highContrast->colorScheme); /* colorScheme */
}
static UINT rail_write_filterkeys(wStream* s, const TS_FILTERKEYS* filterKeys)
{
if (!s || !filterKeys)
return ERROR_INVALID_PARAMETER;
Stream_Write_UINT32(s, filterKeys->Flags);
Stream_Write_UINT32(s, filterKeys->WaitTime);
Stream_Write_UINT32(s, filterKeys->DelayTime);
Stream_Write_UINT32(s, filterKeys->RepeatTime);
Stream_Write_UINT32(s, filterKeys->BounceTime);
return CHANNEL_RC_OK;
}
/**
* Function description
*
@ -144,7 +64,7 @@ static UINT rail_read_server_exec_result_order(wStream* s, RAIL_EXEC_RESULT_ORDE
if (!s || !execResult)
return ERROR_INVALID_PARAMETER;
if (Stream_GetRemainingLength(s) < 8)
if (Stream_GetRemainingLength(s) < RAIL_EXEC_RESULT_ORDER_LENGTH)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
@ -159,44 +79,6 @@ static UINT rail_read_server_exec_result_order(wStream* s, RAIL_EXEC_RESULT_ORDE
: ERROR_INTERNAL_ERROR; /* exeOrFile */
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_read_server_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam)
{
BYTE body;
if (!s || !sysparam)
return ERROR_INVALID_PARAMETER;
if (Stream_GetRemainingLength(s) < 5)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT32(s, sysparam->param); /* systemParam (4 bytes) */
Stream_Read_UINT8(s, body); /* body (1 byte) */
switch (sysparam->param)
{
case SPI_SETSCREENSAVEACTIVE:
sysparam->setScreenSaveActive = (body != 0) ? TRUE : FALSE;
break;
case SPI_SETSCREENSAVESECURE:
sysparam->setScreenSaveSecure = (body != 0) ? TRUE : FALSE;
break;
default:
break;
}
return CHANNEL_RC_OK;
}
/**
* Function description
*
@ -207,7 +89,7 @@ static UINT rail_read_server_minmaxinfo_order(wStream* s, RAIL_MINMAXINFO_ORDER*
if (!s || !minmaxinfo)
return ERROR_INVALID_PARAMETER;
if (Stream_GetRemainingLength(s) < 20)
if (Stream_GetRemainingLength(s) < RAIL_MINMAXINFO_ORDER_LENGTH)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
@ -238,7 +120,7 @@ static UINT rail_read_server_localmovesize_order(wStream* s,
if (!s || !localMoveSize)
return ERROR_INVALID_PARAMETER;
if (Stream_GetRemainingLength(s) < 12)
if (Stream_GetRemainingLength(s) < RAIL_LOCALMOVESIZE_ORDER_LENGTH)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
@ -264,15 +146,16 @@ static UINT rail_read_server_get_appid_resp_order(wStream* s,
if (!s || !getAppidResp)
return ERROR_INVALID_PARAMETER;
if (Stream_GetRemainingLength(s) < 524)
if (Stream_GetRemainingLength(s) < RAIL_GET_APPID_RESP_ORDER_LENGTH)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT32(s, getAppidResp->windowId); /* windowId (4 bytes) */
Stream_Read(s, (BYTE*)&(getAppidResp->applicationId),
520); /* applicationId (260 UNICODE chars) */
Stream_Read_UTF16_String(
s, getAppidResp->applicationId,
ARRAYSIZE(getAppidResp->applicationId)); /* applicationId (260 UNICODE chars) */
return CHANNEL_RC_OK;
}
@ -286,7 +169,7 @@ static UINT rail_read_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* la
if (!s || !langbarInfo)
return ERROR_INVALID_PARAMETER;
if (Stream_GetRemainingLength(s) < 4)
if (Stream_GetRemainingLength(s) < RAIL_LANGBAR_INFO_ORDER_LENGTH)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
@ -357,107 +240,6 @@ static UINT rail_write_client_exec_order(wStream* s, UINT16 flags,
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT rail_write_client_sysparam_order(railPlugin* rail, wStream* s,
const RAIL_SYSPARAM_ORDER* sysparam)
{
BYTE body;
UINT error = CHANNEL_RC_OK;
if (!s || !sysparam)
return ERROR_INVALID_PARAMETER;
Stream_Write_UINT32(s, sysparam->param); /* systemParam (4 bytes) */
switch (sysparam->param)
{
case SPI_SET_DRAG_FULL_WINDOWS:
body = sysparam->dragFullWindows ? 1 : 0;
Stream_Write_UINT8(s, body);
break;
case SPI_SET_KEYBOARD_CUES:
body = sysparam->keyboardCues ? 1 : 0;
Stream_Write_UINT8(s, body);
break;
case SPI_SET_KEYBOARD_PREF:
body = sysparam->keyboardPref ? 1 : 0;
Stream_Write_UINT8(s, body);
break;
case SPI_SET_MOUSE_BUTTON_SWAP:
body = sysparam->mouseButtonSwap ? 1 : 0;
Stream_Write_UINT8(s, body);
break;
case SPI_SET_WORK_AREA:
Stream_Write_UINT16(s, sysparam->workArea.left); /* left (2 bytes) */
Stream_Write_UINT16(s, sysparam->workArea.top); /* top (2 bytes) */
Stream_Write_UINT16(s, sysparam->workArea.right); /* right (2 bytes) */
Stream_Write_UINT16(s, sysparam->workArea.bottom); /* bottom (2 bytes) */
break;
case SPI_DISPLAY_CHANGE:
Stream_Write_UINT16(s, sysparam->displayChange.left); /* left (2 bytes) */
Stream_Write_UINT16(s, sysparam->displayChange.top); /* top (2 bytes) */
Stream_Write_UINT16(s, sysparam->displayChange.right); /* right (2 bytes) */
Stream_Write_UINT16(s, sysparam->displayChange.bottom); /* bottom (2 bytes) */
break;
case SPI_TASKBAR_POS:
Stream_Write_UINT16(s, sysparam->taskbarPos.left); /* left (2 bytes) */
Stream_Write_UINT16(s, sysparam->taskbarPos.top); /* top (2 bytes) */
Stream_Write_UINT16(s, sysparam->taskbarPos.right); /* right (2 bytes) */
Stream_Write_UINT16(s, sysparam->taskbarPos.bottom); /* bottom (2 bytes) */
break;
case SPI_SET_HIGH_CONTRAST:
error = rail_write_high_contrast(s, &sysparam->highContrast);
break;
case SPI_SETCARETWIDTH:
if ((rail->channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED) == 0)
return ERROR_INVALID_DATA;
if (sysparam->caretWidth < 0x0001)
return ERROR_INVALID_DATA;
Stream_Write_UINT32(s, sysparam->caretWidth);
break;
case SPI_SETSTICKYKEYS:
if ((rail->channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED) == 0)
return ERROR_INVALID_DATA;
Stream_Write_UINT32(s, sysparam->stickyKeys);
break;
case SPI_SETTOGGLEKEYS:
if ((rail->channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED) == 0)
return ERROR_INVALID_DATA;
Stream_Write_UINT32(s, sysparam->toggleKeys);
break;
case SPI_SETFILTERKEYS:
if ((rail->channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED) == 0)
return ERROR_INVALID_DATA;
error = rail_write_filterkeys(s, &sysparam->filterKeys);
break;
default:
return ERROR_INVALID_PARAMETER;
}
return error;
}
static UINT rail_write_client_activate_order(wStream* s, const RAIL_ACTIVATE_ORDER* activate)
{
BYTE enabled;
@ -544,13 +326,26 @@ static UINT rail_write_languageime_info_order(wStream* s,
return ERROR_INVALID_PARAMETER;
Stream_Write_UINT32(s, langImeInfo->ProfileType);
Stream_Write_UINT32(s, langImeInfo->LanguageID);
Stream_Write_UINT16(s, langImeInfo->LanguageID);
Stream_Write(s, &langImeInfo->LanguageProfileCLSID, sizeof(langImeInfo->LanguageProfileCLSID));
Stream_Write(s, &langImeInfo->ProfileGUID, sizeof(langImeInfo->ProfileGUID));
Stream_Write_UINT32(s, langImeInfo->KeyboardLayout);
return ERROR_SUCCESS;
}
static UINT rail_write_compartment_info_order(wStream* s,
const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
{
if (!s || !compartmentInfo)
return ERROR_INVALID_PARAMETER;
Stream_Write_UINT32(s, compartmentInfo->ImeState);
Stream_Write_UINT32(s, compartmentInfo->ImeConvMode);
Stream_Write_UINT32(s, compartmentInfo->ImeSentenceMode);
Stream_Write_UINT32(s, compartmentInfo->KanaMode);
return ERROR_SUCCESS;
}
/**
* Function description
*
@ -560,7 +355,6 @@ static UINT rail_recv_handshake_order(railPlugin* rail, wStream* s)
{
RailClientContext* context = rail_get_client_interface(rail);
RAIL_HANDSHAKE_ORDER serverHandshake = { 0 };
RAIL_HANDSHAKE_ORDER clientHandshake = { 0 };
UINT error;
if (!context || !s)
@ -573,10 +367,13 @@ static UINT rail_recv_handshake_order(railPlugin* rail, wStream* s)
}
rail->channelBuildNumber = serverHandshake.buildNumber;
if (rail->sendHandshake)
{
RAIL_HANDSHAKE_ORDER clientHandshake = { 0 };
clientHandshake.buildNumber = 0x00001DB0;
/* 2.2.2.2.3 HandshakeEx PDU (TS_RAIL_ORDER_HANDSHAKE_EX)
* Client response is really a Handshake PDU */
error = context->ClientHandshake(context, &clientHandshake);
}
if (error != CHANNEL_RC_OK)
return error;
@ -618,7 +415,6 @@ static UINT rail_recv_handshake_ex_order(railPlugin* rail, wStream* s)
{
RailClientContext* context = rail_get_client_interface(rail);
RAIL_HANDSHAKE_EX_ORDER serverHandshake = { 0 };
RAIL_HANDSHAKE_ORDER clientHandshake = { 0 };
UINT error;
if (!rail || !context || !s)
@ -635,10 +431,15 @@ static UINT rail_recv_handshake_ex_order(railPlugin* rail, wStream* s)
rail->channelBuildNumber = serverHandshake.buildNumber;
rail->channelFlags = serverHandshake.railHandshakeFlags;
if (rail->sendHandshake)
{
RAIL_HANDSHAKE_ORDER clientHandshake = { 0 };
clientHandshake.buildNumber = 0x00001DB0;
/* 2.2.2.2.3 HandshakeEx PDU (TS_RAIL_ORDER_HANDSHAKE_EX)
* Client response is really a Handshake PDU */
error = context->ClientHandshake(context, &clientHandshake);
}
if (error != CHANNEL_RC_OK)
return error;
@ -701,9 +502,9 @@ static UINT rail_recv_server_sysparam_order(railPlugin* rail, wStream* s)
if (!context || !s)
return ERROR_INVALID_PARAMETER;
if ((error = rail_read_server_sysparam_order(s, &sysparam)))
if ((error = rail_read_sysparam_order(s, &sysparam, FALSE)))
{
WLog_ERR(TAG, "rail_read_server_sysparam_order failed with error %" PRIu32 "!", error);
WLog_ERR(TAG, "rail_read_sysparam_order failed with error %" PRIu32 "!", error);
return error;
}
@ -851,7 +652,7 @@ static UINT rail_read_taskbar_info_order(wStream* s, RAIL_TASKBAR_INFO_ORDER* ta
if (!s || !taskbarInfo)
return ERROR_INVALID_PARAMETER;
if (Stream_GetRemainingLength(s) < 12)
if (Stream_GetRemainingLength(s) < RAIL_TASKBAR_INFO_ORDER_LENGTH)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
@ -888,7 +689,7 @@ static UINT rail_recv_taskbar_info_order(railPlugin* rail, wStream* s)
IFCALLRET(context->ServerTaskBarInfo, error, context, &taskBarInfo);
if (error)
WLog_ERR(TAG, "context.ServerLanguageBarInfo failed with error %" PRIu32 "", error);
WLog_ERR(TAG, "context.ServerTaskBarInfo failed with error %" PRIu32 "", error);
}
return error;
@ -899,7 +700,7 @@ static UINT rail_read_zorder_sync_order(wStream* s, RAIL_ZORDER_SYNC* zorder)
if (!s || !zorder)
return ERROR_INVALID_PARAMETER;
if (Stream_GetRemainingLength(s) < 4)
if (Stream_GetRemainingLength(s) < RAIL_Z_ORDER_SYNC_ORDER_LENGTH)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
@ -938,23 +739,23 @@ static UINT rail_recv_zorder_sync_order(railPlugin* rail, wStream* s)
return error;
}
static UINT rail_read_order_cloak(wStream* s, RAIL_CLOAK* cloak)
static UINT rail_read_cloak_order(wStream* s, RAIL_CLOAK* cloak)
{
if (!s || !cloak)
return ERROR_INVALID_PARAMETER;
BYTE cloaked;
if (Stream_GetRemainingLength(s) < 5)
if (Stream_GetRemainingLength(s) < RAIL_CLOAK_ORDER_LENGTH)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT32(s, cloak->windowId);
Stream_Read_UINT8(s, cloak->cloak);
Stream_Read_UINT32(s, cloak->windowId); /* WindowId (4 bytes) */
Stream_Read_UINT8(s, cloaked); /* Cloaked (1 byte) */
cloak->cloak = (cloaked != 0) ? TRUE : FALSE;
return CHANNEL_RC_OK;
}
static UINT rail_recv_order_cloak(railPlugin* rail, wStream* s)
static UINT rail_recv_cloak_order(railPlugin* rail, wStream* s)
{
RailClientContext* context = rail_get_client_interface(rail);
RAIL_CLOAK cloak = { 0 };
@ -968,7 +769,7 @@ static UINT rail_recv_order_cloak(railPlugin* rail, wStream* s)
if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_BIDIRECTIONAL_CLOAK_SUPPORTED) == 0)
return ERROR_INVALID_DATA;
if ((error = rail_read_order_cloak(s, &cloak)))
if ((error = rail_read_cloak_order(s, &cloak)))
{
WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %" PRIu32 "!", error);
return error;
@ -987,16 +788,19 @@ static UINT rail_recv_order_cloak(railPlugin* rail, wStream* s)
static UINT rail_read_power_display_request_order(wStream* s, RAIL_POWER_DISPLAY_REQUEST* power)
{
UINT32 active;
if (!s || !power)
return ERROR_INVALID_PARAMETER;
if (Stream_GetRemainingLength(s) < 4)
if (Stream_GetRemainingLength(s) < RAIL_POWER_DISPLAY_REQUEST_ORDER_LENGTH)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT32(s, power->active);
Stream_Read_UINT32(s, active);
power->active = active != 0;
return CHANNEL_RC_OK;
}
@ -1156,7 +960,7 @@ UINT rail_order_recv(railPlugin* rail, wStream* s)
return rail_recv_zorder_sync_order(rail, s);
case TS_RAIL_ORDER_CLOAK:
return rail_recv_order_cloak(rail, s);
return rail_recv_cloak_order(rail, s);
case TS_RAIL_ORDER_POWER_DISPLAY_REQUEST:
return rail_recv_power_display_request_order(rail, s);
@ -1300,215 +1104,6 @@ out:
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_send_client_sysparam_order(railPlugin* rail, const RAIL_SYSPARAM_ORDER* sysparam)
{
wStream* s;
size_t length = RAIL_SYSPARAM_ORDER_LENGTH;
UINT error;
if (!rail || !sysparam)
return ERROR_INVALID_PARAMETER;
switch (sysparam->param)
{
case SPI_SET_DRAG_FULL_WINDOWS:
case SPI_SET_KEYBOARD_CUES:
case SPI_SET_KEYBOARD_PREF:
case SPI_SET_MOUSE_BUTTON_SWAP:
length += 1;
break;
case SPI_SETCARETWIDTH:
case SPI_SETSTICKYKEYS:
case SPI_SETTOGGLEKEYS:
length += 4;
break;
case SPI_SETFILTERKEYS:
length += 20;
break;
case SPI_SET_WORK_AREA:
case SPI_DISPLAY_CHANGE:
case SPI_TASKBAR_POS:
length += 8;
break;
case SPI_SET_HIGH_CONTRAST:
length += sysparam->highContrast.colorSchemeLength + 10;
break;
default:
length += 8;
break;
}
s = rail_pdu_init(length);
if (!s)
{
WLog_ERR(TAG, "rail_pdu_init failed!");
return CHANNEL_RC_NO_MEMORY;
}
if ((error = rail_write_client_sysparam_order(rail, s, sysparam)))
{
WLog_ERR(TAG, "rail_write_client_sysparam_order failed with error %" PRIu32 "!", error);
goto out;
}
if ((error = rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSPARAM)))
{
WLog_ERR(TAG, "rail_send_pdu failed with error %" PRIu32 "!", error);
goto out;
}
out:
Stream_Free(s, TRUE);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_send_client_sysparams_order(railPlugin* rail, RAIL_SYSPARAM_ORDER* sysparam)
{
UINT error = CHANNEL_RC_OK;
if (!rail || !sysparam)
return ERROR_INVALID_PARAMETER;
if (sysparam->params & SPI_MASK_SET_HIGH_CONTRAST)
{
sysparam->param = SPI_SET_HIGH_CONTRAST;
if ((error = rail_send_client_sysparam_order(rail, sysparam)))
{
WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %" PRIu32 "!", error);
return error;
}
}
if (sysparam->params & SPI_MASK_TASKBAR_POS)
{
sysparam->param = SPI_TASKBAR_POS;
if ((error = rail_send_client_sysparam_order(rail, sysparam)))
{
WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %" PRIu32 "!", error);
return error;
}
}
if (sysparam->params & SPI_MASK_SET_MOUSE_BUTTON_SWAP)
{
sysparam->param = SPI_SET_MOUSE_BUTTON_SWAP;
if ((error = rail_send_client_sysparam_order(rail, sysparam)))
{
WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %" PRIu32 "!", error);
return error;
}
}
if (sysparam->params & SPI_MASK_SET_KEYBOARD_PREF)
{
sysparam->param = SPI_SET_KEYBOARD_PREF;
if ((error = rail_send_client_sysparam_order(rail, sysparam)))
{
WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %" PRIu32 "!", error);
return error;
}
}
if (sysparam->params & SPI_MASK_SET_DRAG_FULL_WINDOWS)
{
sysparam->param = SPI_SET_DRAG_FULL_WINDOWS;
if ((error = rail_send_client_sysparam_order(rail, sysparam)))
{
WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %" PRIu32 "!", error);
return error;
}
}
if (sysparam->params & SPI_MASK_SET_KEYBOARD_CUES)
{
sysparam->param = SPI_SET_KEYBOARD_CUES;
if ((error = rail_send_client_sysparam_order(rail, sysparam)))
{
WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %" PRIu32 "!", error);
return error;
}
}
if (sysparam->params & SPI_MASK_SET_WORK_AREA)
{
sysparam->param = SPI_SET_WORK_AREA;
if ((error = rail_send_client_sysparam_order(rail, sysparam)))
{
WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %" PRIu32 "!", error);
return error;
}
}
if (sysparam->params & SPI_MASK_SET_CARET_WIDTH)
{
sysparam->param = SPI_SETCARETWIDTH;
if ((error = rail_send_client_sysparam_order(rail, sysparam)))
{
WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %" PRIu32 "!", error);
return error;
}
}
if (sysparam->params & SPI_MASK_SET_STICKY_KEYS)
{
sysparam->param = SPI_SETSTICKYKEYS;
if ((error = rail_send_client_sysparam_order(rail, sysparam)))
{
WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %" PRIu32 "!", error);
return error;
}
}
if (sysparam->params & SPI_MASK_SET_TOGGLE_KEYS)
{
sysparam->param = SPI_SETTOGGLEKEYS;
if ((error = rail_send_client_sysparam_order(rail, sysparam)))
{
WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %" PRIu32 "!", error);
return error;
}
}
if (sysparam->params & SPI_MASK_SET_FILTER_KEYS)
{
sysparam->param = SPI_SETFILTERKEYS;
if ((error = rail_send_client_sysparam_order(rail, sysparam)))
{
WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %" PRIu32 "!", error);
return error;
}
}
return error;
}
/**
* Function description
*
@ -1754,7 +1349,33 @@ UINT rail_send_client_languageime_info_order(railPlugin* rail,
return error;
}
UINT rail_send_client_order_cloak_order(railPlugin* rail, const RAIL_CLOAK* cloak)
UINT rail_send_client_compartment_info_order(railPlugin* rail,
const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
{
wStream* s;
UINT error;
if (!rail || !compartmentInfo)
return ERROR_INVALID_PARAMETER;
s = rail_pdu_init(RAIL_COMPARTMENT_INFO_ORDER_LENGTH);
if (!s)
{
WLog_ERR(TAG, "rail_pdu_init failed!");
return CHANNEL_RC_NO_MEMORY;
}
error = rail_write_compartment_info_order(s, compartmentInfo);
if (ERROR_SUCCESS == error)
error = rail_send_pdu(rail, s, TS_RAIL_ORDER_COMPARTMENTINFO);
Stream_Free(s, TRUE);
return error;
}
UINT rail_send_client_cloak_order(railPlugin* rail, const RAIL_CLOAK* cloak)
{
wStream* s;
UINT error;
@ -1777,7 +1398,7 @@ UINT rail_send_client_order_cloak_order(railPlugin* rail, const RAIL_CLOAK* cloa
return error;
}
UINT rail_send_client_order_snap_arrange_order(railPlugin* rail, const RAIL_SNAP_ARRANGE* snap)
UINT rail_send_client_snap_arrange_order(railPlugin* rail, const RAIL_SNAP_ARRANGE* snap)
{
wStream* s;
UINT error;

View File

@ -29,9 +29,6 @@
#define TAG CHANNELS_TAG("rail.client")
UINT rail_write_client_sysparam_order(railPlugin* rail, wStream* s,
const RAIL_SYSPARAM_ORDER* sysparam);
UINT rail_order_recv(railPlugin* rail, wStream* s);
UINT rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType);
@ -55,7 +52,9 @@ UINT rail_send_client_langbar_info_order(railPlugin* rail,
const RAIL_LANGBAR_INFO_ORDER* langBarInfo);
UINT rail_send_client_languageime_info_order(railPlugin* rail,
const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo);
UINT rail_send_client_order_cloak_order(railPlugin* rail, const RAIL_CLOAK* cloak);
UINT rail_send_client_order_snap_arrange_order(railPlugin* rail, const RAIL_SNAP_ARRANGE* snap);
UINT rail_send_client_cloak_order(railPlugin* rail, const RAIL_CLOAK* cloak);
UINT rail_send_client_snap_arrange_order(railPlugin* rail, const RAIL_SNAP_ARRANGE* snap);
UINT rail_send_client_compartment_info_order(railPlugin* rail,
const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo);
#endif /* FREERDP_CHANNEL_RAIL_CLIENT_ORDERS_H */

View File

@ -23,6 +23,9 @@
#include "rail_common.h"
#include <winpr/crt.h>
#include <freerdp/channels/log.h>
#define TAG CHANNELS_TAG("rail.common")
const char* const RAIL_ORDER_TYPE_STRINGS[] = { "",
"Execute",
@ -48,30 +51,6 @@ const char* const RAIL_ORDER_TYPE_STRINGS[] = { "",
"",
"" };
BOOL rail_string_to_unicode_string(const char* string, RAIL_UNICODE_STRING* unicode_string)
{
WCHAR* buffer = NULL;
int length = 0;
free(unicode_string->string);
unicode_string->string = NULL;
unicode_string->length = 0;
if (!string || strlen(string) < 1)
return TRUE;
length = ConvertToUnicode(CP_UTF8, 0, string, -1, &buffer, 0);
if ((length < 0) || ((size_t)length * sizeof(WCHAR) > UINT16_MAX))
{
free(buffer);
return FALSE;
}
unicode_string->string = (BYTE*)buffer;
unicode_string->length = (UINT16)length * sizeof(WCHAR);
return TRUE;
}
/**
* Function description
*
@ -147,3 +126,383 @@ void rail_write_handshake_ex_order(wStream* s, const RAIL_HANDSHAKE_EX_ORDER* ha
Stream_Write_UINT32(s, handshakeEx->buildNumber); /* buildNumber (4 bytes) */
Stream_Write_UINT32(s, handshakeEx->railHandshakeFlags); /* railHandshakeFlags (4 bytes) */
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT rail_write_unicode_string(wStream* s, const RAIL_UNICODE_STRING* unicode_string)
{
if (!s || !unicode_string)
return ERROR_INVALID_PARAMETER;
if (!Stream_EnsureRemainingCapacity(s, 2 + unicode_string->length))
{
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
return CHANNEL_RC_NO_MEMORY;
}
Stream_Write_UINT16(s, unicode_string->length); /* cbString (2 bytes) */
Stream_Write(s, unicode_string->string, unicode_string->length); /* string */
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT rail_write_unicode_string_value(wStream* s, const RAIL_UNICODE_STRING* unicode_string)
{
size_t length;
if (!s || !unicode_string)
return ERROR_INVALID_PARAMETER;
length = unicode_string->length;
if (length > 0)
{
if (!Stream_EnsureRemainingCapacity(s, length))
{
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
return CHANNEL_RC_NO_MEMORY;
}
Stream_Write(s, unicode_string->string, length); /* string */
}
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_read_high_contrast(wStream* s, RAIL_HIGH_CONTRAST* highContrast)
{
if (!s || !highContrast)
return ERROR_INVALID_PARAMETER;
Stream_Read_UINT32(s, highContrast->flags); /* flags (4 bytes) */
Stream_Read_UINT32(s, highContrast->colorSchemeLength); /* colorSchemeLength (4 bytes) */
return rail_read_unicode_string(s, &highContrast->colorScheme); /* colorScheme */
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_write_high_contrast(wStream* s, const RAIL_HIGH_CONTRAST* highContrast)
{
UINT32 colorSchemeLength;
if (!s || !highContrast)
return ERROR_INVALID_PARAMETER;
colorSchemeLength = highContrast->colorScheme.length + 2;
Stream_Write_UINT32(s, highContrast->flags); /* flags (4 bytes) */
Stream_Write_UINT32(s, colorSchemeLength); /* colorSchemeLength (4 bytes) */
return rail_write_unicode_string(s, &highContrast->colorScheme); /* colorScheme */
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_write_filterkeys(wStream* s, const TS_FILTERKEYS* filterKeys)
{
if (!s || !filterKeys)
return ERROR_INVALID_PARAMETER;
Stream_Write_UINT32(s, filterKeys->Flags);
Stream_Write_UINT32(s, filterKeys->WaitTime);
Stream_Write_UINT32(s, filterKeys->DelayTime);
Stream_Write_UINT32(s, filterKeys->RepeatTime);
Stream_Write_UINT32(s, filterKeys->BounceTime);
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT rail_read_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam, BOOL extendedSpiSupported)
{
BYTE body;
UINT error = CHANNEL_RC_OK;
if (!s || !sysparam)
return ERROR_INVALID_PARAMETER;
if (Stream_GetRemainingLength(s) < 5)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT32(s, sysparam->param); /* systemParam (4 bytes) */
switch (sysparam->param)
{
/* Client sysparams */
case SPI_SET_DRAG_FULL_WINDOWS:
Stream_Read_UINT8(s, body); /* body (1 byte) */
sysparam->dragFullWindows = body != 0;
break;
case SPI_SET_KEYBOARD_CUES:
Stream_Read_UINT8(s, body); /* body (1 byte) */
sysparam->keyboardCues = body != 0;
break;
case SPI_SET_KEYBOARD_PREF:
Stream_Read_UINT8(s, body); /* body (1 byte) */
sysparam->keyboardPref = body != 0;
break;
case SPI_SET_MOUSE_BUTTON_SWAP:
Stream_Read_UINT8(s, body); /* body (1 byte) */
sysparam->mouseButtonSwap = body != 0;
break;
case SPI_SET_WORK_AREA:
if (Stream_GetRemainingLength(s) < 8)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT16(s, sysparam->workArea.left); /* left (2 bytes) */
Stream_Read_UINT16(s, sysparam->workArea.top); /* top (2 bytes) */
Stream_Read_UINT16(s, sysparam->workArea.right); /* right (2 bytes) */
Stream_Read_UINT16(s, sysparam->workArea.bottom); /* bottom (2 bytes) */
break;
case SPI_DISPLAY_CHANGE:
if (Stream_GetRemainingLength(s) < 8)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT16(s, sysparam->displayChange.left); /* left (2 bytes) */
Stream_Read_UINT16(s, sysparam->displayChange.top); /* top (2 bytes) */
Stream_Read_UINT16(s, sysparam->displayChange.right); /* right (2 bytes) */
Stream_Read_UINT16(s, sysparam->displayChange.bottom); /* bottom (2 bytes) */
break;
case SPI_TASKBAR_POS:
if (Stream_GetRemainingLength(s) < 8)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT16(s, sysparam->taskbarPos.left); /* left (2 bytes) */
Stream_Read_UINT16(s, sysparam->taskbarPos.top); /* top (2 bytes) */
Stream_Read_UINT16(s, sysparam->taskbarPos.right); /* right (2 bytes) */
Stream_Read_UINT16(s, sysparam->taskbarPos.bottom); /* bottom (2 bytes) */
break;
case SPI_SET_HIGH_CONTRAST:
if (Stream_GetRemainingLength(s) < 8)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
}
error = rail_read_high_contrast(s, &sysparam->highContrast);
break;
case SPI_SETCARETWIDTH:
if (extendedSpiSupported)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < 4)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT32(s, sysparam->caretWidth);
if (sysparam->caretWidth < 0x0001)
return ERROR_INVALID_DATA;
break;
case SPI_SETSTICKYKEYS:
if (extendedSpiSupported)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < 4)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
}
Stream_Write_UINT32(s, sysparam->stickyKeys);
break;
case SPI_SETTOGGLEKEYS:
if (extendedSpiSupported)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < 4)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
}
Stream_Write_UINT32(s, sysparam->toggleKeys);
break;
case SPI_SETFILTERKEYS:
if (extendedSpiSupported)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < 20)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
}
error = rail_write_filterkeys(s, &sysparam->filterKeys);
break;
/* Server sysparams */
case SPI_SETSCREENSAVEACTIVE:
Stream_Read_UINT8(s, body); /* body (1 byte) */
sysparam->setScreenSaveActive = body != 0;
break;
case SPI_SETSCREENSAVESECURE:
Stream_Read_UINT8(s, body); /* body (1 byte) */
sysparam->setScreenSaveSecure = body != 0;
break;
default:
break;
}
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 err2or code
*/
UINT rail_write_sysparam_order(wStream* s, const RAIL_SYSPARAM_ORDER* sysparam,
BOOL extendedSpiSupported)
{
BYTE body;
UINT error = CHANNEL_RC_OK;
if (!s || !sysparam)
return ERROR_INVALID_PARAMETER;
Stream_Write_UINT32(s, sysparam->param); /* systemParam (4 bytes) */
switch (sysparam->param)
{
/* Client sysparams */
case SPI_SET_DRAG_FULL_WINDOWS:
body = sysparam->dragFullWindows ? 1 : 0;
Stream_Write_UINT8(s, body);
break;
case SPI_SET_KEYBOARD_CUES:
body = sysparam->keyboardCues ? 1 : 0;
Stream_Write_UINT8(s, body);
break;
case SPI_SET_KEYBOARD_PREF:
body = sysparam->keyboardPref ? 1 : 0;
Stream_Write_UINT8(s, body);
break;
case SPI_SET_MOUSE_BUTTON_SWAP:
body = sysparam->mouseButtonSwap ? 1 : 0;
Stream_Write_UINT8(s, body);
break;
case SPI_SET_WORK_AREA:
Stream_Write_UINT16(s, sysparam->workArea.left); /* left (2 bytes) */
Stream_Write_UINT16(s, sysparam->workArea.top); /* top (2 bytes) */
Stream_Write_UINT16(s, sysparam->workArea.right); /* right (2 bytes) */
Stream_Write_UINT16(s, sysparam->workArea.bottom); /* bottom (2 bytes) */
break;
case SPI_DISPLAY_CHANGE:
Stream_Write_UINT16(s, sysparam->displayChange.left); /* left (2 bytes) */
Stream_Write_UINT16(s, sysparam->displayChange.top); /* top (2 bytes) */
Stream_Write_UINT16(s, sysparam->displayChange.right); /* right (2 bytes) */
Stream_Write_UINT16(s, sysparam->displayChange.bottom); /* bottom (2 bytes) */
break;
case SPI_TASKBAR_POS:
Stream_Write_UINT16(s, sysparam->taskbarPos.left); /* left (2 bytes) */
Stream_Write_UINT16(s, sysparam->taskbarPos.top); /* top (2 bytes) */
Stream_Write_UINT16(s, sysparam->taskbarPos.right); /* right (2 bytes) */
Stream_Write_UINT16(s, sysparam->taskbarPos.bottom); /* bottom (2 bytes) */
break;
case SPI_SET_HIGH_CONTRAST:
error = rail_write_high_contrast(s, &sysparam->highContrast);
break;
case SPI_SETCARETWIDTH:
if (!extendedSpiSupported)
return ERROR_INVALID_DATA;
if (sysparam->caretWidth < 0x0001)
return ERROR_INVALID_DATA;
Stream_Write_UINT32(s, sysparam->caretWidth);
break;
case SPI_SETSTICKYKEYS:
if (!extendedSpiSupported)
return ERROR_INVALID_DATA;
Stream_Write_UINT32(s, sysparam->stickyKeys);
break;
case SPI_SETTOGGLEKEYS:
if (!extendedSpiSupported)
return ERROR_INVALID_DATA;
Stream_Write_UINT32(s, sysparam->toggleKeys);
break;
case SPI_SETFILTERKEYS:
if (!extendedSpiSupported)
return ERROR_INVALID_DATA;
error = rail_write_filterkeys(s, &sysparam->filterKeys);
break;
/* Server sysparams */
case SPI_SETSCREENSAVEACTIVE:
body = sysparam->setScreenSaveActive ? 1 : 0;
Stream_Write_UINT8(s, body);
break;
case SPI_SETSCREENSAVESECURE:
body = sysparam->setScreenSaveSecure ? 1 : 0;
Stream_Write_UINT8(s, body);
break;
default:
return ERROR_INVALID_PARAMETER;
}
return error;
}

View File

@ -35,17 +35,27 @@ extern const char* const RAIL_ORDER_TYPE_STRINGS[];
#define RAIL_HANDSHAKE_EX_ORDER_LENGTH 8 /* fixed */
#define RAIL_CLIENT_STATUS_ORDER_LENGTH 4 /* fixed */
#define RAIL_EXEC_ORDER_LENGTH 8 /* variable */
#define RAIL_EXEC_RESULT_ORDER_LENGTH 12 /* variable */
#define RAIL_SYSPARAM_ORDER_LENGTH 4 /* variable */
#define RAIL_MINMAXINFO_ORDER_LENGTH 20 /* fixed */
#define RAIL_LOCALMOVESIZE_ORDER_LENGTH 12 /* fixed */
#define RAIL_ACTIVATE_ORDER_LENGTH 5 /* fixed */
#define RAIL_SYSMENU_ORDER_LENGTH 8 /* fixed */
#define RAIL_SYSCOMMAND_ORDER_LENGTH 6 /* fixed */
#define RAIL_NOTIFY_EVENT_ORDER_LENGTH 12 /* fixed */
#define RAIL_WINDOW_MOVE_ORDER_LENGTH 12 /* fixed */
#define RAIL_SNAP_ARRANGE_ORDER_LENGTH 12 /* fixed */
#define RAIL_GET_APPID_REQ_ORDER_LENGTH 4 /* fixed */
#define RAIL_LANGBAR_INFO_ORDER_LENGTH 4 /* fixed */
#define RAIL_LANGUAGEIME_INFO_ORDER_LENGTH 44 /* fixed */
#define RAIL_LANGUAGEIME_INFO_ORDER_LENGTH 42 /* fixed */
#define RAIL_COMPARTMENT_INFO_ORDER_LENGTH 16 /* fixed */
#define RAIL_CLOAK_ORDER_LENGTH 5 /* fixed */
#define RAIL_TASKBAR_INFO_ORDER_LENGTH 12 /* fixed */
#define RAIL_Z_ORDER_SYNC_ORDER_LENGTH 4 /* fixed */
#define RAIL_POWER_DISPLAY_REQUEST_ORDER_LENGTH 4 /* fixed */
#define RAIL_GET_APPID_RESP_ORDER_LENGTH 524 /* fixed */
#define RAIL_GET_APPID_RESP_EX_ORDER_LENGTH 1048 /* fixed */
BOOL rail_string_to_unicode_string(const char* string, RAIL_UNICODE_STRING* unicode_string);
UINT rail_read_handshake_order(wStream* s, RAIL_HANDSHAKE_ORDER* handshake);
void rail_write_handshake_order(wStream* s, const RAIL_HANDSHAKE_ORDER* handshake);
UINT rail_read_handshake_ex_order(wStream* s, RAIL_HANDSHAKE_EX_ORDER* handshakeEx);
@ -55,4 +65,11 @@ wStream* rail_pdu_init(size_t length);
UINT rail_read_pdu_header(wStream* s, UINT16* orderType, UINT16* orderLength);
void rail_write_pdu_header(wStream* s, UINT16 orderType, UINT16 orderLength);
UINT rail_write_unicode_string(wStream* s, const RAIL_UNICODE_STRING* unicode_string);
UINT rail_write_unicode_string_value(wStream* s, const RAIL_UNICODE_STRING* unicode_string);
UINT rail_read_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam, BOOL extendedSpiSupported);
UINT rail_write_sysparam_order(wStream* s, const RAIL_SYSPARAM_ORDER* sysparam,
BOOL extendedSpiSupported);
#endif /* FREERDP_CHANNEL_RAIL_COMMON_H */

View File

@ -0,0 +1,32 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2019 Mati Shabtay <matishabtay@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.
define_channel_server("rail")
set(${MODULE_PREFIX}_SRCS
../rail_common.c
../rail_common.h
rail_main.c
rail_main.h)
include_directories(..)
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntryEx")
target_link_libraries(${MODULE_NAME} freerdp)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server")

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,44 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RAIL Virtual Channel Plugin
*
* Copyright 2019 Mati Shabtay <matishabtay@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.
*/
#ifndef FREERDP_CHANNEL_RAIL_SERVER_MAIN_H
#define FREERDP_CHANNEL_RAIL_SERVER_MAIN_H
#include <freerdp/rail.h>
#include <freerdp/server/rail.h>
#include <winpr/crt.h>
#include <winpr/wlog.h>
#include <winpr/stream.h>
#include "../rail_common.h"
struct _rail_server_private
{
HANDLE thread;
HANDLE stopEvent;
HANDLE channelEvent;
void* rail_channel;
wStream* input_stream;
DWORD channelFlags;
};
#endif /* FREERDP_CHANNEL_RAIL_SERVER_MAIN_H */

View File

@ -49,6 +49,7 @@
#include <freerdp/server/drdynvc.h>
#include <freerdp/server/remdesk.h>
#include <freerdp/server/encomsp.h>
#include <freerdp/server/rail.h>
#include <freerdp/server/rdpgfx.h>
#include <freerdp/server/disp.h>
@ -63,6 +64,7 @@ void freerdp_channels_dummy(void)
RdpeiServerContext* rdpei;
RemdeskServerContext* remdesk;
EncomspServerContext* encomsp;
RailServerContext* rail;
RdpgfxServerContext* rdpgfx;
DispServerContext* disp;
audin = audin_server_context_new(NULL);
@ -83,6 +85,8 @@ void freerdp_channels_dummy(void)
remdesk_server_context_free(remdesk);
encomsp = encomsp_server_context_new(NULL);
encomsp_server_context_free(encomsp);
rail = rail_server_context_new(NULL);
rail_server_context_free(rail);
rdpgfx = rdpgfx_server_context_new(NULL);
rdpgfx_server_context_free(rdpgfx);
disp = disp_server_context_new(NULL);

View File

@ -31,10 +31,10 @@
* Client Interface
*/
#define RAIL_SVC_CHANNEL_NAME "rail"
typedef struct _rail_client_context RailClientContext;
typedef UINT (*pcRailOnOpen)(RailClientContext* context, BOOL* sendHandshake);
typedef UINT (*pcRailClientExecute)(RailClientContext* context, const RAIL_EXEC_ORDER* exec);
typedef UINT (*pcRailClientActivate)(RailClientContext* context,
const RAIL_ACTIVATE_ORDER* activate);
@ -69,7 +69,7 @@ typedef UINT (*pcRailClientLanguageBarInfo)(RailClientContext* context,
typedef UINT (*pcRailServerLanguageBarInfo)(RailClientContext* context,
const RAIL_LANGBAR_INFO_ORDER* langBarInfo);
typedef UINT (*pcRailClientLanguageIMEInfo)(RailClientContext* context,
const RAIL_LANGUAGEIME_INFO_ORDER* langBarInfo);
const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo);
typedef UINT (*pcRailServerExecuteResult)(RailClientContext* context,
const RAIL_EXEC_RESULT_ORDER* execResult);
typedef UINT (*pcRailClientGetAppIdRequest)(RailClientContext* context,
@ -84,6 +84,8 @@ typedef UINT (*pcRailServerPowerDisplayRequest)(RailClientContext* context,
typedef UINT (*pcRailClientSnapArrange)(RailClientContext* context, const RAIL_SNAP_ARRANGE* snap);
typedef UINT (*pcRailServerGetAppidResponseExtended)(RailClientContext* context,
const RAIL_GET_APPID_RESP_EX* id);
typedef UINT (*pcRailClientCompartmentInfo)(RailClientContext* context,
const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo);
struct _rail_client_context
{
@ -117,6 +119,8 @@ struct _rail_client_context
pcRailServerPowerDisplayRequest ServerPowerDisplayRequest;
pcRailClientSnapArrange ClientSnapArrange;
pcRailServerGetAppidResponseExtended ServerGetAppidResponseExtended;
pcRailClientCompartmentInfo ClientCompartmentInfo;
pcRailOnOpen OnOpen;
};
#endif /* FREERDP_CHANNEL_RAIL_CLIENT_RAIL_H */

View File

@ -26,6 +26,8 @@
#include <freerdp/types.h>
#define RAIL_SVC_CHANNEL_NAME "rail"
/* DEPRECATED: RAIL PDU flags use the spec conformant naming with TS_ prefix */
#define RAIL_EXEC_FLAG_EXPAND_WORKINGDIRECTORY 0x0001
#define RAIL_EXEC_FLAG_TRANSLATE_FILES 0x0002
@ -580,6 +582,8 @@ extern "C"
#endif
FREERDP_API BOOL rail_read_unicode_string(wStream* s, RAIL_UNICODE_STRING* unicode_string);
FREERDP_API BOOL utf8_string_to_rail_string(const char* string,
RAIL_UNICODE_STRING* unicode_string);
#ifdef __cplusplus
}

View File

@ -0,0 +1,149 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RAIL Virtual Channel Plugin
*
* Copyright 2019 Mati Shabtay <matishabtay@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.
*/
#ifndef FREERDP_CHANNEL_RAIL_SERVER_RAIL_H
#define FREERDP_CHANNEL_RAIL_SERVER_RAIL_H
#include <freerdp/api.h>
#include <freerdp/types.h>
#include <freerdp/freerdp.h>
#include <freerdp/rail.h>
#include <freerdp/channels/rail.h>
typedef struct _rail_server_context RailServerContext;
typedef struct _rail_server_private RailServerPrivate;
typedef UINT (*psRailStart)(RailServerContext* context);
typedef BOOL (*psRailStop)(RailServerContext* context);
/* Client side callback types */
typedef UINT (*psRailClientHandshake)(RailServerContext* context,
const RAIL_HANDSHAKE_ORDER* handshake);
typedef UINT (*psRailClientClientStatus)(RailServerContext* context,
const RAIL_CLIENT_STATUS_ORDER* clientStatus);
typedef UINT (*psRailClientExec)(RailServerContext* context, const RAIL_EXEC_ORDER* exec);
typedef UINT (*psRailClientSysparam)(RailServerContext* context,
const RAIL_SYSPARAM_ORDER* sysparam);
typedef UINT (*psRailClientActivate)(RailServerContext* context,
const RAIL_ACTIVATE_ORDER* activate);
typedef UINT (*psRailClientSysmenu)(RailServerContext* context, const RAIL_SYSMENU_ORDER* sysmenu);
typedef UINT (*psRailClientSyscommand)(RailServerContext* context,
const RAIL_SYSCOMMAND_ORDER* syscommand);
typedef UINT (*psRailClientNotifyEvent)(RailServerContext* context,
const RAIL_NOTIFY_EVENT_ORDER* notifyEvent);
typedef UINT (*psRailClientGetAppidReq)(RailServerContext* context,
const RAIL_GET_APPID_REQ_ORDER* getAppidReq);
typedef UINT (*psRailClientWindowMove)(RailServerContext* context,
const RAIL_WINDOW_MOVE_ORDER* windowMove);
typedef UINT (*psRailClientSnapArrange)(RailServerContext* context,
const RAIL_SNAP_ARRANGE* snapArrange);
typedef UINT (*psRailClientLangbarInfo)(RailServerContext* context,
const RAIL_LANGBAR_INFO_ORDER* langbarInfo);
typedef UINT (*psRailClientLanguageImeInfo)(RailServerContext* context,
const RAIL_LANGUAGEIME_INFO_ORDER* languageImeInfo);
typedef UINT (*psRailClientCompartmentInfo)(RailServerContext* context,
const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo);
typedef UINT (*psRailClientCloak)(RailServerContext* context, const RAIL_CLOAK* cloak);
/* Server side messages sending methods */
typedef UINT (*psRailServerHandshake)(RailServerContext* context,
const RAIL_HANDSHAKE_ORDER* handshake);
typedef UINT (*psRailServerHandshakeEx)(RailServerContext* context,
const RAIL_HANDSHAKE_EX_ORDER* handshakeEx);
typedef UINT (*psRailServerSysparam)(RailServerContext* context,
const RAIL_SYSPARAM_ORDER* sysparam);
typedef UINT (*psRailServerLocalMoveSize)(RailServerContext* context,
const RAIL_LOCALMOVESIZE_ORDER* localMoveSize);
typedef UINT (*psRailServerMinMaxInfo)(RailServerContext* context,
const RAIL_MINMAXINFO_ORDER* minMaxInfo);
typedef UINT (*psRailServerTaskbarInfo)(RailServerContext* context,
const RAIL_TASKBAR_INFO_ORDER* taskbarInfo);
typedef UINT (*psRailServerLangbarInfo)(RailServerContext* context,
const RAIL_LANGBAR_INFO_ORDER* langbarInfo);
typedef UINT (*psRailServerExecResult)(RailServerContext* context,
const RAIL_EXEC_RESULT_ORDER* execResult);
typedef UINT (*psRailServerGetAppidResp)(RailServerContext* context,
const RAIL_GET_APPID_RESP_ORDER* getAppIdResp);
typedef UINT (*psRailServerZOrderSync)(RailServerContext* context,
const RAIL_ZORDER_SYNC* zOrderSync);
typedef UINT (*psRailServerCloak)(RailServerContext* context, const RAIL_CLOAK* cloak);
typedef UINT (*psRailServerPowerDisplayRequest)(
RailServerContext* context, const RAIL_POWER_DISPLAY_REQUEST* PowerDisplayRequest);
typedef UINT (*psRailServerGetAppidRespEx)(RailServerContext* context,
const RAIL_GET_APPID_RESP_EX* GetAppidRespEx);
struct _rail_server_context
{
HANDLE vcm;
void* custom;
psRailStart Start;
psRailStop Stop;
/* Callbacks from client */
psRailClientHandshake ClientHandshake;
psRailClientClientStatus ClientClientStatus;
psRailClientExec ClientExec;
psRailClientSysparam ClientSysparam;
psRailClientActivate ClientActivate;
psRailClientSysmenu ClientSysmenu;
psRailClientSyscommand ClientSyscommand;
psRailClientNotifyEvent ClientNotifyEvent;
psRailClientGetAppidReq ClientGetAppidReq;
psRailClientWindowMove ClientWindowMove;
psRailClientSnapArrange ClientSnapArrange;
psRailClientLangbarInfo ClientLangbarInfo;
psRailClientLanguageImeInfo ClientLanguageImeInfo;
psRailClientCompartmentInfo ClientCompartmentInfo;
psRailClientCloak ClientCloak;
/* Methods for sending server side messages */
psRailServerHandshake ServerHandshake;
psRailServerHandshakeEx ServerHandshakeEx;
psRailServerSysparam ServerSysparam;
psRailServerLocalMoveSize ServerLocalMoveSize;
psRailServerMinMaxInfo ServerMinMaxInfo;
psRailServerTaskbarInfo ServerTaskbarInfo;
psRailServerLangbarInfo ServerLangbarInfo;
psRailServerExecResult ServerExecResult;
psRailServerZOrderSync ServerZOrderSync;
psRailServerCloak ServerCloak;
psRailServerPowerDisplayRequest ServerPowerDisplayRequest;
psRailServerGetAppidResp ServerGetAppidResp;
psRailServerGetAppidRespEx ServerGetAppidRespEx;
RailServerPrivate* priv;
rdpContext* rdpContext;
};
#ifdef __cplusplus
extern "C"
{
#endif
FREERDP_API RailServerContext* rail_server_context_new(HANDLE vcm);
FREERDP_API void rail_server_context_free(RailServerContext* context);
FREERDP_API UINT rail_server_handle_messages(RailServerContext* context);
#ifdef __cplusplus
}
#endif
#endif /* FREERDP_CHANNEL_RAIL_SERVER_RAIL_H */

View File

@ -86,7 +86,6 @@ static BOOL update_recv_orders(rdpUpdate* update, wStream* s)
static BOOL update_read_bitmap_data(rdpUpdate* update, wStream* s, BITMAP_DATA* bitmapData)
{
WINPR_UNUSED(update);
if (Stream_GetRemainingLength(s) < 18)
return FALSE;
@ -2251,7 +2250,6 @@ BOOL update_send_window_icon(rdpContext* context, const WINDOW_ORDER_INFO* order
Stream_Write_UINT16(s, orderSize);
Stream_SetPosition(s, orderEndPos);
update->numberOrders++;
/* Write body */
return TRUE;
}

View File

@ -68,6 +68,30 @@ BOOL rail_read_unicode_string(wStream* s, RAIL_UNICODE_STRING* unicode_string)
return TRUE;
}
BOOL utf8_string_to_rail_string(const char* string, RAIL_UNICODE_STRING* unicode_string)
{
WCHAR* buffer = NULL;
int length = 0;
free(unicode_string->string);
unicode_string->string = NULL;
unicode_string->length = 0;
if (!string || strlen(string) < 1)
return TRUE;
length = ConvertToUnicode(CP_UTF8, 0, string, -1, &buffer, 0);
if ((length < 0) || ((size_t)length * sizeof(WCHAR) > UINT16_MAX))
{
free(buffer);
return FALSE;
}
unicode_string->string = (BYTE*)buffer;
unicode_string->length = (UINT16)length * sizeof(WCHAR);
return TRUE;
}
/* See [MS-RDPERP] 2.2.1.2.3 Icon Info (TS_ICON_INFO) */
static BOOL update_read_icon_info(wStream* s, ICON_INFO* iconInfo)
{
@ -993,7 +1017,10 @@ BOOL update_recv_altsec_window_order(rdpUpdate* update, wStream* s)
}
if (!window_order_supported(update->context->settings, orderInfo.fieldFlags))
{
WLog_INFO(TAG, "Window order %08" PRIx32 " not supported!", orderInfo.fieldFlags);
return FALSE;
}
if (orderInfo.fieldFlags & WINDOW_ORDER_TYPE_WINDOW)
rc = update_recv_window_info_order(update, s, &orderInfo);