40b3c53263e10404390a6158fd01486c9adcf1f2
[metze/wireshark/wip.git] / reordercap.c
1 /* Reorder the frames from an input dump file, and write to output dump file.
2  * Martin Mathieson
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License along
21  * with this program; if not, write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  *
24  */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdarg.h>
30
31 #include "wtap.h"
32
33
34 /* Show command-line usage */
35 /* TODO: add reoder list length as an optional param? */
36 static void usage(void)
37 {
38     printf("usage:  reorder <infile> <outfile>\n");
39 }
40
41 /* Remember where this frame was in the file */
42 typedef struct FrameRecord_t {
43     gint64               offset;
44     guint32              length;
45
46     struct wtap_nstime   time;
47
48     /* List item pointers */
49     struct FrameRecord_t *prev;
50     struct FrameRecord_t *next;
51 } FrameRecord_t;
52
53 /* This is pretty big, but I don't mind waiting a few seconds */
54 #define MAX_REORDER_LIST_LENGTH 3000
55 static int g_FrameRecordCount;
56
57 /* This is the list of frames, sorted by time.  Later frames at the front, earlier
58    ones at the end */
59 static FrameRecord_t *g_FrameListHead;
60 static FrameRecord_t *g_FrameListTail;
61
62
63 /**************************************************/
64 /* Debugging only                                 */
65
66 /* Enable this symbol to see debug output */
67 /* #define REORDER_DEBUG */
68
69 #ifdef REORDER_DEBUG
70 static void ReorderListDebugPrint(void)
71 {
72     int count=0;
73     FrameRecord_t *tmp = g_FrameListHead;
74     printf("\n");
75     while (tmp != NULL) {
76         printf("%6d: offset=%6llu, length=%6u, time=%lu:%u",
77                ++count, tmp->offset, tmp->length, tmp->time.secs, tmp->time.nsecs);
78
79         if (tmp == g_FrameListHead) {
80             printf(" (head)");
81         }
82         if (tmp == g_FrameListTail) {
83             printf(" (tail)\n");
84         }
85         printf("\n");
86
87         tmp = tmp->next;
88     }
89     printf("\n");
90 }
91 #else
92 #define ReorderListDebugPrint()
93 #endif
94
95 #ifdef REORDER_DEBUG
96 #define DEBUG_PRINT printf
97 #else
98 #define DEBUG_PRINT(...)
99 #endif
100
101 /**************************************************/
102
103 /* Counting frames that weren't in order */
104 static int g_OutOfOrder = 0;
105
106
107 /* Is time1 later than time2? */
108 static gboolean isLaterTime(struct wtap_nstime time1,
109                             struct wtap_nstime time2)
110 {
111     if (time1.secs > time2.secs) {
112         return TRUE;
113     }
114     if (time1.secs == time2.secs) {
115         return (time1.nsecs > time2.nsecs);
116     }
117     else {
118         return FALSE;
119     }
120 }
121
122 /* Is the reorder list empty? */
123 static gboolean ReorderListEmpty(void)
124 {
125     return (g_FrameRecordCount == 0);
126 }
127
128 /* Is the reorder list full? */
129 static gboolean ReorderListFull(void)
130 {
131     return (g_FrameRecordCount >= MAX_REORDER_LIST_LENGTH);
132 }
133
134 /* Add a new frame to the reorder list */
135 /* Adding later ones to the front */
136 static void ReorderListAdd(gint64 offset, guint32 length,
137                            struct wtap_nstime time)
138 {
139     FrameRecord_t *tmp;
140     FrameRecord_t *newFrameRecord = g_malloc(sizeof(FrameRecord_t));
141
142     /* Populate fields */
143     DEBUG_PRINT("\nAdded with offset=%06llu, length=%05u, secs=%lu, nsecs=%d\n",
144                 offset, length, time.secs, time.nsecs);
145     newFrameRecord->offset = offset;
146     newFrameRecord->length = length;
147     newFrameRecord->time = time;
148
149     /* We will definitely add it below, so inc counter */
150     g_FrameRecordCount++;
151
152     /* First time, this will be the head */
153     if (g_FrameListHead == NULL) {
154         DEBUG_PRINT("this item will be head - only item\n");
155         g_FrameListHead = newFrameRecord;
156         newFrameRecord->prev = NULL;
157         newFrameRecord->next = NULL;
158         g_FrameListTail = newFrameRecord;
159         return;
160     }
161
162     /* Look for the place in the list where this item fits */
163     tmp = g_FrameListHead;
164     while (tmp != NULL) {
165         if (isLaterTime(time, tmp->time)) {
166             DEBUG_PRINT("Time was Later, writing before element\n");
167
168             /* Insert newFrameRecord *before* tmp */
169
170             /* Fix up prev item */
171             if (tmp == g_FrameListHead) {
172                 /* Inserting before existing head */
173                 g_FrameListHead = newFrameRecord;
174             }
175             else {
176                 /* Our prev is tmps old prev */
177                 newFrameRecord->prev = tmp->prev;
178                 /* Its next points to us */
179                 newFrameRecord->prev->next = newFrameRecord;
180             }
181
182             /* Fix up next item */
183             newFrameRecord->next = tmp;
184             tmp->prev = newFrameRecord;
185
186             g_OutOfOrder++;
187
188             return;
189         }
190
191         /* Didn't find an item to insert in front of */
192         if (tmp->next == NULL) {
193             DEBUG_PRINT("Reached the end of the list, so insert here\n");
194
195             /* We are the new last item */
196             tmp->next = newFrameRecord;
197             newFrameRecord->prev = tmp;
198             newFrameRecord->next = NULL;
199             g_FrameListTail = newFrameRecord;
200
201             return;
202         }
203         else {
204             /* Move onto the next item */
205             DEBUG_PRINT("Time was earlier, move to next position\n");
206             tmp = tmp->next;
207         }
208     }
209 }
210
211 /* Dump the earliest item in the reorder list to the output file, and pop it */
212 static void ReorderListDumpEarliest(wtap *wth, wtap_dumper *pdh)
213 {
214     union wtap_pseudo_header pseudo_header;
215     int    err;
216     gchar  *errinfo;
217     const struct wtap_pkthdr *phdr;
218     guint8 buf[16000];
219     struct wtap_pkthdr new_phdr;
220
221     FrameRecord_t *prev_tail = g_FrameListTail;
222
223     DEBUG_PRINT("\nDumping frame (offset=%llu, length=%u) (%u items in list)\n", 
224                 g_FrameListHead->offset, g_FrameListHead->length,
225                 g_FrameRecordCount);
226
227     /* Re-read the first frame from the stored location */
228     wtap_seek_read(wth,
229                    g_FrameListTail->offset,
230                    &pseudo_header,
231                    buf,
232                    g_FrameListTail->length,
233                    &err,
234                    &errinfo);
235     DEBUG_PRINT("re-read: err is %u, buf is (%s)\n", err, buf);
236
237     /* Get packet header */
238     phdr = wtap_phdr(wth);
239
240     /* Copy, and set length and timestamp from item. */
241     memcpy((void*)&new_phdr, phdr, sizeof(struct wtap_pkthdr));
242     new_phdr.len = g_FrameListTail->length;
243     new_phdr.ts.secs = g_FrameListTail->time.secs;
244     new_phdr.ts.nsecs = g_FrameListTail->time.nsecs;
245
246     /* Dump frame to outfile */
247     if (!wtap_dump(pdh, &new_phdr, &pseudo_header, buf, &err)) {
248         printf("Error (%s) writing frame to outfile\n", wtap_strerror(err));
249         exit(1);
250     }
251
252     /* Now remove this (the last/earliest) item from the list */
253     if (g_FrameListTail->prev == NULL) {
254         g_FrameListTail = NULL;
255         g_FrameListHead = NULL;
256     }
257     else {
258         /* 2nd last item is now last */
259         g_FrameListTail->prev->next = NULL;
260         g_FrameListTail = g_FrameListTail->prev;
261     }
262
263     /* And free the struct */
264     g_free(prev_tail);
265     g_FrameRecordCount--;
266
267     DEBUG_PRINT("Frame written, %u remaining\n", g_FrameRecordCount);
268 }
269
270
271
272 /********************************************************************/
273 /* Main function.                                                   */
274 /********************************************************************/
275 int main(int argc, char *argv[])
276 {
277     wtap *wth = NULL;
278     wtap_dumper *pdh = NULL;
279     int err;
280     gchar *err_info;
281     gint64 data_offset;
282     const struct wtap_pkthdr *phdr;
283     guint32 read_count = 0;
284
285     /* 1st arg is infile, 2nd arg is outfile */
286     char *infile;
287     char *outfile;
288     if (argc == 3) {
289         infile = argv[1];
290         outfile = argv[2];
291     }
292     else {
293         usage();
294         exit(1);
295     }
296
297     /* Open infile */
298     wth = wtap_open_offline(infile, &err, &err_info, TRUE);
299     if (wth == NULL) {
300         printf("reorder: Can't open %s: %s\n", infile, wtap_strerror(err));
301         exit(1);
302     }
303
304     DEBUG_PRINT("file_type is %u\n", wtap_file_type(wth));
305
306     /* Open outfile (same filetype/encap as input file) */
307     pdh = wtap_dump_open(outfile, wtap_file_type(wth), wtap_file_encap(wth), 65535, FALSE, &err);
308     if (pdh == NULL) {
309         printf("Failed to open output file: (%s) - error %s\n", outfile, wtap_strerror(err));
310         exit(1);
311     }
312
313
314     /* Read each frame from infile */
315     while (wtap_read(wth, &err, &err_info, &data_offset)) {
316         read_count++;
317         phdr = wtap_phdr(wth);
318
319         /* Add it to the reordering list */
320         ReorderListAdd(data_offset, phdr->len, phdr->ts);
321         ReorderListDebugPrint();
322
323         /* If/when the list gets full, dump the earliest item out */
324         if (ReorderListFull()) {
325             DEBUG_PRINT("List is full, dumping earliest!\n");
326
327             /* Write out the earliest one */
328             ReorderListDumpEarliest(wth, pdh);
329             ReorderListDebugPrint();
330         }
331     }
332
333     /* Flush out the remaining (ordered) frames */
334     while (!ReorderListEmpty()) {
335         ReorderListDumpEarliest(wth, pdh);
336         ReorderListDebugPrint();
337     }
338
339     /* Close outfile */
340     if (!wtap_dump_close(pdh, &err)) {
341         printf("reorder: Error closing %s: %s\n", outfile, wtap_strerror(err));
342         exit(1);
343     }
344
345     /* Write how many frames, and how many were out of order */
346     printf("%u frames, %u out of order\n", read_count, g_OutOfOrder);
347
348     /* Finally, close infile */
349     wtap_fdclose(wth);
350
351     return 0;
352 }
353