⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ztcp.c

📁 uCOSII上实现的tcpip协议实现代码(gcc编译)
💻 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 + -