tcptap.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:14k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * Copyright (c) 1997, 1998 The Regents of the University of California.
  3.  * All rights reserved.
  4.  * 
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *  This product includes software developed by the MASH Research
  16.  * Group at the University of California, Berkeley.
  17.  * 4. Neither the name of the University nor of the Research Group may be used
  18.  *    to endorse or promote products derived from this software without
  19.  *    specific prior written permission.
  20.  * 
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33. #ifndef lint
  34. static const char rcsid[] =
  35.     "@(#) $Header: /cvsroot/nsnam/ns-2/emulate/tcptap.cc,v 1.4 2002/09/23 23:25:05 alefiyah Exp $ (ISI)";
  36. #endif
  37. #include "tcptap.h"
  38. static class TCPTapAgentClass : public TclClass {
  39.  public:
  40. TCPTapAgentClass() : TclClass("Agent/TCPTap") {}
  41. TclObject* create(int, const char*const*) {
  42. return (new TCPTapAgent());
  43. }
  44. } class_tcptap_agent;
  45. TCPTapAgent::TCPTapAgent() {
  46.     adv_window = DEFAULT_ADV_WINDOW;
  47.     bzero(&extnode, sizeof(struct sockaddr_in));
  48.     extnode.sin_port = DEFAULT_EXT_PORT;
  49.     extnode.sin_addr.s_addr = inet_addr(DEFAULT_EXT_ADDR);
  50.     extnode.sin_family = AF_INET;
  51.     bzero(&nsnode, sizeof(struct sockaddr_in));
  52.     nsnode.sin_port = DEFAULT_NS_PORT;
  53.     nsnode.sin_addr.s_addr = inet_addr(DEFAULT_NS_ADDR);
  54.     nsnode.sin_family = AF_INET;
  55.     
  56.     dropp = 0; 
  57. }
  58. /*
  59.  * Methods to set ip addresses and port numbers from Tcl scripts.
  60.  */
  61. int
  62. TCPTapAgent::command(int argc, const char*const* argv)
  63. {
  64.   if (argc == 3) {
  65.     if (strcmp(argv[1], "nsipaddr") == 0) {
  66.       if ((nsnode.sin_addr.s_addr = inet_addr(argv[2])) 
  67.   == INADDR_NONE) {
  68. printf("Error setting ns ip address");
  69. exit(1);
  70.       }
  71.       return (TCL_OK);
  72.     }
  73.     
  74.     
  75.     if (strcmp(argv[1], "extipaddr") == 0) {
  76.       if ((extnode.sin_addr.s_addr = inet_addr(argv[2])) 
  77.   == INADDR_NONE) {
  78. printf("Error setting external ip address");
  79. exit(1);
  80.       }
  81.       return (TCL_OK);
  82.     }
  83.     
  84.     if (strcmp(argv[1], "extport") == 0) {
  85.       extnode.sin_port = atoi(argv[2]);
  86.       return (TCL_OK);
  87.     }
  88.     if (strcmp(argv[1], "advertised-window") == 0) {
  89.       adv_window = atoi(argv[2]);
  90.       return (TCL_OK);
  91.     }
  92.     
  93.   } /* if (argc == 3) */
  94.   return (TapAgent::command(argc, argv));
  95. }
  96. unsigned short 
  97. TCPTapAgent::trans_check(unsigned char proto,
  98.  char *packet,
  99.  int length,
  100.  struct in_addr source_address,
  101.  struct in_addr dest_address)
  102. {
  103.   char *pseudo_packet;
  104.   unsigned short answer;
  105.   
  106.   pseudohdr.protocol = proto;
  107.   pseudohdr.length = htons(length);
  108.   pseudohdr.place_holder = 0;
  109.   pseudohdr.source_address = source_address;
  110.   pseudohdr.dest_address = dest_address;
  111.   
  112.   if((pseudo_packet = (char *) malloc(sizeof(pseudohdr) + length)) == NULL)  {
  113.     perror("malloc");
  114.     exit(1);
  115.   }
  116.   
  117.   memcpy(pseudo_packet,&pseudohdr,sizeof(pseudohdr));
  118.   memcpy((pseudo_packet + sizeof(pseudohdr)),
  119.  packet,length);
  120.   
  121.   answer = (unsigned short)in_cksum((unsigned short *)pseudo_packet,
  122.     (length + sizeof(pseudohdr)));
  123.   free(pseudo_packet);
  124.   return answer;
  125. }
  126. /*
  127.  * Taken from the raw-sock program
  128.  */
  129. unsigned short 
  130. TCPTapAgent::in_cksum(unsigned short *addr, int len)
  131. {
  132.   register int sum = 0;
  133.   u_short answer = 0;
  134.   register u_short *w = addr;
  135.   register int nleft = len;
  136.   
  137.   /*
  138.    * Our algorithm is simple, using a 32 bit accumulator (sum), we add
  139.    * sequential 16 bit words to it, and at the end, fold back all the
  140.    * carry bits from the top 16 bits into the lower 16 bits.
  141.    */
  142.   while (nleft > 1)  {
  143.     sum += *w++;
  144.     nleft -= 2;
  145.   }
  146.   
  147.   /* mop up an odd byte, if necessary */
  148.   if (nleft == 1) {
  149.     *(u_char *)(&answer) = *(u_char *)w ;
  150.     sum += answer;
  151.   }
  152.   
  153.   /* add back carry outs from top 16 bits to low 16 bits */
  154.   sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
  155.   sum += (sum >> 16);                     /* add carry */
  156.   answer = ~sum;                          /* truncate to 16 bits */
  157.   return(answer);
  158.   
  159. }
  160. void 
  161. TCPTapAgent::ip_gen(char *packet, unsigned char protocol, 
  162.     struct in_addr saddr, struct in_addr daddr,
  163.     unsigned short length, unsigned char ttl)
  164. {
  165.   struct ip *ipheader;
  166.   
  167.   ipheader = (struct ip *) packet;
  168.   bzero((void *) ipheader, IP_HEADER_LEN);
  169.   ipheader->ip_hl = (IP_HEADER_LEN / 4);
  170.   ipheader->ip_v = IPVERSION;
  171.   ipheader->ip_len = length;
  172.   ipheader->ip_id = 0;
  173.   ipheader->ip_ttl = ttl;
  174.   ipheader->ip_p = protocol;
  175.   
  176.   ipheader->ip_src = saddr;
  177.   ipheader->ip_dst = daddr;
  178.   ipheader->ip_len = ntohs(ipheader->ip_len);
  179.   ipheader->ip_off = ntohs(ipheader->ip_off);
  180.   ipheader->ip_sum = (unsigned short) in_cksum((unsigned short *) ipheader,
  181. sizeof(struct ip));
  182. }
  183. void
  184. TCPTapAgent::tcp_gen(char *packet, unsigned short sport, unsigned short dport, 
  185. Packet *nsp)
  186. {
  187.   struct tcphdr *tcpheader;
  188.   hdr_tcp* ns_tcphdr = HDR_TCP(nsp);
  189.   tcpheader = (struct tcphdr *) packet;
  190.   memset((char *)tcpheader, '', sizeof(struct tcphdr));
  191. #ifndef LINUX_TCP_HEADER
  192.   tcpheader->th_sport = htons(sport);
  193.   tcpheader->th_dport = htons(dport);
  194.   tcpheader->th_seq = htonl(ns_tcphdr->seqno_);
  195.   tcpheader->th_ack = htonl(ns_tcphdr->ackno_);
  196.   
  197.   tcpheader->th_off = (TCP_HEADER_LEN / 4);
  198.   
  199.   tcpheader->th_win = htons(adv_window);
  200.   /* 
  201.      Here we only propogate the "well-known" flags.
  202.      If you want to add other flags, uncomment this line
  203.      and comment the rest.
  204.   tcpheader->th_flags = ns_tcphdr->tcp_flags_;
  205.   */
  206.   tcpheader->th_flags = 0;
  207.   if (ns_tcphdr->tcp_flags_ & TH_FIN) 
  208.     tcpheader->th_flags |= TH_FIN;
  209.   if (ns_tcphdr->tcp_flags_ & TH_SYN) 
  210.     tcpheader->th_flags |= TH_SYN;
  211.   if (ns_tcphdr->tcp_flags_ & TH_RST) 
  212.     tcpheader->th_flags |= TH_RST;
  213.   if (ns_tcphdr->tcp_flags_ & TH_PUSH) 
  214.     tcpheader->th_flags |= TH_PUSH;
  215.   if (ns_tcphdr->tcp_flags_ & TH_ACK) 
  216.     tcpheader->th_flags |= TH_ACK;
  217.   if (ns_tcphdr->tcp_flags_ & TH_URG) 
  218.     tcpheader->th_flags |= TH_URG;
  219. #else  /* LINUX_TCP_HEADER */
  220. #define TH_FIN  0x01
  221. #define TH_SYN  0x02
  222. #define TH_RST  0x04
  223. #define TH_PUSH 0x08
  224. #define TH_ACK  0x10
  225. #define TH_URG  0x20
  226.   tcpheader->source = htons(sport);
  227.   tcpheader->dest = htons(dport);
  228.   tcpheader->seq = htonl(ns_tcphdr->seqno_);
  229.   tcpheader->ack_seq = htonl(ns_tcphdr->ackno_);
  230.   
  231.   tcpheader->doff = (TCP_HEADER_LEN / 4);
  232.   tcpheader->window = htons(adv_window);
  233.   /* Set the appropriate flag bits */
  234.  if (ns_tcphdr->tcp_flags_ & TH_FIN) 
  235.     tcpheader->fin= 1;
  236.   if (ns_tcphdr->tcp_flags_ & TH_SYN) 
  237.     tcpheader->syn = 1;
  238.   if (ns_tcphdr->tcp_flags_ & TH_RST) 
  239.     tcpheader->rst =1;
  240.   if (ns_tcphdr->tcp_flags_ & TH_PUSH) 
  241.     tcpheader->psh = 1;
  242.   if (ns_tcphdr->tcp_flags_ & TH_ACK) 
  243.     tcpheader->ack = 1;
  244.   if (ns_tcphdr->tcp_flags_ & TH_URG) 
  245.     tcpheader->urg =1;
  246. #endif /* End of LINUX_TCP_HEADER */
  247. }
  248. void
  249. TCPTapAgent::pkt_handler(void *clientdata, Packet *p, const struct timeval &ts)
  250. {
  251.   TCPTapAgent *inst = (TCPTapAgent *)clientdata;
  252.   inst->processpkt(p, ts);
  253. }
  254. void
  255. TCPTapAgent::processpkt(Packet *p, const struct timeval &ts)
  256. {
  257.   struct ip *ipheader;
  258.   struct tcphdr *tcpheader;
  259.   unsigned char *buf;
  260.   
  261.   /* Ip header information from the grabbed packet. */
  262.   unsigned char ttl;
  263.   
  264.   /* Code to drop packet, if needed 
  265.   dropp++;
  266.   if ((dropp % 10) == 0) {
  267.     fprintf(stdout,
  268.     "Dropping packet number : %dn", dropp);
  269.     Packet::free(p);
  270.     return ;
  271.     
  272.     } */
  273.  
  274.   ipheader = (struct ip *) p->accessdata();
  275.   if (in_cksum((unsigned short *) ipheader, (ipheader->ip_hl * 4))) {
  276.     fprintf(stderr,
  277.     "TCPTapAgent(%s): packet received with invalid IP checksum.n",
  278.     name());
  279.     drop(p);
  280.     return;
  281.   }
  282.   ttl = ipheader->ip_ttl;
  283.   if (!(--ttl)) {
  284.     fprintf(stderr, 
  285.     "TCPTapAgent(%s): packet received with ttl zero.n",
  286.     name());
  287.     drop(p);
  288.     return;
  289.     
  290.   }    
  291.   buf = p->accessdata(); 
  292.   tcpheader = (struct tcphdr *) (buf + (ipheader->ip_hl * 4));
  293.   
  294.   Packet *nspacket = allocpkt();
  295.   hdr_ip *ns_iphdr = HDR_IP(nspacket);
  296.   ns_iphdr->ttl() = ttl;
  297.   hdr_tcp *ns_tcphdr = HDR_TCP(nspacket);
  298. #ifndef LINUX_TCP_HEADER 
  299.   ns_tcphdr->seqno() = ntohl(tcpheader->th_seq);
  300.   ns_tcphdr->ackno() = ntohl(tcpheader->th_ack);
  301.   ns_tcphdr->hlen() = (ipheader->ip_hl + tcpheader->th_off) * 4;
  302.   ns_tcphdr->ts() = Scheduler::instance().clock();
  303.   ns_tcphdr->reason() |= REASON_UNKNOWN;
  304.   /* 
  305.      Here we only propogate the "well-known" flags.
  306.      If you want to add other flags, uncomment this line
  307.      and comment the rest.
  308.      ns_tcphdr->flags() = tcpheader->th_flags;
  309.   */
  310.   ns_tcphdr->flags() = 0;
  311.   if (tcpheader->th_flags & TH_FIN)
  312.     ns_tcphdr->flags() |= TH_FIN;
  313.   if (tcpheader->th_flags & TH_SYN) 
  314.         ns_tcphdr->flags() |= TH_SYN;
  315.   if (tcpheader->th_flags & TH_RST) 
  316.         ns_tcphdr->flags() |= TH_RST;
  317.   if (tcpheader->th_flags & TH_PUSH) 
  318.         ns_tcphdr->flags() |= TH_PUSH;
  319.   if (tcpheader->th_flags & TH_ACK) 
  320.         ns_tcphdr->flags() |= TH_ACK;
  321.   if (tcpheader->th_flags & TH_URG) 
  322.         ns_tcphdr->flags() |= TH_URG;
  323. #else /* LINUX_TCP_HEADER */
  324.  
  325.   ns_tcphdr->seqno() = ntohl(tcpheader->seq);
  326.   ns_tcphdr->ackno() = ntohl(tcpheader->ack);
  327.   ns_tcphdr->hlen() = (ipheader->ip_hl + tcpheader->doff) * 4;
  328.   ns_tcphdr->ts() = Scheduler::instance().clock();
  329.   ns_tcphdr->reason() |= REASON_UNKNOWN;
  330.   /* 
  331.      Here we only propogate the "well-known" flags.
  332.      If you want to add other flags, uncomment this line
  333.      and comment the rest.
  334.      ns_tcphdr->flags() = tcpheader->th_flags;
  335.   */
  336. #define TH_FIN  0x01
  337. #define TH_SYN  0x02
  338. #define TH_RST  0x04
  339. #define TH_PUSH 0x08
  340. #define TH_ACK  0x10
  341. #define TH_URG  0x20
  342.   ns_tcphdr->flags() = 0;
  343.   if (tcpheader->fin == 1 )
  344.     ns_tcphdr->flags() |= TH_FIN;
  345.   if (tcpheader->syn == 1 ) 
  346.         ns_tcphdr->flags() |= TH_SYN;
  347.   if (tcpheader->rst == 1 ) 
  348.         ns_tcphdr->flags() |= TH_RST;
  349.   if (tcpheader->psh == 1) 
  350.         ns_tcphdr->flags() |= TH_PUSH;
  351.   if (tcpheader->ack == 1) 
  352.         ns_tcphdr->flags() |= TH_ACK;
  353.   if (tcpheader->urg == 1) 
  354.         ns_tcphdr->flags() |= TH_URG;
  355. #endif  /* LINUX_TCP_HEADER */
  356.   hdr_cmn *ns_cmnhdr = HDR_CMN(nspacket);
  357.   ns_cmnhdr->size() = ntohs(ipheader->ip_len);
  358.   Packet::free(p);
  359.   // inject into simulator
  360.   target_->recv(nspacket);
  361.   return;
  362. }
  363. /*
  364.  * ns scheduler calls TapAgent::dispatch which calls recvpkt.
  365.  * 
  366.  * recvpkt then calls the network (net_) to receive as many packets
  367.  * as there are from the packet capture facility.
  368.  * For every packet received through the callback, it converts to ns
  369.  * FullTcp packet and injects it into the simulator by calling target_->recv
  370.  * 
  371.  */
  372. void
  373. TCPTapAgent::recvpkt()
  374. {
  375.   if (net_->mode() != O_RDWR && net_->mode() != O_RDONLY) {
  376.     fprintf(stderr,
  377.     "TCPTapAgent(%s): recvpkt called while in write-only mode!n",
  378.     name());
  379.     return;
  380.   }
  381.   
  382.   int cc = net_->recv(pkt_handler, this);
  383.   if (cc <= 0) {
  384.     if (cc < 0) {
  385.       perror("recv");
  386.     }
  387.     return;
  388.   }
  389.   TDEBUG4("%f: TCPTapAgent(%s): recvpkt, cc:%dn", now(), name(), cc);
  390.   // nothing to do coz pkt_handler would have called processpkt()
  391.   // that would have injected packets into the simulator
  392. }
  393. /*
  394.  * simulator schedules TapAgent::recv which calls sendpkt
  395.  *
  396.  * Grabs a ns Full TCP packet, converts it into real TCP packet 
  397.  * and injects onto the network using net_->send
  398.  *
  399.  */
  400. int
  401. TCPTapAgent::sendpkt(Packet* p)
  402. {
  403.   int byteswritten, datalen;
  404.   unsigned char *packet;
  405.   unsigned char received_ttl;
  406.   int hlength = IP_HEADER_LEN + TCP_HEADER_LEN;
  407.   struct tcphdr *tcpheader;
  408.   if (net_->mode() != O_RDWR && net_->mode() != O_WRONLY) {
  409.     fprintf(stderr,
  410.     "TCPTapAgent(%s): sendpkt called while in read-only mode!n",
  411.     name());
  412.     return (-1);
  413.   }
  414.   
  415.   // send packet into the live network
  416.   hdr_cmn* ns_cmnhdr = HDR_CMN(p);
  417.   if (net_ == NULL) {
  418.     fprintf(stderr,
  419.     "TCPTapAgent(%s): sendpkt attempted with NULL netn",
  420.     name());
  421.     drop(p);
  422.     return (-1);
  423.   }
  424.   
  425.   hdr_tcp* ns_tcphdr = HDR_TCP(p);
  426.   hdr_ip * ns_iphdr = HDR_IP(p);
  427.   received_ttl = ns_iphdr->ttl_;
  428.   // Here we check if ns has sent any data in the packet.
  429.   datalen = ns_cmnhdr->size() - ns_tcphdr->hlen();
  430.   packet = (unsigned char *) calloc (1, sizeof(unsigned char) * 
  431.      (hlength + datalen));
  432.   if (packet == NULL) {
  433.     fprintf(stderr,
  434.     "TCPTapAgent(%s) : Error %d allocating memory.n", name(), errno);
  435.     return (-1);
  436.   }
  437.   // Create real world tcp packet.
  438.   ip_gen((char *)packet, (unsigned char) IPPROTO_TCP, 
  439.  nsnode.sin_addr, extnode.sin_addr, 
  440.  hlength + datalen, received_ttl);
  441.   tcpheader = (struct tcphdr*) (packet + IP_HEADER_LEN);
  442.   tcp_gen((char *)tcpheader, nsnode.sin_port, extnode.sin_port, p);
  443. #ifndef LINUX_TCP_HEADER
  444.   tcpheader->th_sum = trans_check(IPPROTO_TCP, (char *) tcpheader,
  445.   sizeof(struct tcphdr) + datalen,
  446.   nsnode.sin_addr, extnode.sin_addr);
  447. #else 
  448.   tcpheader->check = trans_check(IPPROTO_TCP, (char *) tcpheader,
  449.   sizeof(struct tcphdr) + datalen,
  450.   nsnode.sin_addr, extnode.sin_addr);
  451. #endif 
  452.   /* 
  453.      Limits the packets going out to only IP + TCP header. 
  454.      ns will act as an ACK machine.
  455.    */
  456.   byteswritten = net_->send(packet, hlength + datalen);
  457.   if (byteswritten < 0) {
  458.     fprintf(stderr,"TCPTapAgent(%s): sendpkt (%p, %d): %sn",
  459.     name(), p->accessdata(), ns_cmnhdr->size(), strerror(errno));
  460.     Packet::free(p);
  461.     free(packet);
  462.     return (-1);
  463.     
  464.   }
  465.   
  466.   free(packet);
  467.   TDEBUG3("TCPTapAgent(%s): sent packet (sz: %d)n", name(), byteswritten);
  468.   return 0;
  469. }