FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
pcap.c
1
20#include <freerdp/config.h>
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include <winpr/wtypes.h>
27#include <winpr/assert.h>
28#include <winpr/file.h>
29#include <winpr/crt.h>
30#include <winpr/sysinfo.h>
31
32#include <freerdp/types.h>
33#include <freerdp/utils/pcap.h>
34
35#define PCAP_MAGIC 0xA1B2C3D4
36
37struct rdp_pcap
38{
39 FILE* fp;
40 char* name;
41 BOOL write;
42 INT64 file_size;
43 size_t record_count;
44 pcap_header header;
45 pcap_record* head;
46 pcap_record* tail;
47 pcap_record* record;
48};
49
50static BOOL pcap_read_header(rdpPcap* pcap, pcap_header* header)
51{
52 WINPR_ASSERT(pcap);
53 WINPR_ASSERT(header);
54
55 return fread(header, sizeof(pcap_header), 1, pcap->fp) == 1;
56}
57
58static BOOL pcap_write_header(rdpPcap* pcap, const pcap_header* header)
59{
60 WINPR_ASSERT(pcap);
61 WINPR_ASSERT(header);
62
63 return fwrite(header, sizeof(pcap_header), 1, pcap->fp) == 1;
64}
65
66static BOOL pcap_read_record_header(rdpPcap* pcap, pcap_record_header* record)
67{
68 WINPR_ASSERT(pcap);
69 WINPR_ASSERT(record);
70
71 return fread(record, sizeof(pcap_record_header), 1, pcap->fp) == 1;
72}
73
74static BOOL pcap_write_record_header(rdpPcap* pcap, const pcap_record_header* record)
75{
76 WINPR_ASSERT(pcap);
77 WINPR_ASSERT(record);
78
79 return fwrite(record, sizeof(pcap_record_header), 1, pcap->fp) == 1;
80}
81
82static BOOL pcap_read_record(rdpPcap* pcap, pcap_record* record)
83{
84 WINPR_ASSERT(pcap);
85 WINPR_ASSERT(record);
86
87 if (!pcap_read_record_header(pcap, &record->header))
88 return FALSE;
89
90 record->length = record->header.incl_len;
91 record->data = malloc(record->length);
92 if (!record->data)
93 return FALSE;
94
95 if (fread(record->data, record->length, 1, pcap->fp) != 1)
96 {
97 free(record->data);
98 record->data = NULL;
99 return FALSE;
100 }
101 return TRUE;
102}
103
104static BOOL pcap_write_record(rdpPcap* pcap, const pcap_record* record)
105{
106 WINPR_ASSERT(pcap);
107 WINPR_ASSERT(record);
108
109 return pcap_write_record_header(pcap, &record->header) &&
110 (fwrite(record->cdata, record->length, 1, pcap->fp) == 1);
111}
112
113BOOL pcap_add_record(rdpPcap* pcap, const void* data, size_t length)
114{
115 WINPR_ASSERT(pcap);
116 WINPR_ASSERT(data || (length == 0));
117 WINPR_ASSERT(length <= UINT32_MAX);
118
119 pcap_record* record = (pcap_record*)calloc(1, sizeof(pcap_record));
120 if (!record)
121 return FALSE;
122
123 record->cdata = data;
124 record->length = (UINT32)length;
125 record->header.incl_len = (UINT32)length;
126 record->header.orig_len = (UINT32)length;
127
128 const UINT64 ns = winpr_GetUnixTimeNS();
129
130 record->header.ts_sec = (UINT32)WINPR_TIME_NS_TO_S(ns);
131 record->header.ts_usec = (UINT32)WINPR_TIME_NS_REM_US(ns);
132
133 if (pcap->tail == NULL)
134 {
135 pcap->tail = record;
136 if (!pcap->tail)
137 return FALSE;
138
139 pcap->head = pcap->tail;
140 }
141 else
142 {
143 record->next = pcap->tail;
144 pcap->tail = record;
145 }
146
147 if (pcap->record == NULL)
148 pcap->record = record;
149
150 return TRUE;
151}
152
153BOOL pcap_has_next_record(const rdpPcap* pcap)
154{
155 WINPR_ASSERT(pcap);
156
157 if (pcap->file_size - (_ftelli64(pcap->fp)) <= 16)
158 return FALSE;
159
160 return TRUE;
161}
162
163BOOL pcap_get_next_record_header(rdpPcap* pcap, pcap_record* record)
164{
165 WINPR_ASSERT(pcap);
166 WINPR_ASSERT(record);
167
168 if (pcap_has_next_record(pcap) != TRUE)
169 return FALSE;
170
171 pcap_read_record_header(pcap, &record->header);
172 record->length = record->header.incl_len;
173
174 return TRUE;
175}
176
177BOOL pcap_get_next_record_content(rdpPcap* pcap, pcap_record* record)
178{
179 WINPR_ASSERT(pcap);
180 WINPR_ASSERT(record);
181
182 return fread(record->data, record->length, 1, pcap->fp) == 1;
183}
184
185BOOL pcap_get_next_record(rdpPcap* pcap, pcap_record* record)
186{
187 WINPR_ASSERT(pcap);
188 WINPR_ASSERT(record);
189
190 return pcap_has_next_record(pcap) && pcap_read_record(pcap, record);
191}
192
193rdpPcap* pcap_open(const char* name, BOOL write)
194{
195 WINPR_ASSERT(name);
196
197 rdpPcap* pcap = (rdpPcap*)calloc(1, sizeof(rdpPcap));
198 if (!pcap)
199 goto fail;
200
201 pcap->name = _strdup(name);
202 pcap->write = write;
203 pcap->record_count = 0;
204 pcap->fp = winpr_fopen(name, write ? "w+b" : "rb");
205
206 if (pcap->fp == NULL)
207 goto fail;
208
209 if (write)
210 {
211 pcap->header.magic_number = PCAP_MAGIC;
212 pcap->header.version_major = 2;
213 pcap->header.version_minor = 4;
214 pcap->header.thiszone = 0;
215 pcap->header.sigfigs = 0;
216 pcap->header.snaplen = UINT32_MAX;
217 pcap->header.network = 0;
218 if (!pcap_write_header(pcap, &pcap->header))
219 goto fail;
220 }
221 else
222 {
223 (void)_fseeki64(pcap->fp, 0, SEEK_END);
224 pcap->file_size = _ftelli64(pcap->fp);
225 (void)_fseeki64(pcap->fp, 0, SEEK_SET);
226 if (!pcap_read_header(pcap, &pcap->header))
227 goto fail;
228 }
229
230 return pcap;
231
232fail:
233 pcap_close(pcap);
234 return NULL;
235}
236
237void pcap_flush(rdpPcap* pcap)
238{
239 WINPR_ASSERT(pcap);
240
241 while (pcap->record != NULL)
242 {
243 (void)pcap_write_record(pcap, pcap->record);
244 pcap->record = pcap->record->next;
245 }
246
247 if (pcap->fp != NULL)
248 (void)fflush(pcap->fp);
249}
250
251void pcap_close(rdpPcap* pcap)
252{
253 if (!pcap)
254 return;
255
256 pcap_flush(pcap);
257
258 if (pcap->fp != NULL)
259 (void)fclose(pcap->fp);
260
261 free(pcap->name);
262 free(pcap);
263}