Ethereal-dev: [ethereal-dev] Real-Time display without threads

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

From: Christian Brunner <chb@xxxxxx>
Date: Tue, 9 Mar 1999 20:33:14 +0100 (CET)
Hi,

I just discovered gtk_idle_add() and gtk_timeout_add() as a simple way to
perform background actions in GTK applications. I find them quite useful
and maybe this is the sollution to the realtime capture/display problem. 

We could simply create a idle function, that performs a pcap_dispatch() 
with "cnt" set to -1. The callback function of pcap_dispatch() then could
feed the decoding and display routines.

Since I am not that familiar with libpcap, I'm not really sure weather we
would loose packets when there are many other GTK events. But at first
glance I'd say that the problem isn't worse than it would be using threads
(at least on single processor systems :). 

Below you find a modified "Hello World" as an example, that captures all
packets on "eth0" and prints its MAC-Addresses to stderr. 

Christian (chb@xxxxxx)

---
#include <gtk/gtk.h>
#include <pcap.h>

static pcap_t *pd;

void callback( GtkWidget *widget,
               gpointer   data )
{
    g_print ("Hello again - %s was pressed\n", (char *) data);
}

/* pcap_dispatch callback */
void p_callback(u_char *user, const struct pcap_pkthdr *h, const u_char *bp) {
	int i;
	
	for(i=0; i<6; i++) {
		fprintf(stderr, "%02X:", bp[i]);
	}
	fprintf(stderr, "\b ");
	for(i=0; i<6; i++) {
		fprintf(stderr, "%02X:", bp[i+6]);
	}
	fprintf(stderr, "\b\n");
}

/* idle function */
static void pcap_receive(gpointer data) {
	u_char *pcap_userdata;
	pcap_userdata = 0;

	pcap_dispatch(pd, -1, p_callback, pcap_userdata);
}

int main( int   argc,
          char *argv[] )
{
    GtkWidget *window;
    GtkWidget *button;
    GtkWidget *box1;
    char ebuf[PCAP_ERRBUF_SIZE];

    gtk_init (&argc, &argv);

    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

    gtk_container_set_border_width (GTK_CONTAINER (window), 10);

    box1 = gtk_hbox_new(FALSE, 0);
    gtk_container_add (GTK_CONTAINER (window), box1);
    button = gtk_button_new_with_label ("Button 1");
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
			GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");
    gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
    gtk_widget_show(button);
    gtk_widget_show(box1);

    gtk_widget_show (window);

    pd = pcap_open_live("eth0",  68, TRUE, 1000, ebuf);
    if (pd == NULL) {
          fprintf(stderr, "%s\n", ebuf);
          exit(255);
    }

    gtk_idle_add((GtkFunction) pcap_receive, NULL);

    gtk_main ();
}