📄 tcp.c
字号:
{
bufferptr = startBuffer; //Set the pointer to the start of the buffer
}
*bufferptr++ = (unsigned char)((*frameptr++)&0xff);
if (bufferptr > bufferptr2) //If the bufferpointer has moved beyond the end
{
bufferptr = startBuffer; //Set the pointer to the start of the buffer
}
}
if ( (tcbptr->segLEN-tcbptr->segHdrLEN) & 1 ) //If the data size was odd bytes, get the last byte
{
*bufferptr = (unsigned char)(((*frameptr)>>8)&0xff);
}
tcbptr->rcvNXT +=(tcbptr->segLEN-tcbptr->segHdrLEN); //Update next expected SEQnr.
tcbptr->writeIn += (tcbptr->segLEN-tcbptr->segHdrLEN); //Update writeIn pointer
}
}
}
/*checkTCP runs everytime a timer interrupt occursp-> The function checks
the retransmission queue to see if there are frames to be sent and
checks the sockets to see if there are new frames to be sent.*/
void checkTCP ( void )
{
SOCKET *socketptr;
TCB *tcbptr;
unsigned char socketNr;
ticker++; //Increase counter
updateBuffer(); //Update retransmission buffer, segments with timeout is retransmitted.
tcbptr = tcb;
socketptr = sockets;
for (socketNr=0;socketNr<TCP_MAX_SOCKETS;socketNr++) //For every transmission control block.
{
// tcbptr = &tcb[socketNr];
// socketptr = &sockets[socketNr];
tcbptr->segLEN = 20; //Prepare a frame for sending.
tcbptr->segHdrLEN = 20;
tcbptr->CTL = 0; //Clear flags. If flags is set, the segment is sent.
tcbptr->readOut = ((tcbptr->readOut)%TCP_WIN_SIZE); //Ensure the pointers are not outside the
tcbptr->writeOut = ((tcbptr->writeOut)%TCP_WIN_SIZE);
tcbptr->readIn = ((tcbptr->readIn)%TCP_WIN_SIZE);
tcbptr->writeIn = ((tcbptr->writeIn)%TCP_WIN_SIZE);
if ( (tcbptr->state == TCP_STATE_TIME_WAIT) ) //If the state is TIME_WAIT
{
deleteSocket(socketNr); //Just delete the socket
}
else if ( ((tcbptr->state == TCP_STATE_ESTABLISHED) || (tcbptr->state == TCP_STATE_CLOSE_WAIT)) && freeRT() )
{
if ( (tcbptr->readOut != tcbptr->writeOut) ) //If there is data to be sent.
{
tcbptr->segLEN += putData(socketNr); //Put data in segment
if (tcbptr->segLEN > 20)
{
tcbptr->CTL |= TCP_ACK|TCP_PSH; //Set ACK|PSH flags
}
}
if ( (tcbptr->open == FALSE) && (tcbptr->state == TCP_STATE_ESTABLISHED) )
{ //There is no data and connection should be closed.
tcbptr->CTL |= TCP_FIN | TCP_ACK; //Send FIN and enter FIN_WAIT1
tcbptr->state = TCP_STATE_FIN_WAIT1;
socketptr->state = HALF_CLOSED;
}
}
if ( (tcbptr->state == TCP_STATE_CLOSE_WAIT) && (tcbptr->open == FALSE) && freeRT() )
{ //If state is CLOSE_WAIT and connection should be closed
tcbptr->CTL |= TCP_ACK | TCP_FIN;
tcbptr->state = TCP_STATE_LAST_ACK;
socketptr->state = HALF_CLOSED;
}
else if ( (((TCP_WIN_SIZE-tcbptr->sndWND)- writtenIn(socketNr)) > (TCP_WIN_SIZE/10)) )
{ //If the window size has increased more than 1/10 of window size, send a notice to client
tcbptr->CTL |= TCP_ACK;
}
if (tcbptr->CTL) //If there is a flag that is set, the segment should be sent.
{
prepareFrame(socketNr);
transmitIP(tcbptr->segLEN, socketptr->hisIP0, socketptr->hisIP1, 6);
if (tcbptr->state == TCP_STATE_FIN_WAIT1) //Update SEQnr.
{
tcbptr->sndNXT++;
}
tcbptr->sndNXT += (tcbptr->segLEN - tcbptr->segHdrLEN);
}
tcbptr++;
socketptr++;
}
}
/*putBuffer puts a segment in the retransmission buffer*/
unsigned char putBuffer(unsigned int *pointer, unsigned int length, unsigned char sNr)
{
unsigned char bufferNr;
unsigned int i, *bufferptr;
RT *RTbufferptr = RTframes;
SOCKET *socketptr = &sockets[sNr];
TCB *tcbptr = &tcb[sNr];
for (bufferNr=0;bufferNr<TCP_NUMBER_RT_BUF;bufferNr++) //Find free buffer space
{
// RTbufferptr = &RTframes[bufferNr];
if (RTbufferptr->socketNr == 0xff)
{
bufferptr = &RTbufferptr->buffer[0];
if ( ((length+1)/2)< TCP_RT_BUFFER_SIZE) //If there is room for the segment
{
RTbufferptr->nextTICK = ticker + TCP_TICKS_BEFORE_RT; //Set timeout
RTbufferptr->RTOs = 0; //Reset number of retransmissions
RTbufferptr->size = length; //Set length
RTbufferptr->socketNr = sNr; //Set socketNr
RTbufferptr->hisIP0 = socketptr->hisIP0;
RTbufferptr->hisIP1 = socketptr->hisIP1;
RTbufferptr->SEQ = tcbptr->sndNXT+(length-tcbptr->segHdrLEN); //Set sequence number for the segment
for (i=0;i<(length+1)/2;i++) //Copy the segment into the buffer
{
*bufferptr++ = *pointer++;
}
return (bufferNr);
}
}
RTbufferptr++;
}
return 0xff;
}
/*deleteBuffer deletes all segments in retransmission buffer
which belong to a deleted socket*/
void deleteBuffer(unsigned char sNr)
{
unsigned char bufferNr;
for (bufferNr=0;bufferNr<TCP_NUMBER_RT_BUF;bufferNr++)//For every segment in buffer
{
if (RTframes[bufferNr].socketNr == sNr) //Is the socketNr correct
{
RTframes[bufferNr].socketNr = 0xff; //Delete the segment
}
}
}
/* updateBuffer checks all segment in retransmission buffer
for timeout. If a timeout has occured, the segment is retransmitted
and number of retransmissions (RTOs) increased. If RTOs has exceeded
TCP_MAX_RT (maximum number of retransmissions) the socket is deleted*/
void updateBuffer(void)
{
unsigned char bufferNr;
unsigned int i, *frameptr, *buffer;
RT *RTbufferptr = RTframes;
for (bufferNr=0;bufferNr<TCP_NUMBER_RT_BUF;bufferNr++) //For every segment in buffer
{
// RTbufferptr = &RTframes[bufferNr];
if ( (RTbufferptr->nextTICK == ticker) && (RTbufferptr->socketNr < 0xff) ) //If there is a segment and timeout
{
frameptr = &frame[TCP_SENDER_PORT];
buffer = RTbufferptr->buffer;
for (i=0;i<(RTbufferptr->size+1)/2;i++) //Copy segment into frame and send it.
{
*frameptr++ = *buffer++;
}
transmitIP(RTbufferptr->size, RTbufferptr->hisIP0, RTbufferptr->hisIP1, 6);
RTbufferptr->RTOs++;
if (RTbufferptr->RTOs >= TCP_MAX_RT) //If number of retransmissions has exceeded TCP_MAX_RT
{
deleteSocket(RTbufferptr->socketNr); //Delete the socket and segment
RTbufferptr->socketNr=0xff;
}
else
{
RTbufferptr->nextTICK += TCP_TICKS_BEFORE_RT; //Set a new timeout for the segment.
}
}
RTbufferptr++;
}
}
/*updateRT is called when segments is ACKed. Deletes all ACKed segments.*/
void updateRT (unsigned char sNr)
{
unsigned char bufferNr;
unsigned int *frameptr, *buffer, i;
RT *RTbufferptr = RTframes;
for (bufferNr=0;bufferNr<TCP_NUMBER_RT_BUF;bufferNr++) //For all segments in buffer
{
// RTbufferptr = &RTframes[bufferNr];
if ( (RTbufferptr->socketNr == sNr) ) //If segment belongs to this socket.
{
if ( (RTbufferptr->SEQ <= tcb[sNr].sndUNA) ) //If the segment is ACKed.
{
RTbufferptr->socketNr = 0xff; //Delete the socket
}
else
{
frameptr = &frame[TCP_SENDER_PORT]; //If the segment is not ACKed, retransmit it!
buffer = RTbufferptr->buffer;
for (i=0;i<(RTbufferptr->size+1)/2;i++)
{
*frameptr++ = *buffer++;
}
transmitIP(RTbufferptr->size, RTbufferptr->hisIP0, RTbufferptr->hisIP1, 6);
}
}
RTbufferptr++;
}
}
/*freeRT returns TRUE if there is room for another segment
in retransmission buffer, else false*/
unsigned char freeRT ( void )
{
unsigned char i;
RT *RTbufferptr = RTframes;
for (i=0;i<TCP_NUMBER_RT_BUF;i++) //For every segment in buffer
{
// RTbufferptr = &RTframes[i];
if ( (RTbufferptr->socketNr == 0xff) ) //Is this buffer space free?
{
return TRUE;
}
}
i=0;
return FALSE;
}
/*writtenOut returns the amount of bytes in outBuffer*/
unsigned int writtenOut(unsigned char socketNr)
{
unsigned int readOut, writeOut;
TCB *tcbptr = &tcb[socketNr];
tcbptr->readOut = tcbptr->readOut%TCP_WIN_SIZE;
readOut = tcbptr->readOut;
tcbptr->writeOut = tcbptr->writeOut%TCP_WIN_SIZE;
writeOut = tcbptr->writeOut;
if ( readOut > writeOut)
{
return (TCP_WIN_SIZE - readOut + writeOut);
}
else
{
return (writeOut - readOut);
}
}
/*putData puts data from outBuffer into the frame to be sent.
The amount of data depends on how much is waiting, and
how much it is allowed to send.*/
unsigned int putData(unsigned char socketNr)
{
unsigned int unsent, i, send;
unsigned int *frameptr;
unsigned char *bufferptr, *startptr, *endptr;
TCB *tcbptr = &tcb[socketNr];
unsent = writtenOut(socketNr); //Get amount of data in outBuffer
if ( unsent ) //If there was data
{
if ( (unsent < tcbptr->rcvWND) && (unsent < tcbptr->MSS) )
{ //If data size is less than client's window and maximum segment size
send = unsent;
}
else if ( (unsent > tcbptr->rcvWND) && (unsent < tcbptr->MSS) )
{ //If data size is less than MSS, but greater than client's window.
send = tcbptr->rcvWND;
}
else if ( (unsent < tcbptr->rcvWND) && (unsent > tcbptr->MSS) )
{ //If data size is less than receiver's windoe, but greater than MSS
send = tcbptr->MSS;
}
else if ( (tcbptr->rcvWND < tcbptr->MSS) )
{ //In case data size is greater than both MSS and client's window. Pick the smallest.
send = tcbptr->rcvWND;
}
else
{
send = tcbptr->MSS;
}
frameptr = &frame[TCP_DATA];
bufferptr = &tcbptr->outBuffer[tcbptr->readOut];
startptr = tcbptr->outBuffer;
endptr = &tcbptr->outBuffer[TCP_WIN_SIZE-1];
for (i=0;i<send/2;i++) //Copy data to frame.
{
*frameptr = ((*bufferptr++)<<8)&0xff00;
if (bufferptr > endptr) //If bufferptr exceeds buffer, start at beginning.
{
bufferptr = startptr;
}
*frameptr++ |= ((*bufferptr++)&0xff);
if (bufferptr > endptr) //If bufferptr exceeds buffer, start at beginning.
{
bufferptr = startptr;
}
}
if (send & 1) //Copy last byte if odd number of bytes.
{
*frameptr = ((*bufferptr)<<8)&0xff00;
}
tcbptr->readOut += send; //Update readOut pointer.
return send; //Return number of bytes copied.
}
return 0;
}
/*TCPfindSockets find the top of the linked list with sockets
to the specified port and returns a pointer to it.*/
SOCKET *TCPfindSockets (unsigned int port)
{
unsigned char i;
SOCKET *socketptr = sockets;
for (i=0;i<TCP_MAX_SOCKETS;i++) //For every socket.
{
// socketptr = &sockets[i];
if (socketptr->myPort == port && (socketptr->previous == NULL) ) //Is this the correct port and the first element?
{
return socketptr;
}
socketptr++;
}
return NULL;
}
/*popen ~ Passive open. Create a TCB and put the connection in state LISTEN.*/
char TCPpopen (unsigned int port, unsigned long ip)
{
unsigned char x;
LISTEN *listenptr = listenList;
for (x=0;x<TCP_MAX_CONNECTIONS;x++)
{
if ( (listenptr->portNr == port) && (listenptr->ip == ip) ) //Do we already listen to the port?
{
return 0;
}
listenptr++;
}
listenptr = listenList;
for (x=0;x<TCP_MAX_CONNECTIONS;x++)
{
if ( !listenptr->portNr ) //Find a free entry for this port.
{
listenptr->portNr = port;
listenptr->ip = ip;
return 1;
}
listenptr++;
}
return 0;
}
/*TCPfindTCB finds a free transmission Control Block and
returns the number of the block if it find one, else oxff.*/
unsigned char TCPfindTCB( void )
{
unsigned char socketNr;
SOCKET *socketptr = sockets;
for (socketNr=0;socketNr<TCP_MAX_SOCKETS;socketNr++)
{
// socketptr = &sockets[socketNr];
if ( (socketptr++->socketNr == 0xff) ) //Is this TCB free?
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -