Tcp.cpp
上传用户:karykuang
上传日期:2010-02-26
资源大小:103k
文件大小:16k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

  1. // Tcp.cpp: implementation of the CTcp class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "demo.h"
  6. #include "Tcp.h"
  7. #ifdef _DEBUG
  8. #undef THIS_FILE
  9. static char THIS_FILE[]=__FILE__;
  10. #define new DEBUG_NEW
  11. #endif
  12. //////////////////////////////////////////////////////////////////////
  13. // Construction/Destruction
  14. //////////////////////////////////////////////////////////////////////
  15. CTcp::CTcp()
  16. {
  17. }
  18. CTcp::~CTcp()
  19. {
  20. }
  21. /*
  22.  * Initialize the tcp implementation
  23.  */
  24. void CTcp::tcp_Init()
  25. {
  26.     //extern eth_HwAddress sed_lclEthAddr;
  27.     /* initialize ethernet interface */
  28.     //sed_Init();
  29.     tcp_allsocs = NIL;
  30. #ifdef DEBUG
  31.     tcp_logState = 0;
  32. #endif
  33.     tcp_id = 0;
  34.     /* hack - assume the network number */
  35. //    sin_lclINAddr = ;//本机IP地址
  36. }
  37. /*
  38.  * Actively open a TCP connection to a particular destination.
  39.  */
  40. void CTcp::tcp_Open(tcp_Socket *s,word lport,in_HwAddress ina,word port,procref datahandler)
  41. {
  42.     //extern eth_HwAddress sed_ethBcastAddr;//以太网广播地址
  43.     s->state = tcp_StateSYNSENT;
  44.     s->timeout = tcp_LONGTIMEOUT;
  45.     //if ( lport == 0 ) lport = clock_ValueRough();
  46.     s->myport = lport;
  47.     /*if ( ! sar_MapIn2Eth(ina, &s->hisethaddr[0]) ) {//地址解析
  48.         printf("tcp_Open of 0x%x: defaulting ethernet address to broadcastn", ina);
  49.         Move(&sed_ethBcastAddr[0], &s->hisethaddr[0], sizeof(eth_HwAddress));
  50.     }*/
  51.     s->hisaddr = ina;
  52.     s->hisport = port;
  53.     s->seqnum = 0;
  54.     s->dataSize = 0;
  55.     s->flags = tcp_FlagSYN;
  56.     s->unhappy = true;
  57.     s->dataHandler = datahandler;
  58.     s->next = tcp_allsocs;
  59.     tcp_allsocs = s;
  60.     tcp_Send(s);
  61. }
  62. /*
  63.  * Passive open: listen for a connection on a particular port
  64.  */
  65. void CTcp::tcp_Listen(tcp_Socket *s,word port,procref datahandler,longword timeout)
  66. {
  67.     s->state = tcp_StateLISTEN;
  68.     if ( timeout == 0 ) s->timeout = 0x7ffffff; /* forever... */
  69.     else s->timeout = timeout;
  70.     s->myport = port;
  71.     s->hisport = 0;
  72.     s->seqnum = 0;
  73.     s->dataSize = 0;
  74.     s->flags = 0;
  75.     s->unhappy = 0;
  76.     s->dataHandler = datahandler;
  77.     s->next = tcp_allsocs;
  78.     tcp_allsocs = s;
  79. }
  80. /*
  81.  * Send a FIN on a particular port -- only works if it is open
  82.  */
  83. void CTcp::tcp_Close(tcp_Socket *s)
  84. {
  85.     if ( s->state == tcp_StateESTAB || s->state == tcp_StateSYNREC ) {
  86.         s->flags = tcp_FlagACK | tcp_FlagFIN;
  87.         s->state = tcp_StateFINWT1;
  88.         s->unhappy = true;
  89.     }
  90. }
  91. /*
  92.  * Abort a tcp connection
  93.  */
  94. void CTcp::tcp_Abort(tcp_Socket *s)
  95. {
  96.     if ( s->state != tcp_StateLISTEN && s->state != tcp_StateCLOSED ) {
  97.         s->flags = tcp_FlagRST | tcp_FlagACK;
  98.         tcp_Send(s);
  99.     }
  100.     s->unhappy = 0;
  101.     s->dataSize = 0;
  102.     s->state = tcp_StateCLOSED;
  103.     s->dataHandler(s, 0, -1);
  104.     tcp_Unthread(s);
  105. }
  106. /*
  107.  * Retransmitter - called periodically to perform tcp retransmissions
  108.  */
  109. void CTcp::tcp_Retransmitter()
  110. {
  111.     tcp_Socket *s;
  112.     BOOL x;
  113.     for ( s = tcp_allsocs; s; s = s->next ) {
  114.         x = false;
  115.         if ( s->dataSize > 0 || s->unhappy ) {
  116.             tcp_Send(s);
  117.             x = true;
  118.         }
  119.         if ( x || s->state != tcp_StateESTAB )
  120.             s->timeout -= tcp_RETRANSMITTIME;
  121.         if ( s->timeout <= 0 ) {
  122.             if ( s->state == tcp_StateTIMEWT ) {
  123.                 writelog("Closed.");
  124.                 s->state = tcp_StateCLOSED;
  125.                 s->dataHandler(s, 0, 0);
  126.                 tcp_Unthread(s);
  127.             } else {
  128.                 writelog("Timeout, aborting");
  129.                 tcp_Abort(s);
  130.             }
  131.         }
  132.     }
  133. }
  134. /*
  135.  * Unthread a socket from the socket list, if it's there 
  136.  */
  137. void CTcp::tcp_Unthread(tcp_Socket *ds)
  138. {
  139.     tcp_Socket *s, **sp;
  140.     sp = &tcp_allsocs;
  141.     for (;;) {
  142.         s = *sp;
  143.         if ( s == ds ) {
  144.             *sp = s->next;
  145.             break;
  146.         }
  147.         if ( s == NIL ) break;
  148.         sp = &s->next;
  149.     }
  150. }
  151. /*
  152.  * busy-wait loop for tcp.  Also calls an "application proc"
  153.  */
  154. void CTcp::tcpapp(procref application)
  155. {
  156.     in_Header *ip;
  157.     longword timeout, start;
  158.     int x;
  159. //    sed_Receive(0);
  160.     timeout = 0;
  161.     while ( tcp_allsocs ) {
  162. //        start = clock_ValueRough();
  163. //        ip = sed_IsPacket();//收到包否
  164.         /*If no packet is returned withing 'timeout' milliseconds,
  165.    then the routine returns zero.*/
  166. //        if ( ip == NIL ) {//没收到包
  167. //            if ( clock_ValueRough() > timeout ) {
  168. //                tcp_Retransmitter();
  169. //                timeout = clock_ValueRough() + tcp_RETRANSMITTIME;
  170. //            }
  171.             application();
  172.             continue;
  173. //        }
  174.         
  175. //         if ( sed_CheckPacket(ip, 0x800) == 1 ) {//检查是不是IP包
  176.           /* do IP */
  177. if ( ip->destination == sin_lclINAddr && //检查目标地址是否相符
  178.                  in_GetProtocol(ip) == 6 &&
  179.                  checksum((unsigned short*)ip, in_GetHdrlenBytes(ip)) == 0xFFFF ) {
  180.                 tcp_Handler(ip);  //处理收到的IP包
  181.             }
  182. //        }
  183.         /* recycle buffer */
  184.         //sed_Receive(ip);
  185. //        x = clock_ValueRough() - start;
  186. //        timeout -= x;
  187.     }
  188. //    return ( 1 );
  189. }
  190. /*
  191.  * Write data to a connection.
  192.  * Returns number of bytes written, == 0 when connection is not in
  193.  * established state.
  194.  */
  195. int CTcp::tcp_Write(tcp_Socket *s,byte * dp,int len)
  196. {
  197.     int x;
  198.     if ( s->state != tcp_StateESTAB ) len = 0;
  199.     if ( len > (x = tcp_MaxData - s->dataSize) ) len = x;
  200.     if ( len > 0 ) {
  201.         Move(dp, &s->data[s->dataSize], len);
  202.         s->dataSize += len;
  203.         tcp_Flush(s);
  204.     }
  205.     return ( len );
  206. }
  207. /*
  208.  * Send pending data
  209.  */
  210. void CTcp::tcp_Flush(tcp_Socket *s)
  211. {
  212.     if ( s->dataSize > 0 ) {
  213.         s->flags |= tcp_FlagPUSH;
  214.         tcp_Send(s);
  215.     }
  216. }
  217. /*
  218.  * Handler for incoming packets.
  219.  */
  220. void CTcp::tcp_Handler(in_Header *ip)
  221. {
  222.     tcp_Header *tp;
  223.     tcp_PseudoHeader ph;
  224.     int len;
  225.     byte *dp;
  226.     int x, diff;
  227.     tcp_Socket *s;
  228.     word flags;
  229.     len = in_GetHdrlenBytes(ip);
  230.     tp = (tcp_Header *)((byte *)ip + len);//获取IP包中TCP的首部结构
  231.     len = ip->length - len;
  232.     /* demux to active sockets */
  233.     for ( s = tcp_allsocs; s; s = s->next )
  234.         if ( s->hisport != 0 &&
  235.              tp->dstPort == s->myport &&
  236.              tp->srcPort == s->hisport &&
  237.              ip->source == s->hisaddr ) break;
  238.     if ( s == NIL ) {
  239.         /* demux to passive sockets */
  240.         for ( s = tcp_allsocs; s; s = s->next )
  241.             if ( s->hisport == 0 && tp->dstPort == s->myport ) break;
  242.     }
  243.     if ( s == NIL ) {
  244. #ifdef DEBUG
  245.         if ( tcp_logState & tcp_LOGPACKETS ) tcp_DumpHeader(ip, tp, "Discarding");
  246. #endif
  247.         return;
  248.     }
  249. #ifdef DEBUG
  250.     if ( tcp_logState & tcp_LOGPACKETS )
  251.         tcp_DumpHeader(ip, tp, "Received");
  252. #endif
  253.     /* save his ethernet address */
  254.     //MoveW(&((((eth_Header *)ip) - 1)->source[0]), &s->hisethaddr[0], sizeof(eth_HwAddress));
  255.     ph.src = ip->source;
  256.     ph.dst = ip->destination;
  257.     ph.mbz = 0;
  258.     ph.protocol = 6;
  259.     ph.length = len;
  260.     ph.checksum = checksum((word*)tp, len);
  261.     if ( checksum((unsigned short*)&ph, sizeof ph) != 0xffff )
  262.          writelog("bad tcp checksum, received anyway.");
  263.     flags = tp->flags;
  264.     if ( flags & tcp_FlagRST ) {
  265.         writelog("connection reset");
  266.         s->state = tcp_StateCLOSED;
  267.         s->dataHandler(s, 0, -1);
  268.         tcp_Unthread(s);
  269.         return;
  270.     }
  271.     char* tempstr;
  272. switch ( s->state ) {
  273.     case tcp_StateLISTEN:
  274.         if ( flags & tcp_FlagSYN ) {
  275.             s->acknum = tp->seqnum + 1;
  276.             s->hisport = tp->srcPort;
  277.             s->hisaddr = ip->source;
  278.             s->flags = tcp_FlagSYN | tcp_FlagACK;
  279.             tcp_Send(s);
  280.             s->state = tcp_StateSYNREC;
  281.             s->unhappy = true;
  282.             s->timeout = tcp_TIMEOUT;
  283.             sprintf(tempstr,"Syn from 0x%x#%d (seq 0x%x)", s->hisaddr, s->hisport, tp->seqnum);
  284. writelog(tempstr);
  285. }
  286.         break;
  287.     case tcp_StateSYNSENT:
  288.         if ( flags & tcp_FlagSYN ) {
  289.             s->acknum++;
  290.             s->flags = tcp_FlagACK;
  291.             s->timeout = tcp_TIMEOUT;
  292.             if ( (flags & tcp_FlagACK) && tp->acknum == (s->seqnum + 1) ) {
  293.                 sprintf(tempstr,"Open");
  294. writelog(tempstr);
  295.                 s->state = tcp_StateESTAB;
  296.                 s->seqnum++;
  297.                 s->acknum = tp->seqnum + 1;
  298.                 s->unhappy = false;
  299.             } else {
  300.                 s->state = tcp_StateSYNREC;
  301.             }
  302.         }
  303.         break;
  304.     case tcp_StateSYNREC:
  305.         if ( flags & tcp_FlagSYN ) {
  306.             s->flags = tcp_FlagSYN | tcp_FlagACK;
  307.             tcp_Send(s);
  308.             s->timeout = tcp_TIMEOUT;
  309.             sprintf(tempstr," retransmit of original syn");
  310. writelog(tempstr);
  311.         }
  312.         if ( (flags & tcp_FlagACK) && tp->acknum == (s->seqnum + 1) ) {
  313.             s->flags = tcp_FlagACK;
  314.             tcp_Send(s);
  315.             s->seqnum++;
  316.             s->unhappy = false;
  317.             s->state = tcp_StateESTAB;
  318.             s->timeout = tcp_TIMEOUT;
  319.             printf("Synack received - connection established");
  320. writelog(tempstr);
  321.         }
  322.         break;
  323.     case tcp_StateESTAB:
  324.         if ( (flags & tcp_FlagACK) == 0 ) return;
  325.         /* process ack value in packet */
  326.         diff = tp->acknum - s->seqnum;
  327.         if ( diff > 0 ) {
  328.             Move(&s->data[diff], &s->data[0], diff);
  329.             s->dataSize -= diff;
  330.             s->seqnum += diff;
  331.         }
  332.         s->flags = tcp_FlagACK;
  333.         tcp_ProcessData(s, tp, len);
  334.         break;
  335.     case tcp_StateFINWT1:
  336.         if ( (flags & tcp_FlagACK) == 0 ) return;
  337.         diff = tp->acknum - s->seqnum - 1;
  338.         s->flags = tcp_FlagACK | tcp_FlagFIN;
  339.         if ( diff == 0 ) {
  340.             s->state = tcp_StateFINWT2;
  341.             s->flags = tcp_FlagACK;
  342.             sprintf(tempstr,"finack received.");
  343. writelog(tempstr);
  344.         }
  345.         tcp_ProcessData(s, tp, len);
  346.         break;
  347.     case tcp_StateFINWT2:
  348.         s->flags = tcp_FlagACK;
  349.         tcp_ProcessData(s, tp, len);
  350.         break;
  351.     case tcp_StateCLOSING:
  352.         if ( tp->acknum == (s->seqnum + 1) ) {
  353.             s->state = tcp_StateTIMEWT;
  354.             s->timeout = tcp_TIMEOUT;
  355.         }
  356.         break;
  357.     case tcp_StateLASTACK:
  358.         if ( tp->acknum == (s->seqnum + 1) ) {
  359.             s->state = tcp_StateCLOSED;
  360.             s->unhappy = false;
  361.             s->dataSize = 0;
  362.             s->dataHandler(s, 0, 0);
  363.             tcp_Unthread(s);
  364.             sprintf(tempstr,"Closed. ");
  365. writelog(tempstr);
  366.         } else {
  367.             s->flags = tcp_FlagACK | tcp_FlagFIN;
  368.             tcp_Send(s);
  369.             s->timeout = tcp_TIMEOUT;
  370.             sprintf(tempstr,"retransmitting FIN");
  371. writelog(tempstr);
  372.         }
  373.         break;
  374.     case tcp_StateTIMEWT:
  375.         s->flags = tcp_FlagACK;
  376.         tcp_Send(s);
  377.     }
  378. }
  379. /*
  380.  * Process the data in an incoming packet.
  381.  * Called from all states where incoming data can be received: established,
  382.  * fin-wait-1, fin-wait-2
  383.  */
  384. void CTcp::tcp_ProcessData(tcp_Socket *s,tcp_Header * tp,int len)
  385. {
  386.     int diff, x;
  387.     word flags;
  388.     byte *dp;
  389.     flags = tp->flags;
  390.     diff = s->acknum - tp->seqnum;
  391.     if ( flags & tcp_FlagSYN ) diff--;
  392.     x = tcp_GetDataOffset(tp) << 2;
  393.     dp = (byte *)tp + x;
  394.     len -= x;
  395.     if ( diff >= 0 ) {
  396.         dp += diff;
  397.         len -= diff;
  398.         s->acknum += len;
  399.         s->dataHandler(s, dp, len);
  400.         if ( flags & tcp_FlagFIN ) {
  401.             s->acknum++;
  402. #ifdef DEBUG
  403.             writelog("consumed fin.");
  404. #endif
  405.             switch(s->state) {
  406.               case tcp_StateESTAB:
  407.                 /* note: skip state CLOSEWT by automatically closing conn */
  408.                 x = tcp_StateLASTACK;
  409.                 s->flags |= tcp_FlagFIN;
  410.                 s->unhappy = true;
  411. #ifdef DEBUG
  412.                 writelog("sending fin.");
  413. #endif
  414.                 break;
  415.               case tcp_StateFINWT1:
  416.                 x = tcp_StateCLOSING;
  417.                 break;
  418.               case tcp_StateFINWT2:
  419.                 x = tcp_StateTIMEWT;
  420.                 break;
  421.             }
  422.             s->state = x;
  423.         }
  424.     }
  425.     s->timeout = tcp_TIMEOUT;
  426.     tcp_Send(s);
  427. }
  428. /*
  429.  * Format and send an outgoing segment
  430.  */
  431. void CTcp::tcp_Send(tcp_Socket *s)
  432. {
  433.     tcp_PseudoHeader ph;
  434.     struct _pkt {
  435.         in_Header in;
  436.         tcp_Header tcp;
  437.         longword maxsegopt;
  438.     } *pkt;
  439.     byte *dp;
  440. //    pkt = (struct _pkt *)sed_FormatPacket(&s->hisethaddr[0], 0x800);//Format an ethernet header in the transmit buffer
  441.  //   dp = &pkt->maxsegopt;
  442.     pkt->in.length = sizeof(in_Header) + sizeof(tcp_Header) + s->dataSize;
  443.     /* tcp header */
  444.     pkt->tcp.srcPort = s->myport;
  445.     pkt->tcp.dstPort = s->hisport;
  446.     pkt->tcp.seqnum = s->seqnum;
  447.     pkt->tcp.acknum = s->acknum;
  448.     pkt->tcp.window = 1024;
  449.     pkt->tcp.flags = s->flags | 0x5000;
  450.     pkt->tcp.checksum = 0;
  451.     pkt->tcp.urgentPointer = 0;
  452.     if ( s->flags & tcp_FlagSYN ) {
  453.         pkt->tcp.flags += 0x1000;
  454.         pkt->in.length += 4;
  455.         pkt->maxsegopt = 0x02040578; /* 1400 bytes */
  456.         dp += 4;
  457.     }
  458.     Move(s->data, dp, s->dataSize);
  459.     /* internet header */
  460.     pkt->in.vht = 0x4500;   /* version 4, hdrlen 5, tos 0 */
  461.     pkt->in.identification = tcp_id++;
  462.     pkt->in.frag = 0;
  463.     pkt->in.ttlProtocol = (250<<8) + 6;
  464.     pkt->in.checksum = 0;
  465.     pkt->in.source = sin_lclINAddr;
  466.     pkt->in.destination = s->hisaddr;
  467.     pkt->in.checksum = ~checksum((word*)&pkt->in, sizeof(in_Header));
  468.     /* compute tcp checksum */
  469.     ph.src = pkt->in.source;//ph:tcp_PseudoHeader
  470.     ph.dst = pkt->in.destination;
  471.     ph.mbz = 0;
  472.     ph.protocol = 6;
  473.     ph.length = pkt->in.length - sizeof(in_Header);
  474.     ph.checksum = checksum((word*)&pkt->tcp, ph.length);
  475.     pkt->tcp.checksum = ~checksum((word*)&ph, sizeof ph);
  476. #ifdef DEBUG
  477.     if ( tcp_logState & tcp_LOGPACKETS )
  478.         tcp_DumpHeader(&pkt->in, &pkt->tcp, "Sending");
  479. #endif
  480.   //  sed_Send(pkt->in.length);//发送
  481. }
  482. /*
  483.  * Do a one's complement checksum
  484.  */
  485. longword CTcp::checksum(word *dp,int length)
  486. {
  487.     int len;
  488.     longword sum;
  489.     len = length >> 1;
  490.     sum = 0;
  491.     while ( len-- > 0 ) sum += *dp++;
  492.     if ( length & 1 ) sum += (*dp & 0xFF00);
  493.     sum = (sum & 0xFFFF) + ((sum >> 16) & 0xFFFF);
  494.     sum = (sum & 0xFFFF) + ((sum >> 16) & 0xFFFF);
  495.     return ( sum );
  496. }
  497. /*
  498.  * Dump the tcp protocol header of a packet
  499.  */
  500. void CTcp::tcp_DumpHeader(in_Header * ip,tcp_Header *tp, char *mesg )
  501. {
  502.     
  503.     static char *flags[] = { "FIN", "SYN", "RST", "PUSH", "ACK", "URG" };
  504.     int len;
  505.     word f;
  506. char* tempstr;
  507. tp = (tcp_Header *)((byte *)ip + in_GetHdrlenBytes(ip));
  508.     len =  ip->length - ((tcp_GetDataOffset(tp) + in_GetHdrlen(ip)) << 2);
  509.     sprintf(tempstr,"TCP: %s packet:nS: %x; D: %x; SN=%x ACK=%x W=%d DLen=%dn",
  510.            mesg, tp->srcPort, tp->dstPort, tp->seqnum, tp->acknum,
  511.            tp->window, len);
  512. writelog(tempstr);
  513.     printf(tempstr,"DO=%d, C=%x U=%d",
  514.            tcp_GetDataOffset(tp), tp->checksum, tp->urgentPointer);
  515. writelog(tempstr);
  516.     /* output flags */
  517.     f = tp->flags;
  518.     for ( len = 0; len < 6; len++ )
  519.         if ( f & (1 << len) ) writelog(flags[len]);
  520.     //printf("n");
  521. }
  522. /*
  523.  * Move bytes from hither(here) to yon(there)
  524.  */
  525. void CTcp::Move(byte *src,byte * dest,int numbytes )
  526. {
  527.     if ( numbytes <= 0 ) return;
  528.     if ( src < dest ) {
  529.         src += numbytes;
  530.         dest += numbytes;
  531.         do {
  532.             *--dest = *--src;
  533.         } while ( --numbytes > 0 );
  534.     } else
  535.         do {
  536.              *dest++ = *src++;
  537.         } while ( --numbytes > 0 );
  538. }
  539. void CTcp::writelog(CString temp)
  540. {
  541. CStdioFile file;
  542. CString filename;
  543. CTime time;
  544. time=CTime::GetCurrentTime();
  545. filename=time.Format("%Y%m%d");
  546. file.Open(filename+".tcp",CFile::modeNoTruncate|CFile::modeCreate|CFile::modeWrite|CFile::typeText);
  547. file.SeekToEnd();
  548. temp=time.Format("%Y.%m.%d %H:%M:%S  ")+temp+"rn";
  549. file.Write(temp,temp.GetLength());
  550. file.Close();
  551. }