📄 tcp.c
字号:
{
if ( (tcbptr->sndUNA <= tcbptr->segACK) && (tcbptr->segACK <= tcbptr->sndNXT) )
{
if ( (tcbptr->segACK == tcbptr->sndNXT) ) //Is the ACK to our FIN?
{
tcbptr->state = TCP_STATE_FIN_WAIT2;
socketptr->state = HALF_CLOSED;
}
tcbptr->sndUNA = tcbptr->segACK;
updateRT(socketNr); //Update retransmission buffer
tcbptr->segLEN = 20;
tcbptr->segHdrLEN = 20;
tcbptr->CTL = TCP_ACK;
if ( ((tcbptr->sndWL1 < tcbptr->segSEQ) ||
((tcbptr->sndWL1 == tcbptr->segSEQ) && (tcbptr->sndWL2 <= tcbptr->segACK))) )
{
tcbptr->rcvWND = tcbptr->segWND;
tcbptr->sndWL1 = tcbptr->segSEQ;
tcbptr->sndWL2 = tcbptr->segACK;
}
if ( (tcbptr->segHdrLEN < tcbptr->segLEN) && (tcbptr->state != TCP_STATE_FIN_WAIT2) )
{
prepareFrame( socketNr );
transmitIP(tcbptr->segLEN, socketptr->hisIP0, socketptr->hisIP1, 6);
}
}
}
}
}
/*TCPfin_wait2 does almost the same as TCPestablished. This state
is entered when our FIN to the client is ACKed. If the segment
contains a FIN, ACK the FIN and go to TIME_WAIT. Extract data if any.`*/
void TCPfin_wait2 ( unsigned char socketNr )
{
SOCKET *socketptr = &sockets[socketNr];
TCB *tcbptr = &tcb[socketNr];
if ( (acceptable(socketNr) == TRUE) ) //If segment is acceptable
{
if ( tcbptr->segHdrLEN < tcbptr->segLEN )//Any data?
{
extractData ( socketNr );
}
if ( (tcbptr->segCTL & (TCP_RST|TCP_SYN)) ) //Illegal flags?
{
deleteSocket(socketNr);
}
else if ( (tcbptr->segCTL & TCP_ACK) )
{
if ( (tcbptr->sndUNA <= tcbptr->segACK) && (tcbptr->segACK <= tcbptr->sndNXT) )
{
if ( ((tcbptr->sndWL1 < tcbptr->segSEQ) ||
((tcbptr->sndWL1 == tcbptr->segSEQ) && (tcbptr->sndWL2 <= tcbptr->segACK))) )
{
tcbptr->rcvWND = tcbptr->segWND; //Update window information
tcbptr->sndWL1 = tcbptr->segSEQ;
tcbptr->sndWL2 = tcbptr->segACK;
}
tcbptr->sndUNA = tcbptr->segACK;
updateRT(socketNr); //Update retransmission buffer
if ( (tcbptr->segCTL & TCP_FIN) ) //Do the client want to close the connection?
{
tcbptr->state = TCP_STATE_TIME_WAIT; //Go to TIME_WAIT
socketptr->state = CLOSED;
tcbptr->rcvNXT++;
}
tcbptr->segLEN = 20;
tcbptr->segHdrLEN = 20;
tcbptr->CTL = TCP_ACK;
prepareFrame(socketNr);
transmitIP(tcbptr->segLEN, socketptr->hisIP0, socketptr->hisIP1, 6);
}
}
}
}
/*The client has closed his part of the connection and this server is
not done sending data. Segments received here should only contain
ACKs to our data.*/
void TCPclose_wait ( unsigned char socketNr)
{
TCB *tcbptr = &tcb[socketNr];
if ( (acceptable(socketNr) == TRUE) )
{
if ( (tcbptr->segCTL & (TCP_RST|TCP_SYN)) ) //Illegal flags?
{
deleteSocket(socketNr);
}
else if ( (tcbptr->segCTL & TCP_ACK) )
{
if ( (tcbptr->sndUNA <= tcbptr->segACK) && (tcbptr->segACK <= tcbptr->sndNXT) )
{
tcbptr->sndUNA = tcbptr->segACK;
updateRT(socketNr); //update retransmission buffer
if ( ((tcbptr->sndWL1 < tcbptr->segSEQ) ||
((tcbptr->sndWL1 == tcbptr->segSEQ) && (tcbptr->sndWL2 <= tcbptr->segACK))) )
{
tcbptr->rcvWND = tcbptr->segWND;
tcbptr->sndWL1 = tcbptr->segSEQ;
tcbptr->sndWL2 = tcbptr->segACK;
}
}
}
}
}
/*After CLOSE_WAIT, we must wait for client to ACK our
FIN. If the segment is acceptable, delete the socket*/
void TCPlast_ack ( unsigned char socketNr )
{
TCB *tcbptr = &tcb[socketNr];
if ( (acceptable(socketNr) == TRUE) )
{
if ( (tcbptr->segCTL & (TCP_RST|TCP_SYN|TCP_ACK)) )
{
deleteSocket(socketNr); // drop frame
}
}
}
/*deleteSocket deletes the socket and make it ready
for a new connection.*/
void deleteSocket( unsigned char socketNr )
{
SOCKET *socketptr = &sockets[socketNr];
TCB *tcbptr = &tcb[socketNr];
if (socketptr->previous != NULL) //If the linked list contain more sockets,
{ //make sure the linking maintains.
if (socketptr->next != NULL)
{
socketptr->previous->next = socketptr->next;
socketptr->next->previous = socketptr->previous;
}
else
{
socketptr->previous->next = NULL;
}
}
else if (socketptr->next != NULL)
{
socketptr->next->previous = NULL;
}
socketptr->next=NULL;
socketptr->previous=NULL;
socketptr->state = UNLOCKED; //Delete socket information
socketptr->socketNr = 0xff;
socketptr->hisIP0 = 0;
socketptr->hisIP1 = 0;
socketptr->hisPort = 0;
socketptr->myPort = 0;
socketptr->hisIP0 = 0; //Delete TCB information
socketptr->hisIP1 = 0;
socketptr->hisPort = 0;
tcbptr->sndUNA = 0;
tcbptr->sndWND = TCP_WIN_SIZE;
tcbptr->sndWL1 = 0;
tcbptr->sndWL2 = 0;
tcbptr->rcvNXT = 0;
tcbptr->rcvWND = 0;
tcbptr->IRS = 0;
tcbptr->segSEQ = 0;
tcbptr->segACK = 0;
tcbptr->segLEN = 0;
tcbptr->segWND = 0;
tcbptr->readIn = 0;
tcbptr->writeIn = 0;
tcbptr->readOut = 0;
tcbptr->writeOut = 0;
tcbptr->CTL = 0;
tcbptr->state = TCP_STATE_CLOSED;
tcbptr->open = FALSE;
socketptr->myPort = 0;
deleteBuffer(socketNr);
}
/*prepareFrame creates a new frame according to the information
in TCB. Data must already be placed in frame.*/
void prepareFrame (unsigned char socketNr)
{
unsigned int *frameptr = &frame[TCP_SENDER_PORT-6];
SOCKET *socketptr = &sockets[socketNr];
TCB *tcbptr = &tcb[socketNr];
tcbptr->sndWND = (TCP_WIN_SIZE-2) - writtenIn(socketNr); //Update window size
*frameptr++ = ID.IP0; //Make pseudo header
*frameptr++ = ID.IP1;
*frameptr++ = socketptr->hisIP0;
*frameptr++ = socketptr->hisIP1;
*frameptr++ = 6;
*frameptr++ = tcbptr->segLEN;
*frameptr++ = socketptr->myPort; //Make header
*frameptr++ = socketptr->hisPort;
*frameptr++ = (unsigned int)((tcbptr->sndNXT>>16)&0xffff); //SEQ0
*frameptr++ = (unsigned int)(tcbptr->sndNXT&0xffff); //SEQ1
*frameptr++ = (unsigned int)((tcbptr->rcvNXT>>16)&0xffff); //ACK0
*frameptr++ = (unsigned int)(tcbptr->rcvNXT&0xffff); //ACK1
*frameptr++ = ((tcbptr->segHdrLEN<<10)&0xf000) | tcbptr->CTL; //FLAGS
*frameptr++ = tcbptr->sndWND; //WINDOW
*frameptr = 0; //CHECKSUM
*(frameptr+1) = 0; //URGENT
*frameptr = checksum(&frame[TCP_SENDER_PORT-6], ((tcbptr->segLEN+12))); //New checksum
if ( (tcbptr->CTL & (TCP_SYN|TCP_FIN|TCP_PSH|TCP_URG)) || (tcbptr->segHdrLEN < tcbptr->segLEN) )
{//Put in retransmission buffer if anything other than an ACK
putBuffer(&frame[TCP_SENDER_PORT], tcbptr->segLEN, socketNr);
}
}
/*checkProtocol checks the frame and return the number of
the socket. If there is an error in the frame
with this connection, then the number 0xff is returned.
If there is no socket with this connection, the socket
number of a free socket is returned.*/
unsigned char checkProtocol(unsigned int ip0, unsigned int ip1, unsigned int hisPort, unsigned int myPort)
{
unsigned char i, j, socketNr;
SOCKET *tmpSocketptr;
SOCKET *socketptr = sockets;
TCB *tcbptr = tcb;
// socketptr = sockets;
for (i=0;i<TCP_MAX_SOCKETS;i++) //Find the correct socket
{
// socketptr = &sockets[i];
if ( (socketptr->hisIP0 == ip0) && (socketptr->hisIP1 == ip1) && (socketptr->hisPort == hisPort) )
{
return (socketptr->socketNr); //return socketNr
}
socketptr++;
}
for (i=0;i<TCP_MAX_CONNECTIONS;i++) // There were no such socket.
{
if ( (listenList[i].portNr == myPort) && //Do we listen to this port?
((listenList[i].ip == (((((unsigned long)ip1)<<16)) | ip0)) || listenList[i].ip==0) )
{
socketptr = sockets;
for (socketNr=0;socketNr<TCP_MAX_SOCKETS;socketNr++) //Find free socket
{
// socketptr = &sockets[socketNr];
if (socketptr->socketNr == 0xff) //Found one!
{
// tcbptr = &tcb[socketNr];
tcbptr->open = TRUE;
tcbptr->state = TCP_STATE_LISTEN; //Fill in information
socketptr->socketNr = socketNr;
socketptr->hisIP0 = ip0;
socketptr->hisIP1 = ip1;
socketptr->hisPort = hisPort;
socketptr->myPort = myPort;
socketptr->state = HALF_OPEN;
socketptr->next = NULL;
/* if (socketNr > 0)
{
temp = socketNr;
}
*/
tmpSocketptr = sockets;
for (j=0;j<TCP_MAX_SOCKETS;j++) //Link the socket together with the rest of the sockets on this port.
{
// tmpSocketptr = &sockets[j];
if ( (tmpSocketptr->myPort == myPort) && (tmpSocketptr->next == NULL) && (socketptr != tmpSocketptr) )
{
tmpSocketptr->next = socketptr;
socketptr->previous = tmpSocketptr;
return (socketptr->socketNr);
}
tmpSocketptr++;;
}
socketptr->previous = NULL;
return (socketptr->socketNr); //Return new socketNr.
}
socketptr++;
tcbptr++;
}
}
}
return (0xff); // The segment was not accepted.
}
/*Function acceptable is called to check if the frame follow the
spesifications. return TRUE if frame is OK, else send response and
return FALSE*/
unsigned char acceptable(unsigned char socketNr)
{
SOCKET *socketptr = &sockets[socketNr];
TCB *tcbptr = &tcb[socketNr];
if ( (tcbptr->segSEQ == tcbptr->rcvNXT) ) //Is the SEQnr what we expect?
{
if ( (((tcbptr->segLEN-tcbptr->segHdrLEN) == 0) && (tcbptr->sndWND == 0)) ) //If the window size is 0, the data length must be 0.
{
return TRUE;
}
else if ( (((tcbptr->segLEN-tcbptr->segHdrLEN) == 0) && (tcbptr->sndWND > 0)) && //If the window size > 0, and SEQ is within the window.
(tcbptr->rcvNXT <= tcbptr->segSEQ) && (tcbptr->segSEQ < (tcbptr->rcvNXT+tcbptr->sndWND)) )
{
return TRUE;
}
else if ( ((tcbptr->rcvNXT <= (tcbptr->segSEQ+(tcbptr->segLEN-tcbptr->segHdrLEN))) && //All data in the segment is within the window.
((tcbptr->segSEQ+(tcbptr->segLEN-tcbptr->segHdrLEN)) <= (tcbptr->rcvNXT+tcbptr->sndWND))) )
{
return TRUE;
}
}
tcbptr->segLEN = 20; //Else send an ACK not including information about this segment
tcbptr->segHdrLEN = 20;
tcbptr->CTL = TCP_ACK;
prepareFrame(socketNr);
transmitIP(tcbptr->segLEN, socketptr->hisIP0, socketptr->hisIP1, 6);
return FALSE;
}
/*writtenIn returns the amount of data written into the
inBuffer*/
unsigned int writtenIn(unsigned char socketNr)
{
TCB *tcbptr = &tcb[socketNr];
tcbptr->readIn = tcbptr->readIn%TCP_WIN_SIZE; //Make sure offsets are within buffer
tcbptr->writeIn = tcbptr->writeIn%TCP_WIN_SIZE;
if (tcbptr->writeIn < tcbptr->readIn) //Calculate amount of data and return
{
return (TCP_WIN_SIZE - (tcbptr->readIn-tcbptr->writeIn));
}
else
{
return (tcbptr->writeIn - tcbptr->readIn);
}
}
/* extractData extracts data from the frame and is called
when the TCP state is ESTABLISHED, FIN_WAIT1 and FIN_WAIT2.
If the frame is "out-of-order" the data is extracted and information
about the data is written to segmentList. extractData can only handle
one "out-of-order"-frame at one time.*/
void extractData ( unsigned char socketNr )
{
unsigned int unwritten, i;
unsigned char *bufferptr, *bufferptr2, *startBuffer;
unsigned int *frameptr=&frame[TCP_DATA];
TCB *tcbptr = &tcb[socketNr];
unwritten = TCP_WIN_SIZE - writtenIn(socketNr);
if (unwritten > (tcbptr->segLEN-tcbptr->segHdrLEN) ) //extract data only if the data amount is less than buffer size
{
if (tcbptr->rcvNXT == tcbptr->segSEQ)
{
unwritten = (tcbptr->segLEN - tcbptr->segHdrLEN)/2; //Find number of bytes data in segment
bufferptr = &tcbptr->inBuffer[tcbptr->writeIn]; //Make a pointer to the end of buffer
bufferptr2 = &tcbptr->inBuffer[TCP_WIN_SIZE-1]; //Make a pointer to start of buffer
startBuffer = &tcbptr->inBuffer[0];
for (i=0;i<unwritten;i++)
{
*bufferptr++ = (unsigned char)(((*frameptr)>>8)&0xff);
if (bufferptr > bufferptr2) //If the bufferpointer has moved beyond the end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -