📄 ztcp.c
字号:
#include "include/zeth.h"
#include "include/zarp.h"
#include "include/ztcp.h"
#include "include/ztask.h"
#include "include/zstats.h"
void led_change(int i);
/*******************static ver in TCP implement**********************/
static tcp_pcb_t tcp_pcb_table[ZNET_MAX_USER + 1];
static sys_sem_t _tcp_sem_table[ZNET_MAX_USER + 1];
static tcp_seg_t _tcp_seg_buffer[TCP_SEGMENT_NUMBER];
static u8_t _tcp_seg_flags[TCP_SEGMENT_NUMBER];
tcp_pcb_t *ptcp_active_chain;
tcp_pcb_t *ptcp_listen_chain;
tcp_pcb_t *ptcp_tw_chain;
u32_t tcp_ticks;
/* Incremented every coarse grained timer shot
(typically every 500 ms, determined by TCP_COARSE_TIMEOUT). */
static const u8_t tcp_backoff[13] =
{ 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64};
/*==========================================================*/
static u32_t tcp_next_iss(void);
void tcp_init(void)
{
u8_t i;
for ( i = 1; i <= ZNET_MAX_USER; i++)
{
tcp_pcb_table[i]._psocket = NULL;
_tcp_sem_table[i] = NULL;
}
for ( i = 0; i < TCP_SEGMENT_NUMBER; i++)
{
_tcp_seg_flags[i] = 0;
_tcp_seg_buffer[i]._id = i;
}
ptcp_active_chain = NULL;
ptcp_listen_chain = NULL;
ptcp_tw_chain = NULL;
#ifdef ZSTATS
zstats.seg_used = TCP_SEGMENT_NUMBER;
#endif
return;
}
u8_t tcp_open(zsocket_t *psocket)
{
tcp_pcb_t *ptcp = NULL;
ptcp = tcp_pcb_new(psocket);
if ( ptcp != NULL)
return 0;
else
return -1;
}
u8_t tcp_close(zsocket_t *psocket)
{
tcp_pcb_t *ptcp = NULL;
s8_t err;
if ( psocket != NULL && tcp_pcb_table[psocket->_id]._psocket != psocket)
return -1;
ptcp = &tcp_pcb_table[psocket->_id];
sys_wait_sem(znet_sem_tmr, 0, &err);
err = tcp_pcb_close(ptcp);
sys_signal_sem(znet_sem_tmr);
return err;
}
u8_t tcp_listen(zsocket_t *psocket)
{
tcp_pcb_t *ptcp = NULL;
if ( psocket != NULL && tcp_pcb_table[psocket->_id]._psocket != psocket)
return -1;
ptcp = &tcp_pcb_table[psocket->_id];
ptcp->state = LISTEN;
return 0;
}
s8_t tcp_accept(zsocket_t *psocket)
{
tcp_pcb_t *ptcp = NULL;
tcp_pcb_t *pclient = NULL;
tcp_pcb_t *tcp_tmp_pcb = NULL;
s8_t rid;
u8_t err;
if ( psocket != NULL && tcp_pcb_table[psocket->_id]._psocket != psocket)
return -1;
ptcp = &tcp_pcb_table[psocket->_id];
sys_enter_critical(); /*this operation must ciritical*/
TCP_REG((&ptcp_listen_chain), ptcp);
sys_exit_critical();
while(1)
{
sys_wait_sem(ptcp->user_sem, 0 , &err);
if ( ptcp->accept > 0)
{
rid = ptcp->accept;
pclient = &tcp_pcb_table[rid];
if ( pclient->state == CLOSE_WAIT) /* if incoming have FIN*/
{
tcp_close(pclient->_psocket);
sys_enter_critical();
ptcp->accept = 0;
sys_exit_critical();
continue;
}
if ( pclient->state == CLOSED)
{
sys_enter_critical();
ptcp->accept = 0;
sys_exit_critical();
continue;
}
sys_enter_critical();
ptcp->accept = 0;
TCP_RMV((&ptcp_listen_chain), ptcp);
sys_exit_critical();
return rid;
}
}
return -1;
}
u8_t tcp_recv(zsocket_t *psocket, zbuffer_t **ppbuf, u8_t flags)
{
tcp_pcb_t *ptcp = NULL;
u8_t err;
if ( psocket != NULL && tcp_pcb_table[psocket->_id]._psocket != psocket)
return -1;
ptcp = &tcp_pcb_table[psocket->_id];
while(1)
{
sys_enter_critical();
*ppbuf = ptcp->recv_pbuf;
ptcp->recv_pbuf = NULL;
sys_exit_critical();
if ( *ppbuf == NULL)
{
if ( ptcp->state != ESTABLISHED)
{
return -1;
}
else
{
sys_wait_sem( ptcp->user_sem, 50, &err);
continue;
}
}
else
{
sys_enter_critical();
ptcp->rcv_wnd += ((*ppbuf)->tot_len);
sys_exit_critical();
return 0;
}
}
return 0;
}
u8_t tcp_sent(zsocket_t *psocket, u8_t *pdata, u16_t *len, u8_t flags)
{
tcp_pcb_t *ptcp = NULL;
u8_t err;
s8_t ret;
if ( psocket != NULL && tcp_pcb_table[psocket->_id]._psocket != psocket)
return -1;
ptcp = &tcp_pcb_table[psocket->_id];
sys_wait_sem(znet_sem_tmr, 0, &err);
if ( ptcp->state != ESTABLISHED)
{
*len = -1;
sys_signal_sem(znet_sem_tmr);
return -1;
}
ret = tcp_insert_queue( ptcp, pdata, *len, 0, NULL, 0);
tcp_output(ptcp);
sys_signal_sem(znet_sem_tmr);
if ( ret != ERR_OK)
{
*len = 0;
return -1;
}
else
{
while(1)
{
if (ptcp->unacked == NULL || ptcp->state != ESTABLISHED)
{
if (ptcp->state != ESTABLISHED)
return -1;
else
return 0;
}
sys_wait_sem(ptcp->user_sem, 50, &err);
}
}
return 0;
}
void tcp_debug(s8_t id, u8_t cmd)
{
u8_t i;
tcp_pcb_t *ptcp;
ptcp = ptcp_listen_chain;
i = 0;
sys_enter_critical();
while( ptcp != NULL)
{
i++;
ptcp = ptcp->next;
}
sys_exit_critical();
printf("listen chain's number = %d\n", i);
ptcp = ptcp_active_chain;
i = 0;
sys_enter_critical();
while( ptcp != NULL)
{
i++;
ptcp = ptcp->next;
}
sys_exit_critical();
printf("active chain's number = %d\n", i);
ptcp = ptcp_tw_chain;
i = 0;
sys_enter_critical();
while( ptcp != NULL)
{
i++;
ptcp = ptcp->next;
}
sys_exit_critical();
printf("time wait chain's number = %d\n", i);
}
/*===================TCP basic function===========================*/
static u32_t tcp_next_iss(void)
{
static u32_t iss = 6510;
iss += tcp_ticks;
return iss;
}
tcp_pcb_t *tcp_pcb_new(zsocket_t *psocket)
{
tcp_pcb_t *ptcp;
u32_t iss;
if ( tcp_pcb_table[psocket->_id]._psocket != NULL)
{
return NULL;
}
ptcp = &tcp_pcb_table[psocket->_id];
bzero ( ptcp, sizeof(tcp_pcb_t));
ptcp->accept = 0;
ptcp->state = CLOSED;
ptcp->snd_buf = TCP_SND_BUF;
ptcp->snd_queuelen = 0;
ptcp->rcv_wnd = TCP_WND;
ptcp->mss = TCP_MSS;
ptcp->rto = 3000 / TCP_SLOW_INTERVAL;
ptcp->sa = 0;
ptcp->sv = 3000 / TCP_SLOW_INTERVAL;
ptcp->rtime = 0;
ptcp->cwnd = 1;
iss = tcp_next_iss();
ptcp->snd_wl2 = iss;
ptcp->snd_nxt = iss;
ptcp->snd_max = iss;
ptcp->lastack = iss;
ptcp->snd_lbb = iss;
ptcp->tmr = tcp_ticks;
if ( _tcp_sem_table[ psocket->_id ] != NULL)
{
ptcp->user_sem = _tcp_sem_table[psocket->_id];
sys_reset_sem( ptcp->user_sem, 0);
_tcp_sem_table[psocket->_id] = NULL;
}
else
ptcp->user_sem = sys_new_sem(0);
ptcp->_psocket = psocket;
return ptcp;
}
void tcp_pcb_delete(tcp_pcb_t *ptcp)
{
zsocket_t *psocket;
s8_t id;
if ( ptcp->state != CLOSED)
tcp_pcb_clean(ptcp);
ptcp->state = CLOSED;
psocket = ptcp->_psocket;
_tcp_sem_table[ psocket->_id] = ptcp->user_sem; /*this we will use again*/
id = ptcp->_psocket->_id;
tcp_pcb_table[id]._psocket = NULL; /*Identify this ptcp will not used*/
zshutdown( id ); /*Identify zsocket will not uesd*/
}
void tcp_pcb_clean(tcp_pcb_t *ptcp)
{
tcp_seg_delete(ptcp->unsent);
ptcp->unsent = NULL;
tcp_seg_delete(ptcp->unacked);
ptcp->unacked = NULL;
zbuffer_delete(ptcp->recv_pbuf);
ptcp->recv_pbuf = NULL;
}
void tcp_pcb_remove(tcp_pcb_t **pcblist, tcp_pcb_t *ptcp)
{
tcp_pcb_t *tcp_tmp_pcb;
TCP_RMV(pcblist, ptcp);
tcp_pcb_clean(ptcp);
/* if there is an outstanding delayed ACKs, send it */
if(ptcp->state != TIME_WAIT && ptcp->state != LISTEN &&
ptcp->flags & TF_ACK_DELAY)
{
ptcp->flags |= TF_ACK_NOW; /*just ack last once*/
tcp_output(ptcp);
}
ptcp->state = CLOSED;
}
tcp_pcb_t *tcp_pcb_query(s8_t id)
{
zsocket_t *psocket;
psocket = query_zsocket(id);
if ( psocket != NULL && tcp_pcb_table[id]._psocket == psocket)
{
return &tcp_pcb_table[id];
}
return NULL;
}
static s8_t tcp_send_ctrl(tcp_pcb_t *ptcp, u8_t flags)
{
return tcp_insert_queue(ptcp, NULL, 0, flags, NULL, 0);
}
s8_t tcp_pcb_close(tcp_pcb_t *ptcp)
{
s8_t err;
#if 0
DEBUGF(TCP_DEBUG, ("tcp_close: closing in state "));
tcp_debug_print_state(pcb->state);
DEBUGF(TCP_DEBUG, ("\n"));
#endif
switch(ptcp->state)
{
case LISTEN:
err = ERR_OK;
tcp_pcb_remove(&ptcp_listen_chain, ptcp);
tcp_pcb_delete(ptcp);
ptcp = NULL;
break;
case SYN_SENT:
err = ERR_OK;
tcp_pcb_remove(&ptcp_listen_chain, ptcp);
tcp_pcb_delete(ptcp);
ptcp = NULL;
break;
case SYN_RCVD:
err = tcp_send_ctrl(ptcp, TCP_FIN);
if(err == ERR_OK)
{
ptcp->state = FIN_WAIT_1;
}
break;
case ESTABLISHED:
err = tcp_send_ctrl(ptcp, TCP_FIN);
if(err == ERR_OK)
{
ptcp->state = FIN_WAIT_1;
}
break;
case CLOSE_WAIT:
err = tcp_send_ctrl(ptcp, TCP_FIN);
if(err == ERR_OK)
{
ptcp->state = LAST_ACK;
}
break;
default:
/* Has already been closed, do nothing. */
err = ERR_OK;
ptcp = NULL;
break;
}
if(ptcp != NULL && err == ERR_OK)
{
err = tcp_output(ptcp);
}
return err;
}
tcp_seg_t *tcp_seg_new()
{
u8_t i;
for ( i = 0; i < TCP_SEGMENT_NUMBER; i++)
{
if ( _tcp_seg_flags[i] == 0)
{
_tcp_seg_flags[i] = 1;
_tcp_seg_buffer[i].next = NULL;
_tcp_seg_buffer[i]._ori_pbuffer = NULL;
_tcp_seg_buffer[i].pbuffer = NULL;
_tcp_seg_buffer[i].pdata = NULL;
_tcp_seg_buffer[i].ptcpheader = NULL;
#ifdef ZSTATS
zstats.seg_used --;
#endif
return &_tcp_seg_buffer[i];
}
}
return NULL;
}
static void _tcp_seg_delete( tcp_seg_t *pseg)
{
if ( pseg != NULL)
{
_tcp_seg_flags[ pseg->_id ] = 0;
#ifdef ZSTATS
zstats.seg_used ++;
#endif
}
}
void tcp_seg_delete(tcp_seg_t *pseg)
{
tcp_seg_t *tmp;
while( pseg != NULL)
{
tmp = pseg->next;
pseg->next = NULL;
zbuffer_delete(pseg->_ori_pbuffer);
pseg->_ori_pbuffer = NULL;
_tcp_seg_delete(pseg);
pseg = tmp;
}
}
/*=======================TCP tmr=====================*/
static void tcp_fast_tmr(void);
static void tcp_slow_tmr(void);
void tcp_tmr(void *pdata)
{
u8_t count = 0;
u8_t err;
for(;;)
{
sys_delay(10);
sys_wait_sem( znet_sem_tmr, 0, &err);
led_change(1);
count ++;
if ( count == 10)
count =0;
if ( count & 1)
{
tcp_fast_tmr();
}
if ( count == 0 || count == 5)
{
tcp_slow_tmr();
change_led1();
}
sys_signal_sem( znet_sem_tmr);
}
}
static void tcp_fast_tmr(void)
{
tcp_pcb_t *ptcp;
/* send delayed ACKs */
for(ptcp = ptcp_active_chain; ptcp != NULL; ptcp = ptcp->next)
{
if(ptcp->flags & TF_ACK_DELAY)
{
/*DEBUGF(TCP_DEBUG, ("tcp_timer_fine: delayed ACK\n"));*/
tcp_ack_now(ptcp);
ptcp->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
}
}
}
static void tcp_slow_tmr(void)
{
tcp_pcb_t *ptcp, *pcb2, *prev;
tcp_seg_t *seg, *useg;
static u32_t eff_wnd;
static u8_t pcb_remove; /* flag if a PCB should be removed */
++tcp_ticks;
/* Steps through all of the active PCBs. */
prev = NULL;
ptcp = ptcp_active_chain;
while(ptcp != NULL)
{
/*ASSERT("tcp_timer_coarse: active pcb->state != CLOSED", pcb->state != CLOSED);
ASSERT("tcp_timer_coarse: active pcb->state != LISTEN", pcb->state != LISTEN);
ASSERT("tcp_timer_coarse: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);*/
pcb_remove = 0;
if(ptcp->state == SYN_SENT && ptcp->nrtx == TCP_SYNMAXRTX)
{
++pcb_remove;
}
else if(ptcp->nrtx == TCP_MAXRTX)
{
++pcb_remove;
}
else
{
++ptcp->rtime;
seg = ptcp->unacked;
if(seg != NULL && ptcp->rtime >= ptcp->rto)
{
/*DEBUGF(TCP_RTO_DEBUG, ("tcp_timer_coarse: rtime %ld pcb->rto %d\n",
tcp_ticks - pcb->rtime, pcb->rto));*/
/* Double retransmission time-out unless we are trying to
connect to somebody (i.e., we are in SYN_SENT). */
if(ptcp->state != SYN_SENT)
{
ptcp->rto = ((ptcp->sa >> 3) + ptcp->sv) << tcp_backoff[ptcp->nrtx];
printf("change time out = %d\n", ptcp->rto);
}
/* Move all other unacked segments to the unsent queue. */
if(seg->next != NULL)
{
for(useg = seg->next; useg->next != NULL; useg = useg->next);
/* useg now points to the last segment on the unacked queue. */
useg->next = ptcp->unsent;
ptcp->unsent = seg->next;
seg->next = NULL;
ptcp->snd_nxt = (ptcp->unsent->ptcpheader->seqno);
}
/* Do the actual retransmission. */
tcp_rexmit_seg(ptcp, seg);
/* Reduce congestion window and ssthresh. */
eff_wnd = MIN(ptcp->cwnd, ptcp->snd_wnd);
ptcp->ssthresh = eff_wnd >> 1;
if(ptcp->ssthresh < ptcp->mss)
{
ptcp->ssthresh = ptcp->mss * 2;
}
ptcp->cwnd = ptcp->mss;
/*
DEBUGF(TCP_CWND_DEBUG, ("tcp_rexmit_seg: cwnd %u ssthresh %u\n",
pcb->cwnd, pcb->ssthresh));
*/
}
}
/* Check if this PCB has stayed too long in FIN-WAIT-2 */
if(ptcp->state == FIN_WAIT_2)
{
if((u32_t)(tcp_ticks - ptcp->tmr) >
TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL)
{
++pcb_remove;
}
}
/* Check if this PCB has stayed too long in SYN-RCVD */
if(ptcp->state == SYN_RCVD)
{
if((u32_t)(tcp_ticks - ptcp->tmr) >
TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL)
{
++pcb_remove;
}
}
/* If the PCB should be removed, do it. */
if(pcb_remove)
{
/* Remove PCB from tcp_active_pcbs list. */
if(prev != NULL)
{
/*ASSERT("tcp_timer_coarse: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs);
* */
prev->next = ptcp->next;
}
else
{
/* This PCB was the first. */
/*
ASSERT("tcp_timer_coarse: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb);
*/
ptcp_active_chain = ptcp->next;
}
pcb2 = ptcp->next;
tcp_pcb_clean(ptcp);
sys_signal_sem(ptcp->user_sem);
tcp_pcb_delete(ptcp);
ptcp = pcb2;
}
else
{
/* We check if we should poll the connection. */
/*XXX TODO for connect timeout*/
prev = ptcp;
ptcp = ptcp->next;
}
}
/* Steps through all of the TIME-WAIT PCBs. */
prev = NULL;
ptcp = ptcp_tw_chain;
while(ptcp != NULL)
{
/*ASSERT("tcp_timer_coarse: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
*/
pcb_remove = 0;
/* Check if this PCB has stayed long enough in TIME-WAIT */
if((u32_t)(tcp_ticks - ptcp->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL)
{
++pcb_remove;
}
/* If the PCB should be removed, do it. */
if(pcb_remove)
{
tcp_pcb_clean(ptcp);
/* Remove PCB from tcp_tw_pcbs list. */
if(prev != NULL)
{
/*
ASSERT("tcp_timer_coarse: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs);
*/
prev->next = ptcp->next;
}
else
{
/* This PCB was the first. */
/*
* ASSERT("tcp_timer_coarse: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb);
*/
ptcp_tw_chain = ptcp->next;
}
pcb2 = ptcp->next;
tcp_pcb_delete(ptcp);
ptcp = pcb2;
}
else
{
prev = ptcp;
ptcp = ptcp->next;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -