4 * $Id: file.c,v 1.10 1998/10/13 07:03:32 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@zing.org>
8 * Copyright 1998 Gerald Combs
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.
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.
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.
39 #ifdef NEED_SNPRINTF_H
45 # include "snprintf.h"
48 #ifdef HAVE_SYS_TYPES_H
49 # include <sys/types.h>
52 #ifdef HAVE_NETINET_IN_H
53 # include <netinet/in.h>
62 extern GtkWidget *packet_list, *prog_bar, *info_bar, *byte_view, *tree_view;
63 extern guint file_ctx;
65 static guint32 ssec, susec;
66 static guint32 lastsec, lastusec;
69 open_cap_file(char *fname, capture_file *cf) {
71 char err_str[PCAP_ERRBUF_SIZE];
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.");
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.");
84 /* Next, try to open the file */
85 cf->fh = fopen(fname, "r");
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);
97 /* set the file name beacuse we need it to set the follow stream filter */
98 cf->filename = g_strdup( fname );
100 /* Next, find out what type of file we're dealing with */
102 cf->cd_t = CD_UNKNOWN;
103 cf->lnk_t = DLT_NULL;
110 if (cf->plist == NULL) {
111 cf->plist = g_list_alloc();
112 cf->plist->data = (frame_data *) g_malloc(sizeof(frame_data));
114 cf->plist = g_list_first(cf->plist);
117 lastsec = 0, lastusec = 0;
119 if (magic[0] == PCAP_MAGIC || magic[0] == SWAP32(PCAP_MAGIC)) {
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.");
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.");
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;
144 cf->cd_t = CD_PCAP_LE;
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) {
152 simple_dialog(ESD_TYPE_WARN, NULL, "The snoop format is not yet supported.");
155 fread(&sfh, sizeof(snoop_file_hdr), 1, cf->fh);
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)",
163 switch (ntohl(sfh.s_lnk_t)) {
165 cf->lnk_t = DLT_EN10MB;
171 if (cf->cd_t == CD_UNKNOWN) {
172 simple_dialog(ESD_TYPE_WARN, NULL, "Can't determine file type.");
178 /* Reset everything to a pristine state */
180 close_cap_file(capture_file *cf, GtkWidget *w, guint context) {
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));
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);
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'";
212 close_cap_file(cf, info_bar, file_ctx);
214 if ((name_ptr = (gchar *) strrchr(fname, '/')) == NULL)
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);
222 timeout = gtk_timeout_add(250, file_progress_cb, (gpointer) &cf);
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);
230 cf->plist = g_list_first(cf->plist);
231 cf->fh = fopen(fname, "r");
232 gtk_clist_thaw(GTK_CLIST(packet_list));
235 gtk_timeout_remove(timeout);
236 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
238 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
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);
248 set_menu_sensitivity("<Main>/File/Close", TRUE);
249 set_menu_sensitivity("<Main>/File/Reload", TRUE);
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);
256 set_menu_sensitivity("<Main>/File/Close", FALSE);
257 set_menu_sensitivity("<Main>/File/Reload", FALSE);
264 pcap_dispatch_cb(u_char *user, const struct pcap_pkthdr *phdr,
267 /* To do: make sure this is big enough. */
268 gchar p_info[NUM_COLS][256];
270 capture_file *cf = (capture_file *) user;
271 guint32 tssecs, tsusecs;
273 while (gtk_events_pending())
274 gtk_main_iteration();
276 fdata = cf->plist->data;
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;
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) {
291 susec = fdata->usecs;
294 /* Do the same for the time stamp of the previous packet. */
295 if (!lastsec && !lastusec) {
296 lastsec = fdata->secs;
297 lastusec = fdata->usecs;
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;
305 cf->eusec = (fdata->usecs + 1000000) - susec;
309 /* Compute the time stamp. */
310 switch (timestamp_type) {
311 case RELATIVE: /* Relative to the first packet */
315 case DELTA: /* Relative to the previous packet */
316 tssecs = fdata->secs - lastsec;
317 if (lastusec <= fdata->usecs) {
318 tsusecs = fdata->usecs - lastusec;
320 tsusecs = (fdata->usecs + 1000000) - lastusec;
324 default: /* Absolute time, or bogus timestamp_type value */
325 tssecs = 0; /* Not used */
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; }
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);
340 cf->plist = cf->plist->next;
343 /* Uncomment when we handle snoop files again.
346 read_frame_header(capture_file *cf) {
347 snoop_frame_hdr shdr;
349 gint16 pkt_len, cap_len;
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));
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);
364 pkt_len = phdr.pkt_len;
365 cap_len = phdr.cap_len;
366 secs = phdr.tm.tv_sec;
367 usecs = phdr.tm.tv_usec;
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;
384 cf->eusec = susec - usecs;
389 fdata->pkt_len = pkt_len;
390 fdata->cap_len = cap_len;
392 fdata->usecs = usecs;
393 g_list_append(cf->plist, (gpointer) fdata);
394 if (!ssec && !susec) {
398 cf->esec = secs - ssec;
400 cf->eusec = usecs - susec;
402 cf->eusec = susec - usecs;