From owner-p4-projects@FreeBSD.ORG Mon Aug 3 16:57:41 2009 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 031EF1065675; Mon, 3 Aug 2009 16:57:41 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id B207A106566B for ; Mon, 3 Aug 2009 16:57:40 +0000 (UTC) (envelope-from fangwang@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 976958FC1A for ; Mon, 3 Aug 2009 16:57:40 +0000 (UTC) (envelope-from fangwang@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id n73GvenE077609 for ; Mon, 3 Aug 2009 16:57:40 GMT (envelope-from fangwang@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id n73GvepS077607 for perforce@freebsd.org; Mon, 3 Aug 2009 16:57:40 GMT (envelope-from fangwang@FreeBSD.org) Date: Mon, 3 Aug 2009 16:57:40 GMT Message-Id: <200908031657.n73GvepS077607@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to fangwang@FreeBSD.org using -f From: Fang Wang To: Perforce Change Reviews Cc: Subject: PERFORCE change 166971 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 03 Aug 2009 16:57:42 -0000 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 ==== //depot/projects/soc2009/tcputo/src/tools/regression/netinet/tcputo/tcputo.c#5 (text+ko) ==== @@ -29,8 +29,11 @@ #include #include +#include #include -#include +#include +//#include +#include "tcp.h" #include @@ -41,16 +44,171 @@ #include #include #include +#include +#include +#include + 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); }