forked from osmocom/wireshark
Check our capture filter syntax in a separate thread.
svn path=/trunk/; revision=39349
This commit is contained in:
parent
29e823dfba
commit
8e5c7e2da9
|
@ -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 *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), &ptr)) {
|
||||
g_assert_not_reached(); /* Programming error: somehow nothing is active */
|
||||
}
|
||||
if ((dlt = GPOINTER_TO_INT(ptr)) == -1) {
|
||||
g_assert_not_reached(); /* Programming error: somehow managed to select an "unsupported" entry */
|
||||
}
|
||||
GtkWidget *filter_cm, *filter_te, *linktype_combo_box;
|
||||
gchar *filter_text;
|
||||
gpointer dlt_ptr;
|
||||
|
||||
if (!prefs.capture_syntax_check_filter)
|
||||
return;
|
||||
|
||||
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 ((cfc_data.dlt = GPOINTER_TO_INT(dlt_ptr)) == -1) {
|
||||
g_assert_not_reached(); /* Programming error: somehow managed to select an "unsupported" entry */
|
||||
}
|
||||
|
||||
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,11 +1638,17 @@ 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 {
|
||||
|
@ -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)) {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue