Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 3 Aug 2009 16:57:40 GMT
From:      Fang Wang <fangwang@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 166971 for review
Message-ID:  <200908031657.n73GvepS077607@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=166971

Change 166971 by fangwang@fangwang_utobsd on 2009/08/03 16:56:52

	Tcputo regression test code, use libpcap to capture the retransmission packets

Affected files ...

.. //depot/projects/soc2009/tcputo/src/tools/regression/netinet/tcputo/Makefile#3 edit
.. //depot/projects/soc2009/tcputo/src/tools/regression/netinet/tcputo/tcputo.c#5 edit

Differences ...

==== //depot/projects/soc2009/tcputo/src/tools/regression/netinet/tcputo/Makefile#3 (text+ko) ====

@@ -3,6 +3,7 @@
 #
 
 PROG=	tcputo
+CFLAGS+= -lpcap -lpthread
 NO_MAN=
 
 .include <bsd.prog.mk>

==== //depot/projects/soc2009/tcputo/src/tools/regression/netinet/tcputo/tcputo.c#5 (text+ko) ====

@@ -29,8 +29,11 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 
+#include <net/ethernet.h>
 #include <netinet/in.h>
-#include <netinet/tcp.h>
+#include <netinet/ip.h>
+//#include <netinet/tcp.h>
+#include "tcp.h"
 
 #include <arpa/inet.h>
 
@@ -41,16 +44,171 @@
 #include <string.h>
 #include <unistd.h>
 #include <time.h>
+#include <signal.h>
 
+#include <pcap.h>
+#include <pthread.h>
+
 static void
 usage(void)
 {
 
-	fprintf(stderr, "tcpconnect server port [user timeout]\n");
-	fprintf(stderr, "tcpconnect client ip port [user timeout]\n");
+	fprintf(stderr, "tcpconnect [-e] server port [user timeout]\n");
+	fprintf(stderr, "tcpconnect [-e] client ip port [user timeout]\n");
 	exit(-1);
 }
 
+#define	SIZE_ETHERNET	sizeof(struct ether_header)
+
+struct tcprxt {
+	struct timeval ts;
+	u_int length;
+	u_int th_off;
+	tcp_seq th_seq;
+	tcp_seq th_ack;
+	u_char th_flags;
+};
+
+#define	MAX_RXT	200
+
+struct tcprxt rxts[MAX_RXT];
+
+void
+parse_packet(u_char *args, const struct pcap_pkthdr *pkt_header, const u_char *packet)
+{
+	const struct ip *ip;			/* The IP header */
+	const struct tcphdr *tcp;		/* The TCP header */
+	const u_char *tcpopt;			/* Tcp option */
+	struct tcprxt rxt;
+	u_int opt, optlen;
+	u_int hlen;
+	u_int length;
+
+	length = pkt_header->len - SIZE_ETHERNET;
+	ip = (struct ip *)(packet + SIZE_ETHERNET);
+	hlen = ip->ip_hl * 4;
+	length -= hlen;
+	if (hlen < 20) {
+		printf("   * Invalid IP header length: %u bytes\n", hlen);
+		return;
+	}
+	tcp = (struct tcphdr *)((u_char *)ip + hlen);
+	hlen = tcp->th_off * 4;
+	length -= hlen;
+	if (hlen < 20) {
+		printf("   * Invalid TCP header length: %u bytes\n", hlen);
+		return;
+	}
+	tcpopt = (u_char *)tcp + sizeof(*tcp);
+	hlen -= sizeof(*tcp);
+	while (hlen > 0) {
+		opt = *tcpopt++;
+		hlen--;
+		if (opt == TCPOPT_EOL)
+			break;
+		if (opt == TCPOPT_NOP)
+			continue;
+		optlen = *tcpopt++;
+		if (opt == TCPOPT_UTO) {
+			u_int uto = htons(*(u_short *)tcpopt);
+			if (uto & 1)
+				uto = (uto >> 1) * 60;
+			else
+				uto >>= 1;
+			printf("Time:%u.%u Seq:%u Ack:%u Win:%u Length:%u UTO:%u\n", pkt_header->ts.tv_sec, pkt_header->ts.tv_usec, htonl(tcp->th_seq), htonl(tcp->th_ack), htons(tcp->th_win), length, uto);
+		}
+		hlen -= optlen - 1;
+		tcpopt += optlen - 2;
+	}
+	if (length > 0 || tcp->th_flags & TH_RST) {
+		memset(&rxt, 0, sizeof(rxt));
+		memcpy(&rxt.ts, &pkt_header->ts, sizeof(rxt.ts));
+		rxt.length = length;
+		rxt.th_off = tcp->th_off;
+		rxt.th_ack = tcp->th_ack;
+		rxt.th_seq = tcp->th_seq;
+		rxt.th_flags = tcp->th_flags;
+		memcpy(&rxts[0], &rxts[1], sizeof(struct tcprxt) * (MAX_RXT - 1));
+		memcpy(&rxts[MAX_RXT - 1], &rxt, sizeof(rxt));
+	}
+}
+
+void
+dump_packet(void *arg)
+{
+	pcap_t *handle;			/* Session handle */
+	char *dev;			/* The device to sniff on */
+	//char dev[] = "le1";			/* The device to sniff on */
+	char errbuf[PCAP_ERRBUF_SIZE];	/* Error string */
+	struct bpf_program fp;		/* The compiled filter */
+	char filter_exp[] = "tcp port 8000";	/* The filter expression */
+	bpf_u_int32 mask;		/* Our netmask */
+	bpf_u_int32 net;		/* Our IP */
+	struct pcap_pkthdr header;	/* The header that pcap gives us */
+	const u_char *packet;		/* The actual packet */
+
+	/* Define the device */
+	dev = pcap_lookupdev(errbuf);
+	if (dev == NULL) {
+		fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
+		exit(-1);
+	}
+	/* Find the properties for the device */
+	if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
+		fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf);
+		net = 0;
+		mask = 0;
+	}
+	/* Open the session in promiscuous mode */
+	handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
+	if (handle == NULL) {
+		fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
+		exit(-1);
+	}
+	/* Compile and apply the filter */
+	if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
+		fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
+		exit(-1);
+	}
+	if (pcap_setfilter(handle, &fp) == -1) {
+		fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
+		exit(-1);
+	}
+	pcap_loop(handle, -1, parse_packet, NULL);
+	pcap_close(handle);
+}
+
+void print_result()
+{
+	tcp_seq rxt_seq;
+	int i, last, rxt_nr;
+	struct tm *p;
+
+	rxt_seq = rxts[MAX_RXT - 2].th_seq;
+	for (last = -1, rxt_nr = 0, i = 0; i < MAX_RXT; i++) {
+		if (rxts[i].th_seq == rxt_seq || rxts[i].th_flags & TH_RST) {
+			if (rxts[i].th_flags & TH_RST)
+				printf("reset packet, ");
+			else if (rxt_nr)
+				printf("retransmit %d, ", rxt_nr);
+			else if (!rxt_nr)
+				printf("send packet, ");
+			p = localtime(&rxts[i].ts.tv_sec);
+			printf("time %d:%d:%d.%-6u, ", p->tm_hour, p->tm_min, p->tm_sec, rxts[i].ts.tv_usec);
+			printf("seq %u, ack %u, ", rxts[i].th_seq, rxts[i].th_ack);
+			if (last != -1) {
+				if (rxts[i].ts.tv_usec < rxts[last].ts.tv_usec)
+					printf("interval %u.%-6u, ", rxts[i].ts.tv_sec - rxts[last].ts.tv_sec - 1, 1000000 + rxts[i].ts.tv_usec - rxts[last].ts.tv_usec);
+				else
+					printf("interval %u.%-6u, ", rxts[i].ts.tv_sec - rxts[last].ts.tv_sec, rxts[i].ts.tv_usec - rxts[last].ts.tv_usec);
+			}
+			printf("length %u\n", rxts[i].length);
+			last = i;
+			rxt_nr++;
+		}
+	}
+}
+
 static int
 tcputo_timer(void)
 {
@@ -82,6 +240,7 @@
 	int user_timeout;
 	int optval;
 	struct tcputo uto;
+	pthread_t tid;
 
 	if (argc != 1 && argc != 2)
 		usage();
@@ -121,6 +280,8 @@
 	if (setsockopt(accept_sock, IPPROTO_TCP, TCP_UTO, &uto, sizeof(uto)) == -1)
 		err(-1, "setsockopt");
 	close(listen_sock);
+	if (pthread_create(&tid, NULL, dump_packet, NULL))
+		err(-1, "create thread");
 	while(1) {
 		sleep(1);
 		printf("server again %d\n", optval++);
@@ -130,12 +291,13 @@
 			(void)tcputo_timer();
 			continue;
 		}
-		puts(strerror(errno));
 		user_timeout = tcputo_timer();
 		printf("Connection timeout, %d seconds.\n", user_timeout);
 		break;
 	}
-
+	/* wait for the reset packet to be captured */
+	sleep(1);
+	pthread_kill(tid, SIGTERM);
 	close(accept_sock);
 }
 
@@ -150,6 +312,7 @@
 	int user_timeout;
 	int optval = 4*1024;
 	struct tcputo uto;
+	pthread_t tid;
 
 	if (argc != 2 && argc != 3)
 		usage();
@@ -179,7 +342,8 @@
 	}
 	if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) == -1)
 		err(-1, "connect");
-	
+	if (pthread_create(&tid, NULL, dump_packet, NULL))
+		err(-1, "create thread");
 	while (1) {
 		sleep(1);
 		printf("client again %d\n", optval++);
@@ -189,19 +353,19 @@
 			(void)tcputo_timer();
 			continue;
 		}
-		puts(strerror(errno));
 		user_timeout = tcputo_timer();
 		printf("Connection timeout, %d seconds.\n", user_timeout);
 		break;
 	}
-
+	/* wait for the reset packet to be captured */
+	sleep(1);
+	pthread_kill(tid, SIGTERM);
 	close(sock);
 }
 
 int
 main(int argc, char *argv[])
 {
-
 	if (argc < 2)
 		usage();
 
@@ -211,6 +375,6 @@
 		tcputo_client(argc - 2, argv + 2);
 	else
 		usage();
-
+	print_result();
 	exit(0);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200908031657.n73GvepS077607>