www.pudn.com > uCOSII上实现的tcpip.rar > 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; 
		} 
	} 
}