📄 tcp.c
字号:
tcp_newstate(soc, TCP_STATE_CLOSED);
break;
case TCP_STATE_FINW1:
case TCP_STATE_FINW2:
case TCP_STATE_CLOSING:
case TCP_STATE_TIMED_WAIT:
case TCP_STATE_LAST_ACK:
/* We are closing already */
break;
case TCP_STATE_CONNECTED:
/* Is there unacked data? */
if(soc->send_unacked == soc->send_next ) {
/* There is no unacked data */
soc->myflags = TCP_FLAG_ACK | TCP_FLAG_FIN;
soc->send_next++;
tcp_sendcontrol(sochandle);
tcp_newstate(soc, TCP_STATE_FINW1);
} else {
/* Can't do much but raise pollable flag to soc->flags */
/* and process it on tcp_poll */
soc->flags |= TCP_INTFLAGS_CLOSEPENDING;
return(sochandle);
}
break;
default:
return(-1);
}
return(sochandle);
}
/** \brief Get current state of the socket
* \ingroup tcp_app_api
* \author
* \li Jari Lahti (jari.lahti@violasystems.com)
* \date 21.07.2002
* \param sochandle handle to the socket to be queried
* \return
* \li -1 - Error
* \li >0 - Socket state
*
* Use this function for querying socket state. This is usually not needed
* directly, but could be usefull for some special purposes.
*/
INT8 tcp_getstate (INT8 sochandle)
{
struct tcb* soc;
if( NO_OF_TCPSOCKETS < 0 )
return(-1);
if( NO_OF_TCPSOCKETS == 0 )
return(-1);
if( sochandle > NO_OF_TCPSOCKETS ) {
TCP_DEBUGOUT("Socket handle non-valid\r\n");
return(-1);
}
if( sochandle < 0 ) {
TCP_DEBUGOUT("Socket handle non-valid\r\n");
return(-1);
}
soc = &tcp_socket[sochandle]; /* Get referense */
return(soc->state);
}
/** \brief Checks if it's possible to send data using given socket
* \ingroup tcp_app_api
* \author
* \li Jari Lahti (jari.lahti@violasystems.com)
* \date 23.07.2002
* \param sochandle handle to the socket to be inspected
* \return
* \li -1 - not possible to send over a socket (previously sent data is
* still not akcnowledged)
* \li >0 - it is possible to send data over a socket
*
* Invoke this function to get information whether it is possible to send
* data or not. This may, sometimes, be preffered way of getting this type
* of information to waiting for #TCP_EVENT_ACK in event_listener function.
*/
INT16 tcp_checksend (INT8 sochandle)
{
struct tcb* soc;
if( NO_OF_TCPSOCKETS < 0 )
return(-1);
if( NO_OF_TCPSOCKETS == 0 )
return(-1);
if( sochandle > NO_OF_TCPSOCKETS ) {
TCP_DEBUGOUT("Socket handle non-valid\r\n");
return(-1);
}
soc = &tcp_socket[sochandle]; /* Get referense */
if(soc->state != TCP_STATE_CONNECTED)
return(-1);
if(soc->send_unacked == soc->send_next)
return(soc->send_mtu);
return(-1);
}
/** \brief Reset connection and place socket to closed state
* \ingroup tcp_app_api
* \author
* \li Jari Lahti (jari.lahti@violasystems.com)
* \date 21.07.2002
* \param sochandle handle to socket to be aborted
* \return
* \li -1 - error
* \li >=0 - OK (value represents handle to aborted socket)
*
* Use this function in cases when TCP connection must be immediately closed.
* Note that the preffered (more elegant) way of closing the TCP connection
* is to invoke tcp_close() which starts a proper closing procedure.
* tcp_abort should be used only in cases when it is really necessary to
* immediately and quickly close the connection.
*/
INT8 tcp_abort (INT8 sochandle)
{
struct tcb* soc;
TCP_DEBUGOUT("FUNCTION: tcp_abort\r\n");
if( NO_OF_TCPSOCKETS < 0 )
return(-1);
if( NO_OF_TCPSOCKETS == 0 )
return(-1);
if( sochandle > NO_OF_TCPSOCKETS ) {
TCP_DEBUGOUT("Socket handle non-valid\r\n");
return(-1);
}
if( sochandle < 0 ) {
TCP_DEBUGOUT("Socket handle non-valid\r\n");
return(-1);
}
soc = &tcp_socket[sochandle]; /* Get referense */
switch (soc->state) {
case TCP_STATE_FREE:
return(-1);
case TCP_STATE_RESERVED:
case TCP_STATE_CLOSED:
return(sochandle);
case TCP_STATE_TIMED_WAIT:
case TCP_STATE_LISTENING:
tcp_newstate(soc, TCP_STATE_CLOSED);
return(sochandle);
case TCP_STATE_SYN_SENT:
case TCP_STATE_SYN_RECEIVED:
case TCP_STATE_CONNECTED:
case TCP_STATE_FINW1:
case TCP_STATE_FINW2:
case TCP_STATE_CLOSING:
case TCP_STATE_LAST_ACK:
soc->myflags = TCP_FLAG_RESET;
tcp_sendcontrol(sochandle);
tcp_newstate(soc, TCP_STATE_CLOSED);
return(sochandle);
default:
return(-1);
}
}
/** \brief Poll TCP sockets periodically
* \ingroup periodic_functions
* \author
* \li Jari Lahti (jari.lahti@violasystems.com)
* \date 19.07.2002
* \warning
* \li This function <b>must be</b> invoked periodically from
* the main loop. See main_demo.c for an example.
*
* This function checks all TCP sockets and performs various actions
* if timeouts occur. What kind of action is performed is defined by the
* state of the TCP socket.
*/
void tcp_poll (void)
{
struct tcb* soc;
static UINT8 handle = 0;
UINT8 i;
INT32 temp;
UINT8 old_retries;
for(i=0; i < NO_OF_TCPSOCKETS; i++ ) {
if(handle > NO_OF_TCPSOCKETS)
handle = 0;
soc = &tcp_socket[handle];
switch(soc->state) {
case TCP_STATE_FREE:
case TCP_STATE_RESERVED:
case TCP_STATE_CLOSED:
case TCP_STATE_LISTENING:
break;
case TCP_STATE_CONNECTED:
/* In CONNECTED State we have */
/* something to do only if we have unacked data */
/* or if connection has been IDLE too long or */
/* unserved close is isuued by user */
/*if(soc->send_next > soc->send_unacked)
temp = soc->send_next - soc->send_unacked;
else
temp = soc->send_unacked - soc->send_next;
*/
temp = soc->send_next - soc->send_unacked;
/* Unserved Close? */
if(soc->flags & TCP_INTFLAGS_CLOSEPENDING) {
/* Can we send the close now */
if(temp == 0) {
soc->myflags = TCP_FLAG_ACK | TCP_FLAG_FIN;
soc->send_next++;
tcp_sendcontrol(handle);
tcp_newstate(soc, TCP_STATE_FINW1);
soc->flags ^= TCP_INTFLAGS_CLOSEPENDING;
handle++;
return;
}
}
/* Socket timeout? */
if(check_timer(soc->persist_timerh) == 0)
{
soc->myflags = TCP_FLAG_ACK | TCP_FLAG_FIN;
soc->send_next++;
tcp_sendcontrol(handle);
tcp_newstate(soc, TCP_STATE_FINW1);
/* Inform application */
soc->event_listener(handle, TCP_EVENT_CLOSE, soc->rem_ip, soc->remport);
handle++;
return;
}
/* Is there unacked data? */
if(temp == 0)
break;
/* Is there timeout? */
if( check_timer(soc->retransmit_timerh) != 0 )
break;
/* De we have retries left */
if(soc->retries_left == 0) {
/* No retries, must reset */
TCP_DEBUGOUT("Retries used up, resetting\r\n");
soc->myflags = TCP_FLAG_RESET;
tcp_sendcontrol(handle);
/* Inform application */
soc->event_listener(handle, TCP_EVENT_ABORT, soc->rem_ip, soc->remport);
if(soc->type & TCP_TYPE_SERVER )
tcp_newstate(soc, TCP_STATE_LISTENING);
else
tcp_newstate(soc, TCP_STATE_CLOSED);
handle++;
return;
}
soc->retries_left--;
init_timer(soc->retransmit_timerh, TCP_DEF_RETRY_TOUT*TIMERTIC);
/* Yep, there is unacked data */
/* Application should send the old data */
if(temp>soc->send_mtu)
temp = soc->send_mtu;
/* Rewind Send Next because the send process will adjust it */
/* So cheat the tcp_send to think there is no unacked data */
soc->send_next = soc->send_unacked;
/* tcp_send will set the retiries_left to maximum but this is */
/* retransmitting already so we need to retain it in order to */
/* avoid dead-lock */
old_retries = soc->retries_left;
#ifdef IPv6
temp = soc->event_listener(handle, TCP_EVENT_REGENERATE, (IPv6Addr *)&temp, 0);
#else
temp = soc->event_listener(handle, TCP_EVENT_REGENERATE, (UINT32)temp, 0);
#endif
soc->retries_left = old_retries;
if(temp <= 0) {
/* No data by application, must be something wrong */
soc->myflags = TCP_FLAG_RESET;
tcp_sendcontrol(handle);
/* Inform application */
soc->event_listener(handle, TCP_EVENT_ABORT, soc->rem_ip, soc->remport);
if(soc->type & TCP_TYPE_SERVER )
tcp_newstate(soc, TCP_STATE_LISTENING);
else
tcp_newstate(soc, TCP_STATE_CLOSED);
handle++;
return;
}
/* Application has send data */
handle++;
return;
case TCP_STATE_SYN_SENT:
case TCP_STATE_SYN_RECEIVED:
/* Is there timeout? */
if( check_timer(soc->retransmit_timerh) != 0 )
break;
TCP_DEBUGOUT("Timeout\r\n");
/* Yep, timeout. Is there reties left? */
if( soc->retries_left ) {
soc->retries_left--;
if(soc->state == TCP_STATE_SYN_SENT)
init_timer(soc->retransmit_timerh, TCP_SYN_RETRY_TOUT*TIMERTIC);
else
init_timer(soc->retransmit_timerh, TCP_DEF_RETRY_TOUT*TIMERTIC);
tcp_sendcontrol(handle);
handle++;
return;
} else {
/* Retries used up */
TCP_DEBUGOUT("Retries used up, resetting\r\n");
if(soc->type & TCP_TYPE_SERVER )
tcp_newstate(soc, TCP_STATE_LISTENING);
else
tcp_newstate(soc, TCP_STATE_CLOSED);
soc->myflags = TCP_FLAG_RESET;
tcp_sendcontrol(handle);
/* Inform application */
soc->event_listener(handle, TCP_EVENT_ABORT, soc->rem_ip, soc->remport);
handle++;
return;
}
break;
case TCP_STATE_TIMED_WAIT:
/* Is there timeout? */
if( check_timer(soc->retransmit_timerh) != 0 )
break;
TCP_DEBUGOUT("Timeout\r\n");
if(soc->retries_left) {
soc->retries_left--;
init_timer(soc->retransmit_timerh, TCP_DEF_RETRY_TOUT*TIMERTIC);
break;
}
if(soc->type & TCP_TYPE_SERVER )
tcp_newstate(soc, TCP_STATE_LISTENING);
else
tcp_newstate(soc, TCP_STATE_CLOSED);
break;
case TCP_STATE_LAST_ACK:
case TCP_STATE_FINW1:
case TCP_STATE_CLOSING:
/* Is there timeout? */
if( check_timer(soc->retransmit_timerh) != 0 )
break;
TCP_DEBUGOUT("Timeout\r\n");
/* Yep, timeout. Is there reties left? */
if( soc->retries_left ) {
soc->retries_left--;
init_timer(soc->retransmit_timerh, TCP_DEF_RETRY_TOUT*TIMERTIC);
soc->myflags = TCP_FLAG_FIN | TCP_FLAG_ACK;
tcp_sendcontrol(handle);
handle++;
return;
} else {
/* Retries used up */
TCP_DEBUGOUT("Retries used up, resetting\r\n");
if(soc->type & TCP_TYPE_SERVER )
tcp_newstate(soc, TCP_STATE_LISTENING);
else
tcp_newstate(soc, TCP_STATE_CLOSED);
soc->myflags = TCP_FLAG_RESET;
tcp_sendcontrol(handle);
/* Inform application */
soc->event_listener(handle, TCP_EVENT_ABORT, soc->rem_ip, soc->remport);
handle++;
return;
}
break;
case TCP_STATE_FINW2:
/* Is there timeout? */
if( check_timer(soc->retransmit_timerh) != 0 )
break;
TCP_DEBUGOUT("Timeout\r\n");
/* Yep, timeout. Is there reties left? */
if( soc->retries_left ) {
/* Still keep waiting for FIN */
soc->retries_left--;
init_timer(soc->retransmit_timerh, TCP_DEF_RETRY_TOUT*TIMERTIC);
break;
} else {
/* Retries used up */
TCP_DEBUGOUT("Retries used up, resetting\r\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -