diff --git a/configure b/configure
index 7fd2d264f9c901f1b0361af975c7d1c4b01a1e43..f90f240822df11e58b965eef836b9065cf503f8b 100755
--- a/configure
+++ b/configure
@@ -1239,6 +1239,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
 	vis/top2png vis/render \
 	rc.d/GNUmakefile rc.d/2.mysql-server.sh rc.d/3.testbed.sh \
 	rc.d/cvsupd.sh rc.d/2.elvind.sh \
+	tools/pcapper/GNUmakefile \
 	$eventfiles \
 	apache/GNUmakefile apache/apache.conf "
 
diff --git a/configure.in b/configure.in
index 72600d90d86f952fbc759d8ed0cfa2a93310727b..39518afb97347025b7449d118304292c63fcbaa4 100755
--- a/configure.in
+++ b/configure.in
@@ -311,6 +311,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
 	vis/top2png vis/render \
 	rc.d/GNUmakefile rc.d/2.mysql-server.sh rc.d/3.testbed.sh \
 	rc.d/cvsupd.sh rc.d/2.elvind.sh \
+	tools/pcapper/GNUmakefile \
 	$eventfiles \
 	apache/GNUmakefile apache/apache.conf "
 
diff --git a/tools/pcapper/GNUmakefile b/tools/pcapper/GNUmakefile
deleted file mode 100644
index ecdf04863c97750ff5004cefd6bb439711b49432..0000000000000000000000000000000000000000
--- a/tools/pcapper/GNUmakefile
+++ /dev/null
@@ -1,19 +0,0 @@
-CPPFLAGS= -D_THREAD_SAFE -DEMULAB
-CPPFLAGS_FREEBSD= $(CPPFLAGS) -I/usr/local/include/pthread/linuxthreads
-CPPFLAGS_LINUX= $(CPPFLAGS) -I/usr/include/pcap 
-#CFLAGS=-pedantic -ansi -Wall -Werror
-CFLAGS=-Wall
-LDFLAGS= -lpcap -llthread -llgcc_r -L/usr/local/lib
-
-all: pcapper
-
-clean:
-	-rm pcapper pcapper.linux
-
-pcapper: pcapper.c GNUmakefile
-	$(CC) $(CFLAGS) $(CPPFLAGS_FREEBSD) $(LDFLAGS) pcapper.c \
-		-o pcapper -lpcap
-
-pcapper.linux: pcapper.c GNUmakefile
-	$(CC) $(CFLAGS) $(CPPFLAGS_LINUX) -L/usr/lib -lpthread -lpcap \
-	pcapper.c -o pcapper.linux -lpcap
diff --git a/tools/pcapper/GNUmakefile.in b/tools/pcapper/GNUmakefile.in
new file mode 100644
index 0000000000000000000000000000000000000000..f0edf6ca35e5b3db92a8678fde4eee16770eb15c
--- /dev/null
+++ b/tools/pcapper/GNUmakefile.in
@@ -0,0 +1,47 @@
+SRCDIR          = @srcdir@
+TESTBED_SRCDIR  = @top_srcdir@
+OBJDIR          = ../..
+SUBDIR          = tools/pcapper
+
+include $(OBJDIR)/Makeconf
+
+all: pcapper
+
+include $(TESTBED_SRCDIR)/GNUmakerules
+
+PTHREADCFLAGS = -D_THREAD_SAFE -I/usr/local/include/pthread/linuxthreads
+PTHREADLIBS   = -L/usr/local/lib -llthread -llgcc_r
+
+ELVINFLAGS    = `elvin-config --cflags vin4c`
+ELVINLIBS     = -L/usr/local/lib -lvin4c -lvin4 -lssl -lcrypto -lm
+
+TBCFLAGS      = -I$(TESTBED_SRCDIR)/event/lib -I$(TESTBED_SRCDIR)/lib/libtb
+TBLIBS        = $(OBJDIR)/event/lib/event.o $(OBJDIR)/event/lib/util.o \
+		$(OBJDIR)/lib/libtb/libtb.a
+
+PCAPLIBS=-lpcap
+
+CFLAGS  = -Wall -static $(PTHREADCFLAGS) $(TBCFLAGS) $(ELVINFLAGS) \
+	-DEVENTSYS -DEMULAB -g -DDROPROOT -DBOSSNODE=\"@BOSSNODE@\"
+LDFLAGS = -static
+
+CFLAGS_FREEBSD = $(CFLAGS) 
+CLAGS_LINUX    = $(CLAGS) -I/usr/include/pcap 
+LIBS           = $(PTHREADLIBS) $(TBLIBS) $(ELVINLIBS) $(PCAPLIBS)
+
+
+clean:
+	-rm pcapper pcapper.linux
+
+pcapper: GNUmakefile pcapper.o
+	$(CC) $(LDFLAGS) $(CFLAGS_FREEBSD) pcapper.o $(LIBS) \
+		-o pcapper
+		cp pcapper pcapper.debug
+		strip pcapper
+
+#
+# Note: Building on Linux with the event system is mighty tricky
+#
+pcapper.linux: pcapper.c GNUmakefile
+	$(CC) $(CFLAGS) $(CPPFLAGS_LINUX) -L/usr/lib -lpthread -lpcap \
+	pcapper.c -o pcapper.linux -lpcap
diff --git a/tools/pcapper/pcapper.c b/tools/pcapper/pcapper.c
index ef7e41e0b4c28f852deecc085afd6db2b047d51a..c81532a6b0cf3eba1b9b1a4053d0fe4072a5e50a 100644
--- a/tools/pcapper/pcapper.c
+++ b/tools/pcapper/pcapper.c
@@ -13,6 +13,9 @@
 #ifdef __linux__
 #define __PREFER_BSD
 #define __USE_BSD
+#define __FAVOR_BSD
+#define uh_ulen len
+#define th_off doff
 #endif
 
 #include <sys/types.h>
@@ -26,9 +29,13 @@
 #include <sys/sockio.h>
 #endif
 
+#include <netinet/in_systm.h>
 #include <net/ethernet.h>
 #include <net/if.h>
 #include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
 #include <arpa/inet.h>
 
 #include <err.h>
@@ -43,9 +50,16 @@
 #include <string.h>
 #include <unistd.h>
 
+#ifdef EVENTSYS
+#include "event.h"
+#include "tbdefs.h"
+#include "log.h"
+#endif
+
 #define PORT 4242
 #define MAX_INTERFACES 10
 #define MAX_CLIENTS 10
+#define MAX_FILES 10
 
 /*
  * Program run to determine the control interface.
@@ -53,7 +67,7 @@
 #define CONTROL_IFACE "/etc/testbed/control_interface"
 
 /*
- * Some struct definitions shamelessly stolen from tcpdump.org
+ * A struct definitions shamelessly stolen from tcpdump.org
  */
 
 /* Ethernet header */
@@ -63,26 +77,6 @@ struct sniff_ethernet {
 	u_short ether_type; /* IP? ARP? RARP? etc */
 };
 
-/* IP header */
-struct sniff_ip {
-#if BYTE_ORDER == LITTLE_ENDIAN
-	u_int ip_hl:4, /* header length */
-	ip_v:4; /* version */
-#endif
-#if BYTE_ORDER == BIG_ENDIAN
-	u_int ip_v:4, /* version */
-	ip_hl:4; /* header length */
-#endif
-	u_char ip_tos; /* type of service */
-	u_short ip_len; /* total length */
-	u_short ip_id; /* identification */
-	u_short ip_off; /* fragment offset field */
-	u_char ip_ttl; /* time to live */
-	u_char ip_p; /* protocol */
-	u_short ip_sum; /* checksum */
-	struct in_addr ip_src,ip_dst; /* source and dest address */
-};
-
 /*
  * Arguments to the readpackets function - passed in a struct since
  * pthread-starting functions take a single void* as a parameter.
@@ -146,9 +140,15 @@ struct interface_counter {
  */
 void *readpackets(void *args);
 void *feedclient(void *args);
+void *runeventsys(void *args);
 void got_packet(u_char *args, const struct pcap_pkthdr *header,
 	const u_char *packet);
 int getaddr(char *dev, struct in_addr *addr);
+#ifdef EVENTSYS
+static void
+callback(event_handle_t handle,
+	event_notification_t notification, void *data);
+#endif
 
 /*
  * Number of interfaces we've detected, and their names.
@@ -163,6 +163,40 @@ char interface_names[MAX_INTERFACES][1024];
  */
 int ontime_packets = 0, early_packets = 0;
 
+/*
+ * Nonzero if we're supposed to count payload only
+ */
+int payload_only = 0;
+
+/*
+ * Nonzero if we're supposed to add ethernet headers to the packet size
+ */
+int add_ethernet = 0;
+
+/*
+ * Nonzero if we're supposed to _not_ count zero-sized packets in the
+ * packet counts (obviously, they're already ignored in the byte counts.
+ */
+int no_zero = 0;
+
+#ifdef EVENTSYS
+/*
+ * Time to subtract out of each timestamp reported to clients - this allows
+ * us to report times relative to event system time start events.
+ */
+struct timeval start_time;
+
+/*
+ * 1 if we're adjusting timestamps by start_time, 0 otherwise
+ */
+int adjust_time = 0;
+
+/*
+ * A barrier, so that the main thread can wait for time to start
+ */
+pthread_cond_t time_started;
+#endif
+
 /*
  * For getopt()
  */
@@ -196,8 +230,32 @@ int client_connected[MAX_CLIENTS];
 
 int MAX(int a, int b) { if ((a) > (b)) return (a); else return (b); }
 
+void usage(char *progname) {
+    char *short_usage = "Usage: %s [-f filename] [-i interval] [-p] "
+#ifdef EVENTSYS
+			"[-e eid/pid] "
+#endif
+			"[interfaces...]\n";
+    char *long_usage = "-f filename   Log output to a file\n"
+    		       "-i interval   When logging to a file, the interval "
+			   "(in ms) to report\n"
+		       "-p            Count only payload (not header) size\n"
+		       "-n            Add in ethernet header size\n"
+		       "-z            Don't count zero-length packets\n"
+		       "-o            Print output to stdout\n"
+#ifdef EVENTSYS
+		       "-e pid/eid    Wait for a time start for experiment\n"
+		       "-s server     Use <server> for event server\n"
+#endif
+		       "interfaces... A list of interfaces to monitor\n";
+
+    fprintf(stderr,short_usage,progname);
+    fprintf(stderr,long_usage);
+    exit(-1);
+}
+
 /*
- * XXX: Shorten
+ * XXX: Break up into smaller chunks
  */
 int main (int argc, char **argv) {
 	pthread_t thread;
@@ -206,40 +264,87 @@ int main (int argc, char **argv) {
 	struct sockaddr_in address;
 	struct in_addr ifaddr;
 	struct hostent *host;
-	FILE *control_interface;
 	int i;
 	struct sigaction action;
 	int limit_interfaces;
 	struct ifconf ifc;
 	void  *ptr;
 	char lastname[IFNAMSIZ];
-	char *filename;
+	char *filenames[MAX_FILES];
 	int filetime;
 	char ch;
-
+	char *event_server;
+#ifdef EVENTSYS
+	char *exp;
+	address_tuple_t tuple;
+#endif
 #ifdef EMULAB
+	FILE *control_interface;
 	char control[1024];
+#endif
+#ifdef DROPROOT
+	uid_t uid;
 #endif
 	/*
 	 * Defaults for command-line arugments
 	 */
-
-	filename = NULL;
+	bzero(filenames,sizeof(filenames));
 	filetime = 1000;
+#ifdef EMULAB
+	event_server = BOSSNODE;
+#else
+	event_server = NULL;
+#endif
+
+#ifdef EVENTSYS
+	exp = 0;
+#endif
 
 	/*
 	 * Process command-line arguments
 	 */
-	while ((ch = getopt(argc, argv, "f:i:")) != -1)
+	while ((ch = getopt(argc, argv, "f:i:e:hpnzs:o")) != -1)
 		switch(ch) {
 		case 'f':
-			filename = optarg;
+			/* Find the first empty slot */
+			for (i = 0; filenames[i] != NULL; i++) {}
+			filenames[i] = optarg;
 			break;
 		case 'i':
 			filetime = atoi(optarg);
 			break;
+		case 'p':
+			payload_only = 1;
+			break;
+		case 'n':
+			add_ethernet = 1;
+			break;
+		case 'z':
+			no_zero = 1;
+			break;
+		case 'o':
+			/* Find the first empty slot */
+			for (i = 0; filenames[i] != NULL; i++) {}
+			filenames[i] = "-";
+			break;
+
+#ifdef EVENTSYS
+		case 'e':
+			adjust_time = 1;
+			exp = optarg;
+			break;
+		case 's':
+			event_server = optarg;
+			break;
+
+#endif
+		case 'h':
+			usage(argv[0]);
+			break;
 		default:
 			fprintf(stderr,"Bad argument\n");
+			usage(argv[0]);
+			break;
 		}
 	argc -= optind;
 	argv += optind;
@@ -248,7 +353,7 @@ int main (int argc, char **argv) {
 	 * If they give any more arguments, we take those as interface/hostname
 	 * names to match against, and skip all others.
 	 */
-	if (argc > 1) {
+	if (argc > 0) {
 	    	limit_interfaces = 1;
 	} else {
 	    	limit_interfaces = 0;
@@ -405,7 +510,7 @@ int main (int argc, char **argv) {
 			 */
 			if (limit_interfaces) {
 				int j;
-				for (j = 1; j < argc; j++) {
+				for (j = 0; j < argc; j++) {
 					if ((strstr(name,argv[j])) ||
 					    (strstr(hostname,argv[j]))) {
 					    break;
@@ -446,20 +551,90 @@ int main (int argc, char **argv) {
 			printf("down\n");
 		}
 	}
-
 	close(sock);
 
+	if (interfaces <= 0) {
+		fprintf(stderr,"No interfaces to monitor!\n");
+		exit(-1);
+	}
+
+#ifdef DROPROOT
+	if (geteuid() == 0) {
+	    uid = getuid();
+	    seteuid(uid);
+	}
+#endif
+
 	/*
-	 * If they gave us a filename to log to, open it up.
+	 * Wait for time to start
 	 */
-	if (filename) {
+#ifdef EVENTSYS
+	if (adjust_time) {
+	    event_handle_t ehandle;
+	    char server_string[1024];
+
+	    printf("Waiting for time start in experiment %s\n",exp);
+	    tuple = address_tuple_alloc();
+	    if (tuple == NULL) {
+		fatal("could not allocate an address tuple");
+	    }      
+	    tuple->host      = ADDRESSTUPLE_ANY;
+	    tuple->site      = ADDRESSTUPLE_ANY;
+	    tuple->group     = ADDRESSTUPLE_ANY;
+	    tuple->expt      = exp ? exp : ADDRESSTUPLE_ANY;
+	    tuple->objtype   = TBDB_OBJECTTYPE_TIME;
+	    tuple->objname   = ADDRESSTUPLE_ANY;
+	    tuple->eventtype = TBDB_EVENTTYPE_START;
+
+	    pthread_cond_init(&time_started,NULL);
+
+	    if (event_server) {
+		snprintf(server_string,sizeof(server_string),"elvin://%s",
+			event_server);
+	    } else {
+		server_string[0] = '\0';
+	    }
+
+	    ehandle = event_register(server_string,0);
+	    if (ehandle == NULL) {
+		fatal("could not register with event system");
+	    }
+	    if (!event_subscribe(ehandle, callback, tuple, NULL)) {
+		fatal("could not subscribe to TIME events");
+	    }
+	    address_tuple_free(tuple);
+
+	    /*
+	     * We put the event system main loop into a new thread, since
+	     * we can't use the threaded API with linuxthreads
+	     */
+	    if (pthread_create(&thread,NULL,runeventsys,&ehandle)) {
+		fprintf(stderr,"Unable to start thread!\n");
+		exit(1);
+	    }
+	    pthread_cond_wait(&time_started,&lock);
+	    pthread_mutex_unlock(&lock);
+	}
+#endif
+
+	/*
+	 * If they gave us filenames to log to, open them up.
+	 */
+	for (i = 0; filenames[i] != NULL; i++) {
 		int fd;
 		struct feedclient_args *args;
 
-		fd = open(filename,O_WRONLY | O_CREAT | O_TRUNC);
-		if (fd < 0) {
+		/*
+		 * Allow use the of '-' for stdout
+		 */
+		if (!strcmp(filenames[i],"-")) {
+		    fd = 1;
+		} else {
+		    fd = open(filenames[i],O_WRONLY | O_CREAT | O_TRUNC);
+		    if (fd < 0) {
 			perror("Opening savefile");
 			exit(1);
+		    }
 		}
 
 		/*
@@ -624,6 +799,7 @@ void *feedclient(void *args) {
 		int used = 0;
 		int writerv;
 		struct timeval sleepintr;
+		struct timeval timestamp;
 		struct timespec sleepintr_ts;
 		struct pcap_stat ps;
 
@@ -668,11 +844,20 @@ void *feedclient(void *args) {
 		 */
 		timeradd(&next_time,&interval_tv,&next_time);
 
+		timestamp.tv_sec = now.tv_sec;
+		timestamp.tv_usec = now.tv_usec;
+
+#ifdef EVENTSYS
+		if (adjust_time) {
+		    timersub(&now,&start_time,&timestamp);
+		}
+#endif
+
 		/*
 		 * Put a timestamp on the beginning of each line
 		 */
-		used += sprintf((outbuf +used),"%li.%06li ",now.tv_sec,
-				now.tv_usec);
+		used += sprintf((outbuf +used),"%li.%06li ", timestamp.tv_sec,
+				timestamp.tv_usec);
 
 		/*
 		 * Gather up the counts for each interface into
@@ -748,7 +933,8 @@ void *readpackets(void *args) {
 	/*
 	 * How much of the packet we want to grab. For some reason 
 	 */
-	size = sizeof(struct sniff_ethernet) + sizeof(struct sniff_ip);
+	size = sizeof(struct sniff_ethernet) + sizeof(struct ip) +
+	    sizeof(struct tcphdr);
 	sargs = (struct readpackets_args*)args;
 
 	/*
@@ -756,7 +942,7 @@ void *readpackets(void *args) {
 	 * don't get to see packets until a certain number have been buffered
 	 * up, for some reason.
 	 */
-	dev = pcap_open_live(sargs->devname,size,1,1000,ebuf);
+	dev = pcap_open_live(sargs->devname,size,1,1,ebuf);
 
 	if (!dev) {
 		fprintf(stderr,"Failed to open %s: %s\n",sargs->devname,ebuf);
@@ -795,7 +981,7 @@ void got_packet(u_char *args, const struct pcap_pkthdr *header,
 	const u_char *packet) {
 
 	struct sniff_ethernet *ether_pkt;
-	struct sniff_ip *ip_pkt; 
+	struct ip *ip_pkt; 
 	int length;
 	int type;
 	int index;
@@ -809,12 +995,16 @@ void got_packet(u_char *args, const struct pcap_pkthdr *header,
 		return;
 	}
 
-	ip_pkt = (struct sniff_ip*)(packet + sizeof(struct sniff_ethernet));
+	ip_pkt = (struct ip*)(packet + sizeof(struct sniff_ethernet));
 
 	/*
 	 * Add this packet length to the appropriate total
 	 */
-	length = ntohs(ip_pkt->ip_len);
+	if (!add_ethernet) {
+		length = ntohs(ip_pkt->ip_len);
+	} else {
+		length = ntohs(ip_pkt->ip_len) + sizeof (struct sniff_ethernet);
+	}
 	type = ip_pkt->ip_p;
 
 	/* printf("got type %d, len=%d(0x%x)\n", type, length, length); */
@@ -855,21 +1045,65 @@ void got_packet(u_char *args, const struct pcap_pkthdr *header,
 				ontime_packets*1.0/
 					(ontime_packets + early_packets),
 				ontime_packets,early_packets);
-			*/
+				*/
 
 			/*
 			 * Now, just  add it into the approprate counts
 			 */
 			switch (type) {
-				case 1:  count->icmp_bytes  += length;
-					 count->icmp_packets++;
-					 break;
-				case 6:  count->tcp_bytes   += length;
-					 count->tcp_packets++;
-					 break;
-				case 17: count->udp_bytes   += length;
-					 count->udp_packets++;
-					 break;
+				case 1: 
+				    count->icmp_bytes  += length;
+				    count->icmp_packets++;
+				    break;
+				case 6:
+				    if (payload_only) {
+					/*
+					 * Find the TCP header in the packet
+					 */
+					struct tcphdr *tcp_hdr =
+					    (struct tcphdr*)((char*)ip_pkt +
+							     ip_pkt->ip_hl*4);
+					int hdr_len = ip_pkt->ip_hl *4 +
+					    tcp_hdr->th_off *4;
+					count->tcp_bytes  += length - hdr_len;
+					length = length - hdr_len;
+				    } else {
+					count->tcp_bytes  += length;
+				    }
+				    if (no_zero) {
+					if (length > 0) {
+					    count->tcp_packets++;
+					}
+				    } else {
+					count->tcp_packets++;
+				    }
+
+				    break;
+
+				case 17:
+				    if (payload_only) {
+					/*
+					 * Find the UDP header in the packet
+					 */
+					struct udphdr *udp_hdr =
+					    (struct udphdr*)((char*)ip_pkt +
+							     ip_pkt->ip_hl*4);
+					int pay_len = htons(udp_hdr->uh_ulen) -
+					    sizeof(struct udphdr);
+					count->udp_bytes  += pay_len;
+					length = pay_len;
+				    } else {
+					count->udp_bytes  += length;
+				    }
+
+				    if (no_zero) {
+					if (length > 0) {
+					    count->udp_packets++;
+					}
+				    } else {
+					count->udp_packets++;
+				    }
+				    break;
 				default: count->other_bytes += length;
 					 count->other_packets++;
 					 break;
@@ -918,3 +1152,41 @@ int getaddr(char *dev, struct in_addr *addr) {
 		return 0;
 	}
 }
+
+#ifdef EVENTSYS
+/*
+ * Callback used for the event system. Resets the experiment start time,
+ * and signals the main thread, which may be waiting on the condition
+ * variable before it starts
+ */
+static void
+callback(event_handle_t handle,
+	         event_notification_t notification, void *data) {
+
+	char objtype[256], eventtype[256];
+	int len = 256;
+
+	printf("Received an event\n");
+	event_notification_get_objtype(handle, notification, objtype, len);
+	event_notification_get_eventtype(handle, notification, eventtype, len);
+
+	if (!strcmp(objtype,TBDB_OBJECTTYPE_TIME) &&
+		!strcmp(eventtype,TBDB_EVENTTYPE_START)) {
+	    /* OK, time has started */
+	    gettimeofday(&start_time,NULL);
+	    pthread_cond_signal(&time_started);
+	    printf("Event time started at UNIX time %lu.%lu\n",
+		    start_time.tv_sec, start_time.tv_usec);
+	}
+	return;
+}
+
+/*
+ * Simple function that starts up the event main loop - suitable for use as
+ * an argument to pthread_create .
+ */
+void *runeventsys(void *args) {
+    event_main(*((event_handle_t*)args));
+    return NULL;
+}
+#endif