📄 tinytcp.c
字号:
tp = (tcp_Header *)((BYTE *)ip + len);
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 ) {
tcp_Reset( ip, tp );
#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 */
Move(&((((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((WORD *)&ph, sizeof ph) != 0xFFFF )
{
#ifdef DEBUG
print("bad tcp checksum, received anyway\r\n");
#endif
}
flags = tp->flags;
if ( flags & tcp_FlagRST ) {
#ifdef DEBUG
print("connection reset\r\n");
#endif
s->state = tcp_StateCLOSED;
// s->dataHandler((tcp_Socket *)s,(BYTE*) 0, (WORD *)-1);
DATAHANDLER((tcp_Socket *)s,(BYTE*) 0,-1);
tcp_Unthread(s);
return;
}
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;
#ifdef DEBUG
print("Syn from 0x%x#%d (seq 0x%x)\r\n", s->hisaddr, s->hisport, tp->seqnum);
#endif
}
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) ) {
#ifdef DEBUG
print("Open\r\n");
#endif
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;
#ifdef DEBUG
print(" retransmit of original syn\r\n");
#endif
}
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;
#ifdef DEBUG
print("Synack received - connection established\r\n");
#endif
}
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->datas[diff], &s->datas[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;
/*
* This is modified by Jun-Ku.
* If we send data and it's unacked. then send FIN. the receiver send diff = dataSize+1 (and it's ACK on FIN ).
* if ( diff == 0 ) {
*/
if ( diff == 0 || diff == s->dataSize ) {
s->state = tcp_StateFINWT2;
s->flags = tcp_FlagACK;
s->seqnum += (diff+1);
s->dataSize -= diff;
#ifdef DEBUG
print("finack received.\r\n");
#endif
}
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((tcp_Socket *)s,(BYTE *)0, (WORD *)0);
DATAHANDLER((tcp_Socket *)s,(BYTE *)0,0);
tcp_Unthread(s);
#ifdef DEBUG
print("Closed. \r\n");
#endif
} else {
s->flags = tcp_FlagACK | tcp_FlagFIN;
tcp_Send(s);
s->timeout = tcp_TIMEOUT;
#ifdef DEBUG
print("retransmitting FIN\r\n");
#endif
}
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 tcp_ProcessData(tcp_Socket *s, tcp_Header *tp, WORD len)
{
short diff, x;
WORD flags;
BYTE *dp;
flags = tp->flags;
diff = s->acknum - tp->seqnum;
if ( flags & tcp_FlagSYN ) diff--;
x = tcp_GetDataOffset(tp) << 2; /* x = hdrlen in bytes */
dp = (BYTE *)tp + x; /* get first pointer of data */
len -= x; /* len is data length now */
if ( diff >= 0 ) {
dp += diff;
len -= diff;
s->acknum += len;
// s->dataHandler((tcp_Socket *)s,(BYTE *)dp, (WORD *)len);
DATAHANDLER((tcp_Socket *)s,(BYTE *)dp,len);
if ( flags & tcp_FlagFIN ) {
s->acknum++;
#ifdef DEBUG
print("consumed fin.\r\n");
#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
print("fin on estab.\r\n");
#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 tcp_Send(tcp_Socket *s)
{
tcp_PseudoHeader ph;
struct _pkt {
in_Header in;
tcp_Header tcp;
DWORD maxsegopt;
} *pkt;
BYTE *dp;
pkt = (struct _pkt *)sed_FormatPacket(&s->hisethaddr[0], 0x800);
dp = (BYTE *)&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; /* Header length = 20bytes ;; no option */
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->datas, dp, s->dataSize); /* copy data to pointer which is next to tcp header */
/* 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.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);
sed_Send(pkt->in.length);
}
/*
* Format and send an outgoing reset segment
*/
void tcp_Reset( in_Header *ip, tcp_Header *tp )
{
tcp_PseudoHeader ph;
struct _pkt {
in_Header in;
tcp_Header tcp;
DWORD maxsegopt;
} *pkt;
pkt = (struct _pkt *)sed_FormatPacket(&(((eth_Header *)ip)-1)->source[0], 0x800);
pkt->in.length = sizeof(in_Header) + sizeof(tcp_Header);
/* tcp header */
pkt->tcp.srcPort = tp->dstPort;
pkt->tcp.dstPort = tp->srcPort;
pkt->tcp.seqnum = tp->seqnum;
pkt->tcp.acknum = tp->acknum;
pkt->tcp.window = 1024;
pkt->tcp.flags = tcp_FlagRST | 0x5000; /* Header length = 20bytes ;; no option */
pkt->tcp.checksum = 0;
pkt->tcp.urgentPointer = 0;
/* 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 = ip->source;
pkt->in.checksum = ~(checksum((WORD *)&pkt->in, sizeof(in_Header)));
/* compute tcp checksum */
ph.src = pkt->in.source;
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);
sed_Send(pkt->in.length);
}
/*
* Do a one's complement checksum
*/
int checksum(WORD *dp, WORD length)
{
WORD len;
DWORD 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 */
#ifdef DEBUG
void tcp_DumpHeader( in_Header *ip, tcp_Header *tp, BYTE *mesg )
{
return;
/*
tcp_Header *tp = (tcp_Header *)((BYTE *)ip + in_GetHdrlenBytes(ip));
static char *flags[] = { "FIN", "SYN", "RST", "PUSH", "ACK", "URG" };
int len;
WORD f;
len = ip->length - ((tcp_GetDataOffset(tp) + in_GetHdrlen(ip)) << 2);
printf("TCP: %s packet:\r\nS: %x; D: %x; SN=%x ACK=%x W=%d DLen=%d\r\n",
mesg, tp->srcPort, tp->dstPort, tp->seqnum, tp->acknum,
tp->window, len);
printf("DO=%d, C=%x U=%d",
tcp_GetDataOffset(tp), tp->checksum, tp->urgentPointer);
f = tp->flags;
for ( len = 0; len < 6; len++ )
if ( f & (1 << len) ) printf(" %s", flags[len]);
printf("\r\n");
*/
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -