FreeRDP
Loading...
Searching...
No Matches
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 = nullptr;
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 == nullptr)
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 == nullptr)
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 return (pcap->file_size - (_ftelli64(pcap->fp)) > 16);
158}
159
160BOOL pcap_get_next_record_header(rdpPcap* pcap, pcap_record* record)
161{
162 WINPR_ASSERT(pcap);
163 WINPR_ASSERT(record);
164
165 if (pcap_has_next_record(pcap) != TRUE)
166 return FALSE;
167
168 pcap_read_record_header(pcap, &record->header);
169 record->length = record->header.incl_len;
170
171 return TRUE;
172}
173
174BOOL pcap_get_next_record_content(rdpPcap* pcap, pcap_record* record)
175{
176 WINPR_ASSERT(pcap);
177 WINPR_ASSERT(record);
178
179 return fread(record->data, record->length, 1, pcap->fp) == 1;
180}
181
182BOOL pcap_get_next_record(rdpPcap* pcap, pcap_record* record)
183{
184 WINPR_ASSERT(pcap);
185 WINPR_ASSERT(record);
186
187 return pcap_has_next_record(pcap) && pcap_read_record(pcap, record);
188}
189
190rdpPcap* pcap_open(const char* name, BOOL write)
191{
192 WINPR_ASSERT(name);
193
194 rdpPcap* pcap = (rdpPcap*)calloc(1, sizeof(rdpPcap));
195 if (!pcap)
196 goto fail;
197
198 pcap->name = _strdup(name);
199 pcap->write = write;
200 pcap->record_count = 0;
201 pcap->fp = winpr_fopen(name, write ? "w+b" : "rb");
202
203 if (pcap->fp == nullptr)
204 goto fail;
205
206 if (write)
207 {
208 pcap->header.magic_number = PCAP_MAGIC;
209 pcap->header.version_major = 2;
210 pcap->header.version_minor = 4;
211 pcap->header.thiszone = 0;
212 pcap->header.sigfigs = 0;
213 pcap->header.snaplen = UINT32_MAX;
214 pcap->header.network = 0;
215 if (!pcap_write_header(pcap, &pcap->header))
216 goto fail;
217 }
218 else
219 {
220 (void)_fseeki64(pcap->fp, 0, SEEK_END);
221 pcap->file_size = _ftelli64(pcap->fp);
222 (void)_fseeki64(pcap->fp, 0, SEEK_SET);
223 if (!pcap_read_header(pcap, &pcap->header))
224 goto fail;
225 }
226
227 return pcap;
228
229fail:
230 pcap_close(pcap);
231 return nullptr;
232}
233
234void pcap_flush(rdpPcap* pcap)
235{
236 WINPR_ASSERT(pcap);
237
238 while (pcap->record != nullptr)
239 {
240 (void)pcap_write_record(pcap, pcap->record);
241 pcap->record = pcap->record->next;
242 }
243
244 if (pcap->fp != nullptr)
245 (void)fflush(pcap->fp);
246}
247
248void pcap_close(rdpPcap* pcap)
249{
250 if (!pcap)
251 return;
252
253 pcap_flush(pcap);
254
255 if (pcap->fp != nullptr)
256 (void)fclose(pcap->fp);
257
258 free(pcap->name);
259 free(pcap);
260}