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>