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