Improved streamdump file format
This commit is contained in:
parent
2a6950f366
commit
60720e7706
@ -395,7 +395,7 @@ int main(int argc, char* argv[])
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stream_dump_register_handlers(context, CONNECTION_STATE_MCS_CONNECT))
|
if (!stream_dump_register_handlers(context, CONNECTION_STATE_MCS_CONNECT, FALSE))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (freerdp_client_start(context) != 0)
|
if (freerdp_client_start(context) != 0)
|
||||||
|
@ -65,7 +65,7 @@ int main(int argc, char* argv[])
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stream_dump_register_handlers(context, CONNECTION_STATE_MCS_CONNECT))
|
if (!stream_dump_register_handlers(context, CONNECTION_STATE_MCS_CONNECT, FALSE))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (freerdp_client_start(context) != 0)
|
if (freerdp_client_start(context) != 0)
|
||||||
|
@ -2374,6 +2374,42 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
|
|||||||
{
|
{
|
||||||
settings->RedirectDrives = enable;
|
settings->RedirectDrives = enable;
|
||||||
}
|
}
|
||||||
|
CommandLineSwitchCase(arg, "dump")
|
||||||
|
{
|
||||||
|
BOOL failed = FALSE;
|
||||||
|
size_t count = 0;
|
||||||
|
char** args = CommandLineParseCommaSeparatedValues(arg->Value, &count);
|
||||||
|
if (!args || (count != 2))
|
||||||
|
failed = TRUE;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!freerdp_settings_set_string(settings, FreeRDP_TransportDumpFile, args[1]))
|
||||||
|
failed = TRUE;
|
||||||
|
else if (strcmp(args[0], "replay") == 0)
|
||||||
|
{
|
||||||
|
if (!freerdp_settings_set_bool(settings, FreeRDP_TransportDump, FALSE))
|
||||||
|
failed = TRUE;
|
||||||
|
else if (!freerdp_settings_set_bool(settings, FreeRDP_TransportDumpReplay,
|
||||||
|
TRUE))
|
||||||
|
failed = TRUE;
|
||||||
|
}
|
||||||
|
else if (strcmp(args[0], "record") == 0)
|
||||||
|
{
|
||||||
|
if (!freerdp_settings_set_bool(settings, FreeRDP_TransportDump, TRUE))
|
||||||
|
failed = TRUE;
|
||||||
|
else if (!freerdp_settings_set_bool(settings, FreeRDP_TransportDumpReplay,
|
||||||
|
FALSE))
|
||||||
|
failed = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
failed = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(args);
|
||||||
|
if (failed)
|
||||||
|
return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
|
||||||
|
}
|
||||||
CommandLineSwitchCase(arg, "disable-output")
|
CommandLineSwitchCase(arg, "disable-output")
|
||||||
{
|
{
|
||||||
freerdp_settings_set_bool(settings, FreeRDP_DeactivateClientDecoding, enable);
|
freerdp_settings_set_bool(settings, FreeRDP_DeactivateClientDecoding, enable);
|
||||||
|
@ -125,6 +125,8 @@ static const COMMAND_LINE_ARGUMENT_A global_cmd_args[] = {
|
|||||||
"later\" option in MSTSC." },
|
"later\" option in MSTSC." },
|
||||||
{ "drives", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL,
|
{ "drives", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL,
|
||||||
"Redirect all mount points as shares" },
|
"Redirect all mount points as shares" },
|
||||||
|
{ "dump", COMMAND_LINE_VALUE_REQUIRED, "<record|replay>,<file>", NULL, NULL, -1, NULL,
|
||||||
|
"record or replay dump" },
|
||||||
{ "dvc", COMMAND_LINE_VALUE_REQUIRED, "<channel>[,<options>]", NULL, NULL, -1, NULL,
|
{ "dvc", COMMAND_LINE_VALUE_REQUIRED, "<channel>[,<options>]", NULL, NULL, -1, NULL,
|
||||||
"Dynamic virtual channel" },
|
"Dynamic virtual channel" },
|
||||||
{ "dynamic-resolution", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL,
|
{ "dynamic-resolution", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL,
|
||||||
|
@ -34,15 +34,19 @@ extern "C"
|
|||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FREERDP_API BOOL stream_dump_read_line(FILE* fp, wStream* s, UINT64* pts, size_t* pOffset);
|
typedef enum
|
||||||
FREERDP_API BOOL stream_dump_write_line(FILE* fp, wStream* s);
|
{
|
||||||
|
STREAM_MSG_SRV_RX = 1,
|
||||||
|
STREAM_MSG_SRV_TX = 2
|
||||||
|
} StreamDumpDirection;
|
||||||
|
|
||||||
FREERDP_API SSIZE_T stream_dump_append(const rdpContext* context, const char* name, wStream* s,
|
FREERDP_API SSIZE_T stream_dump_append(const rdpContext* context, UINT32 flags, wStream* s,
|
||||||
size_t* offset);
|
size_t* offset);
|
||||||
FREERDP_API SSIZE_T stream_dump_get(const rdpContext* context, const char* name, wStream* s,
|
FREERDP_API SSIZE_T stream_dump_get(const rdpContext* context, UINT32* flags, wStream* s,
|
||||||
size_t* offset, UINT64* pts);
|
size_t* offset, UINT64* pts);
|
||||||
|
|
||||||
FREERDP_API BOOL stream_dump_register_handlers(rdpContext* context, CONNECTION_STATE state);
|
FREERDP_API BOOL stream_dump_register_handlers(rdpContext* context, CONNECTION_STATE state,
|
||||||
|
BOOL isServer);
|
||||||
|
|
||||||
FREERDP_API rdpStreamDumpContext* stream_dump_new(void);
|
FREERDP_API rdpStreamDumpContext* stream_dump_new(void);
|
||||||
FREERDP_API void stream_dump_free(rdpStreamDumpContext* dump);
|
FREERDP_API void stream_dump_free(rdpStreamDumpContext* dump);
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
/**
|
/**
|
||||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
* Static Virtual Channel Interface
|
|
||||||
*
|
*
|
||||||
* Copyright 2021 Armin Novak
|
* RDP session stream dump interface
|
||||||
* Copyright 2021 Thincast Technologies GmbH
|
*
|
||||||
|
* Copyright 2022 Armin Novak
|
||||||
|
* Copyright 2022 Thincast Technologies GmbH
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -27,6 +28,8 @@
|
|||||||
#include <freerdp/streamdump.h>
|
#include <freerdp/streamdump.h>
|
||||||
#include <freerdp/transport_io.h>
|
#include <freerdp/transport_io.h>
|
||||||
|
|
||||||
|
#include "streamdump.h"
|
||||||
|
|
||||||
struct stream_dump_context
|
struct stream_dump_context
|
||||||
{
|
{
|
||||||
rdpTransportIo io;
|
rdpTransportIo io;
|
||||||
@ -35,16 +38,41 @@ struct stream_dump_context
|
|||||||
size_t replayOffset;
|
size_t replayOffset;
|
||||||
UINT64 replayTime;
|
UINT64 replayTime;
|
||||||
CONNECTION_STATE state;
|
CONNECTION_STATE state;
|
||||||
|
BOOL isServer;
|
||||||
};
|
};
|
||||||
|
|
||||||
BOOL stream_dump_read_line(FILE* fp, wStream* s, UINT64* pts, size_t* pOffset)
|
static UINT32 crc32b(const BYTE* data, size_t length)
|
||||||
|
{
|
||||||
|
size_t x;
|
||||||
|
UINT32 crc = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
for (x = 0; x < length; x++)
|
||||||
|
{
|
||||||
|
const UINT32 d = data[x] & 0xFF;
|
||||||
|
crc = crc ^ d;
|
||||||
|
for (int j = 7; j >= 0; j--)
|
||||||
|
{
|
||||||
|
UINT32 mask = -(crc & 1);
|
||||||
|
crc = (crc >> 1) ^ (0xEDB88320 & mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ~crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(BUILD_TESTING)
|
||||||
|
static
|
||||||
|
#endif
|
||||||
|
BOOL
|
||||||
|
stream_dump_read_line(FILE* fp, wStream* s, UINT64* pts, size_t* pOffset, UINT32* flags)
|
||||||
{
|
{
|
||||||
BOOL rc = FALSE;
|
BOOL rc = FALSE;
|
||||||
UINT64 ts;
|
UINT64 ts;
|
||||||
UINT64 size = 0;
|
UINT64 size = 0;
|
||||||
size_t r;
|
size_t r;
|
||||||
|
UINT32 crc32;
|
||||||
|
BYTE received;
|
||||||
|
|
||||||
if (!fp || !s)
|
if (!fp || !s || !flags)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (pOffset)
|
if (pOffset)
|
||||||
@ -53,14 +81,26 @@ BOOL stream_dump_read_line(FILE* fp, wStream* s, UINT64* pts, size_t* pOffset)
|
|||||||
r = fread(&ts, 1, sizeof(ts), fp);
|
r = fread(&ts, 1, sizeof(ts), fp);
|
||||||
if (r != sizeof(ts))
|
if (r != sizeof(ts))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
r = fread(&received, 1, sizeof(received), fp);
|
||||||
|
if (r != sizeof(received))
|
||||||
|
goto fail;
|
||||||
|
r = fread(&crc32, 1, sizeof(crc32), fp);
|
||||||
|
if (r != sizeof(crc32))
|
||||||
|
goto fail;
|
||||||
r = fread(&size, 1, sizeof(size), fp);
|
r = fread(&size, 1, sizeof(size), fp);
|
||||||
if (r != sizeof(size))
|
if (r != sizeof(size))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
if (received)
|
||||||
|
*flags = STREAM_MSG_SRV_RX;
|
||||||
|
else
|
||||||
|
*flags = STREAM_MSG_SRV_TX;
|
||||||
if (!Stream_EnsureRemainingCapacity(s, size))
|
if (!Stream_EnsureRemainingCapacity(s, size))
|
||||||
goto fail;
|
goto fail;
|
||||||
r = fread(Stream_Pointer(s), 1, size, fp);
|
r = fread(Stream_Pointer(s), 1, size, fp);
|
||||||
if (r != size)
|
if (r != size)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
if (crc32 != crc32b(Stream_Pointer(s), size))
|
||||||
|
goto fail;
|
||||||
Stream_Seek(s, size);
|
Stream_Seek(s, size);
|
||||||
|
|
||||||
if (pOffset)
|
if (pOffset)
|
||||||
@ -80,7 +120,11 @@ fail:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL stream_dump_write_line(FILE* fp, wStream* s)
|
#if !defined(BUILD_TESTING)
|
||||||
|
static
|
||||||
|
#endif
|
||||||
|
BOOL
|
||||||
|
stream_dump_write_line(FILE* fp, UINT32 flags, wStream* s)
|
||||||
{
|
{
|
||||||
BOOL rc = FALSE;
|
BOOL rc = FALSE;
|
||||||
const UINT64 t = GetTickCount64();
|
const UINT64 t = GetTickCount64();
|
||||||
@ -91,9 +135,17 @@ BOOL stream_dump_write_line(FILE* fp, wStream* s)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
const UINT32 crc32 = crc32b(data, size);
|
||||||
|
const BYTE received = flags & STREAM_MSG_SRV_RX;
|
||||||
size_t r = fwrite(&t, 1, sizeof(t), fp);
|
size_t r = fwrite(&t, 1, sizeof(t), fp);
|
||||||
if (r != sizeof(t))
|
if (r != sizeof(t))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
r = fwrite(&received, 1, sizeof(received), fp);
|
||||||
|
if (r != sizeof(received))
|
||||||
|
goto fail;
|
||||||
|
r = fwrite(&crc32, 1, sizeof(crc32), fp);
|
||||||
|
if (r != sizeof(crc32))
|
||||||
|
goto fail;
|
||||||
r = fwrite(&size, 1, sizeof(size), fp);
|
r = fwrite(&size, 1, sizeof(size), fp);
|
||||||
if (r != sizeof(size))
|
if (r != sizeof(size))
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -107,10 +159,9 @@ fail:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FILE* stream_dump_get_file(const rdpSettings* settings, const char* name, const char* mode)
|
static FILE* stream_dump_get_file(const rdpSettings* settings, const char* mode)
|
||||||
{
|
{
|
||||||
const char* cfolder;
|
const char* cfolder;
|
||||||
char* folder = NULL;
|
|
||||||
char* file = NULL;
|
char* file = NULL;
|
||||||
FILE* fp = NULL;
|
FILE* fp = NULL;
|
||||||
|
|
||||||
@ -119,58 +170,40 @@ static FILE* stream_dump_get_file(const rdpSettings* settings, const char* name,
|
|||||||
|
|
||||||
cfolder = freerdp_settings_get_string(settings, FreeRDP_TransportDumpFile);
|
cfolder = freerdp_settings_get_string(settings, FreeRDP_TransportDumpFile);
|
||||||
if (!cfolder)
|
if (!cfolder)
|
||||||
folder = GetKnownSubPath(KNOWN_PATH_TEMP, "freerdp-transport-dump");
|
file = GetKnownSubPath(KNOWN_PATH_TEMP, "freerdp-transport-dump");
|
||||||
else
|
else
|
||||||
folder = _strdup(cfolder);
|
file = _strdup(cfolder);
|
||||||
|
|
||||||
if (!folder)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
if (name)
|
|
||||||
{
|
|
||||||
char buffer[8192] = { 0 };
|
|
||||||
int rc = _snprintf(buffer, sizeof(buffer), "%s.dump", name);
|
|
||||||
if ((rc <= 0) || ((size_t)rc >= sizeof(buffer)))
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
if (!winpr_PathFileExists(folder))
|
|
||||||
{
|
|
||||||
if (!winpr_PathMakePath(folder, NULL))
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
file = GetCombinedPath(folder, buffer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!winpr_PathFileExists(folder))
|
|
||||||
goto fail;
|
|
||||||
file = _strdup(folder);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!file)
|
if (!file)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
fp = winpr_fopen(file, mode);
|
fp = winpr_fopen(file, mode);
|
||||||
fail:
|
fail:
|
||||||
free(folder);
|
|
||||||
free(file);
|
free(file);
|
||||||
return fp;
|
return fp;
|
||||||
}
|
}
|
||||||
|
|
||||||
SSIZE_T stream_dump_append(const rdpContext* context, const char* name, wStream* s, size_t* offset)
|
SSIZE_T stream_dump_append(const rdpContext* context, UINT32 flags, wStream* s, size_t* offset)
|
||||||
{
|
{
|
||||||
SSIZE_T rc = -1;
|
SSIZE_T rc = -1;
|
||||||
FILE* fp;
|
FILE* fp;
|
||||||
|
const UINT32 mask = STREAM_MSG_SRV_RX | STREAM_MSG_SRV_TX;
|
||||||
CONNECTION_STATE state = freerdp_get_state(context);
|
CONNECTION_STATE state = freerdp_get_state(context);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!context || !s || !offset)
|
if (!context || !s || !offset)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if ((flags & STREAM_MSG_SRV_RX) && (flags & STREAM_MSG_SRV_TX))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((flags & mask) == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (state < context->dump->state)
|
if (state < context->dump->state)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fp = stream_dump_get_file(context->settings, name, "ab");
|
fp = stream_dump_get_file(context->settings, "ab");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -178,7 +211,7 @@ SSIZE_T stream_dump_append(const rdpContext* context, const char* name, wStream*
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (!stream_dump_write_line(fp, s))
|
if (!stream_dump_write_line(fp, flags, s))
|
||||||
goto fail;
|
goto fail;
|
||||||
rc = _ftelli64(fp);
|
rc = _ftelli64(fp);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
@ -189,7 +222,7 @@ fail:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
SSIZE_T stream_dump_get(const rdpContext* context, const char* name, wStream* s, size_t* offset,
|
SSIZE_T stream_dump_get(const rdpContext* context, UINT32* flags, wStream* s, size_t* offset,
|
||||||
UINT64* pts)
|
UINT64* pts)
|
||||||
{
|
{
|
||||||
SSIZE_T rc = -1;
|
SSIZE_T rc = -1;
|
||||||
@ -198,14 +231,14 @@ SSIZE_T stream_dump_get(const rdpContext* context, const char* name, wStream* s,
|
|||||||
|
|
||||||
if (!context || !s || !offset)
|
if (!context || !s || !offset)
|
||||||
return -1;
|
return -1;
|
||||||
fp = stream_dump_get_file(context->settings, name, "rb");
|
fp = stream_dump_get_file(context->settings, "rb");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return -1;
|
return -1;
|
||||||
r = _fseeki64(fp, *offset, SEEK_SET);
|
r = _fseeki64(fp, *offset, SEEK_SET);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (!stream_dump_read_line(fp, s, pts, offset))
|
if (!stream_dump_read_line(fp, s, pts, offset, flags))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
rc = _ftelli64(fp);
|
rc = _ftelli64(fp);
|
||||||
@ -223,7 +256,8 @@ static int stream_dump_transport_write(rdpTransport* transport, wStream* s)
|
|||||||
WINPR_ASSERT(ctx->dump);
|
WINPR_ASSERT(ctx->dump);
|
||||||
WINPR_ASSERT(s);
|
WINPR_ASSERT(s);
|
||||||
|
|
||||||
r = stream_dump_append(ctx, "write", s, &ctx->dump->writeDumpOffset);
|
r = stream_dump_append(ctx, ctx->dump->isServer ? STREAM_MSG_SRV_TX : STREAM_MSG_SRV_RX, s,
|
||||||
|
&ctx->dump->writeDumpOffset);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -244,7 +278,9 @@ static int stream_dump_transport_read(rdpTransport* transport, wStream* s)
|
|||||||
rc = ctx->dump->io.ReadPdu(transport, s);
|
rc = ctx->dump->io.ReadPdu(transport, s);
|
||||||
if (rc > 0)
|
if (rc > 0)
|
||||||
{
|
{
|
||||||
SSIZE_T r = stream_dump_append(ctx, "read", s, &ctx->dump->readDumpOffset);
|
SSIZE_T r =
|
||||||
|
stream_dump_append(ctx, ctx->dump->isServer ? STREAM_MSG_SRV_RX : STREAM_MSG_SRV_TX, s,
|
||||||
|
&ctx->dump->readDumpOffset);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -295,13 +331,17 @@ static int stream_dump_replay_transport_read(rdpTransport* transport, wStream* s
|
|||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
time_t slp = 0;
|
time_t slp = 0;
|
||||||
UINT64 ts = 0;
|
UINT64 ts = 0;
|
||||||
|
UINT32 flags = 0;
|
||||||
|
|
||||||
WINPR_ASSERT(ctx);
|
WINPR_ASSERT(ctx);
|
||||||
WINPR_ASSERT(ctx->dump);
|
WINPR_ASSERT(ctx->dump);
|
||||||
WINPR_ASSERT(s);
|
WINPR_ASSERT(s);
|
||||||
|
|
||||||
if (stream_dump_get(ctx, NULL, s, &ctx->dump->replayOffset, &ts) < 0)
|
do
|
||||||
return -1;
|
{
|
||||||
|
if (stream_dump_get(ctx, &flags, s, &ctx->dump->replayOffset, &ts) < 0)
|
||||||
|
return -1;
|
||||||
|
} while (flags & STREAM_MSG_SRV_RX);
|
||||||
|
|
||||||
if ((ctx->dump->replayTime > 0) && (ts > ctx->dump->replayTime))
|
if ((ctx->dump->replayTime > 0) && (ts > ctx->dump->replayTime))
|
||||||
slp = ts - ctx->dump->replayTime;
|
slp = ts - ctx->dump->replayTime;
|
||||||
@ -368,11 +408,12 @@ static BOOL stream_dump_register_read_handlers(rdpContext* context)
|
|||||||
return freerdp_set_io_callbacks(context, &dump);
|
return freerdp_set_io_callbacks(context, &dump);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL stream_dump_register_handlers(rdpContext* context, CONNECTION_STATE state)
|
BOOL stream_dump_register_handlers(rdpContext* context, CONNECTION_STATE state, BOOL isServer)
|
||||||
{
|
{
|
||||||
WINPR_ASSERT(context);
|
WINPR_ASSERT(context);
|
||||||
WINPR_ASSERT(context->dump);
|
WINPR_ASSERT(context->dump);
|
||||||
context->dump->state = state;
|
context->dump->state = state;
|
||||||
|
context->dump->isServer = isServer;
|
||||||
if (!stream_dump_register_write_handlers(context))
|
if (!stream_dump_register_write_handlers(context))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
return stream_dump_register_read_handlers(context);
|
return stream_dump_register_read_handlers(context);
|
||||||
|
45
libfreerdp/core/streamdump.h
Normal file
45
libfreerdp/core/streamdump.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
|
*
|
||||||
|
* RDP session stream dump interface
|
||||||
|
*
|
||||||
|
* Copyright 2022 Armin Novak
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FREERDP_STREAMDUMP_INTERNAL
|
||||||
|
#define FREERDP_STREAMDUMP_INTERNAL
|
||||||
|
|
||||||
|
#include <freerdp/api.h>
|
||||||
|
#include <winpr/wtypes.h>
|
||||||
|
#include <winpr/stream.h>
|
||||||
|
|
||||||
|
#if !defined(BUILD_TESTING)
|
||||||
|
static
|
||||||
|
#else
|
||||||
|
FREERDP_LOCAL
|
||||||
|
#endif
|
||||||
|
BOOL
|
||||||
|
stream_dump_read_line(FILE* fp, wStream* s, UINT64* pts, size_t* pOffset, UINT32* flags);
|
||||||
|
|
||||||
|
#if !defined(BUILD_TESTING)
|
||||||
|
static
|
||||||
|
#else
|
||||||
|
FREERDP_LOCAL
|
||||||
|
#endif
|
||||||
|
BOOL
|
||||||
|
stream_dump_write_line(FILE* fp, UINT32 flags, wStream* s);
|
||||||
|
|
||||||
|
#endif
|
@ -7,6 +7,8 @@
|
|||||||
#include <freerdp/freerdp.h>
|
#include <freerdp/freerdp.h>
|
||||||
#include <freerdp/streamdump.h>
|
#include <freerdp/streamdump.h>
|
||||||
|
|
||||||
|
#include "../streamdump.h"
|
||||||
|
|
||||||
static BOOL test_entry_read_write(void)
|
static BOOL test_entry_read_write(void)
|
||||||
{
|
{
|
||||||
BOOL rc = FALSE;
|
BOOL rc = FALSE;
|
||||||
@ -14,10 +16,12 @@ static BOOL test_entry_read_write(void)
|
|||||||
wStream *sw = NULL, *sr = NULL;
|
wStream *sw = NULL, *sr = NULL;
|
||||||
size_t offset = 0, x;
|
size_t offset = 0, x;
|
||||||
UINT64 ts = 0;
|
UINT64 ts = 0;
|
||||||
|
UINT32 flags = 0;
|
||||||
BYTE tmp[16] = { 0 };
|
BYTE tmp[16] = { 0 };
|
||||||
char tmp2[64] = { 0 };
|
char tmp2[64] = { 0 };
|
||||||
char* name = NULL;
|
char* name = NULL;
|
||||||
size_t entrysize = sizeof(UINT64) + sizeof(UINT64);
|
size_t entrysize = sizeof(UINT64) /* timestamp */ + sizeof(BYTE) /* direction */ +
|
||||||
|
sizeof(UINT32) /* CRC */ + sizeof(UINT64) /* size */;
|
||||||
|
|
||||||
winpr_RAND(tmp, sizeof(tmp));
|
winpr_RAND(tmp, sizeof(tmp));
|
||||||
|
|
||||||
@ -45,14 +49,14 @@ static BOOL test_entry_read_write(void)
|
|||||||
fp = fopen(name, "wb");
|
fp = fopen(name, "wb");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
goto fail;
|
goto fail;
|
||||||
if (!stream_dump_write_line(fp, sw))
|
if (!stream_dump_write_line(fp, 0, sw))
|
||||||
goto fail;
|
goto fail;
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
fp = fopen(name, "rb");
|
fp = fopen(name, "rb");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
goto fail;
|
goto fail;
|
||||||
if (!stream_dump_read_line(fp, sr, &ts, &offset))
|
if (!stream_dump_read_line(fp, sr, &ts, &offset, &flags))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (entrysize != offset)
|
if (entrysize != offset)
|
||||||
|
@ -923,6 +923,7 @@ static int hook_peer_write_pdu(rdpTransport* transport, wStream* s)
|
|||||||
CONNECTION_STATE state;
|
CONNECTION_STATE state;
|
||||||
testPeerContext* peerCtx;
|
testPeerContext* peerCtx;
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
|
UINT32 flags = 0;
|
||||||
rdpContext* context = transport_get_context(transport);
|
rdpContext* context = transport_get_context(transport);
|
||||||
|
|
||||||
WINPR_ASSERT(context);
|
WINPR_ASSERT(context);
|
||||||
@ -954,18 +955,22 @@ static int hook_peer_write_pdu(rdpTransport* transport, wStream* s)
|
|||||||
if (!ls)
|
if (!ls)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
while (stream_dump_get(context, NULL, ls, &offset, &ts) > 0)
|
while (stream_dump_get(context, &flags, ls, &offset, &ts) > 0)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
if ((last_ts > 0) && (ts > last_ts))
|
/* Skip messages from client. */
|
||||||
|
if (flags & STREAM_MSG_SRV_TX)
|
||||||
{
|
{
|
||||||
UINT64 diff = ts - last_ts;
|
if ((last_ts > 0) && (ts > last_ts))
|
||||||
Sleep(diff);
|
{
|
||||||
|
UINT64 diff = ts - last_ts;
|
||||||
|
Sleep(diff);
|
||||||
|
}
|
||||||
|
last_ts = ts;
|
||||||
|
rc = peerCtx->io.WritePdu(transport, ls);
|
||||||
|
if (rc < 0)
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
last_ts = ts;
|
|
||||||
rc = peerCtx->io.WritePdu(transport, ls);
|
|
||||||
if (rc < 0)
|
|
||||||
goto fail;
|
|
||||||
Stream_SetPosition(ls, 0);
|
Stream_SetPosition(ls, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -542,7 +542,7 @@ static BOOL pf_server_initialize_peer_connection(freerdp_peer* peer)
|
|||||||
pdata->server_receive_channel_data_original = peer->ReceiveChannelData;
|
pdata->server_receive_channel_data_original = peer->ReceiveChannelData;
|
||||||
peer->ReceiveChannelData = pf_server_receive_channel_data_hook;
|
peer->ReceiveChannelData = pf_server_receive_channel_data_hook;
|
||||||
|
|
||||||
if (!stream_dump_register_handlers(peer->context, CONNECTION_STATE_NEGO))
|
if (!stream_dump_register_handlers(peer->context, CONNECTION_STATE_NEGO, TRUE))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user