8adee33cc1fbf833ab1600f4c8300b7824c1115c
[obnox/wireshark/wip.git] / file.c
1 /* file.c
2  * File I/O routines
3  *
4  * $Id: file.c,v 1.16 1999/01/02 06:10:52 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 "ethereal.h"
60 #include "menu.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 firstsec, firstusec;
69 static guint32 lastsec, lastusec;
70
71 #ifdef WITH_WIRETAP
72 static void wtap_dispatch_cb(u_char *, const struct wtap_pkthdr *, int,
73     const u_char *);
74 #else
75 static void pcap_dispatch_cb(u_char *, const struct pcap_pkthdr *,
76     const u_char *);
77 #endif
78
79 int
80 open_cap_file(char *fname, capture_file *cf) {
81 #ifndef WITH_WIRETAP
82   guint32     magic[2];
83   char        err_str[PCAP_ERRBUF_SIZE];
84 #endif
85   struct stat cf_stat;
86
87   /* First, make sure the file is valid */
88   if (stat(fname, &cf_stat)) {
89     simple_dialog(ESD_TYPE_WARN, NULL, "File does not exist.");
90     return 1;
91   }
92   if (! S_ISREG(cf_stat.st_mode) && ! S_ISFIFO(cf_stat.st_mode)) {
93     simple_dialog(ESD_TYPE_WARN, NULL, "The file you have chosen is invalid.");
94     return 1;
95   }
96
97   /* Next, try to open the file */
98   cf->fh = fopen(fname, "r");
99   if (cf->fh == NULL)
100     return (errno);
101
102   fseek(cf->fh, 0L, SEEK_END);
103   cf->f_len = ftell(cf->fh);
104 #ifndef WITH_WIRETAP
105   fseek(cf->fh, 0L, SEEK_SET);
106   fread(magic, sizeof(guint32), 2, cf->fh);
107   fseek(cf->fh, 0L, SEEK_SET);
108 #endif
109   fclose(cf->fh);
110   cf->fh = NULL;
111   /* set the file name beacuse we need it to set the follow stream filter */
112   cf->filename = g_strdup( fname );
113
114   /* Next, find out what type of file we're dealing with */
115 #ifdef WITH_WIRETAP 
116   cf->cd_t  = WTAP_FILE_UNKNOWN;
117   cf->lnk_t = WTAP_ENCAP_NONE;
118 #else
119   cf->cd_t  = CD_UNKNOWN;
120   cf->lnk_t = DLT_NULL;
121 #endif
122   cf->swap  = 0;
123   cf->count = 0;
124   cf->drops = 0;
125   cf->esec  = 0;
126   cf->eusec = 0;
127   cf->snap  = 0;
128   if (cf->plist == NULL) {
129     cf->plist       = g_list_alloc();
130     cf->plist->data = (frame_data *) g_malloc(sizeof(frame_data));
131   } else {
132     cf->plist = g_list_first(cf->plist);
133   }
134   firstsec = 0, firstusec = 0;
135   lastsec = 0, lastusec = 0;
136  
137 #ifndef WITH_WIRETAP
138   if (magic[0] == PCAP_MAGIC || magic[0] == SWAP32(PCAP_MAGIC)) {
139
140     /* Pcap/Tcpdump file */
141     cf->pfh = pcap_open_offline(fname, err_str);
142     if (cf->pfh == NULL) {
143 #else
144         cf->wth = wtap_open_offline(fname, WTAP_FILE_UNKNOWN);
145         if (cf->wth == NULL) {
146 #endif
147
148       simple_dialog(ESD_TYPE_WARN, NULL, "Could not open file.");
149       return 1;
150     }
151
152 #ifndef WITH_WIRETAP
153     if (cf->dfilter) {
154       if (pcap_compile(cf->pfh, &cf->fcode, cf->dfilter, 1, 0) < 0) {
155         simple_dialog(ESD_TYPE_WARN, NULL, "Unable to parse filter string "
156           "\"%s\".", cf->dfilter);
157       } else if (pcap_setfilter(cf->pfh, &cf->fcode) < 0) {
158         simple_dialog(ESD_TYPE_WARN, NULL, "Can't install filter.");
159       }
160     }
161
162     cf->fh   = pcap_file(cf->pfh);
163     cf->swap = pcap_is_swapped(cf->pfh);    
164     if ((cf->swap && BYTE_ORDER == BIG_ENDIAN) ||
165       (!cf->swap && BYTE_ORDER == LITTLE_ENDIAN)) {
166       /* Data is big-endian */
167       cf->cd_t = CD_PCAP_BE;
168     } else {
169       cf->cd_t = CD_PCAP_LE;
170     }
171     cf->vers  = ( ((pcap_major_version(cf->pfh) & 0x0000ffff) << 16) |
172                   pcap_minor_version(cf->pfh) );
173     cf->snap  = pcap_snapshot(cf->pfh);
174     cf->lnk_t = pcap_datalink(cf->pfh);
175   } else if (ntohl(magic[0]) == SNOOP_MAGIC_1 && ntohl(magic[1]) == SNOOP_MAGIC_2) {
176     simple_dialog(ESD_TYPE_WARN, NULL, "The snoop format is not yet supported.");
177     return 1;
178   }
179   
180   if (cf->cd_t == CD_UNKNOWN) {
181     simple_dialog(ESD_TYPE_WARN, NULL, "Can't determine file type.");
182     return 1;
183   }
184 #else
185   cf->fh = wtap_file(cf->wth);
186   cf->cd_t = wtap_file_type(cf->wth);
187   cf->snap = wtap_snapshot_length(cf->wth);
188   cf->lnk_t = wtap_encapsulation(cf->wth);
189 #endif
190
191   return 0;
192 }
193
194 /* Reset everything to a pristine state */
195 void
196 close_cap_file(capture_file *cf, GtkWidget *w, guint context) {
197   if (cf->fh) {
198     fclose(cf->fh);
199     cf->fh = NULL;
200   }
201 #ifdef WITH_WIRETAP
202   if (cf->wth) {
203           wtap_close(cf->wth);
204           cf->wth = NULL;
205         }
206 #else
207   if (cf->pfh) {
208     pcap_close(cf->pfh);
209     cf->pfh = NULL;
210   }
211 #endif
212   gtk_text_freeze(GTK_TEXT(byte_view));
213   gtk_text_set_point(GTK_TEXT(byte_view), 0);
214   gtk_text_forward_delete(GTK_TEXT(byte_view),
215     gtk_text_get_length(GTK_TEXT(byte_view)));
216   gtk_text_thaw(GTK_TEXT(byte_view));
217   gtk_tree_clear_items(GTK_TREE(tree_view), 0,
218     g_list_length(GTK_TREE(tree_view)->children));
219
220   gtk_clist_freeze(GTK_CLIST(packet_list));
221   gtk_clist_clear(GTK_CLIST(packet_list));
222   gtk_clist_thaw(GTK_CLIST(packet_list));
223   gtk_statusbar_pop(GTK_STATUSBAR(w), context);
224 }
225
226 int
227 load_cap_file(char *fname, capture_file *cf) {
228   gchar  *name_ptr, *load_msg, *load_fmt = " Loading: %s...";
229   gchar  *done_fmt = " File: %s  Drops: %d";
230   gchar  *err_fmt  = " Error: Could not load '%s'";
231   gint    timeout;
232   size_t  msg_len;
233   int     err;
234
235   close_cap_file(cf, info_bar, file_ctx);
236   
237   if ((name_ptr = (gchar *) strrchr(fname, '/')) == NULL)
238     name_ptr = fname;
239   else
240     name_ptr++;
241   load_msg = g_malloc(strlen(name_ptr) + strlen(load_fmt) + 2);
242   sprintf(load_msg, load_fmt, name_ptr);
243   gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
244   
245   timeout = gtk_timeout_add(250, file_progress_cb, (gpointer) &cf);
246   
247   err = open_cap_file(fname, cf);
248 #ifdef WITH_WIRETAP
249   if ((err == 0) && (cf->cd_t != WTAP_FILE_UNKNOWN)) {
250 #else
251   if ((err == 0) && (cf->cd_t != CD_UNKNOWN)) {
252 #endif
253     gtk_clist_freeze(GTK_CLIST(packet_list));
254 #ifdef WITH_WIRETAP
255     wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf);
256     wtap_close(cf->wth);
257     cf->wth = NULL;
258 #else
259     pcap_loop(cf->pfh, 0, pcap_dispatch_cb, (u_char *) cf);
260     pcap_close(cf->pfh);
261     cf->pfh = NULL;
262 #endif
263     cf->plist = g_list_first(cf->plist);
264     cf->fh = fopen(fname, "r");
265     gtk_clist_thaw(GTK_CLIST(packet_list));
266   }
267   
268   gtk_timeout_remove(timeout);
269   gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
270
271   gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
272
273   if (err == 0) {
274     msg_len = strlen(name_ptr) + strlen(done_fmt) + 64;
275     load_msg = g_realloc(load_msg, msg_len);
276     snprintf(load_msg, msg_len, done_fmt, name_ptr, cf->drops);
277     gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
278     g_free(load_msg);
279
280     name_ptr[-1] = '\0';
281 #ifdef USE_ITEM
282     set_menu_sensitivity("/File/Close", TRUE);
283     set_menu_sensitivity("/File/Reload", TRUE);
284 #else
285     set_menu_sensitivity("<Main>/File/Close", TRUE);
286     set_menu_sensitivity("<Main>/File/Reload", TRUE);
287 #endif
288   } else {
289     msg_len = strlen(name_ptr) + strlen(err_fmt) + 2;
290     load_msg = g_realloc(load_msg, msg_len);
291     snprintf(load_msg, msg_len, err_fmt, name_ptr);
292     gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
293     g_free(load_msg);
294 #ifdef USE_ITEM
295     set_menu_sensitivity("<Main>/File/Close", FALSE);
296     set_menu_sensitivity("<Main>/File/Reload", FALSE);
297 #else
298     set_menu_sensitivity("<Main>/File/Close", FALSE);
299     set_menu_sensitivity("<Main>/File/Reload", FALSE);
300 #endif
301   }
302
303   return err;
304 }
305
306 static void
307 #ifdef WITH_WIRETAP
308 wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset,
309 #else
310 pcap_dispatch_cb(u_char *user, const struct pcap_pkthdr *phdr,
311 #endif
312   const u_char *buf) {
313   frame_data   *fdata;
314   gint          i, row;
315   capture_file *cf = (capture_file *) user;
316   
317   while (gtk_events_pending())
318     gtk_main_iteration();
319
320   fdata   = cf->plist->data;
321   cf->cur = fdata;
322   cf->count++;
323
324   fdata->pkt_len  = phdr->len;
325   fdata->cap_len  = phdr->caplen;
326 #ifdef WITH_WIRETAP
327   fdata->file_off = offset;
328 #else
329   fdata->file_off = ftell(cf->fh) - phdr->caplen;
330 #endif
331   fdata->abs_secs  = phdr->ts.tv_sec;
332   fdata->abs_usecs = phdr->ts.tv_usec;
333   fdata->lnk_t = phdr->pkt_encap;
334
335   /* If we don't have the time stamp of the first packet, it's because this
336      is the first packet.  Save the time stamp of this packet as the time
337      stamp of the first packet. */
338   if (!firstsec && !firstusec) {
339     firstsec  = fdata->abs_secs;
340     firstusec = fdata->abs_usecs;
341   }
342
343   /* Do the same for the time stamp of the previous packet. */
344   if (!lastsec && !lastusec) {
345     lastsec  = fdata->abs_secs;
346     lastusec = fdata->abs_usecs;
347   }
348
349   /* Get the time elapsed between the first packet and this packet. */
350   cf->esec = fdata->abs_secs - firstsec;
351   if (firstusec <= fdata->abs_usecs) {
352     cf->eusec = fdata->abs_usecs - firstusec;
353   } else {
354     cf->eusec = (fdata->abs_usecs + 1000000) - firstusec;
355     cf->esec--;
356   }
357   fdata->rel_secs = cf->esec;
358   fdata->rel_usecs = cf->eusec;
359   
360   /* Do the same for the previous packet */
361   fdata->del_secs = fdata->abs_secs - lastsec;
362   if (lastusec <= fdata->abs_usecs) {
363     fdata->del_usecs = fdata->abs_usecs - lastusec;
364   } else {
365     fdata->del_usecs = (fdata->abs_usecs + 1000000) - lastusec;
366     fdata->del_secs--;
367   }
368   lastsec = fdata->abs_secs;
369   lastusec = fdata->abs_usecs;
370
371   fdata->cinfo = &cf->cinfo;
372   for (i = 0; i < fdata->cinfo->num_cols; i++) {
373     fdata->cinfo->col_data[i][0] = '\0';
374   }
375   if (check_col(fdata, COL_NUMBER))
376     col_add_fstr(fdata, COL_NUMBER, "%d", cf->count);
377   dissect_packet(buf, fdata, NULL);
378   row = gtk_clist_append(GTK_CLIST(packet_list), fdata->cinfo->col_data);
379   fdata->cinfo = NULL;
380
381   /* Make sure we always have an available list entry */
382   if (cf->plist->next == NULL) {
383     fdata = (frame_data *) g_malloc(sizeof(frame_data));
384     g_list_append(cf->plist, (gpointer) fdata);
385   }
386   cf->plist = cf->plist->next;
387 }