aboutsummaryrefslogtreecommitdiffstats
path: root/gtk
diff options
context:
space:
mode:
authorGerald Combs <gerald@wireshark.org>2011-10-10 22:39:35 +0000
committerGerald Combs <gerald@wireshark.org>2011-10-10 22:39:35 +0000
commit8e5c7e2da97547a939221f24c59b960a3127ee93 (patch)
tree27ccab02d3880c08d9f25105ffe18b104f589740 /gtk
parent29e823dfbaaa76c531003fc539b802de50bb3613 (diff)
Check our capture filter syntax in a separate thread.
svn path=/trunk/; revision=39349
Diffstat (limited to 'gtk')
-rw-r--r--gtk/capture_dlg.c207
-rw-r--r--gtk/capture_dlg.h12
-rw-r--r--gtk/main.c5
3 files changed, 200 insertions, 24 deletions
diff --git a/gtk/capture_dlg.c b/gtk/capture_dlg.c
index 8a3a61a689..6980a1779e 100644
--- a/gtk/capture_dlg.c
+++ b/gtk/capture_dlg.c
@@ -266,43 +266,207 @@ capture_get_cap_settings (gchar *if_name)
return cap_settings;
}
+enum cfc_state_t {
+ CFC_PENDING,
+ CFC_UNKNOWN,
+ CFC_VALID,
+ CFC_INVALID
+};
+
+typedef struct capture_filter_check {
+ enum cfc_state_t state;
+ gchar *filter_text;
+ GtkWidget *filter_te;
+ int dlt;
+} capture_filter_check_t;
+
+/* Valid states:
+ *
+ * Idle: filter_text = NULL, state = ?
+ * Pending: filter_text != NULL, state = CFC_PENDING
+ * Unknown: filter_text != NULL, state = CFC_UNKNOWN
+ * Known: filter_text != NULL, state = CFC_VALID || CFC_INVALID
+ *
+ * We assume that only one text entry is active at a time.
+ */
+
+/* We could make this smarter by caching results */
+capture_filter_check_t cfc_data;
+
+#ifdef USE_THREADS
+GMutex *pcap_compile_mtx = NULL;
+GCond *cfc_data_cond = NULL;
+GMutex *cfc_data_mtx = NULL;
+GThread *cfc_thread = NULL;
+#endif
+
+#if 0
+#define DEBUG_SYNTAX_CHECK(state1, state2) g_warning("CF state %s -> %s : %s", state1, state2, cfc_data.filter_text)
+#else
+#define DEBUG_SYNTAX_CHECK(state1, state2)
+#endif
+
+static void *
+check_capture_filter_syntax(void *data _U_) {
+ struct bpf_program fcode;
+ int pc_err;
+
+#ifdef USE_THREADS
+ while (1) {
+ g_mutex_lock(cfc_data_mtx);
+ while (!cfc_data.filter_text || cfc_data.state != CFC_PENDING) {
+ /* Do we really need to use a mutex here? We only have one thread... */
+ g_cond_wait(cfc_data_cond, cfc_data_mtx);
+ }
+#endif
+ cfc_data.state = CFC_UNKNOWN;
+ DEBUG_SYNTAX_CHECK("pending", "unknown");
+#ifdef USE_THREADS
+ g_mutex_unlock(cfc_data_mtx);
+ g_mutex_lock(pcap_compile_mtx);
+#endif
+ /* pcap_compile_nopcap will not alter the filter string, so the (char *) cast is "safe" */
+ pc_err = pcap_compile_nopcap(DUMMY_SNAPLENGTH /* use a dummy snaplength for syntax-checking */,
+ cfc_data.dlt, &fcode, cfc_data.filter_text, 1 /* Do optimize */,
+ DUMMY_NETMASK /* use a dummy netmask for syntax-checking */);
+#ifdef USE_THREADS
+ g_mutex_unlock(pcap_compile_mtx);
+ g_mutex_lock(cfc_data_mtx);
+#endif
+ if (cfc_data.state == CFC_UNKNOWN) { /* No more input came in */
+ if (pc_err) {
+ DEBUG_SYNTAX_CHECK("unknown", "known bad");
+ cfc_data.state = CFC_INVALID;
+ } else {
+ DEBUG_SYNTAX_CHECK("unknown", "known good");
+ cfc_data.state = CFC_VALID;
+ }
+ }
+#ifdef USE_THREADS
+ g_mutex_unlock(cfc_data_mtx);
+ }
+#endif
+ return NULL;
+}
+
+static gboolean
+update_capture_filter_te(gpointer data _U_) {
+
+ if (!prefs.capture_syntax_check_filter)
+ return TRUE;
+
+#ifdef USE_THREADS
+ g_mutex_lock(cfc_data_mtx);
+#endif
+ if (cfc_data.filter_text && cfc_data.filter_te) {
+ if (cfc_data.state == CFC_VALID) {
+ colorize_filter_te_as_valid(cfc_data.filter_te);
+ } else if (cfc_data.state == CFC_INVALID) {
+ colorize_filter_te_as_invalid(cfc_data.filter_te);
+ } else {
+ colorize_filter_te_as_empty(cfc_data.filter_te);
+ }
+
+ if (cfc_data.state == CFC_VALID || cfc_data.state == CFC_INVALID) {
+ DEBUG_SYNTAX_CHECK("known", "idle");
+ /* Reset the current state to idle. */
+ if (cfc_data.filter_text != NULL) {
+ g_free(cfc_data.filter_text);
+ }
+ cfc_data.filter_text = NULL;
+ cfc_data.state = CFC_PENDING;
+ }
+ }
+#ifdef USE_THREADS
+ g_mutex_unlock(cfc_data_mtx);
+#endif
+ return TRUE;
+}
+
+/** Initialize background capture filter syntax checking
+ */
+void capture_filter_init(void) {
+ cfc_data.filter_text = NULL;
+ cfc_data.filter_te = NULL;
+ cfc_data.state = CFC_PENDING;
+#ifdef USE_THREADS
+ pcap_compile_mtx = g_mutex_new();
+ cfc_data_cond = g_cond_new();
+ cfc_data_mtx = g_mutex_new();
+ g_timeout_add(200, update_capture_filter_te, NULL);
+ g_thread_create(check_capture_filter_syntax, NULL, FALSE, NULL);
+#endif
+}
+
static void
capture_filter_check_syntax_cb(GtkWidget *w _U_, gpointer user_data _U_)
{
- struct bpf_program fcode;
- GtkWidget *filter_cm, *filter_te;
- const gchar *filter_text;
- gpointer ptr;
- int dlt;
+ GtkWidget *filter_cm, *filter_te, *linktype_combo_box;
+ gchar *filter_text;
+ gpointer dlt_ptr;
- GtkWidget *linktype_combo_box = (GtkWidget *) g_object_get_data(G_OBJECT(opt_edit_w), E_CAP_LT_CBX_KEY);
+ if (!prefs.capture_syntax_check_filter)
+ return;
- if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(linktype_combo_box), &ptr)) {
+ linktype_combo_box = (GtkWidget *) g_object_get_data(G_OBJECT(opt_edit_w), E_CAP_LT_CBX_KEY);
+
+ if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(linktype_combo_box), &dlt_ptr)) {
g_assert_not_reached(); /* Programming error: somehow nothing is active */
}
- if ((dlt = GPOINTER_TO_INT(ptr)) == -1) {
+ if ((cfc_data.dlt = GPOINTER_TO_INT(dlt_ptr)) == -1) {
g_assert_not_reached(); /* Programming error: somehow managed to select an "unsupported" entry */
}
- if (!prefs.capture_syntax_check_filter)
- return;
-
filter_cm = g_object_get_data(G_OBJECT(opt_edit_w), E_CFILTER_CM_KEY);
+ if (!filter_cm)
+ return;
filter_te = gtk_bin_get_child(GTK_BIN(filter_cm));
+ if (!filter_te)
+ return;
+
filter_text = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT(filter_cm));
+
if (strlen(filter_text) == 0) {
colorize_filter_te_as_empty(filter_te);
return;
}
- /* pcap_compile_nopcap will not alter the filter string, so the (char *) cast is "safe" */
- if (pcap_compile_nopcap(DUMMY_SNAPLENGTH /* use a dummy snaplength for syntax-checking */,
- dlt, &fcode, (char *)filter_text, 1 /* Do optimize */,
- DUMMY_NETMASK /* use a dummy netmask for syntax-checking */) < 0) {
- colorize_filter_te_as_invalid(filter_te);
- } else {
- colorize_filter_te_as_valid(filter_te);
+#ifdef USE_THREADS
+ g_mutex_lock(cfc_data_mtx);
+#endif
+ /* Ruthlessly clobber the current state. */
+ if (cfc_data.filter_text != NULL) {
+ g_free(cfc_data.filter_text);
+ }
+ cfc_data.filter_text = filter_text;
+ cfc_data.filter_te = filter_te;
+ cfc_data.state = CFC_PENDING;
+ DEBUG_SYNTAX_CHECK("?", "pending");
+#ifdef USE_THREADS
+ g_cond_signal(cfc_data_cond);
+ g_mutex_unlock(cfc_data_mtx);
+#else
+ check_capture_filter_syntax(NULL);
+ update_capture_filter_te(NULL);
+#endif
+}
+
+static void
+capture_filter_destroy_cb(GtkWidget *w _U_, gpointer user_data _U_)
+{
+#ifdef USE_THREADS
+ g_mutex_lock(cfc_data_mtx);
+#endif
+ /* Reset the current state to idle. */
+ if (cfc_data.filter_text != NULL) {
+ g_free(cfc_data.filter_text);
}
+ cfc_data.filter_text = NULL;
+ cfc_data.filter_te = NULL;
+ cfc_data.state = CFC_PENDING;
+#ifdef USE_THREADS
+ g_mutex_unlock(cfc_data_mtx);
+#endif
}
#define TIME_UNIT_SECOND 0
@@ -1474,12 +1638,18 @@ capture_filter_compile_cb(GtkWidget *w _U_, gpointer user_data _U_)
pd = pcap_open_dead(dlt, DUMMY_SNAPLENGTH);
filter_cm = g_object_get_data(G_OBJECT(opt_edit_w), E_CFILTER_CM_KEY);
filter_text = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT(filter_cm));
+#ifdef USE_THREADS
+ g_mutex_lock(pcap_compile_mtx);
+#endif
/* pcap_compile will not alter the filter string, so the (char *) cast is "safe" */
#ifdef PCAP_NETMASK_UNKNOWN
if (pcap_compile(pd, &fcode, (char *)filter_text, 1 /* Do optimize */, PCAP_NETMASK_UNKNOWN) < 0) {
#else
if (pcap_compile(pd, &fcode, (char *)filter_text, 1 /* Do optimize */, 0) < 0) {
#endif
+#ifdef USE_THREADS
+ g_mutex_unlock(pcap_compile_mtx);
+#endif
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", pcap_geterr(pd));
} else {
GString *bpf_code_dump = g_string_new("");
@@ -2052,6 +2222,7 @@ void options_interface_cb(GtkTreeView *view, GtkTreePath *path, GtkTreeViewColum
filter_te = gtk_bin_get_child(GTK_BIN(filter_cm));
colorize_filter_te_as_empty(filter_te);
g_signal_connect(filter_te, "changed", G_CALLBACK(capture_filter_check_syntax_cb), NULL);
+ g_signal_connect(filter_te, "destroy", G_CALLBACK(capture_filter_destroy_cb), NULL);
for (cf_entry = cfilter_list; cf_entry != NULL; cf_entry = g_list_next(cf_entry)) {
if (cf_entry->data && (strlen(cf_entry->data) > 0)) {
diff --git a/gtk/capture_dlg.h b/gtk/capture_dlg.h
index 2cb006486f..c782596504 100644
--- a/gtk/capture_dlg.h
+++ b/gtk/capture_dlg.h
@@ -100,6 +100,10 @@ enum
NUM_COLUMNS
};
+/** Initialize background capture filter syntax checking
+ */
+void capture_filter_init(void);
+
/** User requested the "Capture Options" dialog box by menu or toolbar.
*
* @param widget parent widget (unused)
@@ -160,10 +164,10 @@ typedef struct {
cap_settings_t
capture_get_cap_settings (gchar *if_name);
-GtkTreeModel*
+GtkTreeModel*
create_and_fill_model (GtkTreeView *view);
-gboolean
+gboolean
query_tooltip_tree_view_cb (GtkWidget *widget,
gint x,
gint y,
@@ -171,7 +175,7 @@ query_tooltip_tree_view_cb (GtkWidget *widget,
GtkTooltip *tooltip,
gpointer data);
-void
+void
activate_monitor (GtkTreeViewColumn *tree_column, GtkCellRenderer *renderer,
GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data);
@@ -190,7 +194,7 @@ capture_remote_combo_recent_write_all(FILE *rf);
* @param s string with hostname,port,auth_type
* @return TRUE if correctly added
*/
-gboolean
+gboolean
capture_remote_combo_add_recent(gchar *s);
#endif
diff --git a/gtk/main.c b/gtk/main.c
index d40bae7ba5..492c7529a8 100644
--- a/gtk/main.c
+++ b/gtk/main.c
@@ -1008,7 +1008,7 @@ main_window_delete_event_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer
if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
gtk_window_present(GTK_WINDOW(top_level));
/* user didn't saved his current file, ask him */
- dialog = simple_dialog(ESD_TYPE_CONFIRMATION,
+ dialog = simple_dialog(ESD_TYPE_CONFIRMATION,
((cfile.state == FILE_READ_IN_PROGRESS) ? ESD_BTNS_QUIT_DONTSAVE_CANCEL : ESD_BTNS_SAVE_QUIT_DONTSAVE_CANCEL),
"%sSave capture file before program quit?%s\n\n"
"If you quit the program without saving, your capture data will be discarded.",
@@ -1115,7 +1115,7 @@ file_quit_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
/* user didn't saved his current file, ask him */
- dialog = simple_dialog(ESD_TYPE_CONFIRMATION,
+ dialog = simple_dialog(ESD_TYPE_CONFIRMATION,
((cfile.state == FILE_READ_IN_PROGRESS) ? ESD_BTNS_QUIT_DONTSAVE_CANCEL : ESD_BTNS_SAVE_QUIT_DONTSAVE_CANCEL),
"%sSave capture file before program quit?%s\n\n"
"If you quit the program without saving, your capture data will be discarded.",
@@ -2917,6 +2917,7 @@ main(int argc, char *argv[])
color_filters_init();
decode_as_init();
+ capture_filter_init();
/* the window can be sized only, if it's not already shown, so do it now! */
main_load_window_geometry(top_level);