diff options
Diffstat (limited to 'libfreerdp/utils')
-rw-r--r-- | libfreerdp/utils/CMakeLists.txt | 4 | ||||
-rw-r--r-- | libfreerdp/utils/encoded_types.c | 214 | ||||
-rw-r--r-- | libfreerdp/utils/http.c | 6 | ||||
-rw-r--r-- | libfreerdp/utils/pcap.c | 30 | ||||
-rw-r--r-- | libfreerdp/utils/stopwatch.c | 28 | ||||
-rw-r--r-- | libfreerdp/utils/test/CMakeLists.txt | 6 | ||||
-rw-r--r-- | libfreerdp/utils/test/TestEncodedTypes.c | 212 |
7 files changed, 447 insertions, 53 deletions
diff --git a/libfreerdp/utils/CMakeLists.txt b/libfreerdp/utils/CMakeLists.txt index 52690bf..d644837 100644 --- a/libfreerdp/utils/CMakeLists.txt +++ b/libfreerdp/utils/CMakeLists.txt @@ -47,10 +47,6 @@ if(WIN32) freerdp_library_add(cfgmgr32) endif() -if(${CMAKE_SYSTEM_NAME} MATCHES SunOS) - freerdp_library_add(rt) -endif() - if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/libfreerdp/utils/encoded_types.c b/libfreerdp/utils/encoded_types.c index 68e6e4d..efce694 100644 --- a/libfreerdp/utils/encoded_types.c +++ b/libfreerdp/utils/encoded_types.c @@ -123,8 +123,95 @@ BOOL freerdp_read_four_byte_signed_integer(wStream* s, INT32* value) return TRUE; } +BOOL freerdp_write_four_byte_signed_integer(wStream* s, INT32 value) +{ + FOUR_BYTE_SIGNED_INTEGER si = { 0 }; + + 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, NULL); +} + +BOOL freerdp_read_four_byte_float_exp(wStream* s, double* value, BYTE* exp) +{ FOUR_BYTE_FLOAT f = { 0 }; UINT32 base = 0; BYTE byte = 0; @@ -183,5 +270,132 @@ BOOL freerdp_read_four_byte_float(wStream* s, double* value) 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 = { 0 }; + + 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 = 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 %ld", 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; } diff --git a/libfreerdp/utils/http.c b/libfreerdp/utils/http.c index 70963f0..5c34439 100644 --- a/libfreerdp/utils/http.c +++ b/libfreerdp/utils/http.c @@ -126,12 +126,18 @@ BOOL freerdp_http_request(const char* url, const char* body, long* status_code, { 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()); diff --git a/libfreerdp/utils/pcap.c b/libfreerdp/utils/pcap.c index db50909..c18caf2 100644 --- a/libfreerdp/utils/pcap.c +++ b/libfreerdp/utils/pcap.c @@ -27,27 +27,11 @@ #include <winpr/assert.h> #include <winpr/file.h> #include <winpr/crt.h> +#include <winpr/sysinfo.h> #include <freerdp/log.h> #define TAG FREERDP_TAG("utils") -#ifndef _WIN32 -#include <sys/time.h> -#else -#include <time.h> -#include <sys/timeb.h> -#include <winpr/windows.h> - -int gettimeofday(struct timeval* tp, void* tz) -{ - struct _timeb timebuffer; - _ftime(&timebuffer); - tp->tv_sec = (long)timebuffer.time; - tp->tv_usec = timebuffer.millitm * 1000; - return 0; -} -#endif - #include <freerdp/types.h> #include <freerdp/utils/pcap.h> @@ -131,14 +115,11 @@ static BOOL pcap_write_record(rdpPcap* pcap, const pcap_record* record) BOOL pcap_add_record(rdpPcap* pcap, const void* data, size_t length) { - pcap_record* record = NULL; - struct timeval tp; - WINPR_ASSERT(pcap); WINPR_ASSERT(data || (length == 0)); WINPR_ASSERT(length <= UINT32_MAX); - record = (pcap_record*)calloc(1, sizeof(pcap_record)); + pcap_record* record = (pcap_record*)calloc(1, sizeof(pcap_record)); if (!record) return FALSE; @@ -147,9 +128,10 @@ BOOL pcap_add_record(rdpPcap* pcap, const void* data, size_t length) record->header.incl_len = (UINT32)length; record->header.orig_len = (UINT32)length; - gettimeofday(&tp, 0); - record->header.ts_sec = (UINT32)tp.tv_sec; - record->header.ts_usec = (UINT32)tp.tv_usec; + const UINT64 ns = winpr_GetUnixTimeNS(); + + record->header.ts_sec = WINPR_TIME_NS_TO_S(ns); + record->header.ts_usec = WINPR_TIME_NS_REM_US(ns); if (pcap->tail == NULL) { diff --git a/libfreerdp/utils/stopwatch.c b/libfreerdp/utils/stopwatch.c index 3989638..70b60b3 100644 --- a/libfreerdp/utils/stopwatch.c +++ b/libfreerdp/utils/stopwatch.c @@ -22,38 +22,18 @@ #include <stdio.h> #include <stdlib.h> +#include <winpr/sysinfo.h> #include <freerdp/utils/stopwatch.h> -#ifdef _WIN32 -LARGE_INTEGER stopwatch_freq = { 0 }; -#else -#include <sys/time.h> -#endif - static void stopwatch_set_time(UINT64* usecs) { -#ifdef _WIN32 - LARGE_INTEGER perfcount; - QueryPerformanceCounter(&perfcount); - *usecs = (perfcount.QuadPart * 1000000) / stopwatch_freq.QuadPart; -#else - struct timeval tv; - gettimeofday(&tv, NULL); - *usecs = tv.tv_sec * 1000000 + tv.tv_usec; -#endif + const UINT64 ns = winpr_GetTickCount64NS(); + *usecs = WINPR_TIME_NS_TO_US(ns); } STOPWATCH* stopwatch_create(void) { - STOPWATCH* sw = NULL; -#ifdef _WIN32 - if (stopwatch_freq.QuadPart == 0) - { - QueryPerformanceFrequency(&stopwatch_freq); - } -#endif - - sw = (STOPWATCH*)malloc(sizeof(STOPWATCH)); + STOPWATCH* sw = (STOPWATCH*)calloc(1, sizeof(STOPWATCH)); if (!sw) return NULL; stopwatch_reset(sw); diff --git a/libfreerdp/utils/test/CMakeLists.txt b/libfreerdp/utils/test/CMakeLists.txt index f2b6977..a7a84fc 100644 --- a/libfreerdp/utils/test/CMakeLists.txt +++ b/libfreerdp/utils/test/CMakeLists.txt @@ -7,6 +7,7 @@ set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) set(${MODULE_PREFIX}_TESTS TestRingBuffer.c TestPodArrays.c + TestEncodedTypes.c ) create_test_sourcelist(${MODULE_PREFIX}_SRCS @@ -15,7 +16,10 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -target_link_libraries(${MODULE_NAME} freerdp winpr) +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}") diff --git a/libfreerdp/utils/test/TestEncodedTypes.c b/libfreerdp/utils/test/TestEncodedTypes.c new file mode 100644 index 0000000..f051d9c --- /dev/null +++ b/libfreerdp/utils/test/TestEncodedTypes.c @@ -0,0 +1,212 @@ +/** + * 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> + +#define MIN(x, y) ((x) < (y)) ? (x) : (y) +#define MAX(x, y) ((x) > (y)) ? (x) : (y) + +static BOOL test_signed_integer_read_write_equal(INT32 value) +{ + INT32 rvalue = 0; + BYTE buffer[32] = { 0 }; + wStream sbuffer = { 0 }; + wStream* s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer)); + WINPR_ASSERT(s); + + if (!freerdp_write_four_byte_signed_integer(s, value)) + { + fprintf(stderr, "[%s(%" PRId32 ")] failed to write to stream\n", __func__, value); + return FALSE; + } + if (!Stream_SetPosition(s, 0)) + { + fprintf(stderr, "[%s(%" PRId32 ")] failed to reset stream position\n", __func__, value); + return FALSE; + } + if (!freerdp_read_four_byte_signed_integer(s, &rvalue)) + { + fprintf(stderr, "[%s(%" PRId32 ")] failed to read from stream\n", __func__, value); + return FALSE; + } + if (value != rvalue) + { + 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] = { 0 }; + wStream sbuffer = { 0 }; + wStream* s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer)); + WINPR_ASSERT(s); + + if (freerdp_write_four_byte_signed_integer(s, value)) + { + 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; + winpr_RAND(&val, sizeof(val)); + 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] = { 0 }; + wStream sbuffer = { 0 }; + wStream* s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer)); + WINPR_ASSERT(s); + + if (!freerdp_write_four_byte_float(s, value)) + { + fprintf(stderr, "[%s(%lf)] failed to write to stream\n", __func__, value); + return FALSE; + } + if (!Stream_SetPosition(s, 0)) + { + fprintf(stderr, "[%s(%lf)] failed to reset stream position\n", __func__, value); + return FALSE; + } + if (!freerdp_read_four_byte_float_exp(s, &rvalue, &exp)) + { + fprintf(stderr, "[%s(%lf)] failed to read from stream\n", __func__, value); + return FALSE; + } + const double diff = fabs(value - rvalue); + const UINT64 expdiff = diff * pow(10, exp); + if (expdiff > 0) + { + 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] = { 0 }; + wStream sbuffer = { 0 }; + wStream* s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer)); + WINPR_ASSERT(s); + + if (freerdp_write_four_byte_float(s, value)) + { + 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 + { + winpr_RAND(&val, sizeof(val)); + } 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; +} |