Tcp.cpp
资源名称:PPP0208.rar [点击查看]
上传用户:karykuang
上传日期:2010-02-26
资源大小:103k
文件大小:16k
源码类别:
TCP/IP协议栈
开发平台:
Visual C++
- // Tcp.cpp: implementation of the CTcp class.
- //
- //////////////////////////////////////////////////////////////////////
- #include "stdafx.h"
- #include "demo.h"
- #include "Tcp.h"
- #ifdef _DEBUG
- #undef THIS_FILE
- static char THIS_FILE[]=__FILE__;
- #define new DEBUG_NEW
- #endif
- //////////////////////////////////////////////////////////////////////
- // Construction/Destruction
- //////////////////////////////////////////////////////////////////////
- CTcp::CTcp()
- {
- }
- CTcp::~CTcp()
- {
- }
- /*
- * Initialize the tcp implementation
- */
- void CTcp::tcp_Init()
- {
- //extern eth_HwAddress sed_lclEthAddr;
- /* initialize ethernet interface */
- //sed_Init();
- tcp_allsocs = NIL;
- #ifdef DEBUG
- tcp_logState = 0;
- #endif
- tcp_id = 0;
- /* hack - assume the network number */
- // sin_lclINAddr = ;//本机IP地址
- }
- /*
- * Actively open a TCP connection to a particular destination.
- */
- void CTcp::tcp_Open(tcp_Socket *s,word lport,in_HwAddress ina,word port,procref datahandler)
- {
- //extern eth_HwAddress sed_ethBcastAddr;//以太网广播地址
- s->state = tcp_StateSYNSENT;
- s->timeout = tcp_LONGTIMEOUT;
- //if ( lport == 0 ) lport = clock_ValueRough();
- s->myport = lport;
- /*if ( ! sar_MapIn2Eth(ina, &s->hisethaddr[0]) ) {//地址解析
- printf("tcp_Open of 0x%x: defaulting ethernet address to broadcastn", ina);
- Move(&sed_ethBcastAddr[0], &s->hisethaddr[0], sizeof(eth_HwAddress));
- }*/
- s->hisaddr = ina;
- s->hisport = port;
- s->seqnum = 0;
- s->dataSize = 0;
- s->flags = tcp_FlagSYN;
- s->unhappy = true;
- s->dataHandler = datahandler;
- s->next = tcp_allsocs;
- tcp_allsocs = s;
- tcp_Send(s);
- }
- /*
- * Passive open: listen for a connection on a particular port
- */
- void CTcp::tcp_Listen(tcp_Socket *s,word port,procref datahandler,longword timeout)
- {
- s->state = tcp_StateLISTEN;
- if ( timeout == 0 ) s->timeout = 0x7ffffff; /* forever... */
- else s->timeout = timeout;
- s->myport = port;
- s->hisport = 0;
- s->seqnum = 0;
- s->dataSize = 0;
- s->flags = 0;
- s->unhappy = 0;
- s->dataHandler = datahandler;
- s->next = tcp_allsocs;
- tcp_allsocs = s;
- }
- /*
- * Send a FIN on a particular port -- only works if it is open
- */
- void CTcp::tcp_Close(tcp_Socket *s)
- {
- if ( s->state == tcp_StateESTAB || s->state == tcp_StateSYNREC ) {
- s->flags = tcp_FlagACK | tcp_FlagFIN;
- s->state = tcp_StateFINWT1;
- s->unhappy = true;
- }
- }
- /*
- * Abort a tcp connection
- */
- void CTcp::tcp_Abort(tcp_Socket *s)
- {
- if ( s->state != tcp_StateLISTEN && s->state != tcp_StateCLOSED ) {
- s->flags = tcp_FlagRST | tcp_FlagACK;
- tcp_Send(s);
- }
- s->unhappy = 0;
- s->dataSize = 0;
- s->state = tcp_StateCLOSED;
- s->dataHandler(s, 0, -1);
- tcp_Unthread(s);
- }
- /*
- * Retransmitter - called periodically to perform tcp retransmissions
- */
- void CTcp::tcp_Retransmitter()
- {
- tcp_Socket *s;
- BOOL x;
- for ( s = tcp_allsocs; s; s = s->next ) {
- x = false;
- if ( s->dataSize > 0 || s->unhappy ) {
- tcp_Send(s);
- x = true;
- }
- if ( x || s->state != tcp_StateESTAB )
- s->timeout -= tcp_RETRANSMITTIME;
- if ( s->timeout <= 0 ) {
- if ( s->state == tcp_StateTIMEWT ) {
- writelog("Closed.");
- s->state = tcp_StateCLOSED;
- s->dataHandler(s, 0, 0);
- tcp_Unthread(s);
- } else {
- writelog("Timeout, aborting");
- tcp_Abort(s);
- }
- }
- }
- }
- /*
- * Unthread a socket from the socket list, if it's there
- */
- void CTcp::tcp_Unthread(tcp_Socket *ds)
- {
- tcp_Socket *s, **sp;
- sp = &tcp_allsocs;
- for (;;) {
- s = *sp;
- if ( s == ds ) {
- *sp = s->next;
- break;
- }
- if ( s == NIL ) break;
- sp = &s->next;
- }
- }
- /*
- * busy-wait loop for tcp. Also calls an "application proc"
- */
- void CTcp::tcpapp(procref application)
- {
- in_Header *ip;
- longword timeout, start;
- int x;
- // sed_Receive(0);
- timeout = 0;
- while ( tcp_allsocs ) {
- // start = clock_ValueRough();
- // ip = sed_IsPacket();//收到包否
- /*If no packet is returned withing 'timeout' milliseconds,
- then the routine returns zero.*/
- // if ( ip == NIL ) {//没收到包
- // if ( clock_ValueRough() > timeout ) {
- // tcp_Retransmitter();
- // timeout = clock_ValueRough() + tcp_RETRANSMITTIME;
- // }
- application();
- continue;
- // }
- // if ( sed_CheckPacket(ip, 0x800) == 1 ) {//检查是不是IP包
- /* do IP */
- if ( ip->destination == sin_lclINAddr && //检查目标地址是否相符
- in_GetProtocol(ip) == 6 &&
- checksum((unsigned short*)ip, in_GetHdrlenBytes(ip)) == 0xFFFF ) {
- tcp_Handler(ip); //处理收到的IP包
- }
- // }
- /* recycle buffer */
- //sed_Receive(ip);
- // x = clock_ValueRough() - start;
- // timeout -= x;
- }
- // return ( 1 );
- }
- /*
- * Write data to a connection.
- * Returns number of bytes written, == 0 when connection is not in
- * established state.
- */
- int CTcp::tcp_Write(tcp_Socket *s,byte * dp,int len)
- {
- int x;
- if ( s->state != tcp_StateESTAB ) len = 0;
- if ( len > (x = tcp_MaxData - s->dataSize) ) len = x;
- if ( len > 0 ) {
- Move(dp, &s->data[s->dataSize], len);
- s->dataSize += len;
- tcp_Flush(s);
- }
- return ( len );
- }
- /*
- * Send pending data
- */
- void CTcp::tcp_Flush(tcp_Socket *s)
- {
- if ( s->dataSize > 0 ) {
- s->flags |= tcp_FlagPUSH;
- tcp_Send(s);
- }
- }
- /*
- * Handler for incoming packets.
- */
- void CTcp::tcp_Handler(in_Header *ip)
- {
- tcp_Header *tp;
- tcp_PseudoHeader ph;
- int len;
- byte *dp;
- int x, diff;
- tcp_Socket *s;
- word flags;
- len = in_GetHdrlenBytes(ip);
- tp = (tcp_Header *)((byte *)ip + len);//获取IP包中TCP的首部结构
- len = ip->length - len;
- /* demux to active sockets */
- for ( s = tcp_allsocs; s; s = s->next )
- if ( s->hisport != 0 &&
- tp->dstPort == s->myport &&
- tp->srcPort == s->hisport &&
- ip->source == s->hisaddr ) break;
- if ( s == NIL ) {
- /* demux to passive sockets */
- for ( s = tcp_allsocs; s; s = s->next )
- if ( s->hisport == 0 && tp->dstPort == s->myport ) break;
- }
- if ( s == NIL ) {
- #ifdef DEBUG
- if ( tcp_logState & tcp_LOGPACKETS ) tcp_DumpHeader(ip, tp, "Discarding");
- #endif
- return;
- }
- #ifdef DEBUG
- if ( tcp_logState & tcp_LOGPACKETS )
- tcp_DumpHeader(ip, tp, "Received");
- #endif
- /* save his ethernet address */
- //MoveW(&((((eth_Header *)ip) - 1)->source[0]), &s->hisethaddr[0], sizeof(eth_HwAddress));
- ph.src = ip->source;
- ph.dst = ip->destination;
- ph.mbz = 0;
- ph.protocol = 6;
- ph.length = len;
- ph.checksum = checksum((word*)tp, len);
- if ( checksum((unsigned short*)&ph, sizeof ph) != 0xffff )
- writelog("bad tcp checksum, received anyway.");
- flags = tp->flags;
- if ( flags & tcp_FlagRST ) {
- writelog("connection reset");
- s->state = tcp_StateCLOSED;
- s->dataHandler(s, 0, -1);
- tcp_Unthread(s);
- return;
- }
- char* tempstr;
- switch ( s->state ) {
- case tcp_StateLISTEN:
- if ( flags & tcp_FlagSYN ) {
- s->acknum = tp->seqnum + 1;
- s->hisport = tp->srcPort;
- s->hisaddr = ip->source;
- s->flags = tcp_FlagSYN | tcp_FlagACK;
- tcp_Send(s);
- s->state = tcp_StateSYNREC;
- s->unhappy = true;
- s->timeout = tcp_TIMEOUT;
- sprintf(tempstr,"Syn from 0x%x#%d (seq 0x%x)", s->hisaddr, s->hisport, tp->seqnum);
- writelog(tempstr);
- }
- break;
- case tcp_StateSYNSENT:
- if ( flags & tcp_FlagSYN ) {
- s->acknum++;
- s->flags = tcp_FlagACK;
- s->timeout = tcp_TIMEOUT;
- if ( (flags & tcp_FlagACK) && tp->acknum == (s->seqnum + 1) ) {
- sprintf(tempstr,"Open");
- writelog(tempstr);
- s->state = tcp_StateESTAB;
- s->seqnum++;
- s->acknum = tp->seqnum + 1;
- s->unhappy = false;
- } else {
- s->state = tcp_StateSYNREC;
- }
- }
- break;
- case tcp_StateSYNREC:
- if ( flags & tcp_FlagSYN ) {
- s->flags = tcp_FlagSYN | tcp_FlagACK;
- tcp_Send(s);
- s->timeout = tcp_TIMEOUT;
- sprintf(tempstr," retransmit of original syn");
- writelog(tempstr);
- }
- if ( (flags & tcp_FlagACK) && tp->acknum == (s->seqnum + 1) ) {
- s->flags = tcp_FlagACK;
- tcp_Send(s);
- s->seqnum++;
- s->unhappy = false;
- s->state = tcp_StateESTAB;
- s->timeout = tcp_TIMEOUT;
- printf("Synack received - connection established");
- writelog(tempstr);
- }
- break;
- case tcp_StateESTAB:
- if ( (flags & tcp_FlagACK) == 0 ) return;
- /* process ack value in packet */
- diff = tp->acknum - s->seqnum;
- if ( diff > 0 ) {
- Move(&s->data[diff], &s->data[0], diff);
- s->dataSize -= diff;
- s->seqnum += diff;
- }
- s->flags = tcp_FlagACK;
- tcp_ProcessData(s, tp, len);
- break;
- case tcp_StateFINWT1:
- if ( (flags & tcp_FlagACK) == 0 ) return;
- diff = tp->acknum - s->seqnum - 1;
- s->flags = tcp_FlagACK | tcp_FlagFIN;
- if ( diff == 0 ) {
- s->state = tcp_StateFINWT2;
- s->flags = tcp_FlagACK;
- sprintf(tempstr,"finack received.");
- writelog(tempstr);
- }
- tcp_ProcessData(s, tp, len);
- break;
- case tcp_StateFINWT2:
- s->flags = tcp_FlagACK;
- tcp_ProcessData(s, tp, len);
- break;
- case tcp_StateCLOSING:
- if ( tp->acknum == (s->seqnum + 1) ) {
- s->state = tcp_StateTIMEWT;
- s->timeout = tcp_TIMEOUT;
- }
- break;
- case tcp_StateLASTACK:
- if ( tp->acknum == (s->seqnum + 1) ) {
- s->state = tcp_StateCLOSED;
- s->unhappy = false;
- s->dataSize = 0;
- s->dataHandler(s, 0, 0);
- tcp_Unthread(s);
- sprintf(tempstr,"Closed. ");
- writelog(tempstr);
- } else {
- s->flags = tcp_FlagACK | tcp_FlagFIN;
- tcp_Send(s);
- s->timeout = tcp_TIMEOUT;
- sprintf(tempstr,"retransmitting FIN");
- writelog(tempstr);
- }
- break;
- case tcp_StateTIMEWT:
- s->flags = tcp_FlagACK;
- tcp_Send(s);
- }
- }
- /*
- * Process the data in an incoming packet.
- * Called from all states where incoming data can be received: established,
- * fin-wait-1, fin-wait-2
- */
- void CTcp::tcp_ProcessData(tcp_Socket *s,tcp_Header * tp,int len)
- {
- int diff, x;
- word flags;
- byte *dp;
- flags = tp->flags;
- diff = s->acknum - tp->seqnum;
- if ( flags & tcp_FlagSYN ) diff--;
- x = tcp_GetDataOffset(tp) << 2;
- dp = (byte *)tp + x;
- len -= x;
- if ( diff >= 0 ) {
- dp += diff;
- len -= diff;
- s->acknum += len;
- s->dataHandler(s, dp, len);
- if ( flags & tcp_FlagFIN ) {
- s->acknum++;
- #ifdef DEBUG
- writelog("consumed fin.");
- #endif
- switch(s->state) {
- case tcp_StateESTAB:
- /* note: skip state CLOSEWT by automatically closing conn */
- x = tcp_StateLASTACK;
- s->flags |= tcp_FlagFIN;
- s->unhappy = true;
- #ifdef DEBUG
- writelog("sending fin.");
- #endif
- break;
- case tcp_StateFINWT1:
- x = tcp_StateCLOSING;
- break;
- case tcp_StateFINWT2:
- x = tcp_StateTIMEWT;
- break;
- }
- s->state = x;
- }
- }
- s->timeout = tcp_TIMEOUT;
- tcp_Send(s);
- }
- /*
- * Format and send an outgoing segment
- */
- void CTcp::tcp_Send(tcp_Socket *s)
- {
- tcp_PseudoHeader ph;
- struct _pkt {
- in_Header in;
- tcp_Header tcp;
- longword maxsegopt;
- } *pkt;
- byte *dp;
- // pkt = (struct _pkt *)sed_FormatPacket(&s->hisethaddr[0], 0x800);//Format an ethernet header in the transmit buffer
- // dp = &pkt->maxsegopt;
- pkt->in.length = sizeof(in_Header) + sizeof(tcp_Header) + s->dataSize;
- /* tcp header */
- pkt->tcp.srcPort = s->myport;
- pkt->tcp.dstPort = s->hisport;
- pkt->tcp.seqnum = s->seqnum;
- pkt->tcp.acknum = s->acknum;
- pkt->tcp.window = 1024;
- pkt->tcp.flags = s->flags | 0x5000;
- pkt->tcp.checksum = 0;
- pkt->tcp.urgentPointer = 0;
- if ( s->flags & tcp_FlagSYN ) {
- pkt->tcp.flags += 0x1000;
- pkt->in.length += 4;
- pkt->maxsegopt = 0x02040578; /* 1400 bytes */
- dp += 4;
- }
- Move(s->data, dp, s->dataSize);
- /* internet header */
- pkt->in.vht = 0x4500; /* version 4, hdrlen 5, tos 0 */
- pkt->in.identification = tcp_id++;
- pkt->in.frag = 0;
- pkt->in.ttlProtocol = (250<<8) + 6;
- pkt->in.checksum = 0;
- pkt->in.source = sin_lclINAddr;
- pkt->in.destination = s->hisaddr;
- pkt->in.checksum = ~checksum((word*)&pkt->in, sizeof(in_Header));
- /* compute tcp checksum */
- ph.src = pkt->in.source;//ph:tcp_PseudoHeader
- ph.dst = pkt->in.destination;
- ph.mbz = 0;
- ph.protocol = 6;
- ph.length = pkt->in.length - sizeof(in_Header);
- ph.checksum = checksum((word*)&pkt->tcp, ph.length);
- pkt->tcp.checksum = ~checksum((word*)&ph, sizeof ph);
- #ifdef DEBUG
- if ( tcp_logState & tcp_LOGPACKETS )
- tcp_DumpHeader(&pkt->in, &pkt->tcp, "Sending");
- #endif
- // sed_Send(pkt->in.length);//发送
- }
- /*
- * Do a one's complement checksum
- */
- longword CTcp::checksum(word *dp,int length)
- {
- int len;
- longword sum;
- len = length >> 1;
- sum = 0;
- while ( len-- > 0 ) sum += *dp++;
- if ( length & 1 ) sum += (*dp & 0xFF00);
- sum = (sum & 0xFFFF) + ((sum >> 16) & 0xFFFF);
- sum = (sum & 0xFFFF) + ((sum >> 16) & 0xFFFF);
- return ( sum );
- }
- /*
- * Dump the tcp protocol header of a packet
- */
- void CTcp::tcp_DumpHeader(in_Header * ip,tcp_Header *tp, char *mesg )
- {
- static char *flags[] = { "FIN", "SYN", "RST", "PUSH", "ACK", "URG" };
- int len;
- word f;
- char* tempstr;
- tp = (tcp_Header *)((byte *)ip + in_GetHdrlenBytes(ip));
- len = ip->length - ((tcp_GetDataOffset(tp) + in_GetHdrlen(ip)) << 2);
- sprintf(tempstr,"TCP: %s packet:nS: %x; D: %x; SN=%x ACK=%x W=%d DLen=%dn",
- mesg, tp->srcPort, tp->dstPort, tp->seqnum, tp->acknum,
- tp->window, len);
- writelog(tempstr);
- printf(tempstr,"DO=%d, C=%x U=%d",
- tcp_GetDataOffset(tp), tp->checksum, tp->urgentPointer);
- writelog(tempstr);
- /* output flags */
- f = tp->flags;
- for ( len = 0; len < 6; len++ )
- if ( f & (1 << len) ) writelog(flags[len]);
- //printf("n");
- }
- /*
- * Move bytes from hither(here) to yon(there)
- */
- void CTcp::Move(byte *src,byte * dest,int numbytes )
- {
- if ( numbytes <= 0 ) return;
- if ( src < dest ) {
- src += numbytes;
- dest += numbytes;
- do {
- *--dest = *--src;
- } while ( --numbytes > 0 );
- } else
- do {
- *dest++ = *src++;
- } while ( --numbytes > 0 );
- }
- void CTcp::writelog(CString temp)
- {
- CStdioFile file;
- CString filename;
- CTime time;
- time=CTime::GetCurrentTime();
- filename=time.Format("%Y%m%d");
- file.Open(filename+".tcp",CFile::modeNoTruncate|CFile::modeCreate|CFile::modeWrite|CFile::typeText);
- file.SeekToEnd();
- temp=time.Format("%Y.%m.%d %H:%M:%S ")+temp+"rn";
- file.Write(temp,temp.GetLength());
- file.Close();
- }