The Sniffer-reading code in wiretap now decodes the time field for each
[obnox/wireshark/wip.git] / file.c
1 /* file.c
2  * File I/O routines
3  *
4  * $Id: file.c,v 1.11 1998/11/12 00:06:20 gram Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <gtk/gtk.h>
31
32 #ifdef WITH_WIRETAP
33 #include <pcap.h>
34 #endif
35
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <string.h>
39 #include <sys/stat.h>
40 #include <errno.h>
41
42 #ifdef NEED_SNPRINTF_H
43 # ifdef HAVE_STDARG_H
44 #  include <stdarg.h>
45 # else
46 #  include <varargs.h>
47 # endif
48 # include "snprintf.h"
49 #endif
50
51 #ifdef HAVE_SYS_TYPES_H
52 # include <sys/types.h>
53 #endif
54
55 #ifdef HAVE_NETINET_IN_H
56 # include <netinet/in.h>
57 #endif
58
59 #include "menu.h"
60 #include "ethereal.h"
61 #include "packet.h"
62 #include "file.h"
63 #include "util.h"
64
65 extern GtkWidget *packet_list, *prog_bar, *info_bar, *byte_view, *tree_view;
66 extern guint      file_ctx;
67
68 static guint32 ssec, susec;
69 static guint32 lastsec, lastusec;
70
71 int
72 open_cap_file(char *fname, capture_file *cf) {
73 #ifndef WITH_WIRETAP
74   guint32     magic[2];
75 #endif
76   char        err_str[PCAP_ERRBUF_SIZE];
77   struct stat cf_stat;
78
79   /* First, make sure the file is valid */
80   if (stat(fname, &cf_stat)) {
81     simple_dialog(ESD_TYPE_WARN, NULL, "File does not exist.");
82     return 1;
83   }
84   if (! S_ISREG(cf_stat.st_mode) && ! S_ISFIFO(cf_stat.st_mode)) {
85     simple_dialog(ESD_TYPE_WARN, NULL, "The file you have chosen is invalid.");
86     return 1;
87   }
88
89   /* Next, try to open the file */
90   cf->fh = fopen(fname, "r");
91   if (cf->fh == NULL)
92     return (errno);
93
94   fseek(cf->fh, 0L, SEEK_END);
95   cf->f_len = ftell(cf->fh);
96 #ifndef WITH_WIRETAP
97   fseek(cf->fh, 0L, SEEK_SET);
98   fread(magic, sizeof(guint32), 2, cf->fh);
99   fseek(cf->fh, 0L, SEEK_SET);
100 #endif
101   fclose(cf->fh);
102   cf->fh = NULL;
103   /* set the file name beacuse we need it to set the follow stream filter */
104   cf->filename = g_strdup( fname );
105
106   /* Next, find out what type of file we're dealing with */
107 #ifdef WITH_WIRETAP 
108   cf->cd_t  = WTAP_FILE_UNKNOWN;
109   cf->lnk_t = WTAP_ENCAP_NONE;
110 #else
111   cf->cd_t  = CD_UNKNOWN;
112   cf->lnk_t = DLT_NULL;
113 #endif
114   cf->swap  = 0;
115   cf->count = 0;
116   cf->drops = 0;
117   cf->esec  = 0;
118   cf->eusec = 0;
119   cf->snap  = 0;
120   if (cf->plist == NULL) {
121     cf->plist       = g_list_alloc();
122     cf->plist->data = (frame_data *) g_malloc(sizeof(frame_data));
123   } else {
124     cf->plist = g_list_first(cf->plist);
125   }
126   ssec = 0, susec = 0;
127   lastsec = 0, lastusec = 0;
128  
129 #ifndef WITH_WIRETAP
130   if (magic[0] == PCAP_MAGIC || magic[0] == SWAP32(PCAP_MAGIC)) {
131
132     /* Pcap/Tcpdump file */
133     cf->pfh = pcap_open_offline(fname, err_str);
134     if (cf->pfh == NULL) {
135 #else
136         cf->wth = wtap_open_offline(fname, WTAP_FILE_UNKNOWN);
137         if (cf->wth == NULL) {
138 #endif
139
140       simple_dialog(ESD_TYPE_WARN, NULL, "Could not open file.");
141       return 1;
142     }
143
144 #ifndef WITH_WIRETAP
145     if (cf->dfilter) {
146       if (pcap_compile(cf->pfh, &cf->fcode, cf->dfilter, 1, 0) < 0) {
147         simple_dialog(ESD_TYPE_WARN, NULL, "Unable to parse filter string "
148           "\"%s\".", cf->dfilter);
149       } else if (pcap_setfilter(cf->pfh, &cf->fcode) < 0) {
150         simple_dialog(ESD_TYPE_WARN, NULL, "Can't install filter.");
151       }
152     }
153
154     cf->fh   = pcap_file(cf->pfh);
155     cf->swap = pcap_is_swapped(cf->pfh);    
156     if ((cf->swap && BYTE_ORDER == BIG_ENDIAN) ||
157       (!cf->swap && BYTE_ORDER == LITTLE_ENDIAN)) {
158       /* Data is big-endian */
159       cf->cd_t = CD_PCAP_BE;
160     } else {
161       cf->cd_t = CD_PCAP_LE;
162     }
163     cf->vers  = ( ((pcap_major_version(cf->pfh) & 0x0000ffff) << 16) |
164                   pcap_minor_version(cf->pfh) );
165     cf->snap  = pcap_snapshot(cf->pfh);
166     cf->lnk_t = pcap_datalink(cf->pfh);
167   } else if (ntohl(magic[0]) == SNOOP_MAGIC_1 && ntohl(magic[1]) == SNOOP_MAGIC_2) {
168     /* Snoop file */
169     simple_dialog(ESD_TYPE_WARN, NULL, "The snoop format is not yet supported.");
170     return 1;
171     /*
172     fread(&sfh, sizeof(snoop_file_hdr), 1, cf->fh);
173     cf->cd_t = CD_SNOOP;
174     cf->vers = ntohl(sfh.vers);
175     if (cf->vers < SNOOP_MIN_VERSION || cf->vers > SNOOP_MAX_VERSION) {
176       g_warning("ethereal:open_cap_file:%s:bad snoop file version(%d)",
177         fname, cf->vers);
178       return 1;
179     }
180     switch (ntohl(sfh.s_lnk_t)) {
181       case 4:
182         cf->lnk_t = DLT_EN10MB;
183         break;
184     }
185     */
186   }
187   
188   if (cf->cd_t == CD_UNKNOWN) {
189     simple_dialog(ESD_TYPE_WARN, NULL, "Can't determine file type.");
190     return 1;
191   }
192 #else
193   cf->fh = wtap_file(cf->wth);
194   cf->cd_t = wtap_file_type(cf->wth);
195   cf->snap = wtap_snapshot_length(cf->wth);
196   cf->lnk_t = wtap_encapsulation(cf->wth);
197 #endif
198
199   return 0;
200 }
201
202 /* Reset everything to a pristine state */
203 void
204 close_cap_file(capture_file *cf, GtkWidget *w, guint context) {
205   if (cf->fh) {
206     fclose(cf->fh);
207     cf->fh = NULL;
208   }
209 #ifdef WITH_WIRETAP
210   if (cf->wth) {
211           wtap_close(cf->wth);
212           cf->wth = NULL;
213         }
214 #else
215   if (cf->pfh) {
216     pcap_close(cf->pfh);
217     cf->pfh = NULL;
218   }
219 #endif
220   gtk_text_freeze(GTK_TEXT(byte_view));
221   gtk_text_set_point(GTK_TEXT(byte_view), 0);
222   gtk_text_forward_delete(GTK_TEXT(byte_view),
223     gtk_text_get_length(GTK_TEXT(byte_view)));
224   gtk_text_thaw(GTK_TEXT(byte_view));
225   gtk_tree_clear_items(GTK_TREE(tree_view), 0,
226     g_list_length(GTK_TREE(tree_view)->children));
227
228   gtk_clist_freeze(GTK_CLIST(packet_list));
229   gtk_clist_clear(GTK_CLIST(packet_list));
230   gtk_clist_thaw(GTK_CLIST(packet_list));
231   gtk_statusbar_pop(GTK_STATUSBAR(w), context);
232 }
233
234 int
235 load_cap_file(char *fname, capture_file *cf) {
236   gchar  *name_ptr, *load_msg, *load_fmt = " Loading: %s...";
237   gchar  *done_fmt = " File: %s  Drops: %d";
238   gchar  *err_fmt  = " Error: Could not load '%s'";
239   gint    timeout;
240   size_t  msg_len;
241   int     err;
242
243   close_cap_file(cf, info_bar, file_ctx);
244   
245   if ((name_ptr = (gchar *) strrchr(fname, '/')) == NULL)
246     name_ptr = fname;
247   else
248     name_ptr++;
249   load_msg = g_malloc(strlen(name_ptr) + strlen(load_fmt) + 2);
250   sprintf(load_msg, load_fmt, name_ptr);
251   gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
252   
253   timeout = gtk_timeout_add(250, file_progress_cb, (gpointer) &cf);
254   
255   err = open_cap_file(fname, cf);
256 #ifdef WITH_WIRETAP
257   if ((err == 0) && (cf->cd_t != WTAP_FILE_UNKNOWN)) {
258 #else
259   if ((err == 0) && (cf->cd_t != CD_UNKNOWN)) {
260 #endif
261     gtk_clist_freeze(GTK_CLIST(packet_list));
262 #ifdef WITH_WIRETAP
263         wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf);
264         wtap_close(cf->wth);
265         cf->wth = NULL;
266 #else
267     pcap_loop(cf->pfh, 0, pcap_dispatch_cb, (u_char *) cf);
268     pcap_close(cf->pfh);
269     cf->pfh = NULL;
270 #endif
271     cf->plist = g_list_first(cf->plist);
272     cf->fh = fopen(fname, "r");
273     gtk_clist_thaw(GTK_CLIST(packet_list));
274   }
275   
276   gtk_timeout_remove(timeout);
277   gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
278
279   gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
280
281   if (err == 0) {
282     msg_len = strlen(name_ptr) + strlen(done_fmt) + 64;
283     load_msg = g_realloc(load_msg, msg_len);
284     snprintf(load_msg, msg_len, done_fmt, name_ptr, cf->drops);
285     gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
286     g_free(load_msg);
287
288     name_ptr[-1] = '\0';
289     set_menu_sensitivity("<Main>/File/Close", TRUE);
290     set_menu_sensitivity("<Main>/File/Reload", TRUE);
291   } else {
292     msg_len = strlen(name_ptr) + strlen(err_fmt) + 2;
293     load_msg = g_realloc(load_msg, msg_len);
294     snprintf(load_msg, msg_len, err_fmt, name_ptr);
295     gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
296     g_free(load_msg);
297     set_menu_sensitivity("<Main>/File/Close", FALSE);
298     set_menu_sensitivity("<Main>/File/Reload", FALSE);
299   }
300
301   return err;
302 }
303
304 void
305 #ifdef WITH_WIRETAP
306 wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr,
307 #else
308 pcap_dispatch_cb(u_char *user, const struct pcap_pkthdr *phdr,
309 #endif
310   const u_char *buf) {
311   frame_data   *fdata;
312   /* To do: make sure this is big enough. */
313   gchar         p_info[NUM_COLS][256];
314   gint          i, row;
315   capture_file *cf = (capture_file *) user;
316   guint32 tssecs, tsusecs;
317   
318   while (gtk_events_pending())
319     gtk_main_iteration();
320
321   fdata   = cf->plist->data;
322   cf->cur = fdata;
323   cf->count++;
324
325   fdata->pkt_len  = phdr->len;
326   fdata->cap_len  = phdr->caplen;
327   fdata->file_off = ftell(cf->fh) - phdr->caplen;
328   fdata->secs     = phdr->ts.tv_sec;
329   fdata->usecs    = phdr->ts.tv_usec;
330
331   /* If we don't have the time stamp of the first packet, it's because this
332      is the first packet.  Save the time stamp of this packet as the time
333      stamp of the first packet. */
334   if (!ssec && !susec) {
335     ssec  = fdata->secs;
336     susec = fdata->usecs;
337   }
338
339   /* Do the same for the time stamp of the previous packet. */
340   if (!lastsec && !lastusec) {
341     lastsec  = fdata->secs;
342     lastusec = fdata->usecs;
343   }
344
345   /* Get the time elapsed between the first packet and this packet. */
346   cf->esec = fdata->secs - ssec;
347   if (susec <= fdata->usecs) {
348     cf->eusec = fdata->usecs - susec;
349   } else {
350     cf->eusec = (fdata->usecs + 1000000) - susec;
351     cf->esec--;
352   }
353
354   /* Compute the time stamp. */
355   switch (timestamp_type) {
356     case RELATIVE:      /* Relative to the first packet */
357       tssecs = cf->esec;
358       tsusecs = cf->eusec;
359       break;
360     case DELTA:         /* Relative to the previous packet */
361       tssecs = fdata->secs - lastsec;
362       if (lastusec <= fdata->usecs) {
363         tsusecs = fdata->usecs - lastusec;
364       } else {
365         tsusecs = (fdata->usecs + 1000000) - lastusec;
366         tssecs--;
367       }
368       break;
369     default:            /* Absolute time, or bogus timestamp_type value */
370       tssecs = 0;       /* Not used */
371       tsusecs = 0;
372       break;
373   }
374   for (i = 0; i < NUM_COLS; i++) { fdata->win_info[i] = &p_info[i][0]; }
375   sprintf(fdata->win_info[COL_NUM], "%d", cf->count);
376   dissect_packet(buf, tssecs, tsusecs, fdata, NULL);
377   row = gtk_clist_append(GTK_CLIST(packet_list), fdata->win_info);
378   for (i = 0; i < NUM_COLS; i++) { fdata->win_info[i] = NULL; }
379
380   /* Make sure we always have an available list entry */
381   if (cf->plist->next == NULL) {
382     fdata = (frame_data *) g_malloc(sizeof(frame_data));
383     g_list_append(cf->plist, (gpointer) fdata);
384   }
385   cf->plist = cf->plist->next;
386 }
387
388 /* Uncomment when we handle snoop files again.
389
390 size_t
391 read_frame_header(capture_file *cf) {
392   snoop_frame_hdr  shdr;
393   pcap_frame_hdr   phdr;
394   gint16           pkt_len, cap_len;
395   guint32          secs, usecs;
396   frame_data      *fdata;
397   size_t           err;
398
399   if ((cf->cd_t == CD_PCAP_BE) || (cf->cd_t == CD_PCAP_LE)) {
400     err = fread((char *)&phdr, sizeof(pcap_frame_hdr), 1, cf->fh);
401     if (!err) { return err; }
402     fdata = (frame_data *) g_malloc(sizeof(frame_data));
403     if (cf->swap) {
404       pkt_len = SWAP32(phdr.pkt_len);
405       cap_len = SWAP32(phdr.cap_len);
406       secs    = SWAP32(phdr.tm.tv_sec);
407       usecs   = SWAP32(phdr.tm.tv_usec);
408     } else {
409       pkt_len = phdr.pkt_len;
410       cap_len = phdr.cap_len;
411       secs    = phdr.tm.tv_sec;
412       usecs   = phdr.tm.tv_usec;
413     }
414   } else if (cf->cd_t == CD_SNOOP) {
415     err = fread(&shdr, sizeof(snoop_frame_hdr), 1, cf->fh);
416     fdata = (frame_data *) g_malloc(sizeof(frame_data));
417     if (!err) { return err; }
418     pkt_len = ntohl(shdr.inc_len);
419     cap_len = ntohl(shdr.pr_len) - 24;
420     secs    = ntohl(shdr.secs);
421     usecs   = ntohl(shdr.usecs);
422     shdr.drops  = ntohl(shdr.drops);
423     if (!ssec && !susec) { ssec = secs; susec = usecs; }
424     cf->drops = shdr.drops;
425     cf->esec = secs - ssec;
426     if (susec < shdr.usecs) {
427       cf->eusec = usecs - susec;
428     } else {
429       cf->eusec = susec - usecs;
430       cf->esec--;
431     }
432   }
433   cf->cur = fdata;
434   fdata->pkt_len = pkt_len;
435   fdata->cap_len = cap_len;
436   fdata->secs    = secs;
437   fdata->usecs   = usecs;
438   g_list_append(cf->plist, (gpointer) fdata);
439   if (!ssec && !susec) {
440     ssec  = secs;
441     susec = usecs;
442   }
443   cf->esec = secs - ssec;
444   if (susec < usecs) {
445     cf->eusec = usecs - susec;
446   } else {
447     cf->eusec = susec - usecs;
448     cf->esec--;
449   }
450   return err;
451 }
452 */