Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
68
third_party/FreeRDP/libfreerdp/utils/CMakeLists.txt
vendored
Normal file
68
third_party/FreeRDP/libfreerdp/utils/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# libfreerdp-utils cmake build script
|
||||
#
|
||||
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
set(MODULE_NAME "freerdp-utils")
|
||||
set(MODULE_PREFIX "FREERDP_UTILS")
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
encoded_types.c
|
||||
helpers.c
|
||||
passphrase.c
|
||||
cliprdr_utils.c
|
||||
rdpdr_utils.c
|
||||
pcap.c
|
||||
profiler.c
|
||||
ringbuffer.c
|
||||
platform_signal.h
|
||||
signal.c
|
||||
string.c
|
||||
gfx.c
|
||||
drdynvc.c
|
||||
smartcard_operations.c
|
||||
smartcard_pack.h
|
||||
smartcard_pack.c
|
||||
smartcard_call.c
|
||||
stopwatch.c
|
||||
http.c
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND ${MODULE_PREFIX}_SRCS signal_win32.c)
|
||||
else()
|
||||
list(APPEND ${MODULE_PREFIX}_SRCS signal_posix.c)
|
||||
endif()
|
||||
|
||||
freerdp_module_add(${${MODULE_PREFIX}_SRCS})
|
||||
|
||||
freerdp_library_add(${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
if(WIN32)
|
||||
freerdp_library_add(ws2_32)
|
||||
freerdp_library_add(credui)
|
||||
freerdp_library_add(cfgmgr32)
|
||||
endif()
|
||||
|
||||
check_library_exists(m pow "" HAVE_LIB_M)
|
||||
|
||||
if(HAVE_LIB_M)
|
||||
freerdp_library_add(m)
|
||||
freerdp_pc_add_library_private("m")
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
259
third_party/FreeRDP/libfreerdp/utils/cliprdr_utils.c
vendored
Normal file
259
third_party/FreeRDP/libfreerdp/utils/cliprdr_utils.c
vendored
Normal file
@@ -0,0 +1,259 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Clipboard Virtual Channel Extension
|
||||
*
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2022 Armin Novak <anovak@thincast.com
|
||||
* Copyright 2022 Thincast Technologies GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <winpr/stream.h>
|
||||
#include <freerdp/utils/cliprdr_utils.h>
|
||||
#include <freerdp/channels/cliprdr.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG FREERDP_TAG("utils." CLIPRDR_SVC_CHANNEL_NAME)
|
||||
|
||||
#define CLIPRDR_FILEDESCRIPTOR_SIZE (4 + 32 + 4 + 16 + 8 + 8 + 520)
|
||||
#define CLIPRDR_MAX_FILE_SIZE (2U * 1024 * 1024 * 1024)
|
||||
|
||||
static UINT64 filetime_to_uint64(FILETIME value)
|
||||
{
|
||||
UINT64 converted = 0;
|
||||
converted |= (UINT32)value.dwHighDateTime;
|
||||
converted <<= 32;
|
||||
converted |= (UINT32)value.dwLowDateTime;
|
||||
return converted;
|
||||
}
|
||||
|
||||
static FILETIME uint64_to_filetime(UINT64 value)
|
||||
{
|
||||
FILETIME converted;
|
||||
converted.dwLowDateTime = (UINT32)(value >> 0);
|
||||
converted.dwHighDateTime = (UINT32)(value >> 32);
|
||||
return converted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a packed file list.
|
||||
*
|
||||
* The resulting array must be freed with the `free()` function.
|
||||
*
|
||||
* @param [in] format_data packed `CLIPRDR_FILELIST` to parse.
|
||||
* @param [in] format_data_length length of `format_data` in bytes.
|
||||
* @param [out] file_descriptor_array parsed array of `FILEDESCRIPTOR` structs.
|
||||
* @param [out] file_descriptor_count number of elements in `file_descriptor_array`.
|
||||
*
|
||||
* @returns 0 on success, otherwise a Win32 error code.
|
||||
*/
|
||||
UINT cliprdr_parse_file_list(const BYTE* format_data, UINT32 format_data_length,
|
||||
FILEDESCRIPTORW** file_descriptor_array, UINT32* file_descriptor_count)
|
||||
{
|
||||
UINT result = NO_ERROR;
|
||||
UINT32 count = 0;
|
||||
wStream sbuffer;
|
||||
wStream* s = nullptr;
|
||||
|
||||
if (!format_data || !file_descriptor_array || !file_descriptor_count)
|
||||
return ERROR_BAD_ARGUMENTS;
|
||||
|
||||
s = Stream_StaticConstInit(&sbuffer, format_data, format_data_length);
|
||||
if (!s)
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
|
||||
{
|
||||
result = ERROR_INCORRECT_SIZE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
Stream_Read_UINT32(s, count); /* cItems (4 bytes) */
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, count, CLIPRDR_FILEDESCRIPTOR_SIZE))
|
||||
{
|
||||
result = ERROR_INCORRECT_SIZE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*file_descriptor_count = count;
|
||||
*file_descriptor_array = calloc(count, sizeof(FILEDESCRIPTORW));
|
||||
if (!*file_descriptor_array)
|
||||
{
|
||||
result = ERROR_NOT_ENOUGH_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (UINT32 i = 0; i < count; i++)
|
||||
{
|
||||
FILEDESCRIPTORW* file = &((*file_descriptor_array)[i]);
|
||||
|
||||
if (!cliprdr_read_filedescriptor(s, file))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (Stream_GetRemainingLength(s) > 0)
|
||||
WLog_WARN(TAG, "packed file list has %" PRIuz " excess bytes",
|
||||
Stream_GetRemainingLength(s));
|
||||
out:
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL cliprdr_read_filedescriptor(wStream* s, FILEDESCRIPTORW* descriptor)
|
||||
{
|
||||
UINT64 tmp = 0;
|
||||
WINPR_ASSERT(descriptor);
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, sizeof(FILEDESCRIPTORW)))
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT32(s, descriptor->dwFlags); /* flags (4 bytes) */
|
||||
Stream_Read_UINT32(s, descriptor->clsid.Data1);
|
||||
Stream_Read_UINT16(s, descriptor->clsid.Data2);
|
||||
Stream_Read_UINT16(s, descriptor->clsid.Data3);
|
||||
Stream_Read(s, &descriptor->clsid.Data4, sizeof(descriptor->clsid.Data4));
|
||||
Stream_Read_INT32(s, descriptor->sizel.cx);
|
||||
Stream_Read_INT32(s, descriptor->sizel.cy);
|
||||
Stream_Read_INT32(s, descriptor->pointl.x);
|
||||
Stream_Read_INT32(s, descriptor->pointl.y);
|
||||
Stream_Read_UINT32(s, descriptor->dwFileAttributes); /* fileAttributes (4 bytes) */
|
||||
Stream_Read_UINT64(s, tmp); /* ftCreationTime (8 bytes) */
|
||||
descriptor->ftCreationTime = uint64_to_filetime(tmp);
|
||||
Stream_Read_UINT64(s, tmp); /* ftLastAccessTime (8 bytes) */
|
||||
descriptor->ftLastAccessTime = uint64_to_filetime(tmp);
|
||||
Stream_Read_UINT64(s, tmp); /* lastWriteTime (8 bytes) */
|
||||
descriptor->ftLastWriteTime = uint64_to_filetime(tmp);
|
||||
Stream_Read_UINT32(s, descriptor->nFileSizeHigh); /* fileSizeHigh (4 bytes) */
|
||||
Stream_Read_UINT32(s, descriptor->nFileSizeLow); /* fileSizeLow (4 bytes) */
|
||||
Stream_Read_UTF16_String(s, descriptor->cFileName,
|
||||
ARRAYSIZE(descriptor->cFileName)); /* cFileName (520 bytes) */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL cliprdr_write_filedescriptor(wStream* s, const FILEDESCRIPTORW* descriptor)
|
||||
{
|
||||
WINPR_ASSERT(descriptor);
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(s, sizeof(FILEDESCRIPTORW)))
|
||||
return FALSE;
|
||||
|
||||
Stream_Write_UINT32(s, descriptor->dwFlags); /* flags (4 bytes) */
|
||||
|
||||
Stream_Write_UINT32(s, descriptor->clsid.Data1);
|
||||
Stream_Write_UINT16(s, descriptor->clsid.Data2);
|
||||
Stream_Write_UINT16(s, descriptor->clsid.Data3);
|
||||
Stream_Write(s, &descriptor->clsid.Data4, sizeof(descriptor->clsid.Data4));
|
||||
Stream_Write_INT32(s, descriptor->sizel.cx);
|
||||
Stream_Write_INT32(s, descriptor->sizel.cy);
|
||||
Stream_Write_INT32(s, descriptor->pointl.x);
|
||||
Stream_Write_INT32(s, descriptor->pointl.y);
|
||||
Stream_Write_UINT32(s, descriptor->dwFileAttributes); /* fileAttributes (4 bytes) */
|
||||
Stream_Write_UINT64(s, filetime_to_uint64(descriptor->ftCreationTime));
|
||||
Stream_Write_UINT64(s, filetime_to_uint64(descriptor->ftLastAccessTime));
|
||||
Stream_Write_UINT64(
|
||||
s, filetime_to_uint64(descriptor->ftLastWriteTime)); /* lastWriteTime (8 bytes) */
|
||||
Stream_Write_UINT32(s, descriptor->nFileSizeHigh); /* fileSizeHigh (4 bytes) */
|
||||
Stream_Write_UINT32(s, descriptor->nFileSizeLow); /* fileSizeLow (4 bytes) */
|
||||
Stream_Write_UTF16_String(s, descriptor->cFileName,
|
||||
ARRAYSIZE(descriptor->cFileName)); /* cFileName (520 bytes) */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize a packed file list.
|
||||
*
|
||||
* The resulting format data must be freed with the `free()` function.
|
||||
*
|
||||
* @param [in] file_descriptor_array array of `FILEDESCRIPTOR` structs to serialize.
|
||||
* @param [in] file_descriptor_count number of elements in `file_descriptor_array`.
|
||||
* @param [out] format_data serialized CLIPRDR_FILELIST.
|
||||
* @param [out] format_data_length length of `format_data` in bytes.
|
||||
*
|
||||
* @returns 0 on success, otherwise a Win32 error code.
|
||||
*/
|
||||
UINT cliprdr_serialize_file_list(const FILEDESCRIPTORW* file_descriptor_array,
|
||||
UINT32 file_descriptor_count, BYTE** format_data,
|
||||
UINT32* format_data_length)
|
||||
{
|
||||
return cliprdr_serialize_file_list_ex(CB_STREAM_FILECLIP_ENABLED, file_descriptor_array,
|
||||
file_descriptor_count, format_data, format_data_length);
|
||||
}
|
||||
|
||||
UINT cliprdr_serialize_file_list_ex(UINT32 flags, const FILEDESCRIPTORW* file_descriptor_array,
|
||||
UINT32 file_descriptor_count, BYTE** format_data,
|
||||
UINT32* format_data_length)
|
||||
{
|
||||
UINT result = NO_ERROR;
|
||||
size_t len = 0;
|
||||
wStream* s = nullptr;
|
||||
|
||||
if (!file_descriptor_array || !format_data || !format_data_length)
|
||||
return ERROR_BAD_ARGUMENTS;
|
||||
|
||||
if ((flags & CB_STREAM_FILECLIP_ENABLED) == 0)
|
||||
{
|
||||
WLog_WARN(TAG, "No file clipboard support annouonced!");
|
||||
return ERROR_BAD_ARGUMENTS;
|
||||
}
|
||||
|
||||
s = Stream_New(nullptr, 4 + file_descriptor_count * CLIPRDR_FILEDESCRIPTOR_SIZE);
|
||||
if (!s)
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
|
||||
Stream_Write_UINT32(s, file_descriptor_count); /* cItems (4 bytes) */
|
||||
|
||||
for (UINT32 i = 0; i < file_descriptor_count; i++)
|
||||
{
|
||||
const FILEDESCRIPTORW* file = &file_descriptor_array[i];
|
||||
|
||||
/*
|
||||
* There is a known issue with Windows server getting stuck in
|
||||
* an infinite loop when downloading files that are larger than
|
||||
* 2 gigabytes. Do not allow clients to send such file lists.
|
||||
*
|
||||
* https://support.microsoft.com/en-us/help/2258090
|
||||
*/
|
||||
if ((flags & CB_HUGE_FILE_SUPPORT_ENABLED) == 0)
|
||||
{
|
||||
if ((file->nFileSizeHigh > 0) || (file->nFileSizeLow >= CLIPRDR_MAX_FILE_SIZE))
|
||||
{
|
||||
WLog_ERR(TAG, "cliprdr does not support files over 2 GB");
|
||||
result = ERROR_FILE_TOO_LARGE;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cliprdr_write_filedescriptor(s, file))
|
||||
goto error;
|
||||
}
|
||||
|
||||
Stream_SealLength(s);
|
||||
|
||||
Stream_GetBuffer(s, *format_data);
|
||||
Stream_GetLength(s, len);
|
||||
if (len > UINT32_MAX)
|
||||
goto error;
|
||||
|
||||
*format_data_length = (UINT32)len;
|
||||
|
||||
Stream_Free(s, FALSE);
|
||||
|
||||
return result;
|
||||
|
||||
error:
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
return result;
|
||||
}
|
||||
50
third_party/FreeRDP/libfreerdp/utils/drdynvc.c
vendored
Normal file
50
third_party/FreeRDP/libfreerdp/utils/drdynvc.c
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* drdynvc Utils - Helper functions converting something to string
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2023 Thincast Technologies GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/utils/drdynvc.h>
|
||||
#include <freerdp/channels/drdynvc.h>
|
||||
|
||||
const char* drdynvc_get_packet_type(BYTE cmd)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case CREATE_REQUEST_PDU:
|
||||
return "CREATE_REQUEST_PDU";
|
||||
case DATA_FIRST_PDU:
|
||||
return "DATA_FIRST_PDU";
|
||||
case DATA_PDU:
|
||||
return "DATA_PDU";
|
||||
case CLOSE_REQUEST_PDU:
|
||||
return "CLOSE_REQUEST_PDU";
|
||||
case CAPABILITY_REQUEST_PDU:
|
||||
return "CAPABILITY_REQUEST_PDU";
|
||||
case DATA_FIRST_COMPRESSED_PDU:
|
||||
return "DATA_FIRST_COMPRESSED_PDU";
|
||||
case DATA_COMPRESSED_PDU:
|
||||
return "DATA_COMPRESSED_PDU";
|
||||
case SOFT_SYNC_REQUEST_PDU:
|
||||
return "SOFT_SYNC_REQUEST_PDU";
|
||||
case SOFT_SYNC_RESPONSE_PDU:
|
||||
return "SOFT_SYNC_RESPONSE_PDU";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
417
third_party/FreeRDP/libfreerdp/utils/encoded_types.c
vendored
Normal file
417
third_party/FreeRDP/libfreerdp/utils/encoded_types.c
vendored
Normal file
@@ -0,0 +1,417 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Helper functions to parse encoded types into regular ones
|
||||
*
|
||||
* Copyright 2023 Pascal Nowack <Pascal.Nowack@gmx.de>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <freerdp/channels/log.h>
|
||||
#include <freerdp/utils/encoded_types.h>
|
||||
#include <math.h>
|
||||
|
||||
#define TAG CHANNELS_TAG("encoded_types")
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ONE_BYTE_VAL,
|
||||
TWO_BYTE_VAL,
|
||||
THREE_BYTE_VAL,
|
||||
FOUR_BYTE_VAL,
|
||||
FIVE_BYTE_VAL,
|
||||
SIX_BYTE_VAL,
|
||||
SEVEN_BYTE_VAL,
|
||||
EIGHT_BYTE_VAL,
|
||||
} EncodedTypeByteCount;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
POSITIVE_VAL,
|
||||
NEGATIVE_VAL,
|
||||
} EncodedTypeSign;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
EncodedTypeByteCount c;
|
||||
EncodedTypeSign s;
|
||||
BYTE val1;
|
||||
BYTE val2;
|
||||
BYTE val3;
|
||||
BYTE val4;
|
||||
} FOUR_BYTE_SIGNED_INTEGER;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
EncodedTypeByteCount c;
|
||||
EncodedTypeSign s;
|
||||
BYTE e;
|
||||
BYTE val1;
|
||||
BYTE val2;
|
||||
BYTE val3;
|
||||
BYTE val4;
|
||||
} FOUR_BYTE_FLOAT;
|
||||
|
||||
static inline FOUR_BYTE_SIGNED_INTEGER FOUR_BYTE_SIGNED_INTEGER_init(void)
|
||||
{
|
||||
const FOUR_BYTE_SIGNED_INTEGER empty = {
|
||||
.c = ONE_BYTE_VAL, .s = POSITIVE_VAL, .val1 = 0, .val2 = 0, .val3 = 0, .val4 = 0
|
||||
};
|
||||
return empty;
|
||||
}
|
||||
|
||||
static inline FOUR_BYTE_FLOAT FOUR_BYTE_FLOAT_init(void)
|
||||
{
|
||||
const FOUR_BYTE_FLOAT empty = {
|
||||
.c = ONE_BYTE_VAL, .s = POSITIVE_VAL, .e = 0, .val1 = 0, .val2 = 0, .val3 = 0, .val4 = 0
|
||||
};
|
||||
return empty;
|
||||
}
|
||||
|
||||
BOOL freerdp_read_four_byte_signed_integer(wStream* s, INT32* value)
|
||||
{
|
||||
FOUR_BYTE_SIGNED_INTEGER si = FOUR_BYTE_SIGNED_INTEGER_init();
|
||||
BYTE byte = 0;
|
||||
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(value);
|
||||
|
||||
*value = 0;
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, byte);
|
||||
|
||||
si.c = (EncodedTypeByteCount)((byte & 0xC0) >> 6);
|
||||
si.s = (EncodedTypeSign)((byte & 0x20) >> 5);
|
||||
si.val1 = (byte & 0x1F);
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, si.c))
|
||||
return FALSE;
|
||||
|
||||
switch (si.c)
|
||||
{
|
||||
case ONE_BYTE_VAL:
|
||||
*value = si.val1;
|
||||
break;
|
||||
case TWO_BYTE_VAL:
|
||||
Stream_Read_UINT8(s, si.val2);
|
||||
*value = (((INT32)si.val1) << 8) | ((INT32)si.val2);
|
||||
break;
|
||||
case THREE_BYTE_VAL:
|
||||
Stream_Read_UINT8(s, si.val2);
|
||||
Stream_Read_UINT8(s, si.val3);
|
||||
*value = (((INT32)si.val1) << 16) | (((INT32)si.val2) << 8) | ((INT32)si.val3);
|
||||
break;
|
||||
case FOUR_BYTE_VAL:
|
||||
Stream_Read_UINT8(s, si.val2);
|
||||
Stream_Read_UINT8(s, si.val3);
|
||||
Stream_Read_UINT8(s, si.val4);
|
||||
*value = (((INT32)si.val1) << 24) | (((INT32)si.val2) << 16) | (((INT32)si.val3) << 8) |
|
||||
((INT32)si.val4);
|
||||
break;
|
||||
case FIVE_BYTE_VAL:
|
||||
case SIX_BYTE_VAL:
|
||||
case SEVEN_BYTE_VAL:
|
||||
case EIGHT_BYTE_VAL:
|
||||
default:
|
||||
WLog_ERR(TAG, "Invalid byte count value in si.c: %u", si.c);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (si.s == NEGATIVE_VAL)
|
||||
*value *= -1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL freerdp_write_four_byte_signed_integer(wStream* s, INT32 value)
|
||||
{
|
||||
FOUR_BYTE_SIGNED_INTEGER si = FOUR_BYTE_SIGNED_INTEGER_init();
|
||||
|
||||
WINPR_ASSERT(s);
|
||||
if (value > FREERDP_FOUR_BYTE_SIGNED_INT_MAX)
|
||||
return FALSE;
|
||||
if (value < FREERDP_FOUR_BYTE_SIGNED_INT_MIN)
|
||||
return FALSE;
|
||||
|
||||
if (value < 0)
|
||||
{
|
||||
si.s = NEGATIVE_VAL;
|
||||
value = -value;
|
||||
}
|
||||
|
||||
if (value <= 0x1F)
|
||||
{
|
||||
si.c = ONE_BYTE_VAL;
|
||||
si.val1 = value & 0x1f;
|
||||
}
|
||||
else if (value <= 0x1FFF)
|
||||
{
|
||||
si.c = TWO_BYTE_VAL;
|
||||
si.val1 = (value >> 8) & 0x1f;
|
||||
si.val2 = value & 0xff;
|
||||
}
|
||||
else if (value <= 0x1FFFFF)
|
||||
{
|
||||
si.c = THREE_BYTE_VAL;
|
||||
si.val1 = (value >> 16) & 0x1f;
|
||||
si.val2 = (value >> 8) & 0xff;
|
||||
si.val3 = value & 0xff;
|
||||
}
|
||||
else if (value <= 0x1FFFFFFF)
|
||||
{
|
||||
si.c = FOUR_BYTE_VAL;
|
||||
si.val1 = (value >> 24) & 0x1f;
|
||||
si.val2 = (value >> 16) & 0xff;
|
||||
si.val3 = (value >> 8) & 0xff;
|
||||
si.val4 = value & 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_ERR(TAG, "Invalid byte count for value %" PRId32, value);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(s, si.c + 1))
|
||||
return FALSE;
|
||||
|
||||
const BYTE byte = ((si.c << 6) & 0xC0) | ((si.s << 5) & 0x20) | (si.val1 & 0x1F);
|
||||
Stream_Write_UINT8(s, byte);
|
||||
|
||||
switch (si.c)
|
||||
{
|
||||
case ONE_BYTE_VAL:
|
||||
break;
|
||||
case TWO_BYTE_VAL:
|
||||
Stream_Write_UINT8(s, si.val2);
|
||||
break;
|
||||
case THREE_BYTE_VAL:
|
||||
Stream_Write_UINT8(s, si.val2);
|
||||
Stream_Write_UINT8(s, si.val3);
|
||||
break;
|
||||
case FOUR_BYTE_VAL:
|
||||
Stream_Write_UINT8(s, si.val2);
|
||||
Stream_Write_UINT8(s, si.val3);
|
||||
Stream_Write_UINT8(s, si.val4);
|
||||
break;
|
||||
case FIVE_BYTE_VAL:
|
||||
case SIX_BYTE_VAL:
|
||||
case SEVEN_BYTE_VAL:
|
||||
case EIGHT_BYTE_VAL:
|
||||
default:
|
||||
WLog_ERR(TAG, "Invalid byte count value in si.c: %u", si.c);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL freerdp_read_four_byte_float(wStream* s, double* value)
|
||||
{
|
||||
return freerdp_read_four_byte_float_exp(s, value, nullptr);
|
||||
}
|
||||
|
||||
BOOL freerdp_read_four_byte_float_exp(wStream* s, double* value, BYTE* exp)
|
||||
{
|
||||
FOUR_BYTE_FLOAT f = FOUR_BYTE_FLOAT_init();
|
||||
UINT32 base = 0;
|
||||
BYTE byte = 0;
|
||||
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(value);
|
||||
|
||||
*value = 0.0;
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, byte);
|
||||
|
||||
f.c = (EncodedTypeByteCount)((byte & 0xC0) >> 6);
|
||||
f.s = (EncodedTypeSign)((byte & 0x20) >> 5);
|
||||
f.e = (byte & 0x1C) >> 2;
|
||||
f.val1 = (byte & 0x03);
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, f.c))
|
||||
return FALSE;
|
||||
|
||||
switch (f.c)
|
||||
{
|
||||
case ONE_BYTE_VAL:
|
||||
base = f.val1;
|
||||
break;
|
||||
case TWO_BYTE_VAL:
|
||||
Stream_Read_UINT8(s, f.val2);
|
||||
base = (((UINT32)f.val1) << 8) | ((UINT32)f.val2);
|
||||
break;
|
||||
case THREE_BYTE_VAL:
|
||||
Stream_Read_UINT8(s, f.val2);
|
||||
Stream_Read_UINT8(s, f.val3);
|
||||
base = (((UINT32)f.val1) << 16) | (((UINT32)f.val2) << 8) | ((UINT32)f.val3);
|
||||
break;
|
||||
case FOUR_BYTE_VAL:
|
||||
Stream_Read_UINT8(s, f.val2);
|
||||
Stream_Read_UINT8(s, f.val3);
|
||||
Stream_Read_UINT8(s, f.val4);
|
||||
base = (((UINT32)f.val1) << 24) | (((UINT32)f.val2) << 16) | (((UINT32)f.val3) << 8) |
|
||||
((UINT32)f.val4);
|
||||
break;
|
||||
case FIVE_BYTE_VAL:
|
||||
case SIX_BYTE_VAL:
|
||||
case SEVEN_BYTE_VAL:
|
||||
case EIGHT_BYTE_VAL:
|
||||
default:
|
||||
WLog_ERR(TAG, "Invalid byte count value in f.c: %u", f.c);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*value = base;
|
||||
*value /= pow(10, f.e);
|
||||
|
||||
if (f.s == NEGATIVE_VAL)
|
||||
*value *= -1.0;
|
||||
|
||||
if (exp)
|
||||
*exp = f.e;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL freerdp_write_four_byte_float(wStream* s, double value)
|
||||
{
|
||||
FOUR_BYTE_FLOAT si = FOUR_BYTE_FLOAT_init();
|
||||
|
||||
WINPR_ASSERT(s);
|
||||
|
||||
if (value > FREERDP_FOUR_BYTE_FLOAT_MAX)
|
||||
return FALSE;
|
||||
if (value < FREERDP_FOUR_BYTE_FLOAT_MIN)
|
||||
return FALSE;
|
||||
|
||||
if (value < 0)
|
||||
{
|
||||
si.s = NEGATIVE_VAL;
|
||||
value = -value;
|
||||
}
|
||||
|
||||
int exp = 0;
|
||||
double ival = FP_NAN;
|
||||
const double aval = fabs(value);
|
||||
const double frac = modf(aval, &ival);
|
||||
if (frac != 0.0)
|
||||
{
|
||||
const double maxfrac = frac * 10000000.0;
|
||||
if (maxfrac <= 1.0)
|
||||
exp = 0;
|
||||
else if (maxfrac <= 10.0)
|
||||
exp = 1;
|
||||
else if (maxfrac <= 100.0)
|
||||
exp = 2;
|
||||
else if (maxfrac <= 1000.0)
|
||||
exp = 3;
|
||||
else if (maxfrac <= 10000.0)
|
||||
exp = 4;
|
||||
else if (maxfrac <= 100000.0)
|
||||
exp = 5;
|
||||
else if (maxfrac <= 1000000.0)
|
||||
exp = 6;
|
||||
else
|
||||
exp = 7;
|
||||
}
|
||||
|
||||
UINT64 base = (UINT64)llround(aval);
|
||||
while (exp >= 0)
|
||||
{
|
||||
const double div = pow(10.0, exp);
|
||||
const double dval = (aval * div);
|
||||
base = (UINT64)dval;
|
||||
if (base <= 0x03ffffff)
|
||||
break;
|
||||
exp--;
|
||||
}
|
||||
|
||||
if (exp < 0)
|
||||
return FALSE;
|
||||
|
||||
si.e = (BYTE)exp;
|
||||
if (base <= 0x03)
|
||||
{
|
||||
si.c = ONE_BYTE_VAL;
|
||||
si.val1 = base & 0x03;
|
||||
}
|
||||
else if (base <= 0x03ff)
|
||||
{
|
||||
si.c = TWO_BYTE_VAL;
|
||||
si.val1 = (base >> 8) & 0x03;
|
||||
si.val2 = base & 0xff;
|
||||
}
|
||||
else if (base <= 0x03ffff)
|
||||
{
|
||||
si.c = THREE_BYTE_VAL;
|
||||
si.val1 = (base >> 16) & 0x03;
|
||||
si.val2 = (base >> 8) & 0xff;
|
||||
si.val3 = base & 0xff;
|
||||
}
|
||||
else if (base <= 0x03ffffff)
|
||||
{
|
||||
si.c = FOUR_BYTE_VAL;
|
||||
si.val1 = (base >> 24) & 0x03;
|
||||
si.val2 = (base >> 16) & 0xff;
|
||||
si.val3 = (base >> 8) & 0xff;
|
||||
si.val4 = base & 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_ERR(TAG, "Invalid byte count for value %lf", value);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(s, si.c + 1))
|
||||
return FALSE;
|
||||
|
||||
const BYTE byte =
|
||||
((si.c << 6) & 0xC0) | ((si.s << 5) & 0x20) | ((si.e << 2) & 0x1c) | (si.val1 & 0x03);
|
||||
Stream_Write_UINT8(s, byte);
|
||||
|
||||
switch (si.c)
|
||||
{
|
||||
case ONE_BYTE_VAL:
|
||||
break;
|
||||
case TWO_BYTE_VAL:
|
||||
Stream_Write_UINT8(s, si.val2);
|
||||
break;
|
||||
case THREE_BYTE_VAL:
|
||||
Stream_Write_UINT8(s, si.val2);
|
||||
Stream_Write_UINT8(s, si.val3);
|
||||
break;
|
||||
case FOUR_BYTE_VAL:
|
||||
Stream_Write_UINT8(s, si.val2);
|
||||
Stream_Write_UINT8(s, si.val3);
|
||||
Stream_Write_UINT8(s, si.val4);
|
||||
break;
|
||||
case FIVE_BYTE_VAL:
|
||||
case SIX_BYTE_VAL:
|
||||
case SEVEN_BYTE_VAL:
|
||||
case EIGHT_BYTE_VAL:
|
||||
default:
|
||||
WLog_ERR(TAG, "Invalid byte count value in si.c: %u", si.c);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
97
third_party/FreeRDP/libfreerdp/utils/gfx.c
vendored
Normal file
97
third_party/FreeRDP/libfreerdp/utils/gfx.c
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* GFX Utils - Helper functions converting something to string
|
||||
*
|
||||
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2022 Thincast Technologies GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/utils/gfx.h>
|
||||
#include <freerdp/channels/rdpgfx.h>
|
||||
|
||||
static const char* RDPGFX_CMDID_STRINGS[] = { "RDPGFX_CMDID_UNUSED_0000",
|
||||
"RDPGFX_CMDID_WIRETOSURFACE_1",
|
||||
"RDPGFX_CMDID_WIRETOSURFACE_2",
|
||||
"RDPGFX_CMDID_DELETEENCODINGCONTEXT",
|
||||
"RDPGFX_CMDID_SOLIDFILL",
|
||||
"RDPGFX_CMDID_SURFACETOSURFACE",
|
||||
"RDPGFX_CMDID_SURFACETOCACHE",
|
||||
"RDPGFX_CMDID_CACHETOSURFACE",
|
||||
"RDPGFX_CMDID_EVICTCACHEENTRY",
|
||||
"RDPGFX_CMDID_CREATESURFACE",
|
||||
"RDPGFX_CMDID_DELETESURFACE",
|
||||
"RDPGFX_CMDID_STARTFRAME",
|
||||
"RDPGFX_CMDID_ENDFRAME",
|
||||
"RDPGFX_CMDID_FRAMEACKNOWLEDGE",
|
||||
"RDPGFX_CMDID_RESETGRAPHICS",
|
||||
"RDPGFX_CMDID_MAPSURFACETOOUTPUT",
|
||||
"RDPGFX_CMDID_CACHEIMPORTOFFER",
|
||||
"RDPGFX_CMDID_CACHEIMPORTREPLY",
|
||||
"RDPGFX_CMDID_CAPSADVERTISE",
|
||||
"RDPGFX_CMDID_CAPSCONFIRM",
|
||||
"RDPGFX_CMDID_UNUSED_0014",
|
||||
"RDPGFX_CMDID_MAPSURFACETOWINDOW",
|
||||
"RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE",
|
||||
"RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT",
|
||||
"RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW" };
|
||||
|
||||
const char* rdpgfx_get_cmd_id_string(UINT16 cmdId)
|
||||
{
|
||||
if (cmdId <= RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW)
|
||||
return RDPGFX_CMDID_STRINGS[cmdId];
|
||||
else
|
||||
return "RDPGFX_CMDID_UNKNOWN";
|
||||
}
|
||||
|
||||
const char* rdpgfx_get_codec_id_string(UINT16 codecId)
|
||||
{
|
||||
switch (codecId)
|
||||
{
|
||||
case RDPGFX_CODECID_UNCOMPRESSED:
|
||||
return "RDPGFX_CODECID_UNCOMPRESSED";
|
||||
|
||||
case RDPGFX_CODECID_CAVIDEO:
|
||||
return "RDPGFX_CODECID_CAVIDEO";
|
||||
|
||||
case RDPGFX_CODECID_CLEARCODEC:
|
||||
return "RDPGFX_CODECID_CLEARCODEC";
|
||||
|
||||
case RDPGFX_CODECID_PLANAR:
|
||||
return "RDPGFX_CODECID_PLANAR";
|
||||
|
||||
case RDPGFX_CODECID_AVC420:
|
||||
return "RDPGFX_CODECID_AVC420";
|
||||
|
||||
case RDPGFX_CODECID_AVC444:
|
||||
return "RDPGFX_CODECID_AVC444";
|
||||
|
||||
case RDPGFX_CODECID_AVC444v2:
|
||||
return "RDPGFX_CODECID_AVC444v2";
|
||||
|
||||
case RDPGFX_CODECID_ALPHA:
|
||||
return "RDPGFX_CODECID_ALPHA";
|
||||
|
||||
case RDPGFX_CODECID_CAPROGRESSIVE:
|
||||
return "RDPGFX_CODECID_CAPROGRESSIVE";
|
||||
|
||||
case RDPGFX_CODECID_CAPROGRESSIVE_V2:
|
||||
return "RDPGFX_CODECID_CAPROGRESSIVE_V2";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return "RDPGFX_CODECID_UNKNOWN";
|
||||
}
|
||||
308
third_party/FreeRDP/libfreerdp/utils/helpers.c
vendored
Normal file
308
third_party/FreeRDP/libfreerdp/utils/helpers.c
vendored
Normal file
@@ -0,0 +1,308 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* common helper utilities
|
||||
*
|
||||
* Copyright 2024 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2024 Thincast Technologies GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <freerdp/utils/helpers.h>
|
||||
|
||||
#include <winpr/path.h>
|
||||
#include <winpr/file.h>
|
||||
#include <winpr/build-config.h>
|
||||
#include <freerdp/version.h>
|
||||
#include <freerdp/build-config.h>
|
||||
|
||||
#include "../core/utils.h"
|
||||
|
||||
static INIT_ONCE s_freerdp_app_details_once = INIT_ONCE_STATIC_INIT;
|
||||
static char s_freerdp_vendor_string[MAX_PATH] = WINPR_C_ARRAY_INIT;
|
||||
static char s_freerdp_product_string[MAX_PATH] = WINPR_C_ARRAY_INIT;
|
||||
static char s_freerdp_details_string[3ull * MAX_PATH] = WINPR_C_ARRAY_INIT;
|
||||
static WCHAR s_freerdp_details_string_w[3ull * MAX_PATH] = WINPR_C_ARRAY_INIT;
|
||||
static SSIZE_T s_freerdp_version = -1;
|
||||
static BOOL s_freerdp_app_details_are_custom = FALSE;
|
||||
|
||||
static void updateDetailsString(void)
|
||||
{
|
||||
const char* vendor = s_freerdp_vendor_string;
|
||||
const char* product = s_freerdp_product_string;
|
||||
const SSIZE_T version = s_freerdp_version;
|
||||
|
||||
WINPR_ASSERT(vendor);
|
||||
WINPR_ASSERT(product);
|
||||
if (s_freerdp_app_details_are_custom)
|
||||
{
|
||||
if (version < 0)
|
||||
(void)_snprintf(s_freerdp_details_string, sizeof(s_freerdp_details_string) - 1, "%s-%s",
|
||||
vendor, product);
|
||||
else
|
||||
(void)_snprintf(s_freerdp_details_string, sizeof(s_freerdp_details_string) - 1,
|
||||
"%s-%s%" PRIdz, vendor, product, version);
|
||||
}
|
||||
else if (version < 0)
|
||||
{
|
||||
(void)_snprintf(s_freerdp_details_string, sizeof(s_freerdp_details_string) - 1, "%s",
|
||||
product);
|
||||
}
|
||||
else
|
||||
(void)_snprintf(s_freerdp_details_string, sizeof(s_freerdp_details_string) - 1, "%s%" PRIdz,
|
||||
product, version);
|
||||
|
||||
(void)ConvertUtf8NToWChar(s_freerdp_details_string, sizeof(s_freerdp_details_string),
|
||||
s_freerdp_details_string_w, sizeof(s_freerdp_details_string_w) - 1);
|
||||
}
|
||||
|
||||
static BOOL CALLBACK init_app_details(WINPR_ATTR_UNUSED PINIT_ONCE once,
|
||||
WINPR_ATTR_UNUSED PVOID param,
|
||||
WINPR_ATTR_UNUSED PVOID* context)
|
||||
{
|
||||
const size_t vlen = sizeof(FREERDP_VENDOR_STRING);
|
||||
const size_t plen = sizeof(FREERDP_PRODUCT_STRING);
|
||||
const char* rvlen = strncpy(s_freerdp_vendor_string, FREERDP_VENDOR_STRING, vlen);
|
||||
const char* rplen = strncpy(s_freerdp_product_string, FREERDP_PRODUCT_STRING, plen);
|
||||
if (!rvlen || !rplen)
|
||||
return FALSE;
|
||||
|
||||
#if defined(WITH_RESOURCE_VERSIONING)
|
||||
s_freerdp_version = FREERDP_VERSION_MAJOR;
|
||||
#else
|
||||
s_freerdp_version = -1;
|
||||
#endif
|
||||
updateDetailsString();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL initializeApplicationDetails(void)
|
||||
{
|
||||
return InitOnceExecuteOnce(&s_freerdp_app_details_once, init_app_details, nullptr, nullptr);
|
||||
}
|
||||
|
||||
BOOL freerdp_setApplicationDetails(const char* vendor, const char* product, SSIZE_T version)
|
||||
{
|
||||
if (!initializeApplicationDetails())
|
||||
return -1;
|
||||
|
||||
if (!vendor || !product)
|
||||
return FALSE;
|
||||
const size_t vlen = strnlen(vendor, MAX_PATH);
|
||||
const size_t plen = strnlen(product, MAX_PATH);
|
||||
if ((vlen == MAX_PATH) || (plen == MAX_PATH))
|
||||
return FALSE;
|
||||
|
||||
if (!strncpy(s_freerdp_vendor_string, vendor, vlen + 1))
|
||||
return FALSE;
|
||||
|
||||
if (!strncpy(s_freerdp_product_string, product, plen + 1))
|
||||
return FALSE;
|
||||
|
||||
s_freerdp_version = version;
|
||||
s_freerdp_app_details_are_custom = TRUE;
|
||||
|
||||
const char separator = PathGetSeparatorA(PATH_STYLE_NATIVE);
|
||||
char* str = freerdp_getApplicatonDetailsCombined(separator);
|
||||
if (!str)
|
||||
return FALSE;
|
||||
|
||||
const BOOL rc = winpr_setApplicationDetails(str, "WinPR", -1);
|
||||
free(str);
|
||||
updateDetailsString();
|
||||
return rc;
|
||||
}
|
||||
|
||||
const char* freerdp_getApplicationDetailsVendor(void)
|
||||
{
|
||||
if (!initializeApplicationDetails())
|
||||
return nullptr;
|
||||
return s_freerdp_vendor_string;
|
||||
}
|
||||
|
||||
const char* freerdp_getApplicationDetailsProduct(void)
|
||||
{
|
||||
if (!initializeApplicationDetails())
|
||||
return nullptr;
|
||||
return s_freerdp_product_string;
|
||||
}
|
||||
|
||||
char* freerdp_getApplicatonDetailsRegKey(const char* fmt)
|
||||
{
|
||||
char* val = freerdp_getApplicatonDetailsCombined('\\');
|
||||
if (!val)
|
||||
return nullptr;
|
||||
|
||||
char* str = nullptr;
|
||||
size_t slen = 0;
|
||||
(void)winpr_asprintf(&str, &slen, fmt, val);
|
||||
free(val);
|
||||
return str;
|
||||
}
|
||||
|
||||
char* freerdp_getApplicatonDetailsCombined(char separator)
|
||||
{
|
||||
const SSIZE_T version = freerdp_getApplicationDetailsVersion();
|
||||
const char* vendor = freerdp_getApplicationDetailsVendor();
|
||||
const char* product = freerdp_getApplicationDetailsProduct();
|
||||
|
||||
size_t slen = 0;
|
||||
char* str = nullptr;
|
||||
if (version < 0)
|
||||
{
|
||||
(void)winpr_asprintf(&str, &slen, "%s%c%s", vendor, separator, product);
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)winpr_asprintf(&str, &slen, "%s%c%s%" PRIdz, vendor, separator, product, version);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
SSIZE_T freerdp_getApplicationDetailsVersion(void)
|
||||
{
|
||||
if (!initializeApplicationDetails())
|
||||
return -1;
|
||||
return s_freerdp_version;
|
||||
}
|
||||
|
||||
const char* freerdp_getApplicationDetailsString(void)
|
||||
{
|
||||
return s_freerdp_details_string;
|
||||
}
|
||||
|
||||
const WCHAR* freerdp_getApplicationDetailsStringW(void)
|
||||
{
|
||||
return s_freerdp_details_string_w;
|
||||
}
|
||||
|
||||
BOOL freerdp_areApplicationDetailsCustomized(void)
|
||||
{
|
||||
return s_freerdp_app_details_are_custom;
|
||||
}
|
||||
|
||||
#if !defined(WITH_FULL_CONFIG_PATH)
|
||||
WINPR_ATTR_MALLOC(free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
static char* freerdp_settings_get_legacy_config_path(const char* filename)
|
||||
{
|
||||
char product[sizeof(FREERDP_PRODUCT_STRING)] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
for (size_t i = 0; i < sizeof(product); i++)
|
||||
product[i] = (char)tolower(FREERDP_PRODUCT_STRING[i]);
|
||||
|
||||
char* path = GetKnownSubPath(KNOWN_PATH_XDG_CONFIG_HOME, product);
|
||||
|
||||
if (!path)
|
||||
return nullptr;
|
||||
|
||||
char* filepath = GetCombinedPath(path, filename);
|
||||
free(path);
|
||||
return filepath;
|
||||
}
|
||||
#endif
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
WINPR_ATTR_MALLOC(free, 1) static char* getCustomConfigPath(BOOL system, const char* filename)
|
||||
{
|
||||
eKnownPathTypes id = system ? KNOWN_PATH_SYSTEM_CONFIG_HOME : KNOWN_PATH_XDG_CONFIG_HOME;
|
||||
|
||||
const char* vendor = freerdp_getApplicationDetailsVendor();
|
||||
const char* product = freerdp_getApplicationDetailsProduct();
|
||||
const SSIZE_T version = freerdp_getApplicationDetailsVersion();
|
||||
|
||||
if (!vendor || !product)
|
||||
return nullptr;
|
||||
|
||||
char* config = GetKnownSubPathV(id, "%s", vendor);
|
||||
if (!config)
|
||||
return nullptr;
|
||||
|
||||
char* base = nullptr;
|
||||
if (version < 0)
|
||||
base = GetCombinedPathV(config, "%s", product);
|
||||
else
|
||||
base = GetCombinedPathV(config, "%s%" PRIdz, product, version);
|
||||
free(config);
|
||||
|
||||
if (!base)
|
||||
return nullptr;
|
||||
|
||||
if (!filename)
|
||||
return base;
|
||||
|
||||
char* path = GetCombinedPathV(base, "%s", filename);
|
||||
free(base);
|
||||
return path;
|
||||
}
|
||||
|
||||
char* freerdp_GetConfigFilePath(BOOL system, const char* filename)
|
||||
{
|
||||
#if defined(FREERDP_USE_VENDOR_PRODUCT_CONFIG_DIR)
|
||||
const BOOL customized = TRUE;
|
||||
#else
|
||||
const BOOL customized = freerdp_areApplicationDetailsCustomized();
|
||||
#endif
|
||||
if (customized)
|
||||
return getCustomConfigPath(system, filename);
|
||||
|
||||
eKnownPathTypes id = system ? KNOWN_PATH_SYSTEM_CONFIG_HOME : KNOWN_PATH_XDG_CONFIG_HOME;
|
||||
|
||||
const char* vendor = freerdp_getApplicationDetailsVendor();
|
||||
const char* product = freerdp_getApplicationDetailsProduct();
|
||||
const SSIZE_T version = freerdp_getApplicationDetailsVersion();
|
||||
|
||||
if (!vendor || !product)
|
||||
return nullptr;
|
||||
|
||||
#if !defined(WITH_FULL_CONFIG_PATH)
|
||||
if (!system && (_stricmp(vendor, product) == 0))
|
||||
return freerdp_settings_get_legacy_config_path(filename);
|
||||
#endif
|
||||
|
||||
char* config = GetKnownPath(id);
|
||||
if (!config)
|
||||
return nullptr;
|
||||
|
||||
char* base = nullptr;
|
||||
if (version < 0)
|
||||
base = GetCombinedPathV(config, "%s", product);
|
||||
else
|
||||
base = GetCombinedPathV(config, "%s%" PRIdz, product, version);
|
||||
free(config);
|
||||
|
||||
if (!base)
|
||||
return nullptr;
|
||||
|
||||
if (!filename)
|
||||
return base;
|
||||
|
||||
char* path = GetCombinedPathV(base, "%s", filename);
|
||||
free(base);
|
||||
return path;
|
||||
}
|
||||
|
||||
WINPR_JSON* freerdp_GetJSONConfigFile(BOOL system, const char* filename)
|
||||
{
|
||||
char* path = freerdp_GetConfigFilePath(system, filename);
|
||||
if (!path)
|
||||
return nullptr;
|
||||
|
||||
WINPR_JSON* json = WINPR_JSON_ParseFromFile(path);
|
||||
free(path);
|
||||
return json;
|
||||
}
|
||||
420
third_party/FreeRDP/libfreerdp/utils/http.c
vendored
Normal file
420
third_party/FreeRDP/libfreerdp/utils/http.c
vendored
Normal file
@@ -0,0 +1,420 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Simple HTTP client request utility
|
||||
*
|
||||
* Copyright 2023 Isaac Klein <fifthdegree@protonmail.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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
#include <freerdp/utils/http.h>
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/string.h>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG FREERDP_TAG("utils.http")
|
||||
|
||||
static const char get_header_fmt[] = "GET %s HTTP/1.1\r\n"
|
||||
"Host: %s\r\n"
|
||||
"\r\n";
|
||||
|
||||
static const char post_header_fmt[] = "POST %s HTTP/1.1\r\n"
|
||||
"Host: %s\r\n"
|
||||
"Content-Type: application/x-www-form-urlencoded\r\n"
|
||||
"Content-Length: %lu\r\n"
|
||||
"\r\n";
|
||||
|
||||
#define log_errors(log, msg) log_errors_(log, msg, __FILE__, __func__, __LINE__)
|
||||
static void log_errors_(wLog* log, const char* msg, const char* file, const char* fkt, size_t line)
|
||||
{
|
||||
const DWORD level = WLOG_ERROR;
|
||||
unsigned long ec = 0;
|
||||
|
||||
if (!WLog_IsLevelActive(log, level))
|
||||
return;
|
||||
|
||||
BOOL error_logged = FALSE;
|
||||
while ((ec = ERR_get_error()))
|
||||
{
|
||||
error_logged = TRUE;
|
||||
WLog_PrintTextMessage(log, level, line, file, fkt, "%s: %s", msg,
|
||||
ERR_error_string(ec, nullptr));
|
||||
}
|
||||
if (!error_logged)
|
||||
WLog_PrintTextMessage(log, level, line, file, fkt, "%s (no details available)", msg);
|
||||
}
|
||||
|
||||
static int get_line(BIO* bio, char* buffer, size_t size)
|
||||
{
|
||||
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
|
||||
if (size <= 1)
|
||||
return -1;
|
||||
|
||||
size_t pos = 0;
|
||||
do
|
||||
{
|
||||
int rc = BIO_read(bio, &buffer[pos], 1);
|
||||
if (rc <= 0)
|
||||
return rc;
|
||||
char cur = buffer[pos];
|
||||
pos += rc;
|
||||
if ((cur == '\n') || (pos >= size - 1))
|
||||
{
|
||||
buffer[pos] = '\0';
|
||||
return (int)pos;
|
||||
}
|
||||
} while (1);
|
||||
#else
|
||||
if (size > INT32_MAX)
|
||||
return -1;
|
||||
return BIO_get_line(bio, buffer, (int)size);
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOL freerdp_http_request(const char* url, const char* body, long* status_code, BYTE** response,
|
||||
size_t* response_length)
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
char* hostname = nullptr;
|
||||
const char* path = nullptr;
|
||||
char* headers = nullptr;
|
||||
size_t size = 0;
|
||||
int status = 0;
|
||||
char buffer[1024] = WINPR_C_ARRAY_INIT;
|
||||
BIO* bio = nullptr;
|
||||
SSL_CTX* ssl_ctx = nullptr;
|
||||
SSL* ssl = nullptr;
|
||||
|
||||
WINPR_ASSERT(status_code);
|
||||
WINPR_ASSERT(response);
|
||||
WINPR_ASSERT(response_length);
|
||||
|
||||
wLog* log = WLog_Get(TAG);
|
||||
WINPR_ASSERT(log);
|
||||
|
||||
*response = nullptr;
|
||||
|
||||
if (!url || strnlen(url, 8) < 8 || strncmp(url, "https://", 8) != 0 ||
|
||||
!(path = strchr(url + 8, '/')))
|
||||
{
|
||||
WLog_Print(log, WLOG_ERROR, "invalid url provided");
|
||||
goto out;
|
||||
}
|
||||
|
||||
{
|
||||
const size_t len = WINPR_ASSERTING_INT_CAST(size_t, path - (url + 8));
|
||||
hostname = strndup(&url[8], len);
|
||||
}
|
||||
if (!hostname)
|
||||
return FALSE;
|
||||
|
||||
{
|
||||
size_t blen = 0;
|
||||
if (body)
|
||||
{
|
||||
blen = strlen(body);
|
||||
if (winpr_asprintf(&headers, &size, post_header_fmt, path, hostname, blen) < 0)
|
||||
{
|
||||
free(hostname);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (winpr_asprintf(&headers, &size, get_header_fmt, path, hostname) < 0)
|
||||
{
|
||||
free(hostname);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
ssl_ctx = SSL_CTX_new(TLS_client_method());
|
||||
|
||||
if (!ssl_ctx)
|
||||
{
|
||||
log_errors(log, "could not set up ssl context");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!SSL_CTX_set_default_verify_paths(ssl_ctx))
|
||||
{
|
||||
log_errors(log, "could not set ssl context verify paths");
|
||||
goto out;
|
||||
}
|
||||
|
||||
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
|
||||
|
||||
bio = BIO_new_ssl_connect(ssl_ctx);
|
||||
if (!bio)
|
||||
{
|
||||
log_errors(log, "could not set up connection");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (BIO_set_conn_port(bio, "https") <= 0)
|
||||
{
|
||||
log_errors(log, "could not set port");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!BIO_set_conn_hostname(bio, hostname))
|
||||
{
|
||||
log_errors(log, "could not set hostname");
|
||||
goto out;
|
||||
}
|
||||
|
||||
BIO_get_ssl(bio, &ssl);
|
||||
if (!ssl)
|
||||
{
|
||||
log_errors(log, "could not get ssl");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!SSL_set_tlsext_host_name(ssl, hostname))
|
||||
{
|
||||
log_errors(log, "could not set sni hostname");
|
||||
goto out;
|
||||
}
|
||||
|
||||
WLog_Print(log, WLOG_DEBUG, "headers:\n%s", headers);
|
||||
ERR_clear_error();
|
||||
|
||||
{
|
||||
const size_t hlen = strnlen(headers, size);
|
||||
if (hlen > INT32_MAX)
|
||||
goto out;
|
||||
|
||||
if (BIO_write(bio, headers, (int)hlen) < 0)
|
||||
{
|
||||
log_errors(log, "could not write headers");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (body)
|
||||
{
|
||||
WLog_Print(log, WLOG_DEBUG, "body:\n%s", body);
|
||||
|
||||
if (blen > INT_MAX)
|
||||
{
|
||||
WLog_Print(log, WLOG_ERROR, "body too long!");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ERR_clear_error();
|
||||
if (BIO_write(bio, body, (int)blen) < 0)
|
||||
{
|
||||
log_errors(log, "could not write body");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
status = get_line(bio, buffer, sizeof(buffer));
|
||||
if (status <= 0)
|
||||
{
|
||||
log_errors(log, "could not read response");
|
||||
goto out;
|
||||
}
|
||||
|
||||
const char header[9] = { 'H', 'T', 'T', 'P', '/', '1', '.', '1', ' ' };
|
||||
if ((status < (INT64)sizeof(header)) || (strncmp(header, buffer, sizeof(header)) != 0))
|
||||
{
|
||||
WLog_Print(log, WLOG_ERROR, "invalid HTTP status header");
|
||||
goto out;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
*status_code = strtol(&buffer[sizeof(header)], nullptr, 0);
|
||||
if (errno != 0)
|
||||
{
|
||||
char ebuffer[256] = WINPR_C_ARRAY_INIT;
|
||||
WLog_Print(log, WLOG_ERROR, "invalid HTTP status line: %s [%d]",
|
||||
winpr_strerror(errno, ebuffer, sizeof(ebuffer)), errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
status = get_line(bio, buffer, sizeof(buffer));
|
||||
if (status <= 0)
|
||||
{
|
||||
log_errors(log, "could not read response");
|
||||
goto out;
|
||||
}
|
||||
|
||||
char* val = nullptr;
|
||||
char* name = strtok_s(buffer, ":", &val);
|
||||
if (name && (_stricmp(name, "content-length") == 0))
|
||||
{
|
||||
errno = 0;
|
||||
*response_length = strtoul(val, nullptr, 10);
|
||||
if (errno)
|
||||
{
|
||||
char ebuffer[256] = WINPR_C_ARRAY_INIT;
|
||||
WLog_Print(log, WLOG_ERROR, "could not parse content length (%s): %s [%d]", val,
|
||||
winpr_strerror(errno, ebuffer, sizeof(ebuffer)), errno);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
} while (strcmp(buffer, "\r\n") != 0);
|
||||
|
||||
if (*response_length > 0)
|
||||
{
|
||||
if (*response_length > INT_MAX)
|
||||
{
|
||||
WLog_Print(log, WLOG_ERROR, "response too long!");
|
||||
goto out;
|
||||
}
|
||||
|
||||
*response = calloc(1, *response_length + 1);
|
||||
if (!*response)
|
||||
goto out;
|
||||
|
||||
BYTE* p = *response;
|
||||
size_t left = *response_length;
|
||||
while (left > 0)
|
||||
{
|
||||
const int rd = (left < INT32_MAX) ? (int)left : INT32_MAX;
|
||||
status = BIO_read(bio, p, rd);
|
||||
if (status <= 0)
|
||||
{
|
||||
log_errors(log, "could not read response");
|
||||
goto out;
|
||||
}
|
||||
p += status;
|
||||
if ((size_t)status > left)
|
||||
break;
|
||||
left -= (size_t)status;
|
||||
}
|
||||
}
|
||||
|
||||
WLog_Print(log, WLOG_DEBUG, "response[%" PRIuz "]:\n%s", *response_length,
|
||||
(const char*)(*response));
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
if (!ret)
|
||||
{
|
||||
free(*response);
|
||||
*response = nullptr;
|
||||
*response_length = 0;
|
||||
}
|
||||
free(hostname);
|
||||
free(headers);
|
||||
BIO_free_all(bio);
|
||||
SSL_CTX_free(ssl_ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char* freerdp_http_status_string(long status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case HTTP_STATUS_CONTINUE:
|
||||
return "HTTP_STATUS_CONTINUE";
|
||||
case HTTP_STATUS_SWITCH_PROTOCOLS:
|
||||
return "HTTP_STATUS_SWITCH_PROTOCOLS";
|
||||
case HTTP_STATUS_OK:
|
||||
return "HTTP_STATUS_OK";
|
||||
case HTTP_STATUS_CREATED:
|
||||
return "HTTP_STATUS_CREATED";
|
||||
case HTTP_STATUS_ACCEPTED:
|
||||
return "HTTP_STATUS_ACCEPTED";
|
||||
case HTTP_STATUS_PARTIAL:
|
||||
return "HTTP_STATUS_PARTIAL";
|
||||
case HTTP_STATUS_NO_CONTENT:
|
||||
return "HTTP_STATUS_NO_CONTENT";
|
||||
case HTTP_STATUS_RESET_CONTENT:
|
||||
return "HTTP_STATUS_RESET_CONTENT";
|
||||
case HTTP_STATUS_PARTIAL_CONTENT:
|
||||
return "HTTP_STATUS_PARTIAL_CONTENT";
|
||||
case HTTP_STATUS_WEBDAV_MULTI_STATUS:
|
||||
return "HTTP_STATUS_WEBDAV_MULTI_STATUS";
|
||||
case HTTP_STATUS_AMBIGUOUS:
|
||||
return "HTTP_STATUS_AMBIGUOUS";
|
||||
case HTTP_STATUS_MOVED:
|
||||
return "HTTP_STATUS_MOVED";
|
||||
case HTTP_STATUS_REDIRECT:
|
||||
return "HTTP_STATUS_REDIRECT";
|
||||
case HTTP_STATUS_REDIRECT_METHOD:
|
||||
return "HTTP_STATUS_REDIRECT_METHOD";
|
||||
case HTTP_STATUS_NOT_MODIFIED:
|
||||
return "HTTP_STATUS_NOT_MODIFIED";
|
||||
case HTTP_STATUS_USE_PROXY:
|
||||
return "HTTP_STATUS_USE_PROXY";
|
||||
case HTTP_STATUS_REDIRECT_KEEP_VERB:
|
||||
return "HTTP_STATUS_REDIRECT_KEEP_VERB";
|
||||
case HTTP_STATUS_BAD_REQUEST:
|
||||
return "HTTP_STATUS_BAD_REQUEST";
|
||||
case HTTP_STATUS_DENIED:
|
||||
return "HTTP_STATUS_DENIED";
|
||||
case HTTP_STATUS_PAYMENT_REQ:
|
||||
return "HTTP_STATUS_PAYMENT_REQ";
|
||||
case HTTP_STATUS_FORBIDDEN:
|
||||
return "HTTP_STATUS_FORBIDDEN";
|
||||
case HTTP_STATUS_NOT_FOUND:
|
||||
return "HTTP_STATUS_NOT_FOUND";
|
||||
case HTTP_STATUS_BAD_METHOD:
|
||||
return "HTTP_STATUS_BAD_METHOD";
|
||||
case HTTP_STATUS_NONE_ACCEPTABLE:
|
||||
return "HTTP_STATUS_NONE_ACCEPTABLE";
|
||||
case HTTP_STATUS_PROXY_AUTH_REQ:
|
||||
return "HTTP_STATUS_PROXY_AUTH_REQ";
|
||||
case HTTP_STATUS_REQUEST_TIMEOUT:
|
||||
return "HTTP_STATUS_REQUEST_TIMEOUT";
|
||||
case HTTP_STATUS_CONFLICT:
|
||||
return "HTTP_STATUS_CONFLICT";
|
||||
case HTTP_STATUS_GONE:
|
||||
return "HTTP_STATUS_GONE";
|
||||
case HTTP_STATUS_LENGTH_REQUIRED:
|
||||
return "HTTP_STATUS_LENGTH_REQUIRED";
|
||||
case HTTP_STATUS_PRECOND_FAILED:
|
||||
return "HTTP_STATUS_PRECOND_FAILED";
|
||||
case HTTP_STATUS_REQUEST_TOO_LARGE:
|
||||
return "HTTP_STATUS_REQUEST_TOO_LARGE";
|
||||
case HTTP_STATUS_URI_TOO_LONG:
|
||||
return "HTTP_STATUS_URI_TOO_LONG";
|
||||
case HTTP_STATUS_UNSUPPORTED_MEDIA:
|
||||
return "HTTP_STATUS_UNSUPPORTED_MEDIA";
|
||||
case HTTP_STATUS_RETRY_WITH:
|
||||
return "HTTP_STATUS_RETRY_WITH";
|
||||
case HTTP_STATUS_SERVER_ERROR:
|
||||
return "HTTP_STATUS_SERVER_ERROR";
|
||||
case HTTP_STATUS_NOT_SUPPORTED:
|
||||
return "HTTP_STATUS_NOT_SUPPORTED";
|
||||
case HTTP_STATUS_BAD_GATEWAY:
|
||||
return "HTTP_STATUS_BAD_GATEWAY";
|
||||
case HTTP_STATUS_SERVICE_UNAVAIL:
|
||||
return "HTTP_STATUS_SERVICE_UNAVAIL";
|
||||
case HTTP_STATUS_GATEWAY_TIMEOUT:
|
||||
return "HTTP_STATUS_GATEWAY_TIMEOUT";
|
||||
case HTTP_STATUS_VERSION_NOT_SUP:
|
||||
return "HTTP_STATUS_VERSION_NOT_SUP";
|
||||
default:
|
||||
return "HTTP_STATUS_UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
const char* freerdp_http_status_string_format(long status, char* buffer, size_t size)
|
||||
{
|
||||
const char* code = freerdp_http_status_string(status);
|
||||
(void)_snprintf(buffer, size, "%s [%ld]", code, status);
|
||||
return buffer;
|
||||
}
|
||||
493
third_party/FreeRDP/libfreerdp/utils/passphrase.c
vendored
Normal file
493
third_party/FreeRDP/libfreerdp/utils/passphrase.c
vendored
Normal file
@@ -0,0 +1,493 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Passphrase Handling Utils
|
||||
*
|
||||
* Copyright 2011 Shea Levy <shea@shealevy.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.
|
||||
*/
|
||||
|
||||
#include <winpr/environment.h>
|
||||
|
||||
#include <freerdp/config.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <freerdp/utils/passphrase.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <stdio.h>
|
||||
#include <io.h>
|
||||
#include <conio.h>
|
||||
#include <wincred.h>
|
||||
|
||||
static char read_chr(FILE* f)
|
||||
{
|
||||
char chr;
|
||||
const BOOL isTty = _isatty(_fileno(f));
|
||||
if (isTty)
|
||||
return fgetc(f);
|
||||
if (fscanf_s(f, "%c", &chr, (UINT32)sizeof(char)) && !feof(f))
|
||||
return chr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int freerdp_interruptible_getc(rdpContext* context, FILE* f)
|
||||
{
|
||||
return read_chr(f);
|
||||
}
|
||||
|
||||
const char* freerdp_passphrase_read(rdpContext* context, const char* prompt, char* buf,
|
||||
size_t bufsiz, int from_stdin)
|
||||
{
|
||||
WCHAR UserNameW[CREDUI_MAX_USERNAME_LENGTH + 1] = { 'p', 'r', 'e', 'f', 'i',
|
||||
'l', 'l', 'e', 'd', '\0' };
|
||||
WCHAR PasswordW[CREDUI_MAX_PASSWORD_LENGTH + 1] = WINPR_C_ARRAY_INIT;
|
||||
BOOL fSave = FALSE;
|
||||
DWORD dwFlags = 0;
|
||||
WCHAR* promptW = ConvertUtf8ToWCharAlloc(prompt, nullptr);
|
||||
const DWORD status =
|
||||
CredUICmdLinePromptForCredentialsW(promptW, nullptr, 0, UserNameW, ARRAYSIZE(UserNameW),
|
||||
PasswordW, ARRAYSIZE(PasswordW), &fSave, dwFlags);
|
||||
free(promptW);
|
||||
if (ConvertWCharNToUtf8(PasswordW, ARRAYSIZE(PasswordW), buf, bufsiz) < 0)
|
||||
return nullptr;
|
||||
return buf;
|
||||
}
|
||||
|
||||
#elif !defined(ANDROID)
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <freerdp/utils/signal.h>
|
||||
#include <freerdp/log.h>
|
||||
#if defined(WINPR_HAVE_POLL_H) && !defined(__APPLE__)
|
||||
#include <poll.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
#define TAG FREERDP_TAG("utils.passphrase")
|
||||
|
||||
static int wait_for_fd(int fd, int timeout)
|
||||
{
|
||||
int status = 0;
|
||||
#if defined(WINPR_HAVE_POLL_H) && !defined(__APPLE__)
|
||||
struct pollfd pollset = WINPR_C_ARRAY_INIT;
|
||||
pollset.fd = fd;
|
||||
pollset.events = POLLIN;
|
||||
pollset.revents = 0;
|
||||
|
||||
do
|
||||
{
|
||||
status = poll(&pollset, 1, timeout);
|
||||
} while ((status < 0) && (errno == EINTR));
|
||||
|
||||
#else
|
||||
fd_set rset = WINPR_C_ARRAY_INIT;
|
||||
struct timeval tv = WINPR_C_ARRAY_INIT;
|
||||
FD_ZERO(&rset);
|
||||
FD_SET(fd, &rset);
|
||||
|
||||
if (timeout)
|
||||
{
|
||||
tv.tv_sec = timeout / 1000;
|
||||
tv.tv_usec = (timeout % 1000) * 1000;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
status = select(fd + 1, &rset, nullptr, nullptr, timeout ? &tv : nullptr);
|
||||
} while ((status < 0) && (errno == EINTR));
|
||||
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
static void replace_char(char* buffer, WINPR_ATTR_UNUSED size_t buffer_len, const char* toreplace)
|
||||
{
|
||||
while (*toreplace != '\0')
|
||||
{
|
||||
char* ptr = nullptr;
|
||||
while ((ptr = strrchr(buffer, *toreplace)) != nullptr)
|
||||
*ptr = '\0';
|
||||
toreplace++;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* freerdp_passphrase_read_tty(rdpContext* context, const char* prompt, char* buf,
|
||||
size_t bufsiz, int from_stdin)
|
||||
{
|
||||
BOOL terminal_needs_reset = FALSE;
|
||||
char term_name[L_ctermid] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
FILE* fout = nullptr;
|
||||
|
||||
if (bufsiz == 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ctermid(term_name);
|
||||
int terminal_fildes = 0;
|
||||
if (from_stdin || (strcmp(term_name, "") == 0))
|
||||
{
|
||||
fout = stdout;
|
||||
terminal_fildes = STDIN_FILENO;
|
||||
}
|
||||
else
|
||||
{
|
||||
const int term_file = open(term_name, O_RDWR);
|
||||
if (term_file < 0)
|
||||
{
|
||||
fout = stdout;
|
||||
terminal_fildes = STDIN_FILENO;
|
||||
}
|
||||
else
|
||||
{
|
||||
fout = fdopen(term_file, "w");
|
||||
if (!fout)
|
||||
{
|
||||
close(term_file);
|
||||
return nullptr;
|
||||
}
|
||||
terminal_fildes = term_file;
|
||||
}
|
||||
}
|
||||
|
||||
struct termios orig_flags = WINPR_C_ARRAY_INIT;
|
||||
if (tcgetattr(terminal_fildes, &orig_flags) != -1)
|
||||
{
|
||||
struct termios new_flags = WINPR_C_ARRAY_INIT;
|
||||
new_flags = orig_flags;
|
||||
new_flags.c_lflag &= (uint32_t)~ECHO;
|
||||
new_flags.c_lflag |= ECHONL;
|
||||
terminal_needs_reset = TRUE;
|
||||
if (tcsetattr(terminal_fildes, TCSAFLUSH, &new_flags) == -1)
|
||||
terminal_needs_reset = FALSE;
|
||||
}
|
||||
|
||||
FILE* fp = fdopen(terminal_fildes, "r");
|
||||
if (!fp)
|
||||
goto error;
|
||||
|
||||
(void)fprintf(fout, "%s", prompt);
|
||||
(void)fflush(fout);
|
||||
|
||||
{
|
||||
char* ptr = nullptr;
|
||||
size_t ptr_len = 0;
|
||||
const SSIZE_T res = freerdp_interruptible_get_line(context, &ptr, &ptr_len, fp);
|
||||
if (res < 0)
|
||||
goto error;
|
||||
|
||||
replace_char(ptr, ptr_len, "\r\n");
|
||||
|
||||
strncpy(buf, ptr, MIN(bufsiz, ptr_len));
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
if (terminal_needs_reset)
|
||||
{
|
||||
if (tcsetattr(terminal_fildes, TCSAFLUSH, &orig_flags) == -1)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (terminal_fildes != STDIN_FILENO)
|
||||
(void)fclose(fp);
|
||||
|
||||
return buf;
|
||||
|
||||
error:
|
||||
{
|
||||
// NOLINTNEXTLINE(clang-analyzer-unix.Stream)
|
||||
int saved_errno = errno;
|
||||
if (terminal_needs_reset)
|
||||
(void)tcsetattr(terminal_fildes, TCSAFLUSH, &orig_flags);
|
||||
|
||||
if (terminal_fildes != STDIN_FILENO)
|
||||
{
|
||||
if (fp)
|
||||
(void)fclose(fp);
|
||||
}
|
||||
// NOLINTNEXTLINE(clang-analyzer-unix.Stream)
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static const char* freerdp_passphrase_read_askpass(const char* prompt, char* buf, size_t bufsiz,
|
||||
char const* askpass_env)
|
||||
{
|
||||
char command[4096] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
(void)sprintf_s(command, sizeof(command), "%s 'FreeRDP authentication\n%s'", askpass_env,
|
||||
prompt);
|
||||
// NOLINTNEXTLINE(clang-analyzer-optin.taint.GenericTaint)
|
||||
FILE* askproc = popen(command, "r");
|
||||
if (!askproc)
|
||||
return nullptr;
|
||||
WINPR_ASSERT(bufsiz <= INT32_MAX);
|
||||
if (fgets(buf, (int)bufsiz, askproc) != nullptr)
|
||||
buf[strcspn(buf, "\r\n")] = '\0';
|
||||
else
|
||||
buf = nullptr;
|
||||
const int status = pclose(askproc);
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
||||
buf = nullptr;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char* freerdp_passphrase_read(rdpContext* context, const char* prompt, char* buf,
|
||||
size_t bufsiz, int from_stdin)
|
||||
{
|
||||
// NOLINTNEXTLINE(concurrency-mt-unsafe)
|
||||
const char* askpass_env = getenv("FREERDP_ASKPASS");
|
||||
|
||||
if (askpass_env)
|
||||
return freerdp_passphrase_read_askpass(prompt, buf, bufsiz, askpass_env);
|
||||
else
|
||||
return freerdp_passphrase_read_tty(context, prompt, buf, bufsiz, from_stdin);
|
||||
}
|
||||
|
||||
static BOOL set_termianl_nonblock(int ifd, BOOL nonblock);
|
||||
|
||||
static void restore_terminal(void)
|
||||
{
|
||||
(void)set_termianl_nonblock(-1, FALSE);
|
||||
}
|
||||
|
||||
BOOL set_termianl_nonblock(int ifd, BOOL nonblock)
|
||||
{
|
||||
static int fd = -1;
|
||||
static bool registered = false;
|
||||
static int orig = 0;
|
||||
static struct termios termios = WINPR_C_ARRAY_INIT;
|
||||
|
||||
if (ifd >= 0)
|
||||
fd = ifd;
|
||||
|
||||
if (fd < 0)
|
||||
return FALSE;
|
||||
|
||||
if (nonblock)
|
||||
{
|
||||
if (!registered)
|
||||
{
|
||||
(void)atexit(restore_terminal);
|
||||
registered = true;
|
||||
}
|
||||
|
||||
const int rc1 = fcntl(fd, F_SETFL, orig | O_NONBLOCK);
|
||||
if (rc1 != 0)
|
||||
{
|
||||
char buffer[128] = WINPR_C_ARRAY_INIT;
|
||||
WLog_ERR(TAG, "fcntl(F_SETFL) failed with %s",
|
||||
winpr_strerror(errno, buffer, sizeof(buffer)));
|
||||
return FALSE;
|
||||
}
|
||||
const int rc2 = tcgetattr(fd, &termios);
|
||||
if (rc2 != 0)
|
||||
{
|
||||
char buffer[128] = WINPR_C_ARRAY_INIT;
|
||||
WLog_ERR(TAG, "tcgetattr() failed with %s",
|
||||
winpr_strerror(errno, buffer, sizeof(buffer)));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
struct termios now = termios;
|
||||
cfmakeraw(&now);
|
||||
const int rc3 = tcsetattr(fd, TCSANOW, &now);
|
||||
if (rc3 != 0)
|
||||
{
|
||||
char buffer[128] = WINPR_C_ARRAY_INIT;
|
||||
WLog_ERR(TAG, "tcsetattr(TCSANOW) failed with %s",
|
||||
winpr_strerror(errno, buffer, sizeof(buffer)));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const int rc1 = tcsetattr(fd, TCSANOW, &termios);
|
||||
if (rc1 != 0)
|
||||
{
|
||||
char buffer[128] = WINPR_C_ARRAY_INIT;
|
||||
WLog_ERR(TAG, "tcsetattr(TCSANOW) failed with %s",
|
||||
winpr_strerror(errno, buffer, sizeof(buffer)));
|
||||
return FALSE;
|
||||
}
|
||||
const int rc2 = fcntl(fd, F_SETFL, orig);
|
||||
if (rc2 != 0)
|
||||
{
|
||||
char buffer[128] = WINPR_C_ARRAY_INIT;
|
||||
WLog_ERR(TAG, "fcntl(F_SETFL) failed with %s",
|
||||
winpr_strerror(errno, buffer, sizeof(buffer)));
|
||||
return FALSE;
|
||||
}
|
||||
fd = -1;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int freerdp_interruptible_getc(rdpContext* context, FILE* stream)
|
||||
{
|
||||
int rc = EOF;
|
||||
const int fd = fileno(stream);
|
||||
|
||||
(void)set_termianl_nonblock(fd, TRUE);
|
||||
|
||||
do
|
||||
{
|
||||
const int res = wait_for_fd(fd, 10);
|
||||
if (res != 0)
|
||||
{
|
||||
char c = 0;
|
||||
const ssize_t rd = read(fd, &c, 1);
|
||||
if (rd == 1)
|
||||
{
|
||||
if (c == 3) /* ctrl + c */
|
||||
return EOF;
|
||||
if (c == 4) /* ctrl + d */
|
||||
return EOF;
|
||||
if (c == 26) /* ctrl + z */
|
||||
return EOF;
|
||||
rc = (int)c;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while (!freerdp_shall_disconnect_context(context));
|
||||
|
||||
(void)set_termianl_nonblock(fd, FALSE);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
const char* freerdp_passphrase_read(rdpContext* context, const char* prompt, char* buf,
|
||||
size_t bufsiz, int from_stdin)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int freerdp_interruptible_getc(rdpContext* context, FILE* f)
|
||||
{
|
||||
return EOF;
|
||||
}
|
||||
#endif
|
||||
|
||||
SSIZE_T freerdp_interruptible_get_line(rdpContext* context, char** plineptr, size_t* psize,
|
||||
FILE* stream)
|
||||
{
|
||||
int c = 0;
|
||||
char* n = nullptr;
|
||||
size_t step = 32;
|
||||
size_t used = 0;
|
||||
char* ptr = nullptr;
|
||||
size_t len = 0;
|
||||
|
||||
if (!plineptr || !psize)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool echo = true;
|
||||
#if !defined(_WIN32) && !defined(ANDROID)
|
||||
{
|
||||
const int fd = fileno(stream);
|
||||
|
||||
struct termios termios = WINPR_C_ARRAY_INIT;
|
||||
/* This might fail if /from-stdin is used. */
|
||||
if (tcgetattr(fd, &termios) == 0)
|
||||
echo = (termios.c_lflag & ECHO) != 0;
|
||||
else
|
||||
echo = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (*plineptr && (*psize > 0))
|
||||
{
|
||||
ptr = *plineptr;
|
||||
used = *psize;
|
||||
if (echo)
|
||||
{
|
||||
printf("%s", ptr);
|
||||
(void)fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (used + 2 >= len)
|
||||
{
|
||||
len += step;
|
||||
n = realloc(ptr, len);
|
||||
|
||||
if (!n)
|
||||
{
|
||||
free(ptr);
|
||||
*plineptr = nullptr;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptr = n;
|
||||
}
|
||||
|
||||
c = freerdp_interruptible_getc(context, stream);
|
||||
if (c == 127)
|
||||
{
|
||||
if (used > 0)
|
||||
{
|
||||
ptr[used--] = '\0';
|
||||
if (echo)
|
||||
{
|
||||
printf("\b");
|
||||
printf(" ");
|
||||
printf("\b");
|
||||
(void)fflush(stdout);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (echo)
|
||||
{
|
||||
printf("%c", c);
|
||||
(void)fflush(stdout);
|
||||
}
|
||||
if (c != EOF)
|
||||
ptr[used++] = (char)c;
|
||||
} while ((c != '\n') && (c != '\r') && (c != EOF));
|
||||
|
||||
printf("\n");
|
||||
ptr[used] = '\0';
|
||||
if (c == EOF)
|
||||
{
|
||||
free(ptr);
|
||||
*plineptr = nullptr;
|
||||
return EOF;
|
||||
}
|
||||
*plineptr = ptr;
|
||||
*psize = used;
|
||||
return WINPR_ASSERTING_INT_CAST(SSIZE_T, used);
|
||||
}
|
||||
260
third_party/FreeRDP/libfreerdp/utils/pcap.c
vendored
Normal file
260
third_party/FreeRDP/libfreerdp/utils/pcap.c
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* pcap File Format Utils
|
||||
*
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/file.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/sysinfo.h>
|
||||
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/utils/pcap.h>
|
||||
|
||||
#define PCAP_MAGIC 0xA1B2C3D4
|
||||
|
||||
struct rdp_pcap
|
||||
{
|
||||
FILE* fp;
|
||||
char* name;
|
||||
BOOL write;
|
||||
INT64 file_size;
|
||||
size_t record_count;
|
||||
pcap_header header;
|
||||
pcap_record* head;
|
||||
pcap_record* tail;
|
||||
pcap_record* record;
|
||||
};
|
||||
|
||||
static BOOL pcap_read_header(rdpPcap* pcap, pcap_header* header)
|
||||
{
|
||||
WINPR_ASSERT(pcap);
|
||||
WINPR_ASSERT(header);
|
||||
|
||||
return fread(header, sizeof(pcap_header), 1, pcap->fp) == 1;
|
||||
}
|
||||
|
||||
static BOOL pcap_write_header(rdpPcap* pcap, const pcap_header* header)
|
||||
{
|
||||
WINPR_ASSERT(pcap);
|
||||
WINPR_ASSERT(header);
|
||||
|
||||
return fwrite(header, sizeof(pcap_header), 1, pcap->fp) == 1;
|
||||
}
|
||||
|
||||
static BOOL pcap_read_record_header(rdpPcap* pcap, pcap_record_header* record)
|
||||
{
|
||||
WINPR_ASSERT(pcap);
|
||||
WINPR_ASSERT(record);
|
||||
|
||||
return fread(record, sizeof(pcap_record_header), 1, pcap->fp) == 1;
|
||||
}
|
||||
|
||||
static BOOL pcap_write_record_header(rdpPcap* pcap, const pcap_record_header* record)
|
||||
{
|
||||
WINPR_ASSERT(pcap);
|
||||
WINPR_ASSERT(record);
|
||||
|
||||
return fwrite(record, sizeof(pcap_record_header), 1, pcap->fp) == 1;
|
||||
}
|
||||
|
||||
static BOOL pcap_read_record(rdpPcap* pcap, pcap_record* record)
|
||||
{
|
||||
WINPR_ASSERT(pcap);
|
||||
WINPR_ASSERT(record);
|
||||
|
||||
if (!pcap_read_record_header(pcap, &record->header))
|
||||
return FALSE;
|
||||
|
||||
record->length = record->header.incl_len;
|
||||
record->data = malloc(record->length);
|
||||
if (!record->data)
|
||||
return FALSE;
|
||||
|
||||
if (fread(record->data, record->length, 1, pcap->fp) != 1)
|
||||
{
|
||||
free(record->data);
|
||||
record->data = nullptr;
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL pcap_write_record(rdpPcap* pcap, const pcap_record* record)
|
||||
{
|
||||
WINPR_ASSERT(pcap);
|
||||
WINPR_ASSERT(record);
|
||||
|
||||
return pcap_write_record_header(pcap, &record->header) &&
|
||||
(fwrite(record->cdata, record->length, 1, pcap->fp) == 1);
|
||||
}
|
||||
|
||||
BOOL pcap_add_record(rdpPcap* pcap, const void* data, size_t length)
|
||||
{
|
||||
WINPR_ASSERT(pcap);
|
||||
WINPR_ASSERT(data || (length == 0));
|
||||
WINPR_ASSERT(length <= UINT32_MAX);
|
||||
|
||||
pcap_record* record = (pcap_record*)calloc(1, sizeof(pcap_record));
|
||||
if (!record)
|
||||
return FALSE;
|
||||
|
||||
record->cdata = data;
|
||||
record->length = (UINT32)length;
|
||||
record->header.incl_len = (UINT32)length;
|
||||
record->header.orig_len = (UINT32)length;
|
||||
|
||||
const UINT64 ns = winpr_GetUnixTimeNS();
|
||||
|
||||
record->header.ts_sec = (UINT32)WINPR_TIME_NS_TO_S(ns);
|
||||
record->header.ts_usec = (UINT32)WINPR_TIME_NS_REM_US(ns);
|
||||
|
||||
if (pcap->tail == nullptr)
|
||||
{
|
||||
pcap->tail = record;
|
||||
if (!pcap->tail)
|
||||
return FALSE;
|
||||
|
||||
pcap->head = pcap->tail;
|
||||
}
|
||||
else
|
||||
{
|
||||
record->next = pcap->tail;
|
||||
pcap->tail = record;
|
||||
}
|
||||
|
||||
if (pcap->record == nullptr)
|
||||
pcap->record = record;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL pcap_has_next_record(const rdpPcap* pcap)
|
||||
{
|
||||
WINPR_ASSERT(pcap);
|
||||
|
||||
return (pcap->file_size - (_ftelli64(pcap->fp)) > 16);
|
||||
}
|
||||
|
||||
BOOL pcap_get_next_record_header(rdpPcap* pcap, pcap_record* record)
|
||||
{
|
||||
WINPR_ASSERT(pcap);
|
||||
WINPR_ASSERT(record);
|
||||
|
||||
if (pcap_has_next_record(pcap) != TRUE)
|
||||
return FALSE;
|
||||
|
||||
pcap_read_record_header(pcap, &record->header);
|
||||
record->length = record->header.incl_len;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL pcap_get_next_record_content(rdpPcap* pcap, pcap_record* record)
|
||||
{
|
||||
WINPR_ASSERT(pcap);
|
||||
WINPR_ASSERT(record);
|
||||
|
||||
return fread(record->data, record->length, 1, pcap->fp) == 1;
|
||||
}
|
||||
|
||||
BOOL pcap_get_next_record(rdpPcap* pcap, pcap_record* record)
|
||||
{
|
||||
WINPR_ASSERT(pcap);
|
||||
WINPR_ASSERT(record);
|
||||
|
||||
return pcap_has_next_record(pcap) && pcap_read_record(pcap, record);
|
||||
}
|
||||
|
||||
rdpPcap* pcap_open(const char* name, BOOL write)
|
||||
{
|
||||
WINPR_ASSERT(name);
|
||||
|
||||
rdpPcap* pcap = (rdpPcap*)calloc(1, sizeof(rdpPcap));
|
||||
if (!pcap)
|
||||
goto fail;
|
||||
|
||||
pcap->name = _strdup(name);
|
||||
pcap->write = write;
|
||||
pcap->record_count = 0;
|
||||
pcap->fp = winpr_fopen(name, write ? "w+b" : "rb");
|
||||
|
||||
if (pcap->fp == nullptr)
|
||||
goto fail;
|
||||
|
||||
if (write)
|
||||
{
|
||||
pcap->header.magic_number = PCAP_MAGIC;
|
||||
pcap->header.version_major = 2;
|
||||
pcap->header.version_minor = 4;
|
||||
pcap->header.thiszone = 0;
|
||||
pcap->header.sigfigs = 0;
|
||||
pcap->header.snaplen = UINT32_MAX;
|
||||
pcap->header.network = 0;
|
||||
if (!pcap_write_header(pcap, &pcap->header))
|
||||
goto fail;
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)_fseeki64(pcap->fp, 0, SEEK_END);
|
||||
pcap->file_size = _ftelli64(pcap->fp);
|
||||
(void)_fseeki64(pcap->fp, 0, SEEK_SET);
|
||||
if (!pcap_read_header(pcap, &pcap->header))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return pcap;
|
||||
|
||||
fail:
|
||||
pcap_close(pcap);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void pcap_flush(rdpPcap* pcap)
|
||||
{
|
||||
WINPR_ASSERT(pcap);
|
||||
|
||||
while (pcap->record != nullptr)
|
||||
{
|
||||
(void)pcap_write_record(pcap, pcap->record);
|
||||
pcap->record = pcap->record->next;
|
||||
}
|
||||
|
||||
if (pcap->fp != nullptr)
|
||||
(void)fflush(pcap->fp);
|
||||
}
|
||||
|
||||
void pcap_close(rdpPcap* pcap)
|
||||
{
|
||||
if (!pcap)
|
||||
return;
|
||||
|
||||
pcap_flush(pcap);
|
||||
|
||||
if (pcap->fp != nullptr)
|
||||
(void)fclose(pcap->fp);
|
||||
|
||||
free(pcap->name);
|
||||
free(pcap);
|
||||
}
|
||||
9
third_party/FreeRDP/libfreerdp/utils/platform_signal.h
vendored
Normal file
9
third_party/FreeRDP/libfreerdp/utils/platform_signal.h
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
extern BOOL fsig_handlers_registered;
|
||||
|
||||
void fsig_lock(void);
|
||||
void fsig_unlock(void);
|
||||
void fsig_term_handler(int signum);
|
||||
98
third_party/FreeRDP/libfreerdp/utils/profiler.c
vendored
Normal file
98
third_party/FreeRDP/libfreerdp/utils/profiler.c
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Profiler Utils
|
||||
*
|
||||
* Copyright 2011 Stephen Erisman
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <freerdp/utils/profiler.h>
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#define TAG FREERDP_TAG("utils")
|
||||
|
||||
struct S_PROFILER
|
||||
{
|
||||
char* name;
|
||||
STOPWATCH* stopwatch;
|
||||
};
|
||||
|
||||
PROFILER* profiler_create(const char* name)
|
||||
{
|
||||
PROFILER* profiler = (PROFILER*)calloc(1, sizeof(PROFILER));
|
||||
|
||||
if (!profiler)
|
||||
return nullptr;
|
||||
|
||||
profiler->name = _strdup(name);
|
||||
profiler->stopwatch = stopwatch_create();
|
||||
|
||||
if (!profiler->name || !profiler->stopwatch)
|
||||
goto fail;
|
||||
|
||||
return profiler;
|
||||
fail:
|
||||
profiler_free(profiler);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void profiler_free(PROFILER* profiler)
|
||||
{
|
||||
if (profiler)
|
||||
{
|
||||
free(profiler->name);
|
||||
stopwatch_free(profiler->stopwatch);
|
||||
}
|
||||
|
||||
free(profiler);
|
||||
}
|
||||
|
||||
void profiler_enter(PROFILER* profiler)
|
||||
{
|
||||
stopwatch_start(profiler->stopwatch);
|
||||
}
|
||||
|
||||
void profiler_exit(PROFILER* profiler)
|
||||
{
|
||||
stopwatch_stop(profiler->stopwatch);
|
||||
}
|
||||
|
||||
void profiler_print_header(void)
|
||||
{
|
||||
WLog_INFO(TAG,
|
||||
"-------------------------------+------------+-------------+-----------+-------");
|
||||
WLog_INFO(TAG,
|
||||
"PROFILER NAME | COUNT | TOTAL | AVG | IPS");
|
||||
WLog_INFO(TAG,
|
||||
"-------------------------------+------------+-------------+-----------+-------");
|
||||
}
|
||||
|
||||
void profiler_print(PROFILER* profiler)
|
||||
{
|
||||
double s = stopwatch_get_elapsed_time_in_seconds(profiler->stopwatch);
|
||||
double avg = profiler->stopwatch->count == 0 ? 0 : s / profiler->stopwatch->count;
|
||||
WLog_INFO(TAG, "%-30s | %10u | %10.4fs | %8.6fs | %6.0f", profiler->name,
|
||||
profiler->stopwatch->count, s, avg, profiler->stopwatch->count / s);
|
||||
}
|
||||
|
||||
void profiler_print_footer(void)
|
||||
{
|
||||
WLog_INFO(TAG,
|
||||
"-------------------------------+------------+-------------+-----------+-------");
|
||||
}
|
||||
689
third_party/FreeRDP/libfreerdp/utils/rdpdr_utils.c
vendored
Normal file
689
third_party/FreeRDP/libfreerdp/utils/rdpdr_utils.c
vendored
Normal file
@@ -0,0 +1,689 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SCard utility functions
|
||||
*
|
||||
* Copyright 2021 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2021 Thincast Technologies GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <winpr/wlog.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/smartcard.h>
|
||||
|
||||
#include <freerdp/utils/rdpdr_utils.h>
|
||||
#include <freerdp/channels/scard.h>
|
||||
#include <freerdp/channels/rdpdr.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
|
||||
LONG scard_log_status_error(const char* tag, const char* what, LONG status)
|
||||
{
|
||||
wLog* log = WLog_Get(tag);
|
||||
return scard_log_status_error_wlog(log, what, status);
|
||||
}
|
||||
|
||||
LONG scard_log_status_error_wlog(wLog* log, const char* what, LONG status)
|
||||
{
|
||||
if (status != SCARD_S_SUCCESS)
|
||||
{
|
||||
DWORD level = WLOG_ERROR;
|
||||
switch (status)
|
||||
{
|
||||
case SCARD_E_TIMEOUT:
|
||||
level = WLOG_DEBUG;
|
||||
break;
|
||||
case SCARD_E_NO_READERS_AVAILABLE:
|
||||
level = WLOG_INFO;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
WLog_Print(log, level, "%s failed with error %s [%" PRId32 "]", what,
|
||||
SCardGetErrorString(status), status);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
const char* scard_get_ioctl_string(UINT32 ioControlCode, BOOL funcName)
|
||||
{
|
||||
switch (ioControlCode)
|
||||
{
|
||||
case SCARD_IOCTL_ESTABLISHCONTEXT:
|
||||
return funcName ? "SCardEstablishContext" : "SCARD_IOCTL_ESTABLISHCONTEXT";
|
||||
|
||||
case SCARD_IOCTL_RELEASECONTEXT:
|
||||
return funcName ? "SCardReleaseContext" : "SCARD_IOCTL_RELEASECONTEXT";
|
||||
|
||||
case SCARD_IOCTL_ISVALIDCONTEXT:
|
||||
return funcName ? "SCardIsValidContext" : "SCARD_IOCTL_ISVALIDCONTEXT";
|
||||
|
||||
case SCARD_IOCTL_LISTREADERGROUPSA:
|
||||
return funcName ? "SCardListReaderGroupsA" : "SCARD_IOCTL_LISTREADERGROUPSA";
|
||||
|
||||
case SCARD_IOCTL_LISTREADERGROUPSW:
|
||||
return funcName ? "SCardListReaderGroupsW" : "SCARD_IOCTL_LISTREADERGROUPSW";
|
||||
|
||||
case SCARD_IOCTL_LISTREADERSA:
|
||||
return funcName ? "SCardListReadersA" : "SCARD_IOCTL_LISTREADERSA";
|
||||
|
||||
case SCARD_IOCTL_LISTREADERSW:
|
||||
return funcName ? "SCardListReadersW" : "SCARD_IOCTL_LISTREADERSW";
|
||||
|
||||
case SCARD_IOCTL_INTRODUCEREADERGROUPA:
|
||||
return funcName ? "SCardIntroduceReaderGroupA" : "SCARD_IOCTL_INTRODUCEREADERGROUPA";
|
||||
|
||||
case SCARD_IOCTL_INTRODUCEREADERGROUPW:
|
||||
return funcName ? "SCardIntroduceReaderGroupW" : "SCARD_IOCTL_INTRODUCEREADERGROUPW";
|
||||
|
||||
case SCARD_IOCTL_FORGETREADERGROUPA:
|
||||
return funcName ? "SCardForgetReaderGroupA" : "SCARD_IOCTL_FORGETREADERGROUPA";
|
||||
|
||||
case SCARD_IOCTL_FORGETREADERGROUPW:
|
||||
return funcName ? "SCardForgetReaderGroupW" : "SCARD_IOCTL_FORGETREADERGROUPW";
|
||||
|
||||
case SCARD_IOCTL_INTRODUCEREADERA:
|
||||
return funcName ? "SCardIntroduceReaderA" : "SCARD_IOCTL_INTRODUCEREADERA";
|
||||
|
||||
case SCARD_IOCTL_INTRODUCEREADERW:
|
||||
return funcName ? "SCardIntroduceReaderW" : "SCARD_IOCTL_INTRODUCEREADERW";
|
||||
|
||||
case SCARD_IOCTL_FORGETREADERA:
|
||||
return funcName ? "SCardForgetReaderA" : "SCARD_IOCTL_FORGETREADERA";
|
||||
|
||||
case SCARD_IOCTL_FORGETREADERW:
|
||||
return funcName ? "SCardForgetReaderW" : "SCARD_IOCTL_FORGETREADERW";
|
||||
|
||||
case SCARD_IOCTL_ADDREADERTOGROUPA:
|
||||
return funcName ? "SCardAddReaderToGroupA" : "SCARD_IOCTL_ADDREADERTOGROUPA";
|
||||
|
||||
case SCARD_IOCTL_ADDREADERTOGROUPW:
|
||||
return funcName ? "SCardAddReaderToGroupW" : "SCARD_IOCTL_ADDREADERTOGROUPW";
|
||||
|
||||
case SCARD_IOCTL_REMOVEREADERFROMGROUPA:
|
||||
return funcName ? "SCardRemoveReaderFromGroupA" : "SCARD_IOCTL_REMOVEREADERFROMGROUPA";
|
||||
|
||||
case SCARD_IOCTL_REMOVEREADERFROMGROUPW:
|
||||
return funcName ? "SCardRemoveReaderFromGroupW" : "SCARD_IOCTL_REMOVEREADERFROMGROUPW";
|
||||
|
||||
case SCARD_IOCTL_LOCATECARDSA:
|
||||
return funcName ? "SCardLocateCardsA" : "SCARD_IOCTL_LOCATECARDSA";
|
||||
|
||||
case SCARD_IOCTL_LOCATECARDSW:
|
||||
return funcName ? "SCardLocateCardsW" : "SCARD_IOCTL_LOCATECARDSW";
|
||||
|
||||
case SCARD_IOCTL_GETSTATUSCHANGEA:
|
||||
return funcName ? "SCardGetStatusChangeA" : "SCARD_IOCTL_GETSTATUSCHANGEA";
|
||||
|
||||
case SCARD_IOCTL_GETSTATUSCHANGEW:
|
||||
return funcName ? "SCardGetStatusChangeW" : "SCARD_IOCTL_GETSTATUSCHANGEW";
|
||||
|
||||
case SCARD_IOCTL_CANCEL:
|
||||
return funcName ? "SCardCancel" : "SCARD_IOCTL_CANCEL";
|
||||
|
||||
case SCARD_IOCTL_CONNECTA:
|
||||
return funcName ? "SCardConnectA" : "SCARD_IOCTL_CONNECTA";
|
||||
|
||||
case SCARD_IOCTL_CONNECTW:
|
||||
return funcName ? "SCardConnectW" : "SCARD_IOCTL_CONNECTW";
|
||||
|
||||
case SCARD_IOCTL_RECONNECT:
|
||||
return funcName ? "SCardReconnect" : "SCARD_IOCTL_RECONNECT";
|
||||
|
||||
case SCARD_IOCTL_DISCONNECT:
|
||||
return funcName ? "SCardDisconnect" : "SCARD_IOCTL_DISCONNECT";
|
||||
|
||||
case SCARD_IOCTL_BEGINTRANSACTION:
|
||||
return funcName ? "SCardBeginTransaction" : "SCARD_IOCTL_BEGINTRANSACTION";
|
||||
|
||||
case SCARD_IOCTL_ENDTRANSACTION:
|
||||
return funcName ? "SCardEndTransaction" : "SCARD_IOCTL_ENDTRANSACTION";
|
||||
|
||||
case SCARD_IOCTL_STATE:
|
||||
return funcName ? "SCardState" : "SCARD_IOCTL_STATE";
|
||||
|
||||
case SCARD_IOCTL_STATUSA:
|
||||
return funcName ? "SCardStatusA" : "SCARD_IOCTL_STATUSA";
|
||||
|
||||
case SCARD_IOCTL_STATUSW:
|
||||
return funcName ? "SCardStatusW" : "SCARD_IOCTL_STATUSW";
|
||||
|
||||
case SCARD_IOCTL_TRANSMIT:
|
||||
return funcName ? "SCardTransmit" : "SCARD_IOCTL_TRANSMIT";
|
||||
|
||||
case SCARD_IOCTL_CONTROL:
|
||||
return funcName ? "SCardControl" : "SCARD_IOCTL_CONTROL";
|
||||
|
||||
case SCARD_IOCTL_GETATTRIB:
|
||||
return funcName ? "SCardGetAttrib" : "SCARD_IOCTL_GETATTRIB";
|
||||
|
||||
case SCARD_IOCTL_SETATTRIB:
|
||||
return funcName ? "SCardSetAttrib" : "SCARD_IOCTL_SETATTRIB";
|
||||
|
||||
case SCARD_IOCTL_ACCESSSTARTEDEVENT:
|
||||
return funcName ? "SCardAccessStartedEvent" : "SCARD_IOCTL_ACCESSSTARTEDEVENT";
|
||||
|
||||
case SCARD_IOCTL_LOCATECARDSBYATRA:
|
||||
return funcName ? "SCardLocateCardsByATRA" : "SCARD_IOCTL_LOCATECARDSBYATRA";
|
||||
|
||||
case SCARD_IOCTL_LOCATECARDSBYATRW:
|
||||
return funcName ? "SCardLocateCardsByATRB" : "SCARD_IOCTL_LOCATECARDSBYATRW";
|
||||
|
||||
case SCARD_IOCTL_READCACHEA:
|
||||
return funcName ? "SCardReadCacheA" : "SCARD_IOCTL_READCACHEA";
|
||||
|
||||
case SCARD_IOCTL_READCACHEW:
|
||||
return funcName ? "SCardReadCacheW" : "SCARD_IOCTL_READCACHEW";
|
||||
|
||||
case SCARD_IOCTL_WRITECACHEA:
|
||||
return funcName ? "SCardWriteCacheA" : "SCARD_IOCTL_WRITECACHEA";
|
||||
|
||||
case SCARD_IOCTL_WRITECACHEW:
|
||||
return funcName ? "SCardWriteCacheW" : "SCARD_IOCTL_WRITECACHEW";
|
||||
|
||||
case SCARD_IOCTL_GETTRANSMITCOUNT:
|
||||
return funcName ? "SCardGetTransmitCount" : "SCARD_IOCTL_GETTRANSMITCOUNT";
|
||||
|
||||
case SCARD_IOCTL_RELEASETARTEDEVENT:
|
||||
return funcName ? "SCardReleaseStartedEvent" : "SCARD_IOCTL_RELEASETARTEDEVENT";
|
||||
|
||||
case SCARD_IOCTL_GETREADERICON:
|
||||
return funcName ? "SCardGetReaderIcon" : "SCARD_IOCTL_GETREADERICON";
|
||||
|
||||
case SCARD_IOCTL_GETDEVICETYPEID:
|
||||
return funcName ? "SCardGetDeviceTypeId" : "SCARD_IOCTL_GETDEVICETYPEID";
|
||||
|
||||
default:
|
||||
return funcName ? "SCardUnknown" : "SCARD_IOCTL_UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
const char* rdpdr_component_string(UINT16 component)
|
||||
{
|
||||
switch (component)
|
||||
{
|
||||
case RDPDR_CTYP_PRN:
|
||||
return "RDPDR_CTYP_PRN";
|
||||
case RDPDR_CTYP_CORE:
|
||||
return "RDPDR_CTYP_CORE";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
||||
BOOL rdpdr_write_iocompletion_header(wStream* out, UINT32 DeviceId, UINT32 CompletionId,
|
||||
NTSTATUS ioStatus)
|
||||
{
|
||||
WINPR_ASSERT(out);
|
||||
Stream_ResetPosition(out);
|
||||
if (!Stream_EnsureRemainingCapacity(out, 16))
|
||||
return FALSE;
|
||||
|
||||
Stream_Write_UINT16(out, RDPDR_CTYP_CORE); /* Component (2 bytes) */
|
||||
Stream_Write_UINT16(out, PAKID_CORE_DEVICE_IOCOMPLETION); /* PacketId (2 bytes) */
|
||||
Stream_Write_UINT32(out, DeviceId); /* DeviceId (4 bytes) */
|
||||
Stream_Write_UINT32(out, CompletionId); /* CompletionId (4 bytes) */
|
||||
Stream_Write_INT32(out, ioStatus); /* IoStatus (4 bytes) */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void rdpdr_dump_packet(wLog* log, DWORD lvl, wStream* s, const char* custom, BOOL send)
|
||||
{
|
||||
if (!WLog_IsLevelActive(log, lvl))
|
||||
return;
|
||||
|
||||
const size_t gpos = Stream_GetPosition(s);
|
||||
const size_t pos = send ? Stream_GetPosition(s) : Stream_Length(s);
|
||||
|
||||
UINT16 component = 0;
|
||||
UINT16 packetid = 0;
|
||||
|
||||
Stream_ResetPosition(s);
|
||||
|
||||
if (pos >= 2)
|
||||
Stream_Read_UINT16(s, component);
|
||||
if (pos >= 4)
|
||||
Stream_Read_UINT16(s, packetid);
|
||||
|
||||
switch (packetid)
|
||||
{
|
||||
case PAKID_CORE_SERVER_ANNOUNCE:
|
||||
case PAKID_CORE_CLIENTID_CONFIRM:
|
||||
{
|
||||
UINT16 versionMajor = 0;
|
||||
UINT16 versionMinor = 0;
|
||||
UINT32 clientID = 0;
|
||||
|
||||
if (pos >= 6)
|
||||
Stream_Read_UINT16(s, versionMajor);
|
||||
if (pos >= 8)
|
||||
Stream_Read_UINT16(s, versionMinor);
|
||||
if (pos >= 12)
|
||||
Stream_Read_UINT32(s, clientID);
|
||||
WLog_Print(log, lvl,
|
||||
"%s [%s | %s] [version:%" PRIu16 ".%" PRIu16 "][id:0x%08" PRIx32
|
||||
"] -> %" PRIuz,
|
||||
custom, rdpdr_component_string(component), rdpdr_packetid_string(packetid),
|
||||
versionMajor, versionMinor, clientID, pos);
|
||||
}
|
||||
break;
|
||||
case PAKID_CORE_CLIENT_NAME:
|
||||
{
|
||||
char name[256] = WINPR_C_ARRAY_INIT;
|
||||
UINT32 unicodeFlag = 0;
|
||||
UINT32 codePage = 0;
|
||||
UINT32 computerNameLen = 0;
|
||||
if (pos >= 8)
|
||||
Stream_Read_UINT32(s, unicodeFlag);
|
||||
if (pos >= 12)
|
||||
Stream_Read_UINT32(s, codePage);
|
||||
if (pos >= 16)
|
||||
Stream_Read_UINT32(s, computerNameLen);
|
||||
if (pos >= 16 + computerNameLen)
|
||||
{
|
||||
if (unicodeFlag == 0)
|
||||
Stream_Read(s, name, MIN(sizeof(name), computerNameLen));
|
||||
else
|
||||
(void)ConvertWCharNToUtf8(Stream_ConstPointer(s),
|
||||
computerNameLen / sizeof(WCHAR), name, sizeof(name));
|
||||
}
|
||||
WLog_Print(log, lvl,
|
||||
"%s [%s | %s] [ucs:%" PRIu32 "|cp:%" PRIu32 "][len:0x%08" PRIx32
|
||||
"] '%s' -> %" PRIuz,
|
||||
custom, rdpdr_component_string(component), rdpdr_packetid_string(packetid),
|
||||
unicodeFlag, codePage, computerNameLen, name, pos);
|
||||
}
|
||||
break;
|
||||
|
||||
case PAKID_CORE_DEVICE_IOREQUEST:
|
||||
{
|
||||
UINT32 CompletionId = 0;
|
||||
UINT32 deviceID = 0;
|
||||
UINT32 FileId = 0;
|
||||
UINT32 MajorFunction = 0;
|
||||
UINT32 MinorFunction = 0;
|
||||
|
||||
if (pos >= 8)
|
||||
Stream_Read_UINT32(s, deviceID);
|
||||
if (pos >= 12)
|
||||
Stream_Read_UINT32(s, FileId);
|
||||
if (pos >= 16)
|
||||
Stream_Read_UINT32(s, CompletionId);
|
||||
if (pos >= 20)
|
||||
Stream_Read_UINT32(s, MajorFunction);
|
||||
if (pos >= 24)
|
||||
Stream_Read_UINT32(s, MinorFunction);
|
||||
WLog_Print(log, lvl,
|
||||
"%s [%s | %s] [0x%08" PRIx32 "] FileId=0x%08" PRIx32
|
||||
", CompletionId=0x%08" PRIx32 ", MajorFunction=0x%08" PRIx32
|
||||
", MinorFunction=0x%08" PRIx32 " -> %" PRIuz,
|
||||
custom, rdpdr_component_string(component), rdpdr_packetid_string(packetid),
|
||||
deviceID, FileId, CompletionId, MajorFunction, MinorFunction, pos);
|
||||
}
|
||||
break;
|
||||
case PAKID_CORE_DEVICE_IOCOMPLETION:
|
||||
{
|
||||
UINT32 completionID = 0;
|
||||
UINT32 ioStatus = 0;
|
||||
UINT32 deviceID = 0;
|
||||
if (pos >= 8)
|
||||
Stream_Read_UINT32(s, deviceID);
|
||||
if (pos >= 12)
|
||||
Stream_Read_UINT32(s, completionID);
|
||||
if (pos >= 16)
|
||||
Stream_Read_UINT32(s, ioStatus);
|
||||
|
||||
WLog_Print(log, lvl,
|
||||
"%s [%s | %s] [0x%08" PRIx32 "] completionID=0x%08" PRIx32
|
||||
", ioStatus=0x%08" PRIx32 " -> %" PRIuz,
|
||||
custom, rdpdr_component_string(component), rdpdr_packetid_string(packetid),
|
||||
deviceID, completionID, ioStatus, pos);
|
||||
}
|
||||
break;
|
||||
case PAKID_CORE_DEVICE_REPLY:
|
||||
{
|
||||
UINT32 deviceID = 0;
|
||||
UINT32 status = 0;
|
||||
|
||||
if (pos >= 8)
|
||||
Stream_Read_UINT32(s, deviceID);
|
||||
if (pos >= 12)
|
||||
Stream_Read_UINT32(s, status);
|
||||
WLog_Print(log, lvl,
|
||||
"%s [%s | %s] [id:0x%08" PRIx32 ",status=0x%08" PRIx32 "] -> %" PRIuz,
|
||||
custom, rdpdr_component_string(component), rdpdr_packetid_string(packetid),
|
||||
deviceID, status, pos);
|
||||
}
|
||||
break;
|
||||
case PAKID_CORE_CLIENT_CAPABILITY:
|
||||
case PAKID_CORE_SERVER_CAPABILITY:
|
||||
{
|
||||
UINT16 numCapabilities = 0;
|
||||
if (pos >= 6)
|
||||
Stream_Read_UINT16(s, numCapabilities);
|
||||
if (pos >= 8)
|
||||
Stream_Seek_UINT16(s); /* padding */
|
||||
WLog_Print(log, lvl, "%s [%s | %s] [caps:%" PRIu16 "] -> %" PRIuz, custom,
|
||||
rdpdr_component_string(component), rdpdr_packetid_string(packetid),
|
||||
numCapabilities, pos);
|
||||
for (UINT16 x = 0; x < numCapabilities; x++)
|
||||
{
|
||||
RDPDR_CAPABILITY_HEADER header = WINPR_C_ARRAY_INIT;
|
||||
const UINT error = rdpdr_read_capset_header(log, s, &header);
|
||||
if (error == CHANNEL_RC_OK)
|
||||
Stream_Seek(s, header.CapabilityLength);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PAKID_CORE_DEVICELIST_ANNOUNCE:
|
||||
{
|
||||
size_t offset = 8;
|
||||
UINT32 count = 0;
|
||||
|
||||
if (pos >= offset)
|
||||
Stream_Read_UINT32(s, count);
|
||||
|
||||
WLog_Print(log, lvl, "%s [%s | %s] [%" PRIu32 "] -> %" PRIuz, custom,
|
||||
rdpdr_component_string(component), rdpdr_packetid_string(packetid), count,
|
||||
pos);
|
||||
|
||||
for (UINT32 x = 0; x < count; x++)
|
||||
{
|
||||
RdpdrDevice device = WINPR_C_ARRAY_INIT;
|
||||
|
||||
offset += 20;
|
||||
if (pos >= offset)
|
||||
{
|
||||
Stream_Read_UINT32(s, device.DeviceType); /* DeviceType (4 bytes) */
|
||||
Stream_Read_UINT32(s, device.DeviceId); /* DeviceId (4 bytes) */
|
||||
Stream_Read(s, device.PreferredDosName, 8); /* PreferredDosName (8 bytes) */
|
||||
Stream_Read_UINT32(s, device.DeviceDataLength); /* DeviceDataLength (4 bytes) */
|
||||
device.DeviceData = Stream_Pointer(s);
|
||||
}
|
||||
offset += device.DeviceDataLength;
|
||||
|
||||
WLog_Print(log, lvl,
|
||||
"%s [announce][%" PRIu32 "] %s [0x%08" PRIx32
|
||||
"] '%s' [DeviceDataLength=%" PRIu32 "]",
|
||||
custom, x, freerdp_rdpdr_dtyp_string(device.DeviceType), device.DeviceId,
|
||||
device.PreferredDosName, device.DeviceDataLength);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PAKID_CORE_DEVICELIST_REMOVE:
|
||||
{
|
||||
size_t offset = 8;
|
||||
UINT32 count = 0;
|
||||
|
||||
if (pos >= offset)
|
||||
Stream_Read_UINT32(s, count);
|
||||
|
||||
WLog_Print(log, lvl, "%s [%s | %s] [%" PRIu32 "] -> %" PRIuz, custom,
|
||||
rdpdr_component_string(component), rdpdr_packetid_string(packetid), count,
|
||||
pos);
|
||||
|
||||
for (UINT32 x = 0; x < count; x++)
|
||||
{
|
||||
UINT32 id = 0;
|
||||
|
||||
offset += 4;
|
||||
if (pos >= offset)
|
||||
Stream_Read_UINT32(s, id);
|
||||
|
||||
WLog_Print(log, lvl, "%s [remove][%" PRIu32 "] id=%" PRIu32, custom, x, id);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PAKID_CORE_USER_LOGGEDON:
|
||||
WLog_Print(log, lvl, "%s [%s | %s] -> %" PRIuz, custom,
|
||||
rdpdr_component_string(component), rdpdr_packetid_string(packetid), pos);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
WLog_Print(log, lvl, "%s [%s | %s] -> %" PRIuz, custom,
|
||||
rdpdr_component_string(component), rdpdr_packetid_string(packetid), pos);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// winpr_HexLogDump(log, lvl, Stream_Buffer(s), pos);
|
||||
Stream_SetPosition(s, gpos);
|
||||
}
|
||||
|
||||
void rdpdr_dump_received_packet(wLog* log, DWORD lvl, wStream* out, const char* custom)
|
||||
{
|
||||
rdpdr_dump_packet(log, lvl, out, custom, FALSE);
|
||||
}
|
||||
|
||||
void rdpdr_dump_send_packet(wLog* log, DWORD lvl, wStream* out, const char* custom)
|
||||
{
|
||||
rdpdr_dump_packet(log, lvl, out, custom, TRUE);
|
||||
}
|
||||
|
||||
const char* rdpdr_irp_string(UINT32 major)
|
||||
{
|
||||
switch (major)
|
||||
{
|
||||
case IRP_MJ_CREATE:
|
||||
return "IRP_MJ_CREATE";
|
||||
case IRP_MJ_CLOSE:
|
||||
return "IRP_MJ_CLOSE";
|
||||
case IRP_MJ_READ:
|
||||
return "IRP_MJ_READ";
|
||||
case IRP_MJ_WRITE:
|
||||
return "IRP_MJ_WRITE";
|
||||
case IRP_MJ_DEVICE_CONTROL:
|
||||
return "IRP_MJ_DEVICE_CONTROL";
|
||||
case IRP_MJ_QUERY_VOLUME_INFORMATION:
|
||||
return "IRP_MJ_QUERY_VOLUME_INFORMATION";
|
||||
case IRP_MJ_SET_VOLUME_INFORMATION:
|
||||
return "IRP_MJ_SET_VOLUME_INFORMATION";
|
||||
case IRP_MJ_QUERY_INFORMATION:
|
||||
return "IRP_MJ_QUERY_INFORMATION";
|
||||
case IRP_MJ_SET_INFORMATION:
|
||||
return "IRP_MJ_SET_INFORMATION";
|
||||
case IRP_MJ_DIRECTORY_CONTROL:
|
||||
return "IRP_MJ_DIRECTORY_CONTROL";
|
||||
case IRP_MJ_LOCK_CONTROL:
|
||||
return "IRP_MJ_LOCK_CONTROL";
|
||||
default:
|
||||
return "IRP_UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
const char* rdpdr_cap_type_string(UINT16 capability)
|
||||
{
|
||||
switch (capability)
|
||||
{
|
||||
case CAP_GENERAL_TYPE:
|
||||
return "CAP_GENERAL_TYPE";
|
||||
case CAP_PRINTER_TYPE:
|
||||
return "CAP_PRINTER_TYPE";
|
||||
case CAP_PORT_TYPE:
|
||||
return "CAP_PORT_TYPE";
|
||||
case CAP_DRIVE_TYPE:
|
||||
return "CAP_DRIVE_TYPE";
|
||||
case CAP_SMARTCARD_TYPE:
|
||||
return "CAP_SMARTCARD_TYPE";
|
||||
default:
|
||||
return "CAP_UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
UINT rdpdr_read_capset_header(wLog* log, wStream* s, RDPDR_CAPABILITY_HEADER* header)
|
||||
{
|
||||
WINPR_ASSERT(header);
|
||||
if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT16(s, header->CapabilityType); /* CapabilityType (2 bytes) */
|
||||
Stream_Read_UINT16(s, header->CapabilityLength); /* CapabilityLength (2 bytes) */
|
||||
Stream_Read_UINT32(s, header->Version); /* Version (4 bytes) */
|
||||
|
||||
WLog_Print(log, WLOG_TRACE,
|
||||
"capability %s [0x%04" PRIx16 "] got version %" PRIu32 ", length %" PRIu16,
|
||||
rdpdr_cap_type_string(header->CapabilityType), header->CapabilityType,
|
||||
header->Version, header->CapabilityLength);
|
||||
if (header->CapabilityLength < 8)
|
||||
{
|
||||
WLog_Print(log, WLOG_ERROR, "capability %s got short length %" PRIu32,
|
||||
rdpdr_cap_type_string(header->CapabilityType), header->CapabilityLength);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
header->CapabilityLength -= 8;
|
||||
if (!Stream_CheckAndLogRequiredLengthWLog(log, s, header->CapabilityLength))
|
||||
return ERROR_INVALID_DATA;
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
UINT rdpdr_write_capset_header(wLog* log, wStream* s, const RDPDR_CAPABILITY_HEADER* header)
|
||||
{
|
||||
WINPR_ASSERT(header);
|
||||
WINPR_ASSERT(header->CapabilityLength >= 8);
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(s, header->CapabilityLength))
|
||||
{
|
||||
WLog_Print(log, WLOG_ERROR, "not enough data in stream!");
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
WLog_Print(log, WLOG_TRACE, "writing capability %s version %" PRIu32 ", length %" PRIu16,
|
||||
rdpdr_cap_type_string(header->CapabilityType), header->Version,
|
||||
header->CapabilityLength);
|
||||
Stream_Write_UINT16(s, header->CapabilityType); /* CapabilityType (2 bytes) */
|
||||
Stream_Write_UINT16(s, header->CapabilityLength); /* CapabilityLength (2 bytes) */
|
||||
Stream_Write_UINT32(s, header->Version); /* Version (4 bytes) */
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
const char* rdpdr_irp_val2str(UINT32 ioCode1)
|
||||
{
|
||||
switch (ioCode1)
|
||||
{
|
||||
case RDPDR_IRP_MJ_CREATE:
|
||||
return "MJ_CREATE";
|
||||
case RDPDR_IRP_MJ_CLEANUP:
|
||||
return "MJ_CLEANUP";
|
||||
case RDPDR_IRP_MJ_CLOSE:
|
||||
return "MJ_CLOSE";
|
||||
case RDPDR_IRP_MJ_READ:
|
||||
return "MJ_READ";
|
||||
case RDPDR_IRP_MJ_WRITE:
|
||||
return "MJ_WRITE";
|
||||
case RDPDR_IRP_MJ_FLUSH_BUFFERS:
|
||||
return "MJ_FLUSH_BUFFERS";
|
||||
case RDPDR_IRP_MJ_SHUTDOWN:
|
||||
return "MJ_SHUTDOWN";
|
||||
case RDPDR_IRP_MJ_DEVICE_CONTROL:
|
||||
return "MJ_DEVICE_CONTROL";
|
||||
case RDPDR_IRP_MJ_QUERY_VOLUME_INFORMATION:
|
||||
return "MJ_QUERY_VOLUME_INFORMATION";
|
||||
case RDPDR_IRP_MJ_SET_VOLUME_INFORMATION:
|
||||
return "MJ_SET_VOLUME_INFORMATION";
|
||||
case RDPDR_IRP_MJ_QUERY_INFORMATION:
|
||||
return "MJ_QUERY_INFORMATION";
|
||||
case RDPDR_IRP_MJ_SET_INFORMATION:
|
||||
return "MJ_SET_INFORMATION";
|
||||
case RDPDR_IRP_MJ_DIRECTORY_CONTROL:
|
||||
return "MJ_DIRECTORY_CONTROL";
|
||||
case RDPDR_IRP_MJ_LOCK_CONTROL:
|
||||
return "MJ_LOCK_CONTROL";
|
||||
case RDPDR_IRP_MJ_QUERY_SECURITY:
|
||||
return "MJ_QUERY_SECURITY";
|
||||
case RDPDR_IRP_MJ_SET_SECURITY:
|
||||
return "MJ_SET_SECURITY";
|
||||
default:
|
||||
return "IRP_MJ_UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
const char* rdpdr_irp_mask2str(UINT32 ioCode1Mask, char* buffer, size_t len)
|
||||
{
|
||||
if (len < 1)
|
||||
return nullptr;
|
||||
|
||||
if (!winpr_str_append("{", buffer, len, nullptr))
|
||||
return nullptr;
|
||||
|
||||
for (size_t x = 0; x < 32; x++)
|
||||
{
|
||||
const UINT32 mask = (1u << x);
|
||||
if (ioCode1Mask & mask)
|
||||
{
|
||||
if (!winpr_str_append(rdpdr_irp_val2str(mask), &buffer[1], len - 1, "|"))
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
char number[16] = WINPR_C_ARRAY_INIT;
|
||||
(void)_snprintf(number, sizeof(number), "}[0x%08" PRIx32 "]", ioCode1Mask);
|
||||
if (!winpr_str_append(number, buffer, len, nullptr))
|
||||
return nullptr;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
}
|
||||
311
third_party/FreeRDP/libfreerdp/utils/ringbuffer.c
vendored
Normal file
311
third_party/FreeRDP/libfreerdp/utils/ringbuffer.c
vendored
Normal file
@@ -0,0 +1,311 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Thincast Technologies GmbH
|
||||
* Copyright 2014 Hardening <contact@hardening-consulting.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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <freerdp/utils/ringbuffer.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#ifdef WITH_DEBUG_RINGBUFFER
|
||||
#define TAG FREERDP_TAG("utils.ringbuffer")
|
||||
|
||||
#define DEBUG_RINGBUFFER(...) WLog_DBG(TAG, __VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_RINGBUFFER(...) \
|
||||
do \
|
||||
{ \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
BOOL ringbuffer_init(RingBuffer* ringbuffer, size_t initialSize)
|
||||
{
|
||||
WINPR_ASSERT(ringbuffer);
|
||||
ringbuffer->buffer = malloc(initialSize);
|
||||
|
||||
if (!ringbuffer->buffer)
|
||||
return FALSE;
|
||||
|
||||
ringbuffer->readPtr = ringbuffer->writePtr = 0;
|
||||
ringbuffer->initialSize = ringbuffer->size = ringbuffer->freeSize = initialSize;
|
||||
DEBUG_RINGBUFFER("ringbuffer_init(%p)", (void*)rb);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
size_t ringbuffer_used(const RingBuffer* ringbuffer)
|
||||
{
|
||||
WINPR_ASSERT(ringbuffer);
|
||||
return ringbuffer->size - ringbuffer->freeSize;
|
||||
}
|
||||
|
||||
size_t ringbuffer_capacity(const RingBuffer* ringbuffer)
|
||||
{
|
||||
WINPR_ASSERT(ringbuffer);
|
||||
return ringbuffer->size;
|
||||
}
|
||||
|
||||
void ringbuffer_destroy(RingBuffer* ringbuffer)
|
||||
{
|
||||
DEBUG_RINGBUFFER("ringbuffer_destroy(%p)", (void*)ringbuffer);
|
||||
if (!ringbuffer)
|
||||
return;
|
||||
|
||||
free(ringbuffer->buffer);
|
||||
ringbuffer->buffer = nullptr;
|
||||
}
|
||||
|
||||
static BOOL ringbuffer_realloc(RingBuffer* ringbuffer, size_t targetSize)
|
||||
{
|
||||
WINPR_ASSERT(ringbuffer);
|
||||
BYTE* newData = nullptr;
|
||||
DEBUG_RINGBUFFER("ringbuffer_realloc(%p): targetSize: %" PRIdz "", (void*)rb, targetSize);
|
||||
|
||||
if (ringbuffer->writePtr == ringbuffer->readPtr)
|
||||
{
|
||||
/* when no size is used we can realloc() and set the heads at the
|
||||
* beginning of the buffer
|
||||
*/
|
||||
newData = (BYTE*)realloc(ringbuffer->buffer, targetSize);
|
||||
|
||||
if (!newData)
|
||||
return FALSE;
|
||||
|
||||
ringbuffer->readPtr = ringbuffer->writePtr = 0;
|
||||
ringbuffer->buffer = newData;
|
||||
}
|
||||
else if ((ringbuffer->writePtr >= ringbuffer->readPtr) && (ringbuffer->writePtr < targetSize))
|
||||
{
|
||||
/* we reallocate only if we're in that case, realloc don't touch read
|
||||
* and write heads
|
||||
*
|
||||
* readPtr writePtr
|
||||
* | |
|
||||
* v v
|
||||
* [............|XXXXXXXXXXXXXX|..........]
|
||||
*/
|
||||
newData = (BYTE*)realloc(ringbuffer->buffer, targetSize);
|
||||
|
||||
if (!newData)
|
||||
return FALSE;
|
||||
|
||||
ringbuffer->buffer = newData;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* in case of malloc the read head is moved at the beginning of the new buffer
|
||||
* and the write head is set accordingly
|
||||
*/
|
||||
newData = (BYTE*)malloc(targetSize);
|
||||
|
||||
if (!newData)
|
||||
return FALSE;
|
||||
|
||||
if (ringbuffer->readPtr < ringbuffer->writePtr)
|
||||
{
|
||||
/* readPtr writePtr
|
||||
* | |
|
||||
* v v
|
||||
* [............|XXXXXXXXXXXXXX|..........]
|
||||
*/
|
||||
memcpy(newData, ringbuffer->buffer + ringbuffer->readPtr, ringbuffer_used(ringbuffer));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* writePtr readPtr
|
||||
* | |
|
||||
* v v
|
||||
* [XXXXXXXXXXXX|..............|XXXXXXXXXX]
|
||||
*/
|
||||
BYTE* dst = newData;
|
||||
memcpy(dst, ringbuffer->buffer + ringbuffer->readPtr,
|
||||
ringbuffer->size - ringbuffer->readPtr);
|
||||
dst += (ringbuffer->size - ringbuffer->readPtr);
|
||||
|
||||
if (ringbuffer->writePtr)
|
||||
memcpy(dst, ringbuffer->buffer, ringbuffer->writePtr);
|
||||
}
|
||||
|
||||
ringbuffer->writePtr = ringbuffer->size - ringbuffer->freeSize;
|
||||
ringbuffer->readPtr = 0;
|
||||
free(ringbuffer->buffer);
|
||||
ringbuffer->buffer = newData;
|
||||
}
|
||||
|
||||
ringbuffer->freeSize += (targetSize - ringbuffer->size);
|
||||
ringbuffer->size = targetSize;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write to a ringbuffer
|
||||
*
|
||||
* @param ringbuffer A pointer to the ringbuffer
|
||||
* @param ptr A pointer to the data to write
|
||||
* @param sz The number of bytes to write
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE for failure
|
||||
*/
|
||||
BOOL ringbuffer_write(RingBuffer* ringbuffer, const BYTE* ptr, size_t sz)
|
||||
{
|
||||
size_t toWrite = 0;
|
||||
size_t remaining = 0;
|
||||
|
||||
WINPR_ASSERT(ringbuffer);
|
||||
DEBUG_RINGBUFFER("ringbuffer_write(%p): sz: %" PRIdz "", (void*)rb, sz);
|
||||
|
||||
if ((ringbuffer->freeSize <= sz) && !ringbuffer_realloc(ringbuffer, ringbuffer->size + sz))
|
||||
return FALSE;
|
||||
|
||||
/* the write could be split in two
|
||||
* readHead writeHead
|
||||
* | |
|
||||
* v v
|
||||
* [ ################ ]
|
||||
*/
|
||||
toWrite = sz;
|
||||
remaining = sz;
|
||||
|
||||
if (ringbuffer->size - ringbuffer->writePtr < sz)
|
||||
toWrite = ringbuffer->size - ringbuffer->writePtr;
|
||||
|
||||
if (toWrite)
|
||||
{
|
||||
memcpy(ringbuffer->buffer + ringbuffer->writePtr, ptr, toWrite);
|
||||
remaining -= toWrite;
|
||||
ptr += toWrite;
|
||||
}
|
||||
|
||||
if (remaining)
|
||||
memcpy(ringbuffer->buffer, ptr, remaining);
|
||||
|
||||
ringbuffer->writePtr = (ringbuffer->writePtr + sz) % ringbuffer->size;
|
||||
ringbuffer->freeSize -= sz;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BYTE* ringbuffer_ensure_linear_write(RingBuffer* ringbuffer, size_t sz)
|
||||
{
|
||||
DEBUG_RINGBUFFER("ringbuffer_ensure_linear_write(%p): sz: %" PRIdz "", (void*)rb, sz);
|
||||
|
||||
WINPR_ASSERT(ringbuffer);
|
||||
if (ringbuffer->freeSize < sz)
|
||||
{
|
||||
if (!ringbuffer_realloc(ringbuffer, ringbuffer->size + sz - ringbuffer->freeSize + 32))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (ringbuffer->writePtr == ringbuffer->readPtr)
|
||||
{
|
||||
ringbuffer->writePtr = ringbuffer->readPtr = 0;
|
||||
}
|
||||
|
||||
if (ringbuffer->writePtr + sz < ringbuffer->size)
|
||||
return ringbuffer->buffer + ringbuffer->writePtr;
|
||||
|
||||
/*
|
||||
* to add: .......
|
||||
* [ XXXXXXXXX ]
|
||||
*
|
||||
* result:
|
||||
* [XXXXXXXXX....... ]
|
||||
*/
|
||||
memmove(ringbuffer->buffer, ringbuffer->buffer + ringbuffer->readPtr,
|
||||
ringbuffer->writePtr - ringbuffer->readPtr);
|
||||
ringbuffer->readPtr = 0;
|
||||
ringbuffer->writePtr = ringbuffer->size - ringbuffer->freeSize;
|
||||
return ringbuffer->buffer + ringbuffer->writePtr;
|
||||
}
|
||||
|
||||
BOOL ringbuffer_commit_written_bytes(RingBuffer* ringbuffer, size_t sz)
|
||||
{
|
||||
DEBUG_RINGBUFFER("ringbuffer_commit_written_bytes(%p): sz: %" PRIdz "", (void*)rb, sz);
|
||||
|
||||
WINPR_ASSERT(ringbuffer);
|
||||
if (sz < 1)
|
||||
return TRUE;
|
||||
|
||||
if (ringbuffer->writePtr + sz > ringbuffer->size)
|
||||
return FALSE;
|
||||
|
||||
ringbuffer->writePtr = (ringbuffer->writePtr + sz) % ringbuffer->size;
|
||||
ringbuffer->freeSize -= sz;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int ringbuffer_peek(const RingBuffer* ringbuffer, DataChunk chunks[2], size_t sz)
|
||||
{
|
||||
size_t remaining = sz;
|
||||
size_t toRead = 0;
|
||||
int chunkIndex = 0;
|
||||
int status = 0;
|
||||
DEBUG_RINGBUFFER("ringbuffer_peek(%p): sz: %" PRIdz "", (const void*)rb, sz);
|
||||
|
||||
WINPR_ASSERT(ringbuffer);
|
||||
if (sz < 1)
|
||||
return 0;
|
||||
|
||||
if ((ringbuffer->size - ringbuffer->freeSize) < sz)
|
||||
remaining = ringbuffer->size - ringbuffer->freeSize;
|
||||
|
||||
toRead = remaining;
|
||||
|
||||
if ((ringbuffer->readPtr + remaining) > ringbuffer->size)
|
||||
toRead = ringbuffer->size - ringbuffer->readPtr;
|
||||
|
||||
if (toRead)
|
||||
{
|
||||
chunks[0].data = ringbuffer->buffer + ringbuffer->readPtr;
|
||||
chunks[0].size = toRead;
|
||||
remaining -= toRead;
|
||||
chunkIndex++;
|
||||
status++;
|
||||
}
|
||||
|
||||
if (remaining)
|
||||
{
|
||||
chunks[chunkIndex].data = ringbuffer->buffer;
|
||||
chunks[chunkIndex].size = remaining;
|
||||
status++;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void ringbuffer_commit_read_bytes(RingBuffer* ringbuffer, size_t sz)
|
||||
{
|
||||
DEBUG_RINGBUFFER("ringbuffer_commit_read_bytes(%p): sz: %" PRIdz "", (void*)ringbuffer, sz);
|
||||
|
||||
WINPR_ASSERT(ringbuffer);
|
||||
if (sz < 1)
|
||||
return;
|
||||
|
||||
WINPR_ASSERT(ringbuffer->size - ringbuffer->freeSize >= sz);
|
||||
ringbuffer->readPtr = (ringbuffer->readPtr + sz) % ringbuffer->size;
|
||||
ringbuffer->freeSize += sz;
|
||||
|
||||
/* when we reach a reasonable free size, we can go back to the original size */
|
||||
if ((ringbuffer->size != ringbuffer->initialSize) &&
|
||||
(ringbuffer_used(ringbuffer) < ringbuffer->initialSize / 2))
|
||||
ringbuffer_realloc(ringbuffer, ringbuffer->initialSize);
|
||||
}
|
||||
123
third_party/FreeRDP/libfreerdp/utils/signal.c
vendored
Normal file
123
third_party/FreeRDP/libfreerdp/utils/signal.c
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Signal handling
|
||||
*
|
||||
* Copyright 2011 Shea Levy <shea@shealevy.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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/debug.h>
|
||||
|
||||
#include <freerdp/utils/signal.h>
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#include "platform_signal.h"
|
||||
|
||||
#define TAG FREERDP_TAG("utils.signal")
|
||||
|
||||
#if defined(_WIN32)
|
||||
const char* strsignal(int signum);
|
||||
#endif
|
||||
|
||||
BOOL fsig_handlers_registered = FALSE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void* context;
|
||||
freerdp_signal_handler_t handler;
|
||||
} cleanup_handler_t;
|
||||
|
||||
static size_t cleanup_handler_count = 0;
|
||||
static cleanup_handler_t cleanup_handlers[20] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
void fsig_term_handler(int signum)
|
||||
{
|
||||
static BOOL recursive = FALSE;
|
||||
|
||||
if (!recursive)
|
||||
{
|
||||
recursive = TRUE;
|
||||
// NOLINTNEXTLINE(concurrency-mt-unsafe)
|
||||
WLog_ERR(TAG, "Caught signal '%s' [%d]", strsignal(signum), signum);
|
||||
}
|
||||
|
||||
fsig_lock();
|
||||
for (size_t x = 0; x < cleanup_handler_count; x++)
|
||||
{
|
||||
const cleanup_handler_t empty = WINPR_C_ARRAY_INIT;
|
||||
cleanup_handler_t* cur = &cleanup_handlers[x];
|
||||
if (cur->handler)
|
||||
{
|
||||
// NOLINTNEXTLINE(concurrency-mt-unsafe)
|
||||
cur->handler(signum, strsignal(signum), cur->context);
|
||||
}
|
||||
*cur = empty;
|
||||
}
|
||||
cleanup_handler_count = 0;
|
||||
fsig_unlock();
|
||||
}
|
||||
|
||||
BOOL freerdp_add_signal_cleanup_handler(void* context, freerdp_signal_handler_t handler)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
fsig_lock();
|
||||
if (fsig_handlers_registered)
|
||||
{
|
||||
if (cleanup_handler_count < ARRAYSIZE(cleanup_handlers))
|
||||
{
|
||||
cleanup_handler_t* cur = &cleanup_handlers[cleanup_handler_count++];
|
||||
cur->context = context;
|
||||
cur->handler = handler;
|
||||
}
|
||||
else
|
||||
WLog_WARN(TAG, "Failed to register cleanup handler, only %" PRIuz " handlers supported",
|
||||
ARRAYSIZE(cleanup_handlers));
|
||||
}
|
||||
rc = TRUE;
|
||||
fsig_unlock();
|
||||
return rc;
|
||||
}
|
||||
|
||||
BOOL freerdp_del_signal_cleanup_handler(void* context, freerdp_signal_handler_t handler)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
fsig_lock();
|
||||
if (fsig_handlers_registered)
|
||||
{
|
||||
for (size_t x = 0; x < cleanup_handler_count; x++)
|
||||
{
|
||||
cleanup_handler_t* cur = &cleanup_handlers[x];
|
||||
if ((cur->context == context) && (cur->handler == handler))
|
||||
{
|
||||
const cleanup_handler_t empty = WINPR_C_ARRAY_INIT;
|
||||
for (size_t y = x + 1; y < cleanup_handler_count - 1; y++)
|
||||
{
|
||||
*cur++ = cleanup_handlers[y];
|
||||
}
|
||||
|
||||
*cur = empty;
|
||||
cleanup_handler_count--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
rc = TRUE;
|
||||
fsig_unlock();
|
||||
return rc;
|
||||
}
|
||||
168
third_party/FreeRDP/libfreerdp/utils/signal_posix.c
vendored
Normal file
168
third_party/FreeRDP/libfreerdp/utils/signal_posix.c
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
#include <pthread.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include <winpr/wlog.h>
|
||||
#include <winpr/debug.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#include <freerdp/utils/signal.h>
|
||||
|
||||
#include "platform_signal.h"
|
||||
|
||||
#define TAG FREERDP_TAG("utils.signal.posix")
|
||||
|
||||
static pthread_mutex_t signal_handler_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
void fsig_lock(void)
|
||||
{
|
||||
const int rc = pthread_mutex_lock(&signal_handler_lock);
|
||||
if (rc != 0)
|
||||
{
|
||||
char ebuffer[256] = WINPR_C_ARRAY_INIT;
|
||||
WLog_ERR(TAG, "[pthread_mutex_lock] failed with %s [%d]",
|
||||
winpr_strerror(rc, ebuffer, sizeof(ebuffer)), rc);
|
||||
}
|
||||
}
|
||||
|
||||
void fsig_unlock(void)
|
||||
{
|
||||
const int rc = pthread_mutex_unlock(&signal_handler_lock);
|
||||
if (rc != 0)
|
||||
{
|
||||
char ebuffer[256] = WINPR_C_ARRAY_INIT;
|
||||
WLog_ERR(TAG, "[pthread_mutex_lock] failed with %s [%d]",
|
||||
winpr_strerror(rc, ebuffer, sizeof(ebuffer)), rc);
|
||||
}
|
||||
}
|
||||
|
||||
static void fatal_handler(int signum)
|
||||
{
|
||||
struct sigaction default_sigaction;
|
||||
sigset_t this_mask;
|
||||
static BOOL recursive = FALSE;
|
||||
|
||||
if (!recursive)
|
||||
{
|
||||
recursive = TRUE;
|
||||
// NOLINTNEXTLINE(concurrency-mt-unsafe)
|
||||
WLog_ERR(TAG, "Caught signal '%s' [%d]", strsignal(signum), signum);
|
||||
|
||||
winpr_log_backtrace(TAG, WLOG_ERROR, 20);
|
||||
}
|
||||
|
||||
default_sigaction.sa_handler = SIG_DFL;
|
||||
sigfillset(&(default_sigaction.sa_mask));
|
||||
default_sigaction.sa_flags = 0;
|
||||
sigaction(signum, &default_sigaction, nullptr);
|
||||
sigemptyset(&this_mask);
|
||||
sigaddset(&this_mask, signum);
|
||||
pthread_sigmask(SIG_UNBLOCK, &this_mask, nullptr);
|
||||
(void)raise(signum);
|
||||
}
|
||||
|
||||
static const int term_signals[] = { SIGINT, SIGKILL, SIGQUIT, SIGSTOP, SIGTERM };
|
||||
|
||||
static const int fatal_signals[] = { SIGABRT, SIGALRM, SIGBUS, SIGFPE, SIGHUP,
|
||||
SIGILL, SIGSEGV, SIGTTIN, SIGTTOU,
|
||||
#ifdef SIGPOLL
|
||||
SIGPOLL,
|
||||
#endif
|
||||
#ifdef SIGPROF
|
||||
SIGPROF,
|
||||
#endif
|
||||
#ifdef SIGSYS
|
||||
SIGSYS,
|
||||
#endif
|
||||
SIGTRAP,
|
||||
#ifdef SIGVTALRM
|
||||
SIGVTALRM,
|
||||
#endif
|
||||
SIGXCPU, SIGXFSZ };
|
||||
|
||||
static BOOL register_handlers(const int* signals, size_t count, void (*handler)(int))
|
||||
{
|
||||
WINPR_ASSERT(signals || (count == 0));
|
||||
WINPR_ASSERT(handler);
|
||||
|
||||
sigset_t orig_set = WINPR_C_ARRAY_INIT;
|
||||
struct sigaction saction = WINPR_C_ARRAY_INIT;
|
||||
|
||||
pthread_sigmask(SIG_BLOCK, &(saction.sa_mask), &orig_set);
|
||||
|
||||
sigfillset(&(saction.sa_mask));
|
||||
sigdelset(&(saction.sa_mask), SIGCONT);
|
||||
|
||||
saction.sa_handler = handler;
|
||||
saction.sa_flags = 0;
|
||||
|
||||
for (size_t x = 0; x < count; x++)
|
||||
{
|
||||
struct sigaction orig_sigaction = WINPR_C_ARRAY_INIT;
|
||||
if (sigaction(signals[x], nullptr, &orig_sigaction) == 0)
|
||||
{
|
||||
if (orig_sigaction.sa_handler != SIG_IGN)
|
||||
{
|
||||
sigaction(signals[x], &saction, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pthread_sigmask(SIG_SETMASK, &orig_set, nullptr);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void unregister_handlers(const int* signals, size_t count)
|
||||
{
|
||||
WINPR_ASSERT(signals || (count == 0));
|
||||
|
||||
sigset_t orig_set = WINPR_C_ARRAY_INIT;
|
||||
struct sigaction saction = WINPR_C_ARRAY_INIT;
|
||||
|
||||
pthread_sigmask(SIG_BLOCK, &(saction.sa_mask), &orig_set);
|
||||
|
||||
sigfillset(&(saction.sa_mask));
|
||||
sigdelset(&(saction.sa_mask), SIGCONT);
|
||||
|
||||
saction.sa_handler = SIG_IGN;
|
||||
saction.sa_flags = 0;
|
||||
|
||||
for (size_t x = 0; x < count; x++)
|
||||
{
|
||||
sigaction(signals[x], &saction, nullptr);
|
||||
}
|
||||
|
||||
pthread_sigmask(SIG_SETMASK, &orig_set, nullptr);
|
||||
}
|
||||
|
||||
static void unregister_all_handlers(void)
|
||||
{
|
||||
unregister_handlers(fatal_signals, ARRAYSIZE(fatal_signals));
|
||||
unregister_handlers(term_signals, ARRAYSIZE(term_signals));
|
||||
}
|
||||
|
||||
int freerdp_handle_signals(void)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
fsig_lock();
|
||||
|
||||
WLog_DBG(TAG, "Registering signal hook...");
|
||||
|
||||
(void)atexit(unregister_all_handlers);
|
||||
if (!register_handlers(fatal_signals, ARRAYSIZE(fatal_signals), fatal_handler))
|
||||
goto fail;
|
||||
if (!register_handlers(term_signals, ARRAYSIZE(term_signals), fsig_term_handler))
|
||||
goto fail;
|
||||
|
||||
/* Ignore SIGPIPE signal. */
|
||||
(void)signal(SIGPIPE, SIG_IGN);
|
||||
fsig_handlers_registered = TRUE;
|
||||
rc = 0;
|
||||
fail:
|
||||
fsig_unlock();
|
||||
return rc;
|
||||
}
|
||||
117
third_party/FreeRDP/libfreerdp/utils/signal_win32.c
vendored
Normal file
117
third_party/FreeRDP/libfreerdp/utils/signal_win32.c
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <winpr/wlog.h>
|
||||
#include <winpr/debug.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#include <freerdp/utils/signal.h>
|
||||
|
||||
#include "platform_signal.h"
|
||||
|
||||
#define TAG FREERDP_TAG("utils.signal.posix")
|
||||
|
||||
static CRITICAL_SECTION signal_lock;
|
||||
|
||||
void fsig_lock(void)
|
||||
{
|
||||
EnterCriticalSection(&signal_lock);
|
||||
}
|
||||
|
||||
void fsig_unlock(void)
|
||||
{
|
||||
LeaveCriticalSection(&signal_lock);
|
||||
}
|
||||
|
||||
const char* strsignal(int signum)
|
||||
{
|
||||
#define CASE_STR(x) \
|
||||
case x: \
|
||||
return #x
|
||||
switch (signum)
|
||||
{
|
||||
CASE_STR(SIGINT);
|
||||
CASE_STR(SIGILL);
|
||||
CASE_STR(SIGFPE);
|
||||
CASE_STR(SIGSEGV);
|
||||
CASE_STR(SIGTERM);
|
||||
CASE_STR(SIGBREAK);
|
||||
CASE_STR(SIGABRT);
|
||||
CASE_STR(SIGABRT_COMPAT);
|
||||
default:
|
||||
return "SIG_UNKNOWN";
|
||||
}
|
||||
}
|
||||
static void fatal_handler(int signum)
|
||||
{
|
||||
static BOOL recursive = FALSE;
|
||||
|
||||
if (!recursive)
|
||||
{
|
||||
recursive = TRUE;
|
||||
// NOLINTNEXTLINE(concuSWSrrency-mt-unsafe)
|
||||
WLog_ERR(TAG, "Caught signal '%s' [%d]", strsignal(signum), signum);
|
||||
|
||||
winpr_log_backtrace(TAG, WLOG_ERROR, 20);
|
||||
}
|
||||
|
||||
(void)raise(signum);
|
||||
}
|
||||
|
||||
static const int term_signals[] = { SIGINT, SIGTERM };
|
||||
|
||||
static const int fatal_signals[] = { SIGABRT, SIGFPE, SIGILL, SIGSEGV };
|
||||
|
||||
static BOOL register_handlers(const int* signals, size_t count, void (*handler)(int))
|
||||
{
|
||||
WINPR_ASSERT(signals || (count == 0));
|
||||
WINPR_ASSERT(handler);
|
||||
|
||||
for (size_t x = 0; x < count; x++)
|
||||
{
|
||||
(void)signal(signals[x], handler);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void unregister_handlers(const int* signals, size_t count)
|
||||
{
|
||||
WINPR_ASSERT(signals || (count == 0));
|
||||
|
||||
for (size_t x = 0; x < count; x++)
|
||||
{
|
||||
(void)signal(signals[x], SIG_IGN);
|
||||
}
|
||||
}
|
||||
|
||||
static void unregister_all_handlers(void)
|
||||
{
|
||||
unregister_handlers(fatal_signals, ARRAYSIZE(fatal_signals));
|
||||
unregister_handlers(term_signals, ARRAYSIZE(term_signals));
|
||||
DeleteCriticalSection(&signal_lock);
|
||||
}
|
||||
|
||||
int freerdp_handle_signals(void)
|
||||
{
|
||||
int rc = -1;
|
||||
InitializeCriticalSection(&signal_lock);
|
||||
|
||||
fsig_lock();
|
||||
|
||||
WLog_DBG(TAG, "Registering signal hook...");
|
||||
|
||||
(void)atexit(unregister_all_handlers);
|
||||
if (!register_handlers(fatal_signals, ARRAYSIZE(fatal_signals), fatal_handler))
|
||||
goto fail;
|
||||
if (!register_handlers(term_signals, ARRAYSIZE(term_signals), fsig_term_handler))
|
||||
goto fail;
|
||||
|
||||
fsig_handlers_registered = true;
|
||||
rc = 0;
|
||||
fail:
|
||||
fsig_unlock();
|
||||
return rc;
|
||||
}
|
||||
2104
third_party/FreeRDP/libfreerdp/utils/smartcard_call.c
vendored
Normal file
2104
third_party/FreeRDP/libfreerdp/utils/smartcard_call.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1039
third_party/FreeRDP/libfreerdp/utils/smartcard_operations.c
vendored
Normal file
1039
third_party/FreeRDP/libfreerdp/utils/smartcard_operations.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4018
third_party/FreeRDP/libfreerdp/utils/smartcard_pack.c
vendored
Normal file
4018
third_party/FreeRDP/libfreerdp/utils/smartcard_pack.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
28
third_party/FreeRDP/libfreerdp/utils/smartcard_pack.h
vendored
Normal file
28
third_party/FreeRDP/libfreerdp/utils/smartcard_pack.h
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Smart Card Structure Packing
|
||||
*
|
||||
* Copyright 2025 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2025 Thincast Technologies GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <winpr/wlog.h>
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/channels/scard.h>
|
||||
|
||||
FREERDP_LOCAL void smartcard_trace_long_return_int(wLog* log, const Long_Return* ret,
|
||||
const char* name);
|
||||
79
third_party/FreeRDP/libfreerdp/utils/stopwatch.c
vendored
Normal file
79
third_party/FreeRDP/libfreerdp/utils/stopwatch.c
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Stopwatch Utils
|
||||
*
|
||||
* Copyright 2011 Stephen Erisman
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <winpr/sysinfo.h>
|
||||
#include <freerdp/utils/stopwatch.h>
|
||||
|
||||
static void stopwatch_set_time(UINT64* usecs)
|
||||
{
|
||||
const UINT64 ns = winpr_GetTickCount64NS();
|
||||
*usecs = WINPR_TIME_NS_TO_US(ns);
|
||||
}
|
||||
|
||||
STOPWATCH* stopwatch_create(void)
|
||||
{
|
||||
STOPWATCH* sw = (STOPWATCH*)calloc(1, sizeof(STOPWATCH));
|
||||
if (!sw)
|
||||
return nullptr;
|
||||
stopwatch_reset(sw);
|
||||
|
||||
return sw;
|
||||
}
|
||||
|
||||
void stopwatch_free(STOPWATCH* stopwatch)
|
||||
{
|
||||
free(stopwatch);
|
||||
}
|
||||
|
||||
void stopwatch_start(STOPWATCH* stopwatch)
|
||||
{
|
||||
stopwatch_set_time(&stopwatch->start);
|
||||
stopwatch->count++;
|
||||
}
|
||||
|
||||
void stopwatch_stop(STOPWATCH* stopwatch)
|
||||
{
|
||||
stopwatch_set_time(&stopwatch->end);
|
||||
stopwatch->elapsed += (stopwatch->end - stopwatch->start);
|
||||
}
|
||||
|
||||
void stopwatch_reset(STOPWATCH* stopwatch)
|
||||
{
|
||||
stopwatch->start = 0;
|
||||
stopwatch->end = 0;
|
||||
stopwatch->elapsed = 0;
|
||||
stopwatch->count = 0;
|
||||
}
|
||||
|
||||
double stopwatch_get_elapsed_time_in_seconds(STOPWATCH* stopwatch)
|
||||
{
|
||||
const long double ld = stopwatch->elapsed / 1000000.0L;
|
||||
return (double)ld;
|
||||
}
|
||||
|
||||
void stopwatch_get_elapsed_time_in_useconds(STOPWATCH* stopwatch, UINT32* sec, UINT32* usec)
|
||||
{
|
||||
*sec = (UINT32)stopwatch->elapsed / 1000000;
|
||||
*usec = (UINT32)stopwatch->elapsed % 1000000;
|
||||
}
|
||||
218
third_party/FreeRDP/libfreerdp/utils/string.c
vendored
Normal file
218
third_party/FreeRDP/libfreerdp/utils/string.c
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* String Utils - Helper functions converting something to string
|
||||
*
|
||||
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2022 Thincast Technologies GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <freerdp/utils/string.h>
|
||||
#include <freerdp/settings.h>
|
||||
|
||||
#if defined(CHANNEL_RDPEI)
|
||||
#include <freerdp/channels/rdpei.h>
|
||||
#endif
|
||||
|
||||
const char* rdp_redirection_flags_to_string(UINT32 flags, char* buffer, size_t size)
|
||||
{
|
||||
struct map_t
|
||||
{
|
||||
UINT32 flag;
|
||||
const char* name;
|
||||
};
|
||||
const struct map_t map[] = {
|
||||
{ LB_TARGET_NET_ADDRESS, "LB_TARGET_NET_ADDRESS" },
|
||||
{ LB_LOAD_BALANCE_INFO, "LB_LOAD_BALANCE_INFO" },
|
||||
{ LB_USERNAME, "LB_USERNAME" },
|
||||
{ LB_DOMAIN, "LB_DOMAIN" },
|
||||
{ LB_PASSWORD, "LB_PASSWORD" },
|
||||
{ LB_DONTSTOREUSERNAME, "LB_DONTSTOREUSERNAME" },
|
||||
{ LB_SMARTCARD_LOGON, "LB_SMARTCARD_LOGON" },
|
||||
{ LB_NOREDIRECT, "LB_NOREDIRECT" },
|
||||
{ LB_TARGET_FQDN, "LB_TARGET_FQDN" },
|
||||
{ LB_TARGET_NETBIOS_NAME, "LB_TARGET_NETBIOS_NAME" },
|
||||
{ LB_TARGET_NET_ADDRESSES, "LB_TARGET_NET_ADDRESSES" },
|
||||
{ LB_CLIENT_TSV_URL, "LB_CLIENT_TSV_URL" },
|
||||
{ LB_SERVER_TSV_CAPABLE, "LB_SERVER_TSV_CAPABLE" },
|
||||
{ LB_PASSWORD_IS_PK_ENCRYPTED, "LB_PASSWORD_IS_PK_ENCRYPTED" },
|
||||
{ LB_REDIRECTION_GUID, "LB_REDIRECTION_GUID" },
|
||||
{ LB_TARGET_CERTIFICATE, "LB_TARGET_CERTIFICATE" },
|
||||
};
|
||||
|
||||
for (size_t x = 0; x < ARRAYSIZE(map); x++)
|
||||
{
|
||||
const struct map_t* cur = &map[x];
|
||||
if (flags & cur->flag)
|
||||
{
|
||||
if (!winpr_str_append(cur->name, buffer, size, "|"))
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
const char* rdp_cluster_info_flags_to_string(UINT32 flags, char* buffer, size_t size)
|
||||
{
|
||||
const UINT32 version = (flags & ServerSessionRedirectionVersionMask) >> 2;
|
||||
if (flags & REDIRECTION_SUPPORTED)
|
||||
winpr_str_append("REDIRECTION_SUPPORTED", buffer, size, "|");
|
||||
if (flags & REDIRECTED_SESSIONID_FIELD_VALID)
|
||||
winpr_str_append("REDIRECTED_SESSIONID_FIELD_VALID", buffer, size, "|");
|
||||
if (flags & REDIRECTED_SMARTCARD)
|
||||
winpr_str_append("REDIRECTED_SMARTCARD", buffer, size, "|");
|
||||
|
||||
const char* str = nullptr;
|
||||
switch (version)
|
||||
{
|
||||
case REDIRECTION_VERSION1:
|
||||
str = "REDIRECTION_VERSION1";
|
||||
break;
|
||||
case REDIRECTION_VERSION2:
|
||||
str = "REDIRECTION_VERSION2";
|
||||
break;
|
||||
case REDIRECTION_VERSION3:
|
||||
str = "REDIRECTION_VERSION3";
|
||||
break;
|
||||
case REDIRECTION_VERSION4:
|
||||
str = "REDIRECTION_VERSION4";
|
||||
break;
|
||||
case REDIRECTION_VERSION5:
|
||||
str = "REDIRECTION_VERSION5";
|
||||
break;
|
||||
case REDIRECTION_VERSION6:
|
||||
str = "REDIRECTION_VERSION6";
|
||||
break;
|
||||
default:
|
||||
str = "REDIRECTION_VERSION_UNKNOWN";
|
||||
break;
|
||||
}
|
||||
winpr_str_append(str, buffer, size, "|");
|
||||
{
|
||||
char msg[32] = WINPR_C_ARRAY_INIT;
|
||||
(void)_snprintf(msg, sizeof(msg), "[0x%08" PRIx32 "]", flags);
|
||||
winpr_str_append(msg, buffer, size, "");
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
BOOL freerdp_extract_key_value(const char* str, UINT32* pkey, UINT32* pvalue)
|
||||
{
|
||||
if (!str || !pkey || !pvalue)
|
||||
return FALSE;
|
||||
|
||||
char* end1 = nullptr;
|
||||
errno = 0;
|
||||
unsigned long key = strtoul(str, &end1, 0);
|
||||
if ((errno != 0) || !end1 || (*end1 != '=') || (key > UINT32_MAX))
|
||||
return FALSE;
|
||||
|
||||
errno = 0;
|
||||
unsigned long val = strtoul(&end1[1], nullptr, 0);
|
||||
if ((errno != 0) || (val > UINT32_MAX))
|
||||
return FALSE;
|
||||
|
||||
*pkey = (UINT32)key;
|
||||
*pvalue = (UINT32)val;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
const char* freerdp_desktop_rotation_flags_to_string(UINT32 flags)
|
||||
{
|
||||
#define ENTRY(x) \
|
||||
case x: \
|
||||
return #x
|
||||
|
||||
switch (flags)
|
||||
{
|
||||
ENTRY(ORIENTATION_LANDSCAPE);
|
||||
ENTRY(ORIENTATION_PORTRAIT);
|
||||
ENTRY(ORIENTATION_LANDSCAPE_FLIPPED);
|
||||
ENTRY(ORIENTATION_PORTRAIT_FLIPPED);
|
||||
default:
|
||||
return "ORIENTATION_UNKNOWN";
|
||||
}
|
||||
#undef ENTRY
|
||||
}
|
||||
|
||||
const char* freerdp_input_touch_state_string(DWORD flags)
|
||||
{
|
||||
#if defined(CHANNEL_RDPEI)
|
||||
if (flags & RDPINPUT_CONTACT_FLAG_DOWN)
|
||||
return "RDPINPUT_CONTACT_FLAG_DOWN";
|
||||
else if (flags & RDPINPUT_CONTACT_FLAG_UPDATE)
|
||||
return "RDPINPUT_CONTACT_FLAG_UPDATE";
|
||||
else if (flags & RDPINPUT_CONTACT_FLAG_UP)
|
||||
return "RDPINPUT_CONTACT_FLAG_UP";
|
||||
else if (flags & RDPINPUT_CONTACT_FLAG_INRANGE)
|
||||
return "RDPINPUT_CONTACT_FLAG_INRANGE";
|
||||
else if (flags & RDPINPUT_CONTACT_FLAG_INCONTACT)
|
||||
return "RDPINPUT_CONTACT_FLAG_INCONTACT";
|
||||
else if (flags & RDPINPUT_CONTACT_FLAG_CANCELED)
|
||||
return "RDPINPUT_CONTACT_FLAG_CANCELED";
|
||||
else
|
||||
return "RDPINPUT_CONTACT_FLAG_UNKNOWN";
|
||||
#else
|
||||
return "CHANNEL_RDPEI not supported";
|
||||
#endif
|
||||
}
|
||||
|
||||
const char* freerdp_order_support_flags_string(UINT8 type)
|
||||
{
|
||||
#define ENTRY(x) \
|
||||
case x: \
|
||||
return #x
|
||||
|
||||
switch (type)
|
||||
{
|
||||
ENTRY(NEG_DSTBLT_INDEX);
|
||||
ENTRY(NEG_PATBLT_INDEX);
|
||||
ENTRY(NEG_SCRBLT_INDEX);
|
||||
ENTRY(NEG_MEMBLT_INDEX);
|
||||
ENTRY(NEG_MEM3BLT_INDEX);
|
||||
ENTRY(NEG_ATEXTOUT_INDEX);
|
||||
ENTRY(NEG_AEXTTEXTOUT_INDEX);
|
||||
ENTRY(NEG_DRAWNINEGRID_INDEX);
|
||||
ENTRY(NEG_LINETO_INDEX);
|
||||
ENTRY(NEG_MULTI_DRAWNINEGRID_INDEX);
|
||||
ENTRY(NEG_OPAQUE_RECT_INDEX);
|
||||
ENTRY(NEG_SAVEBITMAP_INDEX);
|
||||
ENTRY(NEG_WTEXTOUT_INDEX);
|
||||
ENTRY(NEG_MEMBLT_V2_INDEX);
|
||||
ENTRY(NEG_MEM3BLT_V2_INDEX);
|
||||
ENTRY(NEG_MULTIDSTBLT_INDEX);
|
||||
ENTRY(NEG_MULTIPATBLT_INDEX);
|
||||
ENTRY(NEG_MULTISCRBLT_INDEX);
|
||||
ENTRY(NEG_MULTIOPAQUERECT_INDEX);
|
||||
ENTRY(NEG_FAST_INDEX_INDEX);
|
||||
ENTRY(NEG_POLYGON_SC_INDEX);
|
||||
ENTRY(NEG_POLYGON_CB_INDEX);
|
||||
ENTRY(NEG_POLYLINE_INDEX);
|
||||
ENTRY(NEG_UNUSED23_INDEX);
|
||||
ENTRY(NEG_FAST_GLYPH_INDEX);
|
||||
ENTRY(NEG_ELLIPSE_SC_INDEX);
|
||||
ENTRY(NEG_ELLIPSE_CB_INDEX);
|
||||
ENTRY(NEG_GLYPH_INDEX_INDEX);
|
||||
ENTRY(NEG_GLYPH_WEXTTEXTOUT_INDEX);
|
||||
ENTRY(NEG_GLYPH_WLONGTEXTOUT_INDEX);
|
||||
ENTRY(NEG_GLYPH_WLONGEXTTEXTOUT_INDEX);
|
||||
ENTRY(NEG_UNUSED31_INDEX);
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
#undef ENTRY
|
||||
}
|
||||
26
third_party/FreeRDP/libfreerdp/utils/test/CMakeLists.txt
vendored
Normal file
26
third_party/FreeRDP/libfreerdp/utils/test/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
set(MODULE_NAME "TestFreeRDPUtils")
|
||||
set(MODULE_PREFIX "TEST_FREERDP_UTILS")
|
||||
|
||||
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
|
||||
|
||||
set(${MODULE_PREFIX}_TESTS TestRingBuffer.c TestPodArrays.c TestEncodedTypes.c)
|
||||
|
||||
create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_TESTS})
|
||||
|
||||
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
|
||||
|
||||
target_link_libraries(${MODULE_NAME} PRIVATE freerdp winpr)
|
||||
if(NOT WIN32)
|
||||
target_link_libraries(${MODULE_NAME} PRIVATE m)
|
||||
endif()
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
|
||||
|
||||
foreach(test ${${MODULE_PREFIX}_TESTS})
|
||||
get_filename_component(TestName ${test} NAME_WE)
|
||||
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
|
||||
endforeach()
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/Test")
|
||||
218
third_party/FreeRDP/libfreerdp/utils/test/TestEncodedTypes.c
vendored
Normal file
218
third_party/FreeRDP/libfreerdp/utils/test/TestEncodedTypes.c
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2024 Thincast Technologies GmbH
|
||||
* Copyright 2024 Armin Novak <anovak@thincast.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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <winpr/crypto.h>
|
||||
#include <freerdp/utils/encoded_types.h>
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(x, y) ((x) < (y)) ? (x) : (y)
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(x, y) ((x) > (y)) ? (x) : (y)
|
||||
#endif
|
||||
|
||||
static BOOL test_signed_integer_read_write_equal(INT32 value)
|
||||
{
|
||||
INT32 rvalue = 0;
|
||||
BYTE buffer[32] = WINPR_C_ARRAY_INIT;
|
||||
wStream sbuffer = WINPR_C_ARRAY_INIT;
|
||||
wStream* s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
|
||||
WINPR_ASSERT(s);
|
||||
|
||||
if (!freerdp_write_four_byte_signed_integer(s, value))
|
||||
{
|
||||
(void)fprintf(stderr, "[%s(%" PRId32 ")] failed to write to stream\n", __func__, value);
|
||||
return FALSE;
|
||||
}
|
||||
Stream_ResetPosition(s);
|
||||
|
||||
if (!freerdp_read_four_byte_signed_integer(s, &rvalue))
|
||||
{
|
||||
(void)fprintf(stderr, "[%s(%" PRId32 ")] failed to read from stream\n", __func__, value);
|
||||
return FALSE;
|
||||
}
|
||||
if (value != rvalue)
|
||||
{
|
||||
(void)fprintf(stderr, "[%s(%" PRId32 ")] read invalid value %" PRId32 " from stream\n",
|
||||
__func__, value, rvalue);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL test_signed_integer_write_oor(INT32 value)
|
||||
{
|
||||
BYTE buffer[32] = WINPR_C_ARRAY_INIT;
|
||||
wStream sbuffer = WINPR_C_ARRAY_INIT;
|
||||
wStream* s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
|
||||
WINPR_ASSERT(s);
|
||||
|
||||
if (freerdp_write_four_byte_signed_integer(s, value))
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"[%s(%" PRId32 ")] out of range value not detected and written to stream\n",
|
||||
__func__, value);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL test_signed_integers(void)
|
||||
{
|
||||
const INT32 outofrange[] = { FREERDP_FOUR_BYTE_SIGNED_INT_MAX + 1,
|
||||
FREERDP_FOUR_BYTE_SIGNED_INT_MIN - 1, INT32_MAX, INT32_MIN };
|
||||
const INT32 limits[] = { 1, 0, -1, FREERDP_FOUR_BYTE_SIGNED_INT_MAX,
|
||||
FREERDP_FOUR_BYTE_SIGNED_INT_MIN };
|
||||
|
||||
for (size_t x = 0; x < ARRAYSIZE(limits); x++)
|
||||
{
|
||||
if (!test_signed_integer_read_write_equal(limits[x]))
|
||||
return FALSE;
|
||||
}
|
||||
for (size_t x = 0; x < ARRAYSIZE(outofrange); x++)
|
||||
{
|
||||
if (!test_signed_integer_write_oor(outofrange[x]))
|
||||
return FALSE;
|
||||
}
|
||||
for (size_t x = 0; x < 100000; x++)
|
||||
{
|
||||
INT32 val = 0;
|
||||
if (winpr_RAND(&val, sizeof(val)) < 0)
|
||||
return FALSE;
|
||||
val = MAX(val, 0);
|
||||
val = MIN(val, FREERDP_FOUR_BYTE_SIGNED_INT_MAX);
|
||||
|
||||
const INT32 nval = -val;
|
||||
if (!test_signed_integer_read_write_equal(val))
|
||||
return FALSE;
|
||||
if (!test_signed_integer_read_write_equal(nval))
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL test_float_read_write_equal(double value)
|
||||
{
|
||||
BYTE exp = 0;
|
||||
double rvalue = FP_NAN;
|
||||
BYTE buffer[32] = WINPR_C_ARRAY_INIT;
|
||||
wStream sbuffer = WINPR_C_ARRAY_INIT;
|
||||
wStream* s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
|
||||
WINPR_ASSERT(s);
|
||||
|
||||
if (!freerdp_write_four_byte_float(s, value))
|
||||
{
|
||||
(void)fprintf(stderr, "[%s(%lf)] failed to write to stream\n", __func__, value);
|
||||
return FALSE;
|
||||
}
|
||||
Stream_ResetPosition(s);
|
||||
|
||||
if (!freerdp_read_four_byte_float_exp(s, &rvalue, &exp))
|
||||
{
|
||||
(void)fprintf(stderr, "[%s(%lf)] failed to read from stream\n", __func__, value);
|
||||
return FALSE;
|
||||
}
|
||||
const double diff = fabs(value - rvalue);
|
||||
const double expdiff = diff * pow(10, exp);
|
||||
if (expdiff >= 1.0)
|
||||
{
|
||||
(void)fprintf(stderr, "[%s(%lf)] read invalid value %lf from stream\n", __func__, value,
|
||||
rvalue);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL test_floag_write_oor(double value)
|
||||
{
|
||||
BYTE buffer[32] = WINPR_C_ARRAY_INIT;
|
||||
wStream sbuffer = WINPR_C_ARRAY_INIT;
|
||||
wStream* s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
|
||||
WINPR_ASSERT(s);
|
||||
|
||||
if (freerdp_write_four_byte_float(s, value))
|
||||
{
|
||||
(void)fprintf(stderr, "[%s(%lf)] out of range value not detected and written to stream\n",
|
||||
__func__, value);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static double get(void)
|
||||
{
|
||||
double val = NAN;
|
||||
do
|
||||
{
|
||||
if (winpr_RAND(&val, sizeof(val)) < 0)
|
||||
{
|
||||
// NOLINTNEXTLINE(concurrency-mt-unsafe)
|
||||
exit(-1);
|
||||
}
|
||||
} while ((val < 0.0) || (val > FREERDP_FOUR_BYTE_FLOAT_MAX) || isnan(val) || isinf(val));
|
||||
return val;
|
||||
}
|
||||
|
||||
static BOOL test_floats(void)
|
||||
{
|
||||
const double outofrange[] = { FREERDP_FOUR_BYTE_FLOAT_MAX + 1, FREERDP_FOUR_BYTE_FLOAT_MIN - 1,
|
||||
DBL_MAX, -DBL_MAX };
|
||||
const double limits[] = { 100045.26129238126, 1, 0, -1, FREERDP_FOUR_BYTE_FLOAT_MAX,
|
||||
FREERDP_FOUR_BYTE_FLOAT_MIN };
|
||||
|
||||
for (size_t x = 0; x < ARRAYSIZE(limits); x++)
|
||||
{
|
||||
if (!test_float_read_write_equal(limits[x]))
|
||||
return FALSE;
|
||||
}
|
||||
for (size_t x = 0; x < ARRAYSIZE(outofrange); x++)
|
||||
{
|
||||
if (!test_floag_write_oor(outofrange[x]))
|
||||
return FALSE;
|
||||
}
|
||||
for (size_t x = 0; x < 100000; x++)
|
||||
{
|
||||
double val = get();
|
||||
|
||||
const double nval = -val;
|
||||
if (!test_float_read_write_equal(val))
|
||||
return FALSE;
|
||||
if (!test_float_read_write_equal(nval))
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int TestEncodedTypes(int argc, char* argv[])
|
||||
{
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
if (!test_signed_integers())
|
||||
return -1;
|
||||
if (!test_floats())
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
132
third_party/FreeRDP/libfreerdp/utils/test/TestPodArrays.c
vendored
Normal file
132
third_party/FreeRDP/libfreerdp/utils/test/TestPodArrays.c
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* TestPodArrays
|
||||
*
|
||||
* Copyright 2022 David Fort <contact@hardening-consulting.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.
|
||||
*/
|
||||
#include <freerdp/utils/pod_arrays.h>
|
||||
|
||||
// NOLINTNEXTLINE(readability-non-const-parameter)
|
||||
static BOOL cb_compute_sum(UINT32* v, void* target)
|
||||
{
|
||||
UINT32* ret = (UINT32*)target;
|
||||
*ret += *v;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL cb_stop_at_5(UINT32* v, void* target)
|
||||
{
|
||||
UINT32* ret = (UINT32*)target;
|
||||
*ret += 1;
|
||||
return (*ret != 5);
|
||||
}
|
||||
|
||||
static BOOL cb_set_to_1(UINT32* v, void* target)
|
||||
{
|
||||
*v = 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL cb_reset_after_1(UINT32* v, void* target)
|
||||
{
|
||||
ArrayUINT32* a = (ArrayUINT32*)target;
|
||||
array_uint32_reset(a);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT32 v1;
|
||||
UINT16 v2;
|
||||
} BasicStruct;
|
||||
|
||||
static BOOL cb_basic_struct(BasicStruct* v, void* target)
|
||||
{
|
||||
return (v->v1 == 1) && (v->v2 == 2);
|
||||
}
|
||||
// NOLINTNEXTLINE(bugprone-suspicious-memory-comparison,cert-exp42-c,cert-flp37-c)
|
||||
POD_ARRAYS_IMPL(BasicStruct, basicstruct)
|
||||
|
||||
int TestPodArrays(int argc, char* argv[])
|
||||
{
|
||||
int rc = -1;
|
||||
UINT32 sum = 0;
|
||||
UINT32 foreach_index = 0;
|
||||
ArrayUINT32 uint32s = WINPR_C_ARRAY_INIT;
|
||||
UINT32* ptr = nullptr;
|
||||
const UINT32* cptr = nullptr;
|
||||
ArrayBasicStruct basicStructs = WINPR_C_ARRAY_INIT;
|
||||
BasicStruct basicStruct = { 1, 2 };
|
||||
|
||||
array_uint32_init(&uint32s);
|
||||
array_basicstruct_init(&basicStructs);
|
||||
|
||||
for (UINT32 i = 0; i < 10; i++)
|
||||
if (!array_uint32_append(&uint32s, i))
|
||||
goto fail;
|
||||
|
||||
sum = 0;
|
||||
if (!array_uint32_foreach(&uint32s, cb_compute_sum, &sum))
|
||||
goto fail;
|
||||
|
||||
if (sum != 45)
|
||||
goto fail;
|
||||
|
||||
foreach_index = 0;
|
||||
if (array_uint32_foreach(&uint32s, cb_stop_at_5, &foreach_index))
|
||||
goto fail;
|
||||
|
||||
if (foreach_index != 5)
|
||||
goto fail;
|
||||
|
||||
if (array_uint32_get(&uint32s, 4) != 4)
|
||||
goto fail;
|
||||
|
||||
array_uint32_set(&uint32s, 4, 5);
|
||||
if (array_uint32_get(&uint32s, 4) != 5)
|
||||
goto fail;
|
||||
|
||||
ptr = array_uint32_data(&uint32s);
|
||||
if (*ptr != 0)
|
||||
goto fail;
|
||||
|
||||
cptr = array_uint32_cdata(&uint32s);
|
||||
if (*cptr != 0)
|
||||
goto fail;
|
||||
|
||||
/* test modifying values of the array during the foreach */
|
||||
if (!array_uint32_foreach(&uint32s, cb_set_to_1, nullptr) || array_uint32_get(&uint32s, 5) != 1)
|
||||
goto fail;
|
||||
|
||||
/* this one is to test that we can modify the array itself during the foreach and that things
|
||||
* go nicely */
|
||||
if (!array_uint32_foreach(&uint32s, cb_reset_after_1, &uint32s) || array_uint32_size(&uint32s))
|
||||
goto fail;
|
||||
|
||||
/* give a try with an array of BasicStructs */
|
||||
if (!array_basicstruct_append(&basicStructs, basicStruct))
|
||||
goto fail;
|
||||
|
||||
if (!array_basicstruct_foreach(&basicStructs, cb_basic_struct, nullptr))
|
||||
goto fail;
|
||||
|
||||
rc = 0;
|
||||
|
||||
fail:
|
||||
array_uint32_uninit(&uint32s);
|
||||
array_basicstruct_uninit(&basicStructs);
|
||||
|
||||
return rc;
|
||||
}
|
||||
227
third_party/FreeRDP/libfreerdp/utils/test/TestRingBuffer.c
vendored
Normal file
227
third_party/FreeRDP/libfreerdp/utils/test/TestRingBuffer.c
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Thincast Technologies GmbH
|
||||
* Copyright 2014 Hardening <contact@hardening-consulting.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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <freerdp/utils/ringbuffer.h>
|
||||
|
||||
static BOOL test_overlaps(void)
|
||||
{
|
||||
RingBuffer rb;
|
||||
DataChunk chunks[2];
|
||||
BYTE bytes[200];
|
||||
int nchunks = 0;
|
||||
int counter = 0;
|
||||
|
||||
for (size_t i = 0; i < sizeof(bytes); i++)
|
||||
bytes[i] = (BYTE)i;
|
||||
|
||||
ringbuffer_init(&rb, 5);
|
||||
if (!ringbuffer_write(&rb, bytes, 4)) /* [0123.] */
|
||||
goto error;
|
||||
counter += 4;
|
||||
ringbuffer_commit_read_bytes(&rb, 2); /* [..23.] */
|
||||
|
||||
if (!ringbuffer_write(&rb, &bytes[counter], 2)) /* [5.234] */
|
||||
goto error;
|
||||
counter += 2;
|
||||
|
||||
nchunks = ringbuffer_peek(&rb, chunks, 4);
|
||||
if (nchunks != 2 || chunks[0].size != 3 || chunks[1].size != 1)
|
||||
goto error;
|
||||
|
||||
for (int x = 0, j = 2; x < nchunks; x++)
|
||||
{
|
||||
for (size_t k = 0; k < chunks[x].size; k++, j++)
|
||||
{
|
||||
if (chunks[x].data[k] != (BYTE)j)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
ringbuffer_commit_read_bytes(&rb, 3); /* [5....] */
|
||||
if (ringbuffer_used(&rb) != 1)
|
||||
goto error;
|
||||
|
||||
if (!ringbuffer_write(&rb, &bytes[counter], 6)) /* [56789ab....] */
|
||||
goto error;
|
||||
|
||||
ringbuffer_commit_read_bytes(&rb, 6); /* [......b....] */
|
||||
nchunks = ringbuffer_peek(&rb, chunks, 10);
|
||||
if (nchunks != 1 || chunks[0].size != 1 || (*chunks[0].data != 0xb))
|
||||
goto error;
|
||||
|
||||
if (ringbuffer_capacity(&rb) != 5)
|
||||
goto error;
|
||||
|
||||
ringbuffer_destroy(&rb);
|
||||
return TRUE;
|
||||
error:
|
||||
ringbuffer_destroy(&rb);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int TestRingBuffer(int argc, char* argv[])
|
||||
{
|
||||
RingBuffer ringBuffer;
|
||||
int testNo = 0;
|
||||
BYTE* tmpBuf = nullptr;
|
||||
BYTE* rb_ptr = nullptr;
|
||||
DataChunk chunks[2];
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
if (!ringbuffer_init(&ringBuffer, 10))
|
||||
{
|
||||
(void)fprintf(stderr, "unable to initialize ringbuffer\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmpBuf = (BYTE*)malloc(50);
|
||||
if (!tmpBuf)
|
||||
return -1;
|
||||
|
||||
for (int i = 0; i < 50; i++)
|
||||
tmpBuf[i] = (char)i;
|
||||
|
||||
(void)fprintf(stderr, "%d: basic tests...", ++testNo);
|
||||
if (!ringbuffer_write(&ringBuffer, tmpBuf, 5) || !ringbuffer_write(&ringBuffer, tmpBuf, 5) ||
|
||||
!ringbuffer_write(&ringBuffer, tmpBuf, 5))
|
||||
{
|
||||
(void)fprintf(stderr, "error when writing bytes\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ringbuffer_used(&ringBuffer) != 15)
|
||||
{
|
||||
(void)fprintf(stderr, "invalid used size got %" PRIuz " when I would expect 15\n",
|
||||
ringbuffer_used(&ringBuffer));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ringbuffer_peek(&ringBuffer, chunks, 10) != 1 || chunks[0].size != 10)
|
||||
{
|
||||
(void)fprintf(stderr, "error when reading bytes\n");
|
||||
return -1;
|
||||
}
|
||||
ringbuffer_commit_read_bytes(&ringBuffer, chunks[0].size);
|
||||
|
||||
/* check retrieved bytes */
|
||||
for (size_t i = 0; i < chunks[0].size; i++)
|
||||
{
|
||||
if (chunks[0].data[i] != i % 5)
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"invalid byte at %" PRIuz ", got %" PRIu8 " instead of %" PRIuz "\n", i,
|
||||
chunks[0].data[i], i % 5U);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ringbuffer_used(&ringBuffer) != 5)
|
||||
{
|
||||
(void)fprintf(stderr, "invalid used size after read got %" PRIuz " when I would expect 5\n",
|
||||
ringbuffer_used(&ringBuffer));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* write some more bytes to have writePtr < readPtr and data split in 2 chunks */
|
||||
if (!ringbuffer_write(&ringBuffer, tmpBuf, 6) ||
|
||||
ringbuffer_peek(&ringBuffer, chunks, 11) != 2 || chunks[0].size != 10 ||
|
||||
chunks[1].size != 1)
|
||||
{
|
||||
(void)fprintf(stderr, "invalid read of split data\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ringbuffer_commit_read_bytes(&ringBuffer, 11);
|
||||
(void)fprintf(stderr, "ok\n");
|
||||
|
||||
(void)fprintf(stderr, "%d: peek with nothing to read...", ++testNo);
|
||||
if (ringbuffer_peek(&ringBuffer, chunks, 10))
|
||||
{
|
||||
(void)fprintf(stderr, "peek returns some chunks\n");
|
||||
return -1;
|
||||
}
|
||||
(void)fprintf(stderr, "ok\n");
|
||||
|
||||
(void)fprintf(stderr, "%d: ensure_linear_write / read() shouldn't grow...", ++testNo);
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
rb_ptr = ringbuffer_ensure_linear_write(&ringBuffer, 50);
|
||||
if (!rb_ptr)
|
||||
{
|
||||
(void)fprintf(stderr, "ringbuffer_ensure_linear_write() error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(rb_ptr, tmpBuf, 50);
|
||||
|
||||
if (!ringbuffer_commit_written_bytes(&ringBuffer, 50))
|
||||
{
|
||||
(void)fprintf(stderr, "ringbuffer_commit_written_bytes() error, i=%d\n", i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ringbuffer_commit_read_bytes(&ringBuffer, 25);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 1000; i++)
|
||||
ringbuffer_commit_read_bytes(&ringBuffer, 25);
|
||||
|
||||
for (int i = 0; i < 1000; i++)
|
||||
ringbuffer_commit_read_bytes(&ringBuffer, 25);
|
||||
|
||||
if (ringbuffer_capacity(&ringBuffer) != 10)
|
||||
{
|
||||
(void)fprintf(stderr, "not the expected capacity, have %" PRIuz " and expects 10\n",
|
||||
ringbuffer_capacity(&ringBuffer));
|
||||
return -1;
|
||||
}
|
||||
(void)fprintf(stderr, "ok\n");
|
||||
|
||||
(void)fprintf(stderr, "%d: free size is correctly computed...", ++testNo);
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
ringbuffer_ensure_linear_write(&ringBuffer, 50);
|
||||
if (!ringbuffer_commit_written_bytes(&ringBuffer, 50))
|
||||
{
|
||||
(void)fprintf(stderr, "ringbuffer_commit_written_bytes() error, i=%d\n", i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
ringbuffer_commit_read_bytes(&ringBuffer, 50ULL * 1000ULL);
|
||||
(void)fprintf(stderr, "ok\n");
|
||||
|
||||
ringbuffer_destroy(&ringBuffer);
|
||||
|
||||
(void)fprintf(stderr, "%d: specific overlaps test...", ++testNo);
|
||||
if (!test_overlaps())
|
||||
{
|
||||
(void)fprintf(stderr, "ko\n");
|
||||
return -1;
|
||||
}
|
||||
(void)fprintf(stderr, "ok\n");
|
||||
|
||||
ringbuffer_destroy(&ringBuffer);
|
||||
free(tmpBuf);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user