Ethereal-dev: [Ethereal-dev] [patch] save & load hostname-cache

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Matthijs Melchior <mmelchior@xxxxxxxxx>
Date: Mon, 20 Oct 2003 23:56:33 +0200
Hi,
   To make it easy on myself when looking at traces from networks
without names I have created the following feature.

The "Edit>Preferences>Name Resolution" dialog is extended with 2 lines,
one to show the file name and one to "Clear", "Load" or "Save" the
hostname-cache in a file. This allows you to preload the hostname-cache
with names of your choise and not having to remember the IP numbers.
And collected IP numbers [with names, if any] can be written to
a file for adding hostnames and reloading.

There may be a need to connect this to some preferences, but that
has not yet been done.

Please apply.

Thanks.

--
Regards,
----------------------------------------------------------------  -o)
Matthijs Melchior                                       Maarssen  /\\
mmelchior@xxxxxxxxx                                  Netherlands _\_v
---------------------------------------------------------------- ----

diff -u epan/resolv.c-ORG epan/resolv.c
--- epan/resolv.c-ORG	2003-08-28 01:01:21.000000000 +0200
+++ epan/resolv.c	2003-10-18 23:14:59.000000000 +0200
@@ -1887,3 +1887,77 @@
 
 	return FALSE;
 }
+
+/*
+ * Clear, Save and Load the contants of the hostname-cache.
+ * Useful for traces from dedicated networks without nameservers:
+ * clear the name cache, load the trace, save name cache,
+ * add names to that file, load that file into the cache again.
+ */
+
+void clear_host_cache()
+{
+	int         i;
+	hashname_t *p, *q;
+
+	for(i=0; i<HASHHOSTSIZE; i++) {
+		p = host_table[i];
+		while(p) {
+			q = p;
+			p = p->next;
+			g_free(q);
+		}
+		host_table[i] = NULL;
+	}
+}
+
+int save_host_cache(char *file)
+{
+  FILE       *hosts;
+  hashname_t *p;
+  int         i;
+  char       *n;
+
+  hosts = fopen(file, "w");
+  if (hosts == 0) {
+    return -1;
+  }
+  fprintf(hosts, "# hostname-cache for ethereal\n\n");
+  for(i=0; i<HASHHOSTSIZE; i++) {
+    p = host_table[i];
+    while(p) {
+	    n = p->name;
+	    if (p->is_dummy_entry)
+		    n = "#";	/* create invalid entry ... */
+	    fprintf(hosts, "%s\t%s\n", ip_to_str((guchar *)&(p->addr)), n);
+	    p = p->next;
+    }
+  }
+  fclose(hosts);
+  return 0;
+}
+
+int load_host_cache(char *file)
+{
+ static char    sep[] = " \t\r\n";
+	FILE   *hosts;
+	int     size = 0;
+	char   *buf = NULL;
+	struct  in_addr a;
+	char   *cp;
+
+	hosts = fopen(file, "r");
+	if (hosts == 0) {
+		return -1;
+	}
+	while(fgetline(&buf, &size, hosts) >= 0) {
+		if ((cp = strchr(buf, '#')))
+			*cp = '\0';
+		if ((cp = strtok(buf, sep)))
+			if (inet_aton(cp, &a))
+				if ((cp = strtok(NULL, sep)))
+					add_host_name(a.s_addr, cp);
+	}
+
+	g_free(buf);
+}
diff -u gtk/nameres_prefs.c-ORG gtk/nameres_prefs.c
--- gtk/nameres_prefs.c-ORG	2003-07-22 05:14:31.000000000 +0200
+++ gtk/nameres_prefs.c	2003-10-20 22:49:45.000000000 +0200
@@ -45,17 +45,137 @@
 # define C_RESOLVE_KEY	"c_resolve"
 # define RESOLVE_CONCURRENCY_KEY "resolve_concurrency"
 #endif /* HAVE_GNU_ADNS */
+#define CACHE_FILE_KEY		  "cache_file_name"
+#define E_FS_CALLER_PTR_KEY	  "fs_caller_ptr"
+#define E_FILE_SEL_DIALOG_PTR_KEY "file_sel_dialog_ptr"
+#define CACHE_FILE_ACTION_FU	  "cache_file_action_fu"
 
 #ifdef HAVE_GNU_ADNS
-# define RESOLV_TABLE_ROWS 5
+# define RESOLV_TABLE_ROWS 7
 #else
-# define RESOLV_TABLE_ROWS 3
+# define RESOLV_TABLE_ROWS 5
 #endif /* HAVE_GNU_ADNS */
+
+void dlg_set_cancel(GtkWidget *widget, GtkWidget *cancel_button);
+char* get_persconffile_path(const char *filename, gboolean for_writing);
+
+typedef int (*actionfu)(gchar *file); /* for function pointers as parameter */
+
+int load_host_cache(gchar *file);
+int save_host_cache(gchar *file);
+int clear_host_cache();
+
+/* This could be a preference */
+static gchar *hosts_cache_filename = 0;
+
+static void
+cache_fs_cancel_cb(GtkWidget *w _U_, gpointer data)
+{
+        gtk_widget_destroy(GTK_WIDGET(data));
+}
+
+static void
+cache_fs_ok_cb(GtkWidget *w, gpointer data)
+{
+       	gchar * name = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(data));
+	actionfu action = OBJECT_GET_DATA(data, CACHE_FILE_ACTION_FU);
+
+        gtk_entry_set_text(GTK_ENTRY(OBJECT_GET_DATA(data, CACHE_FILE_KEY)), name);
+        cache_fs_cancel_cb(w, data);
+
+	action(name);		/* do it */
+}
+
+static void
+cache_fs_destroy_cb(GtkWidget *win, gpointer data _U_)
+{
+	GtkWidget *caller;
+
+	/* Get the widget that requested that we be popped up.
+	   (It should arrange to destroy us if it's destroyed, so
+	   that we don't get a pointer to a non-existent window here.) */
+	caller = OBJECT_GET_DATA(win, E_FS_CALLER_PTR_KEY);
+
+	/* Tell it we no longer exist. */
+	OBJECT_SET_DATA(caller, E_FILE_SEL_DIALOG_PTR_KEY, NULL);
+
+	/* Now nuke this window. */
+	gtk_grab_remove(GTK_WIDGET(win));
+	gtk_widget_destroy(GTK_WIDGET(win));
+}
+
+
+static void
+handle_hostname_cache(GtkWidget *w, gpointer data, actionfu action, gchar *title)
+{
+	GtkWidget *caller = gtk_widget_get_toplevel(w);
+	GtkWidget *fs;
+
+	/* Has a file selection dialog box already been opened for that top-level
+	   widget? */
+	fs = OBJECT_GET_DATA(caller, E_FILE_SEL_DIALOG_PTR_KEY);
+
+	if (fs != NULL) {
+		/* Yes.  Just re-activate that dialog box. */
+		reactivate_window(fs);
+		return;
+	}
+
+	fs = gtk_file_selection_new (title);
+        OBJECT_SET_DATA(fs, CACHE_FILE_KEY, data);
+	OBJECT_SET_DATA(fs, CACHE_FILE_ACTION_FU, action);
+
+	/* Set the E_FS_CALLER_PTR_KEY for the new dialog to point to our caller. */
+	OBJECT_SET_DATA(fs, E_FS_CALLER_PTR_KEY, caller);
+
+	/* Set the E_FILE_SEL_DIALOG_PTR_KEY for the caller to point to us */
+	OBJECT_SET_DATA(caller, E_FILE_SEL_DIALOG_PTR_KEY, fs);
+
+	gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), gtk_entry_get_text(GTK_ENTRY(data)));
+
+	/* Call a handler when the file selection box is destroyed, so we can inform
+	   our caller, if any, that it's been destroyed. */
+	SIGNAL_CONNECT(fs, "destroy", cache_fs_destroy_cb, NULL);
+
+	SIGNAL_CONNECT(GTK_FILE_SELECTION(fs)->ok_button, "clicked",
+		       cache_fs_ok_cb, fs);
+
+	/* Connect the cancel_button to destroy the widget */
+	SIGNAL_CONNECT(GTK_FILE_SELECTION(fs)->cancel_button, "clicked",
+		       cache_fs_cancel_cb, fs);
+
+	/* Catch the "key_press_event" signal in the window, so that we can catch
+	   the ESC key being pressed and act as if the "Cancel" button had
+	   been selected. */
+	dlg_set_cancel(fs, GTK_FILE_SELECTION(fs)->cancel_button);
+
+	gtk_widget_show(fs);
+}
+
+static void
+load_cache_cb(GtkWidget *w, gpointer data)
+{
+	handle_hostname_cache(w, data, load_host_cache, "Ethereal: Load hostname cache from File");
+}
+static void
+save_cache_cb(GtkWidget *w, gpointer data)
+{
+	handle_hostname_cache(w, data, save_host_cache, "Ethereal: Save hostname cache in File");
+}
+
+static void
+clear_cache_cb(GtkWidget *w _U_, gpointer data _U_)
+{
+	clear_host_cache();
+}
+
 GtkWidget*
 nameres_prefs_show(void)
 {
 	GtkWidget	*main_tb, *main_vb;
 	GtkWidget	*m_resolv_cb, *n_resolv_cb, *t_resolv_cb;
+	GtkWidget	*cache_hb, *clear_bt, *save_bt, *load_bt, *file_te;
+	GtkWidget	*label, *event_box;
 #ifdef HAVE_GNU_ADNS
 	GtkWidget	*c_resolv_cb, *resolv_concurrency_te;
 	char		concur_str[10+1];
@@ -115,6 +235,66 @@
 
 #endif /* HAVE_GNU_ADNS */
 
+	label = gtk_label_new("Ethereal hostname-cache filename:");
+	gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
+	gtk_widget_show(label);
+ 
+	event_box = gtk_event_box_new();
+	gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 0, 1, 5, 6);
+	gtk_container_add(GTK_CONTAINER(event_box), label);
+	gtk_widget_show(event_box);
+
+	label = gtk_label_new("Ethereal hostname-cache operations:");
+	gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
+	gtk_widget_show(label);
+ 
+	event_box = gtk_event_box_new();
+	gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 0, 1, 6, 7);
+	gtk_container_add(GTK_CONTAINER(event_box), label);
+	gtk_widget_show(event_box);
+
+	file_te = gtk_entry_new();
+	OBJECT_SET_DATA(main_tb, CACHE_FILE_KEY, file_te);
+	if (hosts_cache_filename == 0) /* this could be a preference */
+		hosts_cache_filename = get_persconffile_path("hostname-cache", TRUE);
+	gtk_entry_set_text(GTK_ENTRY(file_te), hosts_cache_filename);
+	gtk_table_attach_defaults(GTK_TABLE(main_tb), file_te, 1, 2, 5, 6);
+        gtk_widget_show(file_te);
+
+	cache_hb = gtk_hbox_new(TRUE, 8);
+	gtk_table_attach_defaults(GTK_TABLE(main_tb), cache_hb, 1, 2, 6, 7);
+	gtk_widget_show(cache_hb);
+
+#if GTK_MAJOR_VERSION < 2
+	clear_bt = gtk_button_new_with_label("Clear");
+#else
+	clear_bt = gtk_button_new_from_stock(GTK_STOCK_CLEAR);
+#endif
+	gtk_widget_set_sensitive(clear_bt, TRUE);
+	SIGNAL_CONNECT(clear_bt, "clicked", clear_cache_cb, NULL);
+	gtk_box_pack_start(GTK_BOX(cache_hb), clear_bt, TRUE, TRUE, 0);
+	gtk_widget_show(clear_bt);
+
+#if GTK_MAJOR_VERSION < 2
+	load_bt = gtk_button_new_with_label("Load");
+#else
+	load_bt = gtk_button_new_from_stock(GTK_STOCK_OPEN); /* don't have GTK_STOCK_LOAD ... ? */
+#endif
+	gtk_widget_set_sensitive(load_bt, TRUE);
+	SIGNAL_CONNECT(load_bt, "clicked", load_cache_cb, file_te);
+	gtk_box_pack_start(GTK_BOX(cache_hb), load_bt, TRUE, TRUE, 0);
+	gtk_widget_show(load_bt);
+
+#if GTK_MAJOR_VERSION < 2
+	save_bt = gtk_button_new_with_label("Save");
+#else
+	save_bt = gtk_button_new_from_stock(GTK_STOCK_SAVE);
+#endif
+	gtk_widget_set_sensitive(save_bt, TRUE);
+	SIGNAL_CONNECT(save_bt, "clicked", save_cache_cb, file_te);
+	gtk_box_pack_start(GTK_BOX(cache_hb), save_bt, TRUE, TRUE, 0);
+	gtk_widget_show(save_bt);
+ 
 	/* Show 'em what we got */
 	gtk_widget_show_all(main_vb);