diff options
author | Gerald Combs <gerald@wireshark.org> | 2011-10-10 22:39:35 +0000 |
---|---|---|
committer | Gerald Combs <gerald@wireshark.org> | 2011-10-10 22:39:35 +0000 |
commit | 8e5c7e2da97547a939221f24c59b960a3127ee93 (patch) | |
tree | 27ccab02d3880c08d9f25105ffe18b104f589740 /gtk | |
parent | 29e823dfbaaa76c531003fc539b802de50bb3613 (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.c | 207 | ||||
-rw-r--r-- | gtk/capture_dlg.h | 12 | ||||
-rw-r--r-- | gtk/main.c | 5 |
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); |