Update upstream source from tag 'upstream/2.11.5+dfsg1'

Update to upstream version '2.11.5+dfsg1'
with Debian dir 3a144157ec
This commit is contained in:
Mike Gabriel 2024-03-25 16:13:55 +01:00
commit 6fe4ba798f
21 changed files with 698 additions and 235 deletions

View File

@ -104,7 +104,6 @@ ForEachMacros:
...
Language: ObjC
PointerBindsToType: false
ObjCSpaceAfterProperty: true
SortIncludes: false
ObjCBlockIndentWidth: 4
ObjCSpaceAfterProperty: false

View File

@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER})
endif()
set(WITH_LIBRARY_VERSIONING "ON")
set(RAW_VERSION_STRING "2.11.2")
set(RAW_VERSION_STRING "2.11.5")
if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag")
file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING)
elseif(USE_VERSION_FROM_GIT_TAG)

View File

@ -1,3 +1,34 @@
# 2024-01-19 Version 2.11.5
Noteworthy changes:
* Fix integer overflow in progressive decoder
* Update OpenSSL API usage for compatiblility with newer versions (#9747)
* Prevent NULL dereference for single thread decoder (#9712)
For a complete and detailed change log since the last release run:
git log 2.11.5...2.11.4
# 2023-12-14 Version 2.11.4
Notworthy changes:
* fix a typo in unicode commit (#9652)
For a complete and detailed change log since the last release run:
git log 2.11.4...2.11.3
# 2023-12-14 Version 2.11.3
Notworthy changes:
* Disabled windows MEDIA FOUNDATION h264 decoder due to reported issues (#9469)
* Fix issues with drive redirection (#9530,9554, #9586, #9617)
* Use endian safe ICU string converter (#9631)
* Improve AAC support (#9577)
* Fix swiss german keyboard layout (#9560)
* Enable rfx-mode:image (#9428)
For a complete and detailed change log since the last release run:
git log 2.11.3...2.11.2
# 2023-09-20 Version 2.11.2
Notworthy changes:
@ -5,7 +36,7 @@ Notworthy changes:
* Backported #9360: backported certificate algorithm detection
For a complete and detailed change log since the last release run:
git log 2.11.2..2.11.1
git log 2.11.2...2.11.1
# 2023-09-04 Version 2.11.1

View File

@ -35,6 +35,8 @@
#include "rdpdr_main.h"
#include "rdpdr_capabilities.h"
#define RDPDR_CAPABILITY_HEADER_LENGTH 8
/* Output device redirection capability set header */
static void rdpdr_write_capset_header(wStream* s, UINT16 capabilityType, UINT16 capabilityLength,
UINT32 version)
@ -48,39 +50,59 @@ static void rdpdr_write_capset_header(wStream* s, UINT16 capabilityType, UINT16
static void rdpdr_write_general_capset(rdpdrPlugin* rdpdr, wStream* s)
{
WINPR_UNUSED(rdpdr);
rdpdr_write_capset_header(s, CAP_GENERAL_TYPE, 44, GENERAL_CAPABILITY_VERSION_02);
Stream_Write_UINT32(s, 0); /* osType, ignored on receipt */
Stream_Write_UINT32(s, 0); /* osVersion, unused and must be set to zero */
Stream_Write_UINT16(s, 1); /* protocolMajorVersion, must be set to 1 */
Stream_Write_UINT16(s, RDPDR_MINOR_RDP_VERSION_5_2); /* protocolMinorVersion */
Stream_Write_UINT32(s, 0x0000FFFF); /* ioCode1 */
Stream_Write_UINT32(s, 0); /* ioCode2, must be set to zero, reserved for future use */
Stream_Write_UINT32(s, RDPDR_DEVICE_REMOVE_PDUS | RDPDR_CLIENT_DISPLAY_NAME_PDU |
RDPDR_USER_LOGGEDON_PDU); /* extendedPDU */
Stream_Write_UINT32(s, ENABLE_ASYNCIO); /* extraFlags1 */
Stream_Write_UINT32(s, 0); /* extraFlags2, must be set to zero, reserved for future use */
const UINT32 ioCode1 = rdpdr->clientIOCode1 & rdpdr->serverIOCode1;
const UINT32 ioCode2 = rdpdr->clientIOCode2 & rdpdr->serverIOCode2;
rdpdr_write_capset_header(s, CAP_GENERAL_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH + 36,
GENERAL_CAPABILITY_VERSION_02);
Stream_Write_UINT32(s, rdpdr->clientOsType); /* osType, ignored on receipt */
Stream_Write_UINT32(s, rdpdr->clientOsVersion); /* osVersion, unused and must be set to zero */
Stream_Write_UINT16(s, rdpdr->clientVersionMajor); /* protocolMajorVersion, must be set to 1 */
Stream_Write_UINT16(s, rdpdr->clientVersionMinor); /* protocolMinorVersion */
Stream_Write_UINT32(s, ioCode1); /* ioCode1 */
Stream_Write_UINT32(s, ioCode2); /* ioCode2, must be set to zero, reserved for future use */
Stream_Write_UINT32(s, rdpdr->clientExtendedPDU); /* extendedPDU */
Stream_Write_UINT32(s, rdpdr->clientExtraFlags1); /* extraFlags1 */
Stream_Write_UINT32(
s, 0); /* SpecialTypeDeviceCap, number of special devices to be redirected before logon */
s,
rdpdr->clientExtraFlags2); /* extraFlags2, must be set to zero, reserved for future use */
Stream_Write_UINT32(
s, rdpdr->clientSpecialTypeDeviceCap); /* SpecialTypeDeviceCap, number of special devices to
be redirected before logon */
}
/* Process device direction general capability set */
static UINT rdpdr_process_general_capset(rdpdrPlugin* rdpdr, wStream* s)
static UINT rdpdr_process_general_capset(rdpdrPlugin* rdpdr, wStream* s, UINT16 capabilityLength)
{
UINT16 capabilityLength;
WINPR_UNUSED(rdpdr);
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 2))
if (capabilityLength != 36)
{
WLog_Print(rdpdr->log, WLOG_ERROR,
"CAP_GENERAL_TYPE::CapabilityLength expected 36, got %" PRIu32,
capabilityLength);
return ERROR_INVALID_DATA;
}
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength))
return ERROR_INVALID_DATA;
Stream_Read_UINT16(s, capabilityLength);
if (capabilityLength < 4)
return ERROR_INVALID_DATA;
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength - 4U))
return ERROR_INVALID_DATA;
Stream_Seek(s, capabilityLength - 4U);
Stream_Read_UINT32(s, rdpdr->serverOsType); /* osType, ignored on receipt */
Stream_Read_UINT32(s, rdpdr->serverOsVersion); /* osVersion, unused and must be set to zero */
Stream_Read_UINT16(s, rdpdr->serverVersionMajor); /* protocolMajorVersion, must be set to 1 */
Stream_Read_UINT16(s, rdpdr->serverVersionMinor); /* protocolMinorVersion */
Stream_Read_UINT32(s, rdpdr->serverIOCode1); /* ioCode1 */
Stream_Read_UINT32(
s, rdpdr->serverIOCode2); /* ioCode2, must be set to zero, reserved for future use */
Stream_Read_UINT32(s, rdpdr->serverExtendedPDU); /* extendedPDU */
Stream_Read_UINT32(s, rdpdr->serverExtraFlags1); /* extraFlags1 */
Stream_Read_UINT32(
s,
rdpdr->serverExtraFlags2); /* extraFlags2, must be set to zero, reserved for future use */
Stream_Read_UINT32(
s, rdpdr->serverSpecialTypeDeviceCap); /* SpecialTypeDeviceCap, number of special devices to
be redirected before logon */
return CHANNEL_RC_OK;
}
@ -92,23 +114,14 @@ static void rdpdr_write_printer_capset(rdpdrPlugin* rdpdr, wStream* s)
}
/* Process printer direction capability set */
static UINT rdpdr_process_printer_capset(rdpdrPlugin* rdpdr, wStream* s)
static UINT rdpdr_process_printer_capset(rdpdrPlugin* rdpdr, wStream* s, UINT16 capabilityLength)
{
UINT16 capabilityLength;
WINPR_UNUSED(rdpdr);
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 2))
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength))
return ERROR_INVALID_DATA;
Stream_Read_UINT16(s, capabilityLength);
if (capabilityLength < 4)
return ERROR_INVALID_DATA;
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength - 4U))
return ERROR_INVALID_DATA;
Stream_Seek(s, capabilityLength - 4U);
Stream_Seek(s, capabilityLength);
return CHANNEL_RC_OK;
}
@ -120,23 +133,14 @@ static void rdpdr_write_port_capset(rdpdrPlugin* rdpdr, wStream* s)
}
/* Process port redirection capability set */
static UINT rdpdr_process_port_capset(rdpdrPlugin* rdpdr, wStream* s)
static UINT rdpdr_process_port_capset(rdpdrPlugin* rdpdr, wStream* s, UINT16 capabilityLength)
{
UINT16 capabilityLength;
WINPR_UNUSED(rdpdr);
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 2))
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength))
return ERROR_INVALID_DATA;
Stream_Read_UINT16(s, capabilityLength);
if (capabilityLength < 4U)
return ERROR_INVALID_DATA;
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength - 4U))
return ERROR_INVALID_DATA;
Stream_Seek(s, capabilityLength - 4U);
Stream_Seek(s, capabilityLength);
return CHANNEL_RC_OK;
}
@ -148,23 +152,14 @@ static void rdpdr_write_drive_capset(rdpdrPlugin* rdpdr, wStream* s)
}
/* Process drive redirection capability set */
static UINT rdpdr_process_drive_capset(rdpdrPlugin* rdpdr, wStream* s)
static UINT rdpdr_process_drive_capset(rdpdrPlugin* rdpdr, wStream* s, UINT16 capabilityLength)
{
UINT16 capabilityLength;
WINPR_UNUSED(rdpdr);
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 2))
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength))
return ERROR_INVALID_DATA;
Stream_Read_UINT16(s, capabilityLength);
if (capabilityLength < 4)
return ERROR_INVALID_DATA;
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength - 4U))
return ERROR_INVALID_DATA;
Stream_Seek(s, capabilityLength - 4U);
Stream_Seek(s, capabilityLength);
return CHANNEL_RC_OK;
}
@ -176,23 +171,14 @@ static void rdpdr_write_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s)
}
/* Process smartcard redirection capability set */
static UINT rdpdr_process_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s)
static UINT rdpdr_process_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s, UINT16 capabilityLength)
{
UINT16 capabilityLength;
WINPR_UNUSED(rdpdr);
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 2))
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength))
return ERROR_INVALID_DATA;
Stream_Read_UINT16(s, capabilityLength);
if (capabilityLength < 4)
return ERROR_INVALID_DATA;
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength - 4U))
return ERROR_INVALID_DATA;
Stream_Seek(s, capabilityLength - 4U);
Stream_Seek(s, capabilityLength);
return CHANNEL_RC_OK;
}
@ -201,7 +187,6 @@ UINT rdpdr_process_capability_request(rdpdrPlugin* rdpdr, wStream* s)
UINT status = CHANNEL_RC_OK;
UINT16 i;
UINT16 numCapabilities;
UINT16 capabilityType;
if (!rdpdr || !s)
return CHANNEL_RC_NULL_DATA;
@ -217,31 +202,44 @@ UINT rdpdr_process_capability_request(rdpdrPlugin* rdpdr, wStream* s)
for (i = 0; i < numCapabilities; i++)
{
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, sizeof(UINT16)))
UINT16 capabilityType;
UINT16 capabilityLength;
UINT32 version = 0;
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s,
2 * sizeof(UINT16) + sizeof(UINT32)))
return ERROR_INVALID_DATA;
Stream_Read_UINT16(s, capabilityType);
Stream_Read_UINT16(s, capabilityLength);
Stream_Read_UINT32(s, version);
if (capabilityLength < 8)
{
return ERROR_INVALID_DATA;
}
capabilityLength -= 8;
switch (capabilityType)
{
case CAP_GENERAL_TYPE:
status = rdpdr_process_general_capset(rdpdr, s);
status = rdpdr_process_general_capset(rdpdr, s, capabilityLength);
break;
case CAP_PRINTER_TYPE:
status = rdpdr_process_printer_capset(rdpdr, s);
status = rdpdr_process_printer_capset(rdpdr, s, capabilityLength);
break;
case CAP_PORT_TYPE:
status = rdpdr_process_port_capset(rdpdr, s);
status = rdpdr_process_port_capset(rdpdr, s, capabilityLength);
break;
case CAP_DRIVE_TYPE:
status = rdpdr_process_drive_capset(rdpdr, s);
status = rdpdr_process_drive_capset(rdpdr, s, capabilityLength);
break;
case CAP_SMARTCARD_TYPE:
status = rdpdr_process_smartcard_capset(rdpdr, s);
status = rdpdr_process_smartcard_capset(rdpdr, s, capabilityLength);
break;
default:

View File

@ -79,6 +79,41 @@ struct _DEVICE_DRIVE_EXT
BOOL automount;
};
static const char* rdpdr_packetid_string(UINT16 packetid)
{
switch (packetid)
{
case PAKID_CORE_SERVER_ANNOUNCE:
return "PAKID_CORE_SERVER_ANNOUNCE";
case PAKID_CORE_CLIENTID_CONFIRM:
return "PAKID_CORE_CLIENTID_CONFIRM";
case PAKID_CORE_CLIENT_NAME:
return "PAKID_CORE_CLIENT_NAME";
case PAKID_CORE_DEVICELIST_ANNOUNCE:
return "PAKID_CORE_DEVICELIST_ANNOUNCE";
case PAKID_CORE_DEVICE_REPLY:
return "PAKID_CORE_DEVICE_REPLY";
case PAKID_CORE_DEVICE_IOREQUEST:
return "PAKID_CORE_DEVICE_IOREQUEST";
case PAKID_CORE_DEVICE_IOCOMPLETION:
return "PAKID_CORE_DEVICE_IOCOMPLETION";
case PAKID_CORE_SERVER_CAPABILITY:
return "PAKID_CORE_SERVER_CAPABILITY";
case PAKID_CORE_CLIENT_CAPABILITY:
return "PAKID_CORE_CLIENT_CAPABILITY";
case PAKID_CORE_DEVICELIST_REMOVE:
return "PAKID_CORE_DEVICELIST_REMOVE";
case PAKID_CORE_USER_LOGGEDON:
return "PAKID_CORE_USER_LOGGEDON";
case PAKID_PRN_CACHE_DATA:
return "PAKID_PRN_CACHE_DATA";
case PAKID_PRN_USING_XPS:
return "PAKID_PRN_USING_XPS";
default:
return "UNKNOWN";
}
}
static const char* rdpdr_state_str(enum RDPDR_CHANNEL_STATE state)
{
switch (state)
@ -106,6 +141,63 @@ static const char* rdpdr_state_str(enum RDPDR_CHANNEL_STATE state)
}
}
static const char* rdpdr_device_type_string(UINT32 type)
{
switch (type)
{
case RDPDR_DTYP_SERIAL:
return "serial";
case RDPDR_DTYP_PRINT:
return "printer";
case RDPDR_DTYP_FILESYSTEM:
return "drive";
case RDPDR_DTYP_SMARTCARD:
return "smartcard";
case RDPDR_DTYP_PARALLEL:
return "parallel";
default:
return "UNKNOWN";
}
}
static const char* support_str(BOOL val)
{
if (val)
return "supported";
return "not found";
}
static const char* rdpdr_caps_pdu_str(UINT32 flag)
{
switch (flag)
{
case RDPDR_DEVICE_REMOVE_PDUS:
return "RDPDR_USER_LOGGEDON_PDU";
case RDPDR_CLIENT_DISPLAY_NAME_PDU:
return "RDPDR_CLIENT_DISPLAY_NAME_PDU";
case RDPDR_USER_LOGGEDON_PDU:
return "RDPDR_USER_LOGGEDON_PDU";
default:
return "RDPDR_UNKNONW";
}
}
static BOOL rdpdr_check_extended_pdu_flag(rdpdrPlugin* rdpdr, UINT32 flag)
{
WINPR_ASSERT(rdpdr);
const BOOL client = (rdpdr->clientExtendedPDU & flag) != 0;
const BOOL server = (rdpdr->serverExtendedPDU & flag) != 0;
if (!client || !server)
{
WLog_Print(rdpdr->log, WLOG_WARN, "Checking ExtendedPDU::%s, client %s, server %s",
rdpdr_caps_pdu_str(flag), support_str(client), support_str(server));
return FALSE;
}
return TRUE;
}
BOOL rdpdr_state_advance(rdpdrPlugin* rdpdr, enum RDPDR_CHANNEL_STATE next)
{
WINPR_ASSERT(rdpdr);
@ -133,6 +225,16 @@ static UINT rdpdr_send_device_list_remove_request(rdpdrPlugin* rdpdr, UINT32 cou
{
UINT32 i;
wStream* s;
WINPR_ASSERT(rdpdr);
WINPR_ASSERT(ids || (count == 0));
if (count == 0)
return CHANNEL_RC_OK;
if (!rdpdr_check_extended_pdu_flag(rdpdr, RDPDR_DEVICE_REMOVE_PDUS))
return CHANNEL_RC_OK;
s = Stream_New(NULL, count * sizeof(UINT32) + 8);
if (!s)
@ -1115,10 +1217,19 @@ static UINT rdpdr_process_server_announce_request(rdpdrPlugin* rdpdr, wStream* s
if (Stream_GetRemainingLength(s) < 8)
return ERROR_INVALID_DATA;
Stream_Read_UINT16(s, rdpdr->versionMajor);
Stream_Read_UINT16(s, rdpdr->versionMinor);
Stream_Read_UINT16(s, rdpdr->serverVersionMajor);
Stream_Read_UINT16(s, rdpdr->serverVersionMinor);
Stream_Read_UINT32(s, rdpdr->clientID);
rdpdr->sequenceId++;
rdpdr->clientVersionMajor = MIN(RDPDR_VERSION_MAJOR, rdpdr->serverVersionMajor);
rdpdr->clientVersionMinor = MIN(RDPDR_VERSION_MINOR_RDP10X, rdpdr->serverVersionMinor);
WLog_Print(rdpdr->log, WLOG_DEBUG,
"[rdpdr] server announces version %" PRIu32 ".%" PRIu32 ", client uses %" PRIu32
".%" PRIu32,
rdpdr->serverVersionMajor, rdpdr->serverVersionMinor, rdpdr->clientVersionMajor,
rdpdr->clientVersionMinor);
return CHANNEL_RC_OK;
}
@ -1145,8 +1256,8 @@ static UINT rdpdr_send_client_announce_reply(rdpdrPlugin* rdpdr)
Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */
Stream_Write_UINT16(s, PAKID_CORE_CLIENTID_CONFIRM); /* PacketId (2 bytes) */
Stream_Write_UINT16(s, rdpdr->versionMajor);
Stream_Write_UINT16(s, rdpdr->versionMinor);
Stream_Write_UINT16(s, rdpdr->clientVersionMajor);
Stream_Write_UINT16(s, rdpdr->clientVersionMinor);
Stream_Write_UINT32(s, (UINT32)rdpdr->clientID);
return rdpdr_send(rdpdr, s);
}
@ -1209,10 +1320,10 @@ static UINT rdpdr_process_server_clientid_confirm(rdpdrPlugin* rdpdr, wStream* s
Stream_Read_UINT16(s, versionMinor);
Stream_Read_UINT32(s, clientID);
if (versionMajor != rdpdr->versionMajor || versionMinor != rdpdr->versionMinor)
if (versionMajor != rdpdr->clientVersionMajor || versionMinor != rdpdr->clientVersionMinor)
{
rdpdr->versionMajor = versionMajor;
rdpdr->versionMinor = versionMinor;
rdpdr->clientVersionMajor = versionMajor;
rdpdr->clientVersionMinor = versionMinor;
}
if (clientID != rdpdr->clientID)
@ -1241,15 +1352,7 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL use
ULONG_PTR* pKeys = NULL;
if (userLoggedOn)
{
WINPR_ASSERT(rdpdr->state >= RDPDR_CHANNEL_STATE_READY);
rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_USER_LOGGEDON);
}
else
{
WINPR_ASSERT(rdpdr->state >= RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM);
rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_READY);
}
rdpdr->userLoggedOn = TRUE;
s = Stream_New(NULL, 256);
@ -1278,8 +1381,8 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL use
* 3. other devices are sent only after user_loggedon
*/
if ((rdpdr->versionMinor == 0x0005) || (device->type == RDPDR_DTYP_SMARTCARD) ||
userLoggedOn)
if ((rdpdr->clientVersionMinor == RDPDR_VERSION_MINOR_RDP51) ||
(device->type == RDPDR_DTYP_SMARTCARD) || userLoggedOn)
{
data_len = (device->data == NULL ? 0 : Stream_GetPosition(device->data));
@ -1444,6 +1547,8 @@ static UINT rdpdr_process_init(rdpdrPlugin* rdpdr)
DEVICE* device;
ULONG_PTR* pKeys = NULL;
UINT error = CHANNEL_RC_OK;
rdpdr->userLoggedOn = FALSE; /* reset possible received state */
pKeys = NULL;
keyCount = ListDictionary_GetKeys(rdpdr->devman->devices, &pKeys);
@ -1464,18 +1569,50 @@ static UINT rdpdr_process_init(rdpdrPlugin* rdpdr)
return CHANNEL_RC_OK;
}
static BOOL rdpdr_state_check(rdpdrPlugin* rdpdr, UINT16 packetid,
enum RDPDR_CHANNEL_STATE expected, enum RDPDR_CHANNEL_STATE next)
static BOOL state_match(enum RDPDR_CHANNEL_STATE state, size_t count, va_list ap)
{
for (size_t x = 0; x < count; x++)
{
enum RDPDR_CHANNEL_STATE cur = va_arg(ap, enum RDPDR_CHANNEL_STATE);
if (state == cur)
return TRUE;
}
return FALSE;
}
static const char* state_str(size_t count, va_list ap, char* buffer, size_t size)
{
for (size_t x = 0; x < count; x++)
{
enum RDPDR_CHANNEL_STATE cur = va_arg(ap, enum RDPDR_CHANNEL_STATE);
const char* curstr = rdpdr_state_str(cur);
winpr_str_append(curstr, buffer, size, "|");
}
return buffer;
}
static BOOL rdpdr_state_check(rdpdrPlugin* rdpdr, UINT16 packetid, enum RDPDR_CHANNEL_STATE next,
size_t count, ...)
{
va_list ap;
WINPR_ASSERT(rdpdr);
const char* strstate = rdpdr_state_str(rdpdr->state);
if (rdpdr->state != expected)
va_start(ap, count);
BOOL rc = state_match(rdpdr->state, count, ap);
va_end(ap);
if (!rc)
{
const char* strstate = rdpdr_state_str(rdpdr->state);
char buffer[256] = { 0 };
va_start(ap, count);
state_str(count, ap, buffer, sizeof(buffer));
va_end(ap);
WLog_Print(rdpdr->log, WLOG_ERROR,
"channel [RDPDR] received %" PRIu16
", expected state %s but have state %s, aborting.",
packetid, rdpdr_state_str(expected), strstate);
"channel [RDPDR] received %s, expected states [%s] but have state %s, aborting.",
rdpdr_packetid_string(packetid), buffer, strstate);
rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_INITIAL);
return FALSE;
@ -1495,23 +1632,30 @@ static BOOL rdpdr_check_channel_state(rdpdrPlugin* rdpdr, UINT16 packetid)
* then reinitialize the channel after login successful
*/
rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_INITIAL);
return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_INITIAL,
RDPDR_CHANNEL_STATE_ANNOUNCE);
return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_ANNOUNCE, 1,
RDPDR_CHANNEL_STATE_INITIAL);
case PAKID_CORE_SERVER_CAPABILITY:
return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_NAME_REQUEST,
RDPDR_CHANNEL_STATE_SERVER_CAPS);
return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_SERVER_CAPS, 6,
RDPDR_CHANNEL_STATE_NAME_REQUEST,
RDPDR_CHANNEL_STATE_SERVER_CAPS, RDPDR_CHANNEL_STATE_READY,
RDPDR_CHANNEL_STATE_CLIENT_CAPS, PAKID_CORE_CLIENTID_CONFIRM,
PAKID_CORE_USER_LOGGEDON);
case PAKID_CORE_CLIENTID_CONFIRM:
return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_CLIENT_CAPS,
RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM);
case PAKID_CORE_USER_LOGGEDON:
return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_READY,
return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM, 3,
RDPDR_CHANNEL_STATE_CLIENT_CAPS, RDPDR_CHANNEL_STATE_READY,
RDPDR_CHANNEL_STATE_USER_LOGGEDON);
case PAKID_CORE_USER_LOGGEDON:
if (!rdpdr_check_extended_pdu_flag(rdpdr, RDPDR_USER_LOGGEDON_PDU))
return FALSE;
return rdpdr_state_check(
rdpdr, packetid, RDPDR_CHANNEL_STATE_USER_LOGGEDON, 4,
RDPDR_CHANNEL_STATE_NAME_REQUEST, RDPDR_CHANNEL_STATE_CLIENT_CAPS,
RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM, RDPDR_CHANNEL_STATE_READY);
default:
{
enum RDPDR_CHANNEL_STATE state = RDPDR_CHANNEL_STATE_READY;
if (rdpdr->state == RDPDR_CHANNEL_STATE_USER_LOGGEDON)
state = RDPDR_CHANNEL_STATE_USER_LOGGEDON;
return rdpdr_state_check(rdpdr, packetid, state, state);
return rdpdr_state_check(rdpdr, packetid, state, 1, state);
}
}
}
@ -1592,7 +1736,10 @@ static UINT rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s)
"rdpdr_send_device_list_announce_request failed with error %" PRIu32 "",
error);
}
else if (!rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_READY))
{
error = ERROR_INTERNAL_ERROR;
}
break;
case PAKID_CORE_USER_LOGGEDON:
@ -1603,6 +1750,10 @@ static UINT rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s)
"rdpdr_send_device_list_announce_request failed with error %" PRIu32 "",
error);
}
else if (!rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_READY))
{
error = ERROR_INTERNAL_ERROR;
}
break;
@ -2035,6 +2186,10 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p
UINT rc;
rdpdrPlugin* rdpdr;
CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx;
WINPR_ASSERT(pEntryPoints);
WINPR_ASSERT(pInitHandle);
rdpdr = (rdpdrPlugin*)calloc(1, sizeof(rdpdrPlugin));
if (!rdpdr)
@ -2043,7 +2198,18 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p
return FALSE;
}
rdpdr->log = WLog_Get(TAG);
WINPR_ASSERT(rdpdr->log);
rdpdr->clientExtendedPDU =
RDPDR_DEVICE_REMOVE_PDUS | RDPDR_CLIENT_DISPLAY_NAME_PDU | RDPDR_USER_LOGGEDON_PDU;
rdpdr->clientIOCode1 =
RDPDR_IRP_MJ_CREATE | RDPDR_IRP_MJ_CLEANUP | RDPDR_IRP_MJ_CLOSE | RDPDR_IRP_MJ_READ |
RDPDR_IRP_MJ_WRITE | RDPDR_IRP_MJ_FLUSH_BUFFERS | RDPDR_IRP_MJ_SHUTDOWN |
RDPDR_IRP_MJ_DEVICE_CONTROL | RDPDR_IRP_MJ_QUERY_VOLUME_INFORMATION |
RDPDR_IRP_MJ_SET_VOLUME_INFORMATION | RDPDR_IRP_MJ_QUERY_INFORMATION |
RDPDR_IRP_MJ_SET_INFORMATION | RDPDR_IRP_MJ_DIRECTORY_CONTROL | RDPDR_IRP_MJ_LOCK_CONTROL |
RDPDR_IRP_MJ_QUERY_SECURITY | RDPDR_IRP_MJ_SET_SECURITY;
rdpdr->clientExtraFlags1 = ENABLE_ASYNCIO;
rdpdr->channelDef.options =
CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP;

View File

@ -77,12 +77,33 @@ struct rdpdr_plugin
DEVMAN* devman;
UINT16 versionMajor;
UINT16 versionMinor;
UINT16 clientID;
UINT32 serverOsType;
UINT32 serverOsVersion;
UINT16 serverVersionMajor;
UINT16 serverVersionMinor;
UINT32 serverExtendedPDU;
UINT32 serverIOCode1;
UINT32 serverIOCode2;
UINT32 serverExtraFlags1;
UINT32 serverExtraFlags2;
UINT32 serverSpecialTypeDeviceCap;
UINT32 clientOsType;
UINT32 clientOsVersion;
UINT16 clientVersionMajor;
UINT16 clientVersionMinor;
UINT32 clientExtendedPDU;
UINT32 clientIOCode1;
UINT32 clientIOCode2;
UINT32 clientExtraFlags1;
UINT32 clientExtraFlags2;
UINT32 clientSpecialTypeDeviceCap;
UINT32 clientID;
char computerName[256];
UINT32 sequenceId;
BOOL userLoggedOn;
/* hotplug support */
HANDLE hotplugThread;

View File

@ -57,13 +57,6 @@ struct _RDPDR_HEADER
};
typedef struct _RDPDR_HEADER RDPDR_HEADER;
#define RDPDR_VERSION_MAJOR 0x0001
#define RDPDR_VERSION_MINOR_RDP50 0x0002
#define RDPDR_VERSION_MINOR_RDP51 0x0005
#define RDPDR_VERSION_MINOR_RDP52 0x000A
#define RDPDR_VERSION_MINOR_RDP6X 0x000C
#define RDPDR_CAPABILITY_HEADER_LENGTH 8
struct _RDPDR_CAPABILITY_HEADER

View File

@ -23,11 +23,15 @@
#include "config.h"
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <winpr/crt.h>
#include <winpr/assert.h>
#include <winpr/stream.h>
#include <winpr/cmdline.h>
@ -51,8 +55,39 @@ struct rdpsnd_pulse_plugin
pa_stream* stream;
UINT32 latency;
UINT32 volume;
time_t reconnect_delay_seconds;
time_t reconnect_time;
};
static BOOL rdpsnd_check_pulse(rdpsndPulsePlugin* pulse, BOOL haveStream)
{
BOOL rc = TRUE;
WINPR_ASSERT(pulse);
if (!pulse->context)
{
WLog_WARN(TAG, "pulse->context=%p", pulse->context);
rc = FALSE;
}
if (haveStream)
{
if (!pulse->stream)
{
WLog_WARN(TAG, "pulse->stream=%p", pulse->stream);
rc = FALSE;
}
}
if (!pulse->mainloop)
{
WLog_WARN(TAG, "pulse->mainloop=%p", pulse->mainloop);
rc = FALSE;
}
return rc;
}
static BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format);
static void rdpsnd_pulse_get_sink_info(pa_context* c, const pa_sink_info* i, int eol,
@ -65,7 +100,8 @@ static void rdpsnd_pulse_get_sink_info(pa_context* c, const pa_sink_info* i, int
;
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)userdata;
if (!pulse || !c || !i)
WINPR_ASSERT(c);
if (!rdpsnd_check_pulse(pulse, FALSE) || !i)
return;
for (x = 0; x < i->volume.channels; x++)
@ -97,6 +133,10 @@ static void rdpsnd_pulse_context_state_callback(pa_context* context, void* userd
{
pa_context_state_t state;
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)userdata;
WINPR_ASSERT(context);
WINPR_ASSERT(pulse);
state = pa_context_get_state(context);
switch (state)
@ -106,6 +146,14 @@ static void rdpsnd_pulse_context_state_callback(pa_context* context, void* userd
break;
case PA_CONTEXT_FAILED:
// Destroy context now, create new one for next connection attempt
pa_context_unref(pulse->context);
pulse->context = NULL;
if (pulse->reconnect_delay_seconds >= 0)
pulse->reconnect_time = time(NULL) + pulse->reconnect_delay_seconds;
pa_threaded_mainloop_signal(pulse->mainloop, 0);
break;
case PA_CONTEXT_TERMINATED:
pa_threaded_mainloop_signal(pulse->mainloop, 0);
break;
@ -117,21 +165,17 @@ static void rdpsnd_pulse_context_state_callback(pa_context* context, void* userd
static BOOL rdpsnd_pulse_connect(rdpsndDevicePlugin* device)
{
BOOL rc;
pa_operation* o;
pa_context_state_t state;
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
if (!pulse->context)
if (!rdpsnd_check_pulse(pulse, FALSE))
return FALSE;
if (pa_context_connect(pulse->context, NULL, 0, NULL))
{
return FALSE;
}
pa_threaded_mainloop_lock(pulse->mainloop);
if (pa_threaded_mainloop_start(pulse->mainloop) < 0)
if (pa_context_connect(pulse->context, NULL, 0, NULL) < 0)
{
pa_threaded_mainloop_unlock(pulse->mainloop);
return FALSE;
@ -157,27 +201,35 @@ static BOOL rdpsnd_pulse_connect(rdpsndDevicePlugin* device)
if (o)
pa_operation_unref(o);
pa_threaded_mainloop_unlock(pulse->mainloop);
if (state == PA_CONTEXT_READY)
{
return TRUE;
rc = TRUE;
}
else
{
pa_context_disconnect(pulse->context);
return FALSE;
rc = FALSE;
}
pa_threaded_mainloop_unlock(pulse->mainloop);
return rc;
}
static void rdpsnd_pulse_stream_success_callback(pa_stream* stream, int success, void* userdata)
{
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)userdata;
if (!rdpsnd_check_pulse(pulse, TRUE))
return;
pa_threaded_mainloop_signal(pulse->mainloop, 0);
}
static void rdpsnd_pulse_wait_for_operation(rdpsndPulsePlugin* pulse, pa_operation* operation)
{
if (!rdpsnd_check_pulse(pulse, TRUE))
return;
if (!operation)
return;
@ -193,6 +245,11 @@ static void rdpsnd_pulse_stream_state_callback(pa_stream* stream, void* userdata
{
pa_stream_state_t state;
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)userdata;
WINPR_ASSERT(stream);
if (!rdpsnd_check_pulse(pulse, TRUE))
return;
state = pa_stream_get_state(stream);
switch (state)
@ -203,6 +260,8 @@ static void rdpsnd_pulse_stream_state_callback(pa_stream* stream, void* userdata
case PA_STREAM_FAILED:
case PA_STREAM_TERMINATED:
// Stream object is about to be destroyed, clean up our pointer
pulse->stream = NULL;
pa_threaded_mainloop_signal(pulse->mainloop, 0);
break;
@ -214,6 +273,11 @@ static void rdpsnd_pulse_stream_state_callback(pa_stream* stream, void* userdata
static void rdpsnd_pulse_stream_request_callback(pa_stream* stream, size_t length, void* userdata)
{
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)userdata;
WINPR_ASSERT(stream);
if (!rdpsnd_check_pulse(pulse, TRUE))
return;
pa_threaded_mainloop_signal(pulse->mainloop, 0);
}
@ -221,15 +285,20 @@ static void rdpsnd_pulse_close(rdpsndDevicePlugin* device)
{
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
if (!pulse->context || !pulse->stream)
WINPR_ASSERT(pulse);
if (!rdpsnd_check_pulse(pulse, FALSE))
return;
pa_threaded_mainloop_lock(pulse->mainloop);
rdpsnd_pulse_wait_for_operation(
pulse, pa_stream_drain(pulse->stream, rdpsnd_pulse_stream_success_callback, pulse));
pa_stream_disconnect(pulse->stream);
pa_stream_unref(pulse->stream);
pulse->stream = NULL;
if (pulse->stream)
{
rdpsnd_pulse_wait_for_operation(
pulse, pa_stream_drain(pulse->stream, rdpsnd_pulse_stream_success_callback, pulse));
pa_stream_disconnect(pulse->stream);
pa_stream_unref(pulse->stream);
pulse->stream = NULL;
}
pa_threaded_mainloop_unlock(pulse->mainloop);
}
@ -237,7 +306,9 @@ static BOOL rdpsnd_pulse_set_format_spec(rdpsndPulsePlugin* pulse, const AUDIO_F
{
pa_sample_spec sample_spec = { 0 };
if (!pulse->context)
WINPR_ASSERT(format);
if (!rdpsnd_check_pulse(pulse, FALSE))
return FALSE;
if (!rdpsnd_pulse_format_supported(&pulse->device, format))
@ -281,30 +352,52 @@ static BOOL rdpsnd_pulse_set_format_spec(rdpsndPulsePlugin* pulse, const AUDIO_F
return TRUE;
}
static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format,
UINT32 latency)
static BOOL rdpsnd_pulse_context_connect(rdpsndDevicePlugin* device)
{
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
pulse->context = pa_context_new(pa_threaded_mainloop_get_api(pulse->mainloop), "freerdp");
if (!pulse->context)
return FALSE;
pa_context_set_state_callback(pulse->context, rdpsnd_pulse_context_state_callback, pulse);
if (!rdpsnd_pulse_connect((rdpsndDevicePlugin*)pulse))
return FALSE;
return TRUE;
}
static BOOL rdpsnd_pulse_open_stream(rdpsndDevicePlugin* device)
{
pa_stream_state_t state;
pa_stream_flags_t flags;
pa_buffer_attr buffer_attr = { 0 };
char ss[PA_SAMPLE_SPEC_SNPRINT_MAX];
char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = { 0 };
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
if (!pulse->context || pulse->stream)
return TRUE;
if (!rdpsnd_pulse_set_format_spec(pulse, format))
return FALSE;
pulse->latency = latency;
if (pa_sample_spec_valid(&pulse->sample_spec) == 0)
{
pa_sample_spec_snprint(ss, sizeof(ss), &pulse->sample_spec);
return TRUE;
return FALSE;
}
pa_threaded_mainloop_lock(pulse->mainloop);
if (!pulse->context)
{
pa_threaded_mainloop_unlock(pulse->mainloop);
if (pulse->reconnect_delay_seconds >= 0 && time(NULL) - pulse->reconnect_time >= 0)
rdpsnd_pulse_context_connect(device);
pa_threaded_mainloop_lock(pulse->mainloop);
}
if (!rdpsnd_check_pulse(pulse, FALSE))
{
pa_threaded_mainloop_unlock(pulse->mainloop);
return FALSE;
}
pulse->stream = pa_stream_new(pulse->context, "freerdp", &pulse->sample_spec, NULL);
if (!pulse->stream)
@ -320,19 +413,22 @@ static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* fo
if (pulse->latency > 0)
{
buffer_attr.maxlength = pa_usec_to_bytes(pulse->latency * 2 * 1000, &pulse->sample_spec);
buffer_attr.maxlength = UINT32_MAX;
buffer_attr.tlength = pa_usec_to_bytes(pulse->latency * 1000, &pulse->sample_spec);
buffer_attr.prebuf = (UINT32)-1;
buffer_attr.minreq = (UINT32)-1;
buffer_attr.fragsize = (UINT32)-1;
buffer_attr.prebuf = UINT32_MAX;
buffer_attr.minreq = UINT32_MAX;
buffer_attr.fragsize = UINT32_MAX;
flags |= PA_STREAM_ADJUST_LATENCY;
}
if (pa_stream_connect_playback(pulse->stream, pulse->device_name,
pulse->latency > 0 ? &buffer_attr : NULL, flags, NULL, NULL) < 0)
{
WLog_ERR(TAG, "error connecting playback stream");
pa_stream_unref(pulse->stream);
pulse->stream = NULL;
pa_threaded_mainloop_unlock(pulse->mainloop);
return TRUE;
return FALSE;
}
for (;;)
@ -359,6 +455,24 @@ static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* fo
return FALSE;
}
static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format,
UINT32 latency)
{
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
WINPR_ASSERT(format);
if (!rdpsnd_check_pulse(pulse, FALSE))
return TRUE;
if (!rdpsnd_pulse_set_format_spec(pulse, format))
return FALSE;
pulse->latency = latency;
return rdpsnd_pulse_open_stream(device);
}
static void rdpsnd_pulse_free(rdpsndDevicePlugin* device)
{
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
@ -369,9 +483,7 @@ static void rdpsnd_pulse_free(rdpsndDevicePlugin* device)
rdpsnd_pulse_close(device);
if (pulse->mainloop)
{
pa_threaded_mainloop_stop(pulse->mainloop);
}
if (pulse->context)
{
@ -394,6 +506,7 @@ static BOOL rdpsnd_pulse_default_format(rdpsndDevicePlugin* device, const AUDIO_
AUDIO_FORMAT* defaultFormat)
{
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
if (!pulse || !defaultFormat)
return FALSE;
@ -415,6 +528,9 @@ static BOOL rdpsnd_pulse_default_format(rdpsndDevicePlugin* device, const AUDIO_
BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format)
{
WINPR_ASSERT(device);
WINPR_ASSERT(format);
switch (format->wFormatTag)
{
case WAVE_FORMAT_PCM:
@ -439,39 +555,51 @@ static UINT32 rdpsnd_pulse_get_volume(rdpsndDevicePlugin* device)
pa_operation* o;
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
if (!pulse)
return 0;
if (!pulse->context || !pulse->mainloop)
if (!rdpsnd_check_pulse(pulse, FALSE))
return 0;
pa_threaded_mainloop_lock(pulse->mainloop);
o = pa_context_get_sink_info_by_index(pulse->context, 0, rdpsnd_pulse_get_sink_info, pulse);
pa_operation_unref(o);
if (o)
pa_operation_unref(o);
pa_threaded_mainloop_unlock(pulse->mainloop);
return pulse->volume;
}
static void rdpsnd_set_volume_success_cb(pa_context* c, int success, void* userdata)
{
rdpsndPulsePlugin* pulse = userdata;
if (!rdpsnd_check_pulse(pulse, TRUE))
return;
WINPR_ASSERT(c);
WLog_INFO(TAG, "%s: %d", __FUNCTION__, success);
}
static BOOL rdpsnd_pulse_set_volume(rdpsndDevicePlugin* device, UINT32 value)
{
pa_cvolume cv;
pa_cvolume cv = { 0 };
pa_volume_t left;
pa_volume_t right;
pa_operation* operation;
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
if (!pulse->context || !pulse->stream)
if (!rdpsnd_check_pulse(pulse, TRUE))
{
WLog_WARN(TAG, "%s called before pulse backend was initialized");
return FALSE;
}
left = (pa_volume_t)(value & 0xFFFF);
right = (pa_volume_t)((value >> 16) & 0xFFFF);
pa_cvolume_init(&cv);
cv.channels = 2;
cv.values[0] = PA_VOLUME_MUTED + (left * (PA_VOLUME_NORM - PA_VOLUME_MUTED)) / 0xFFFF;
cv.values[1] = PA_VOLUME_MUTED + (right * (PA_VOLUME_NORM - PA_VOLUME_MUTED)) / 0xFFFF;
cv.values[0] = PA_VOLUME_MUTED + (left * (PA_VOLUME_NORM - PA_VOLUME_MUTED)) / PA_VOLUME_NORM;
cv.values[1] = PA_VOLUME_MUTED + (right * (PA_VOLUME_NORM - PA_VOLUME_MUTED)) / PA_VOLUME_NORM;
pa_threaded_mainloop_lock(pulse->mainloop);
operation = pa_context_set_sink_input_volume(pulse->context, pa_stream_get_index(pulse->stream),
&cv, NULL, NULL);
&cv, rdpsnd_set_volume_success_cb, pulse);
if (operation)
pa_operation_unref(operation);
@ -483,28 +611,38 @@ static BOOL rdpsnd_pulse_set_volume(rdpsndDevicePlugin* device, UINT32 value)
static UINT rdpsnd_pulse_play(rdpsndDevicePlugin* device, const BYTE* data, size_t size)
{
size_t length;
void* pa_data;
int status;
pa_usec_t latency;
int negative;
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
if (!pulse->stream || !data)
if (!data)
return 0;
pa_threaded_mainloop_lock(pulse->mainloop);
if (!rdpsnd_check_pulse(pulse, TRUE))
{
pa_threaded_mainloop_unlock(pulse->mainloop);
// Discard this playback request and just attempt to reconnect the stream
WLog_DBG(TAG, "reconnecting playback stream");
rdpsnd_pulse_open_stream(device);
return 0;
}
while (size > 0)
{
while ((length = pa_stream_writable_size(pulse->stream)) == 0)
pa_threaded_mainloop_wait(pulse->mainloop);
length = size;
if (length == (size_t)-1)
status = pa_stream_begin_write(pulse->stream, &pa_data, &length);
if (status < 0)
break;
if (length > size)
length = size;
memcpy(pa_data, data, length);
status = pa_stream_write(pulse->stream, data, length, NULL, 0LL, PA_SEEK_RELATIVE);
status = pa_stream_write(pulse->stream, pa_data, length, NULL, 0LL, PA_SEEK_RELATIVE);
if (status < 0)
{
@ -522,22 +660,24 @@ static UINT rdpsnd_pulse_play(rdpsndDevicePlugin* device, const BYTE* data, size
return latency / 1000;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpsnd_pulse_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* args)
{
int status;
DWORD flags;
COMMAND_LINE_ARGUMENT_A* arg;
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
COMMAND_LINE_ARGUMENT_A rdpsnd_pulse_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED,
"<device>", NULL, NULL, -1, NULL, "device" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } };
COMMAND_LINE_ARGUMENT_A rdpsnd_pulse_args[] = {
{ "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", NULL, NULL, -1, NULL, "device" },
{ "reconnect_delay_seconds", COMMAND_LINE_VALUE_REQUIRED, "<reconnect_delay_seconds>", NULL,
NULL, -1, NULL, "reconnect_delay_seconds" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
};
flags =
COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
WINPR_ASSERT(pulse);
WINPR_ASSERT(args);
status = CommandLineParseArgumentsA(args->argc, args->argv, rdpsnd_pulse_args, flags, pulse,
NULL, NULL);
@ -558,6 +698,15 @@ static UINT rdpsnd_pulse_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV
if (!pulse->device_name)
return ERROR_OUTOFMEMORY;
}
CommandLineSwitchCase(arg, "reconnect_delay_seconds")
{
unsigned long val = strtoul(arg->Value, NULL, 0);
if ((errno != 0) || (val > INT32_MAX))
return ERROR_INVALID_DATA;
pulse->reconnect_delay_seconds = val;
}
CommandLineSwitchEnd(arg)
} while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
@ -570,16 +719,14 @@ static UINT rdpsnd_pulse_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV
#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry
#endif
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints)
{
ADDIN_ARGV* args;
rdpsndPulsePlugin* pulse;
UINT ret;
WINPR_ASSERT(pEntryPoints);
pulse = (rdpsndPulsePlugin*)calloc(1, sizeof(rdpsndPulsePlugin));
if (!pulse)
@ -605,6 +752,8 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p
goto error;
}
}
pulse->reconnect_delay_seconds = 5;
pulse->reconnect_time = time(NULL);
ret = CHANNEL_RC_NO_MEMORY;
pulse->mainloop = pa_threaded_mainloop_new();
@ -612,15 +761,17 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p
if (!pulse->mainloop)
goto error;
pulse->context = pa_context_new(pa_threaded_mainloop_get_api(pulse->mainloop), "freerdp");
pa_threaded_mainloop_lock(pulse->mainloop);
if (!pulse->context)
goto error;
if (pa_threaded_mainloop_start(pulse->mainloop) < 0)
{
pa_threaded_mainloop_unlock(pulse->mainloop);
return FALSE;
}
pa_context_set_state_callback(pulse->context, rdpsnd_pulse_context_state_callback, pulse);
ret = ERROR_INVALID_OPERATION;
pa_threaded_mainloop_unlock(pulse->mainloop);
if (!rdpsnd_pulse_connect((rdpsndDevicePlugin*)pulse))
if (!rdpsnd_pulse_context_connect((rdpsndDevicePlugin*)pulse))
goto error;
pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*)pulse);

View File

@ -126,6 +126,10 @@ struct rdpsnd_plugin
HANDLE thread;
wMessageQueue* queue;
BOOL initialized;
UINT16 wVersion;
UINT32 volume;
BOOL applyVolume;
};
static const char* rdpsnd_is_dyn_str(BOOL dynamic)
@ -268,9 +272,9 @@ static UINT rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd)
static UINT rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream* s)
{
UINT16 index;
UINT16 wVersion;
UINT16 wNumberOfFormats;
UINT ret = ERROR_BAD_LENGTH;
audio_formats_free(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats);
rdpsnd->NumberOfServerFormats = 0;
rdpsnd->ServerFormats = NULL;
@ -285,7 +289,7 @@ static UINT rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream*
Stream_Seek_UINT16(s); /* wDGramPort */
Stream_Read_UINT16(s, wNumberOfFormats);
Stream_Read_UINT8(s, rdpsnd->cBlockNo); /* cLastBlockConfirmed */
Stream_Read_UINT16(s, wVersion); /* wVersion */
Stream_Read_UINT16(s, rdpsnd->wVersion); /* wVersion */
Stream_Seek_UINT8(s); /* bPad */
rdpsnd->NumberOfServerFormats = wNumberOfFormats;
@ -312,7 +316,7 @@ static UINT rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream*
if (ret == CHANNEL_RC_OK)
{
if (wVersion >= CHANNEL_VERSION_WIN_7)
if (rdpsnd->wVersion >= CHANNEL_VERSION_WIN_7)
ret = rdpsnd_send_quality_mode_pdu(rdpsnd);
}
@ -373,6 +377,20 @@ static UINT rdpsnd_recv_training_pdu(rdpsndPlugin* rdpsnd, wStream* s)
return rdpsnd_send_training_confirm_pdu(rdpsnd, wTimeStamp, wPackSize);
}
static BOOL rdpsnd_apply_volume(rdpsndPlugin* rdpsnd)
{
WINPR_ASSERT(rdpsnd);
if (rdpsnd->isOpen && rdpsnd->applyVolume && rdpsnd->device)
{
BOOL rc = IFCALLRESULT(TRUE, rdpsnd->device->SetVolume, rdpsnd->device, rdpsnd->volume);
if (!rc)
return FALSE;
rdpsnd->applyVolume = FALSE;
}
return TRUE;
}
static BOOL rdpsnd_ensure_device_is_open(rdpsndPlugin* rdpsnd, UINT32 wFormatNo,
const AUDIO_FORMAT* format)
{
@ -421,7 +439,7 @@ static BOOL rdpsnd_ensure_device_is_open(rdpsndPlugin* rdpsnd, UINT32 wFormatNo,
rdpsnd->totalPlaySize = 0;
}
return TRUE;
return rdpsnd_apply_volume(rdpsnd);
}
/**
@ -710,7 +728,7 @@ static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd)
*/
static UINT rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s)
{
BOOL rc = FALSE;
BOOL rc = TRUE;
UINT32 dwVolume;
if (Stream_GetRemainingLength(s) < 4)
@ -719,8 +737,10 @@ static UINT rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s)
Stream_Read_UINT32(s, dwVolume);
WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Volume: 0x%08" PRIX32 "",
rdpsnd_is_dyn_str(rdpsnd->dynamic), dwVolume);
if (rdpsnd->device)
rc = IFCALLRESULT(FALSE, rdpsnd->device->SetVolume, rdpsnd->device, dwVolume);
rdpsnd->volume = dwVolume;
rdpsnd->applyVolume = TRUE;
rc = rdpsnd_apply_volume(rdpsnd);
if (!rc)
{

View File

@ -2728,7 +2728,10 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
if (strcmp(arg->Value, "video") == 0)
settings->RemoteFxCodecMode = 0x00;
else if (strcmp(arg->Value, "image") == 0)
{
settings->RemoteFxImageCodec = TRUE;
settings->RemoteFxCodecMode = 0x02;
}
}
CommandLineSwitchCase(arg, "frame-ack")
{

View File

@ -47,12 +47,12 @@ if(NOT WIN32)
CMAKE_DEPENDENT_OPTION(WITH_SANITIZE_ADDRESS "Compile with gcc/clang address sanitizer." OFF
"NOT WITH_VALGRIND_MEMCHECK; NOT WITH_SANITIZE_MEMORY; NOT WITH_SANITIZE_THREAD" OFF)
CMAKE_DEPENDENT_OPTION(WITH_SANITIZE_MEMORY "Compile with gcc/clang memory sanitizer." OFF
"NOT WITH_VALGRIND_MEMCHECK; NOT WITH_SANITIZE_ADDRESS; NOT WITH_SANITIZE_THREAD" OFF)
"NOT WITH_VALGRIND_MEMCHECK; NOT WITH_SANITIZE_ADDRESS; NOT WITH_SANITIZE_THREAD" OFF)
CMAKE_DEPENDENT_OPTION(WITH_SANITIZE_THREAD "Compile with gcc/clang thread sanitizer." OFF
"NOT WITH_VALGRIND_MEMCHECK; NOT WITH_SANITIZE_ADDRESS; NOT WITH_SANITIZE_MEMORY" OFF)
else()
if(NOT UWP)
option(WITH_MEDIA_FOUNDATION "Enable H264 media foundation decoder." ON)
option(WITH_MEDIA_FOUNDATION "Enable H264 media foundation decoder." OFF)
endif()
endif()
@ -98,7 +98,7 @@ option(WITH_SERVER_INTERFACE "Build servers as a library with an interface" ON)
option(WITH_DEBUG_ALL "Print all debug messages." OFF)
if(WITH_DEBUG_ALL)
message(WARNING "WITH_DEBUG_ALL=ON, the build will be slow and might leak sensitive information, do not use with release builds!")
message(WARNING "WITH_DEBUG_ALL=ON, the build will be slow and might leak sensitive information, do not use with release builds!")
set(DEFAULT_DEBUG_OPTION "ON")
else()
set(DEFAULT_DEBUG_OPTION "OFF")
@ -106,7 +106,7 @@ endif()
option(WITH_DEBUG_CERTIFICATE "Print certificate related debug messages." ${DEFAULT_DEBUG_OPTION})
if(WITH_DEBUG_CERTIFICATE)
message(WARNING "WITH_DEBUG_CERTIFICATE=ON, the build might leak sensitive information, do not use with release builds!")
message(WARNING "WITH_DEBUG_CERTIFICATE=ON, the build might leak sensitive information, do not use with release builds!")
endif()
option(WITH_DEBUG_CAPABILITIES "Print capability negotiation debug messages." ${DEFAULT_DEBUG_OPTION})
option(WITH_DEBUG_CHANNELS "Print channel manager debug messages." ${DEFAULT_DEBUG_OPTION})
@ -116,23 +116,23 @@ option(WITH_DEBUG_DVC "Print dynamic virtual channel debug messages." ${DEFAULT_
CMAKE_DEPENDENT_OPTION(WITH_DEBUG_TSMF "Print TSMF virtual channel debug messages." ${DEFAULT_DEBUG_OPTION} "CHANNEL_TSMF" OFF)
option(WITH_DEBUG_KBD "Print keyboard related debug messages." OFF)
if(WITH_DEBUG_KBD)
message(WARNING "WITH_DEBUG_KBD=ON, the build might leak sensitive information, do not use with release builds!")
message(WARNING "WITH_DEBUG_KBD=ON, the build might leak sensitive information, do not use with release builds!")
endif()
option(WITH_DEBUG_LICENSE "Print license debug messages." OFF)
if(WITH_DEBUG_LICENSE)
message(WARNING "WITH_DEBUG_LICENSE=ON, the build might leak sensitive information, do not use with release builds!")
message(WARNING "WITH_DEBUG_LICENSE=ON, the build might leak sensitive information, do not use with release builds!")
endif()
option(WITH_DEBUG_NEGO "Print negotiation related debug messages." OFF)
if(WITH_DEBUG_NEGO)
message(WARNING "WITH_DEBUG_NEGO=ON, the build might leak sensitive information, do not use with release builds!")
message(WARNING "WITH_DEBUG_NEGO=ON, the build might leak sensitive information, do not use with release builds!")
endif()
option(WITH_DEBUG_NLA "Print authentication related debug messages." OFF)
if(WITH_DEBUG_NLA)
message(WARNING "WITH_DEBUG_NLA=ON, the build might leak sensitive information, do not use with release builds!")
message(WARNING "WITH_DEBUG_NLA=ON, the build might leak sensitive information, do not use with release builds!")
endif()
option(WITH_DEBUG_NTLM "Print NTLM debug messages" OFF)
if(WITH_DEBUG_NTLM)
message(WARNING "WITH_DEBUG_NTLM=ON, the build might leak sensitive information, do not use with release builds!")
message(WARNING "WITH_DEBUG_NTLM=ON, the build might leak sensitive information, do not use with release builds!")
endif()
option(WITH_DEBUG_TSG "Print Terminal Server Gateway debug messages" ${DEFAULT_DEBUG_OPTION})
option(WITH_DEBUG_RAIL "Print RemoteApp debug messages" ${DEFAULT_DEBUG_OPTION})
@ -163,13 +163,13 @@ option(WITH_GSSAPI "Compile support for kerberos authentication. (EXPERIMENTAL)"
option(WITH_DSP_EXPERIMENTAL "Enable experimental sound encoder/decoder formats" OFF)
if (WITH_FFMPEG)
option(WITH_DSP_FFMPEG "Use FFMPEG for audio encoding/decoding" OFF)
option(WITH_VAAPI "Use FFMPEG VAAPI (EXPERIMENTAL)" OFF)
option(WITH_DSP_FFMPEG "Use FFMPEG for audio encoding/decoding" OFF)
option(WITH_VAAPI "Use FFMPEG VAAPI (EXPERIMENTAL)" OFF)
endif(WITH_FFMPEG)
option(USE_VERSION_FROM_GIT_TAG "Extract FreeRDP version from git tag." OFF)
option(WITH_CAIRO "Use CAIRO image library for screen resizing" OFF)
option(WITH_CAIRO "Use CAIRO image library for screen resizing" OFF)
option(WITH_SWSCALE "Use SWScale image library for screen resizing" OFF)
option(DEFINE_NO_DEPRECATED "Compile without legacy functions and symbols" OFF)

View File

@ -41,6 +41,14 @@
#define RDPDR_DEVICE_IO_CONTROL_REQ_HDR_LENGTH 32
#define RDPDR_DEVICE_IO_CONTROL_RSP_HDR_LENGTH 4
#define RDPDR_VERSION_MAJOR 0x0001
#define RDPDR_VERSION_MINOR_RDP50 0x0002
#define RDPDR_VERSION_MINOR_RDP51 0x0005
#define RDPDR_VERSION_MINOR_RDP52 0x000A
#define RDPDR_VERSION_MINOR_RDP6X 0x000C
#define RDPDR_VERSION_MINOR_RDP10X 0x000D
/* RDPDR_HEADER.Component */
enum RDPDR_CTYP
{

View File

@ -418,9 +418,29 @@ static BOOL ffmpeg_resample_frame(AVAudioResampleContext* context, AVFrame* in,
static BOOL ffmpeg_encode_frame(AVCodecContext* context, AVFrame* in, AVPacket* packet,
wStream* out)
{
int ret;
if (in->format == AV_SAMPLE_FMT_FLTP)
{
uint8_t** pp = in->extended_data;
for (int y = 0; y < in->channels; y++)
{
float* data = pp[y];
for (int x = 0; x < in->nb_samples; x++)
{
const float val1 = data[x];
if (isnan(val1))
data[x] = 0.0f;
else if (isinf(val1))
{
if (val1 < 0.0f)
data[x] = -1.0f;
else
data[x] = 1.0f;
}
}
}
}
/* send the packet with the compressed data to the encoder */
ret = avcodec_send_frame(context, in);
int ret = avcodec_send_frame(context, in);
if (ret < 0)
{

View File

@ -1496,7 +1496,13 @@ BOOL freerdp_bitmap_planar_context_reset(BITMAP_PLANAR_CONTEXT* context, UINT32
context->bgr = FALSE;
context->maxWidth = PLANAR_ALIGN(width, 4);
context->maxHeight = PLANAR_ALIGN(height, 4);
context->maxPlaneSize = context->maxWidth * context->maxHeight;
const UINT64 tmp = (UINT64)context->maxWidth * context->maxHeight;
if (tmp > UINT32_MAX)
return FALSE;
context->maxPlaneSize = tmp;
if (context->maxWidth > UINT32_MAX / 4)
return FALSE;
context->nTempStep = context->maxWidth * 4;
free(context->planesBuffer);
free(context->pTempData);

View File

@ -1796,13 +1796,13 @@ static INLINE int progressive_process_tiles(PROGRESSIVE_CONTEXT* progressive, wS
for (index = 0; index < region->numTiles; index++)
{
RFX_PROGRESSIVE_TILE* tile = region->tiles[index];
params[index].progressive = progressive;
params[index].region = region;
params[index].context = context;
params[index].tile = tile;
if (progressive->rfx_context->priv->UseThreads)
{
params[index].progressive = progressive;
params[index].region = region;
params[index].context = context;
params[index].tile = tile;
if (!(work_objects[index] = CreateThreadpoolWork(
progressive_process_tiles_tile_work_callback, (void*)&params[index],
&progressive->rfx_context->priv->ThreadPoolEnv)))
@ -1817,7 +1817,10 @@ static INLINE int progressive_process_tiles(PROGRESSIVE_CONTEXT* progressive, wS
}
else
{
progressive_process_tiles_tile_work_callback(0, &params[index], 0);
PROGRESSIVE_TILE_PROCESS_WORK_PARAM param = {
.progressive = progressive, .region = region, .context = context, .tile = tile
};
progressive_process_tiles_tile_work_callback(0, &param, 0);
}
if (status < 0)

View File

@ -950,11 +950,12 @@ WINPR_MD_TYPE crypto_cert_get_signature_alg(X509* xcert)
{
WINPR_ASSERT(xcert);
EVP_PKEY* evp = X509_get0_pubkey(xcert);
EVP_PKEY* evp = X509_get_pubkey(xcert);
WINPR_ASSERT(evp);
int hash_nid = 0;
const int res = EVP_PKEY_get_default_digest_nid(evp, &hash_nid);
EVP_PKEY_free(evp);
if (res <= 0)
return WINPR_MD_NONE;

View File

@ -806,7 +806,7 @@ static const XKB_LAYOUT xkbLayouts[] = {
{ "sk", KBD_SLOVAK, sk_variants }, /* Slovakia */
{ "es", KBD_SPANISH, es_variants }, /* Spain */
{ "se", KBD_SWEDISH, se_variants }, /* Sweden */
{ "ch", KBD_SWISS_FRENCH, ch_variants }, /* Switzerland */
{ "ch", KBD_SWISS_GERMAN, ch_variants }, /* Switzerland */
{ "sy", KBD_SYRIAC, sy_variants }, /* Syria */
{ "tj", 0, tj_variants }, /* Tajikistan */
{ "lk", 0, lk_variants }, /* Sri Lanka */

View File

@ -57,7 +57,7 @@ if (NOT WIN32)
endif()
# Soname versioning
set(RAW_VERSION_STRING "2.11.2")
set(RAW_VERSION_STRING "2.11.5")
if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag")
file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING)
elseif(USE_VERSION_FROM_GIT_TAG)

View File

@ -29,7 +29,7 @@ if (NOT WITH_ICU)
endif(NOT WITH_ICU)
if (WITH_ICU)
find_package(ICU REQUIRED i18n uc io)
find_package(ICU REQUIRED i18n uc io data)
winpr_include_directory_add(${ICU_INCLUDE_DIRS})
winpr_library_add_private(${ICU_LIBRARIES})
endif (WITH_ICU)

View File

@ -40,6 +40,8 @@
#include "../log.h"
#define TAG WINPR_TAG("unicode")
#define UCNV_CONVERT 1
/**
* Notes on cross-platform Unicode portability:
*
@ -201,6 +203,26 @@ int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int
targetCapacity = cchWideChar;
error = U_ZERO_ERROR;
#if defined(UCNV_CONVERT)
if (cchWideChar == 0)
{
targetLength =
ucnv_convert("UTF-16LE", "UTF-8", NULL, 0, lpMultiByteStr, cbMultiByte, &error);
if (targetLength > 0)
targetLength /= sizeof(WCHAR);
cchWideChar = targetLength;
}
else
{
targetLength =
ucnv_convert("UTF-16LE", "UTF-8", targetStart, targetCapacity * sizeof(WCHAR),
lpMultiByteStr, cbMultiByte, &error);
if (targetLength > 0)
targetLength /= sizeof(WCHAR);
cchWideChar = U_SUCCESS(error) ? targetLength : 0;
}
#else
if (cchWideChar == 0)
{
u_strFromUTF8(NULL, 0, &targetLength, lpMultiByteStr, cbMultiByte, &error);
@ -212,6 +234,7 @@ int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int
&error);
cchWideChar = U_SUCCESS(error) ? targetLength : 0;
}
#endif
}
#else
@ -327,6 +350,21 @@ int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int
targetCapacity = cbMultiByte;
error = U_ZERO_ERROR;
#if defined(UCNV_CONVERT)
if (cbMultiByte == 0)
{
targetLength = ucnv_convert("UTF-8", "UTF-16LE", NULL, 0, lpWideCharStr,
cchWideChar * sizeof(WCHAR), &error);
cbMultiByte = targetLength;
}
else
{
targetLength = ucnv_convert("UTF-8", "UTF-16LE", targetStart, targetCapacity,
lpWideCharStr, cchWideChar * sizeof(WCHAR), &error);
cbMultiByte = U_SUCCESS(error) ? targetLength : 0;
}
#else
if (cbMultiByte == 0)
{
u_strToUTF8(NULL, 0, &targetLength, lpWideCharStr, cchWideChar, &error);
@ -338,6 +376,7 @@ int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int
&error);
cbMultiByte = U_SUCCESS(error) ? targetLength : 0;
}
#endif
}
#else

View File

@ -66,7 +66,11 @@ static WINPR_RC4_CTX* winpr_RC4_New_Internal(const BYTE* key, size_t keylen, BOO
if (!evp)
return NULL;
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
EVP_CIPHER_CTX_reset((EVP_CIPHER_CTX*)ctx);
#else
EVP_CIPHER_CTX_init((EVP_CIPHER_CTX*)ctx);
#endif
if (EVP_EncryptInit_ex((EVP_CIPHER_CTX*)ctx, evp, NULL, NULL, NULL) != 1)
{
EVP_CIPHER_CTX_free ((EVP_CIPHER_CTX*)ctx);