From a863c107ab4670b6e22bffe8fdefe48505c2ac2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Fri, 26 Aug 2011 18:36:35 -0400 Subject: [PATCH] libfreerdp-utils: added pcap serializer/deserializer --- cunit/CMakeLists.txt | 2 + cunit/test_freerdp.c | 5 + cunit/test_pcap.c | 95 +++++++++++++++++ cunit/test_pcap.h | 26 +++++ include/freerdp/utils/pcap.h | 80 ++++++++++++++ include/freerdp/utils/stopwatch.h | 4 +- libfreerdp-utils/CMakeLists.txt | 1 + libfreerdp-utils/pcap.c | 172 ++++++++++++++++++++++++++++++ libfreerdp-utils/stopwatch.c | 12 ++- 9 files changed, 395 insertions(+), 2 deletions(-) create mode 100644 cunit/test_pcap.c create mode 100644 cunit/test_pcap.h create mode 100644 include/freerdp/utils/pcap.h create mode 100644 libfreerdp-utils/pcap.c diff --git a/cunit/CMakeLists.txt b/cunit/CMakeLists.txt index 5b5171259..88fe5cc3f 100644 --- a/cunit/CMakeLists.txt +++ b/cunit/CMakeLists.txt @@ -44,6 +44,8 @@ add_executable(test_freerdp test_list.h test_orders.c test_orders.h + test_pcap.c + test_pcap.h test_license.c test_license.h test_stream.c diff --git a/cunit/test_freerdp.c b/cunit/test_freerdp.c index d07206914..d5ffa047c 100644 --- a/cunit/test_freerdp.c +++ b/cunit/test_freerdp.c @@ -37,6 +37,7 @@ #include "test_librfx.h" #include "test_freerdp.h" #include "test_rail.h" +#include "test_pcap.h" void dump_data(unsigned char * p, int len, int width, char* name) { @@ -188,6 +189,10 @@ int main(int argc, char* argv[]) { add_per_suite(); } + else if (strcmp("pcap", argv[*pindex]) == 0) + { + add_pcap_suite(); + } else if (strcmp("ber", argv[*pindex]) == 0) { add_ber_suite(); diff --git a/cunit/test_pcap.c b/cunit/test_pcap.c new file mode 100644 index 000000000..99fb71403 --- /dev/null +++ b/cunit/test_pcap.c @@ -0,0 +1,95 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * pcap File Format Unit Tests + * + * Copyright 2011 Marc-Andre Moreau + * + * 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 +#include +#include + +#include "test_pcap.h" + +int init_pcap_suite(void) +{ + return 0; +} + +int clean_pcap_suite(void) +{ + return 0; +} + +int add_pcap_suite(void) +{ + add_test_suite(pcap); + + add_test_function(pcap); + + return 0; +} + +uint8 test_packet_1[16] = + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"; + +uint8 test_packet_2[32] = + "\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB" + "\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB"; + +uint8 test_packet_3[64] = + "\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC" + "\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC" + "\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC" + "\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC"; + +typedef struct +{ + void* data; + uint32 length; +} test_packet; + +void test_pcap(void) +{ + rdpPcap* pcap; + pcap_record record; + test_packet packets[3]; + + packets[0].data = test_packet_1; + packets[0].length = sizeof(test_packet_1); + packets[1].data = test_packet_2; + packets[1].length = sizeof(test_packet_2); + packets[2].data = test_packet_3; + packets[2].length = sizeof(test_packet_3); + + pcap = pcap_open("/tmp/test.pcap", True); + pcap_add_record(pcap, test_packet_1, sizeof(test_packet_1)); + pcap_add_record(pcap, test_packet_2, sizeof(test_packet_2)); + pcap_add_record(pcap, test_packet_3, sizeof(test_packet_3)); + pcap_close(pcap); + + pcap = pcap_open("/tmp/test.pcap", False); + + int i = 0; + while (pcap_has_next_record(pcap)) + { + pcap_get_next_record(pcap, &record); + CU_ASSERT(record.length == packets[i].length) + i++; + } + + pcap_close(pcap); +} + diff --git a/cunit/test_pcap.h b/cunit/test_pcap.h new file mode 100644 index 000000000..f506edcaa --- /dev/null +++ b/cunit/test_pcap.h @@ -0,0 +1,26 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * pcap File Format Unit Tests + * + * Copyright 2011 Marc-Andre Moreau + * + * 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 "test_freerdp.h" + +int init_pcap_suite(void); +int clean_pcap_suite(void); +int add_pcap_suite(void); + +void test_pcap(void); diff --git a/include/freerdp/utils/pcap.h b/include/freerdp/utils/pcap.h new file mode 100644 index 000000000..893ff8589 --- /dev/null +++ b/include/freerdp/utils/pcap.h @@ -0,0 +1,80 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * pcap File Format Utils + * + * Copyright 2011 Marc-Andre Moreau + * + * 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 __UTILS_PCAP_H +#define __UTILS_PCAP_H + +#include +#include +#include + +struct _pcap_header +{ + uint32 magic_number; /* magic number */ + uint16 version_major; /* major version number */ + uint16 version_minor; /* minor version number */ + sint32 thiszone; /* GMT to local correction */ + uint32 sigfigs; /* accuracy of timestamps */ + uint32 snaplen; /* max length of captured packets, in octets */ + uint32 network; /* data link type */ +}; +typedef struct _pcap_header pcap_header; + +struct _pcap_record_header +{ + uint32 ts_sec; /* timestamp seconds */ + uint32 ts_usec; /* timestamp microseconds */ + uint32 incl_len; /* number of octets of packet saved in file */ + uint32 orig_len; /* actual length of packet */ +}; +typedef struct _pcap_record_header pcap_record_header; + +typedef struct _pcap_record pcap_record; + +struct _pcap_record +{ + pcap_record_header header; + void* data; + uint32 length; + pcap_record* next; +}; + +struct rdp_pcap +{ + FILE* fp; + char* name; + STOPWATCH* sw; + boolean write; + int file_size; + int record_count; + pcap_header header; + pcap_record* head; + pcap_record* tail; + pcap_record* record; +}; +typedef struct rdp_pcap rdpPcap; + +FREERDP_API rdpPcap* pcap_open(char* name, boolean write); +FREERDP_API void pcap_close(rdpPcap* pcap); + +FREERDP_API void pcap_add_record(rdpPcap* pcap, void* data, uint32 length); +FREERDP_API boolean pcap_has_next_record(rdpPcap* pcap); +FREERDP_API boolean pcap_get_next_record(rdpPcap* pcap, pcap_record* record); + +#endif /* __UTILS_PCAP_H */ diff --git a/include/freerdp/utils/stopwatch.h b/include/freerdp/utils/stopwatch.h index c7fa46457..58d7be5e1 100644 --- a/include/freerdp/utils/stopwatch.h +++ b/include/freerdp/utils/stopwatch.h @@ -22,6 +22,7 @@ #include #include +#include #include struct _STOPWATCH @@ -40,6 +41,7 @@ FREERDP_API void stopwatch_start(STOPWATCH* stopwatch); FREERDP_API void stopwatch_stop(STOPWATCH* stopwatch); FREERDP_API void stopwatch_reset(STOPWATCH* stopwatch); -double stopwatch_get_elapsed_time_in_seconds(STOPWATCH* stopwatch); +FREERDP_API double stopwatch_get_elapsed_time_in_seconds(STOPWATCH* stopwatch); +FREERDP_API void stopwatch_get_elapsed_time_in_useconds(STOPWATCH* stopwatch, uint32* sec, uint32* usec); #endif /* __UTILS_STOPWATCH_H */ diff --git a/libfreerdp-utils/CMakeLists.txt b/libfreerdp-utils/CMakeLists.txt index a0b6037dd..cb7adbfbc 100644 --- a/libfreerdp-utils/CMakeLists.txt +++ b/libfreerdp-utils/CMakeLists.txt @@ -30,6 +30,7 @@ set(FREERDP_UTILS_SRCS load_plugin.c memory.c mutex.c + pcap.c profiler.c rail.c registry.c diff --git a/libfreerdp-utils/pcap.c b/libfreerdp-utils/pcap.c new file mode 100644 index 000000000..4282971ee --- /dev/null +++ b/libfreerdp-utils/pcap.c @@ -0,0 +1,172 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * pcap File Format Utils + * + * Copyright 2011 Marc-Andre Moreau + * + * 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 +#include +#include + +#include +#include + +#include + +#define PCAP_MAGIC 0xA1B2C3D4 + +void pcap_read_header(rdpPcap* pcap, pcap_header* header) +{ + fread((void*) header, sizeof(pcap_header), 1, pcap->fp); +} + +void pcap_write_header(rdpPcap* pcap, pcap_header* header) +{ + fwrite((void*) header, sizeof(pcap_header), 1, pcap->fp); +} + +void pcap_read_record_header(rdpPcap* pcap, pcap_record_header* record) +{ + fread((void*) record, sizeof(pcap_record_header), 1, pcap->fp); +} + +void pcap_write_record_header(rdpPcap* pcap, pcap_record_header* record) +{ + fwrite((void*) record, sizeof(pcap_record_header), 1, pcap->fp); +} + +void pcap_read_record(rdpPcap* pcap, pcap_record* record) +{ + pcap_read_record_header(pcap, &record->header); + record->length = record->header.incl_len; + record->data = xmalloc(record->length); + fread(record->data, record->length, 1, pcap->fp); +} + +void pcap_write_record(rdpPcap* pcap, pcap_record* record) +{ + pcap_write_record_header(pcap, &record->header); + fwrite(record->data, record->length, 1, pcap->fp); +} + +void pcap_add_record(rdpPcap* pcap, void* data, uint32 length) +{ + pcap_record* record; + + if (pcap->tail == NULL) + { + pcap->tail = (pcap_record*) xzalloc(sizeof(pcap_record)); + pcap->head = pcap->tail; + pcap->record = pcap->head; + record = pcap->tail; + } + else + { + record = (pcap_record*) xzalloc(sizeof(pcap_record)); + pcap->tail->next = record; + pcap->tail = record; + } + + record->data = data; + record->length = length; + record->header.incl_len = length; + record->header.orig_len = length; + + stopwatch_stop(pcap->sw); + stopwatch_get_elapsed_time_in_useconds(pcap->sw, &record->header.ts_sec, &record->header.ts_usec); + stopwatch_start(pcap->sw); +} + +boolean pcap_has_next_record(rdpPcap* pcap) +{ + if (pcap->file_size - (ftell(pcap->fp)) <= 16) + return False; + + return True; +} + +boolean pcap_get_next_record(rdpPcap* pcap, pcap_record* record) +{ + if (pcap_has_next_record(pcap) != True) + return False; + + pcap_read_record(pcap, record); + + return True; +} + +rdpPcap* pcap_open(char* name, boolean write) +{ + rdpPcap* pcap; + + pcap = (rdpPcap*) xzalloc(sizeof(rdpPcap)); + + if (pcap != NULL) + { + pcap->name = name; + pcap->write = write; + pcap->record_count = 0; + + if (write) + { + pcap->fp = fopen(name, "w+"); + pcap->header.magic_number = 0xA1B2C3D4; + pcap->header.version_major = 2; + pcap->header.version_minor = 4; + pcap->header.thiszone = 0; + pcap->header.sigfigs = 0; + pcap->header.snaplen = 65535; + pcap->header.network = 0; + pcap_write_header(pcap, &pcap->header); + } + else + { + pcap->fp = fopen(name, "r"); + fseek(pcap->fp, 0, SEEK_END); + pcap->file_size = (int) ftell(pcap->fp); + fseek(pcap->fp, 0, SEEK_SET); + pcap_read_header(pcap, &pcap->header); + } + + pcap->sw = stopwatch_create(); + stopwatch_start(pcap->sw); + } + + return pcap; +} + +void pcap_flush(rdpPcap* pcap) +{ + while (pcap->record != NULL) + { + pcap_write_record(pcap, pcap->record); + pcap->record = pcap->record->next; + } + + if (pcap->fp != NULL) + fflush(pcap->fp); +} + +void pcap_close(rdpPcap* pcap) +{ + pcap_flush(pcap); + + if (pcap->fp != NULL) + fclose(pcap->fp); + + stopwatch_stop(pcap->sw); + stopwatch_free(pcap->sw); +} diff --git a/libfreerdp-utils/stopwatch.c b/libfreerdp-utils/stopwatch.c index 55b814f06..e74c1d909 100644 --- a/libfreerdp-utils/stopwatch.c +++ b/libfreerdp-utils/stopwatch.c @@ -56,5 +56,15 @@ void stopwatch_reset(STOPWATCH* stopwatch) double stopwatch_get_elapsed_time_in_seconds(STOPWATCH* stopwatch) { - return ((double)stopwatch->elapsed) / CLOCKS_PER_SEC; + return ((double) stopwatch->elapsed) / CLOCKS_PER_SEC; } + +void stopwatch_get_elapsed_time_in_useconds(STOPWATCH* stopwatch, uint32* sec, uint32* usec) +{ + double uelapsed; + + *sec = ((uint32) stopwatch->elapsed) / CLOCKS_PER_SEC; + uelapsed = stopwatch->elapsed - ((double)(*sec) * CLOCKS_PER_SEC); + *usec = (uelapsed / (CLOCKS_PER_SEC / 1000000)); +} +