summaryrefslogtreecommitdiffstats
path: root/libfreerdp/utils
diff options
context:
space:
mode:
Diffstat (limited to 'libfreerdp/utils')
-rw-r--r--libfreerdp/utils/CMakeLists.txt4
-rw-r--r--libfreerdp/utils/encoded_types.c214
-rw-r--r--libfreerdp/utils/http.c6
-rw-r--r--libfreerdp/utils/pcap.c30
-rw-r--r--libfreerdp/utils/stopwatch.c28
-rw-r--r--libfreerdp/utils/test/CMakeLists.txt6
-rw-r--r--libfreerdp/utils/test/TestEncodedTypes.c212
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;
+}