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

📄 tcp.c

📁 这是基于TI公司的DSP TMS320DM642而开发的TCP/UDP协议
💻 C
📖 第 1 页 / 共 3 页
字号:
/**
 * @file
 *
 * Transmission Control Protocol for IP
 *
 * This file contains common functions for the TCP implementation, such as functinos
 * for manipulating the data structures and the TCP timer functions. TCP functions
 * related to input and output is found in tcp_in.c and tcp_out.c respectively.
 *
 */


#include "tcp.h"
#include "tcpmem.h"

/* Incremented every coarse grained timer shot
   (typically every 500 ms, determined by TCP_COARSE_TIMEOUT). */
u32_t tcp_ticks;

const u8_t tcp_backoff[13] ={ 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};

/* The TCP PCB lists. */

/* List of all TCP PCBs in LISTEN state */
union tcp_listen_pcbs_t tcp_listen_pcbs;
/** List of all TCP PCBs that are in a state in which
 * they accept or send data. */
struct tcp_pcb *tcp_active_pcbs;  
/** List of all TCP PCBs in TIME-WAIT state */
struct tcp_pcb *tcp_tw_pcbs;

struct tcp_pcb *tcp_tmp_pcb;

static u8_t tcp_timer;
Uint32   Timer=0;
static u16_t tcp_new_port(void);
static int tcpip_tcp_timer_active = 0;


void tcpip_tcp_timer(void *arg)
{
	  (void)arg;
	  if(Timer<25)
	  {
	     Timer++;
	     return ;
	  }
	  Timer=0;
	  /* call TCP timer handler */
	  tcp_tmr();
	  /* timer still needed? */
	  if (tcp_active_pcbs || tcp_tw_pcbs) 
	  {
	    /* restart timer */
	//    sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
	  } else {
	    /* disable timer */
	    tcpip_tcp_timer_active = 0;
	  }
}

void tcp_timer_needed(void)
{
  /* timer is off but needed again? */
  if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs))
   {
	    /* enable and start timer */
	    tcpip_tcp_timer_active = 1;
	    //sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
  }
}

static u16_t lwip_chksum(void *dataptr, int len)
{
  u32_t acc;

//  LWIP_DEBUGF(INET_DEBUG, ("lwip_chksum(%p, %d)\n", (void *)dataptr, len));
  for(acc = 0; len > 1; len -= 2) {
      /*    acc = acc + *((u16_t *)dataptr)++;*/
    acc += *(u16_t *)dataptr;
    dataptr = (void *)((u16_t *)dataptr + 1);
  }

  /* add up any odd byte */
  if (len == 1) {
    acc += htons((u16_t)((*(u8_t *)dataptr) & 0xff) << 8);
//    LWIP_DEBUGF(INET_DEBUG, ("inet: chksum: odd byte %d\n", (unsigned int)(*(u8_t *)dataptr)));
  } else {
//    LWIP_DEBUGF(INET_DEBUG, ("inet: chksum: no odd byte\n"));
  }
  acc = (acc >> 16) + (acc & 0xffffUL);

  if ((acc & 0xffff0000) != 0) {
    acc = (acc >> 16) + (acc & 0xffffUL);
  }

  return (u16_t)acc;
}
/* inet_chksum_pseudo:
 *
 * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
 */

u16_t inet_chksum_pseudo(struct pbuf *p,
       struct ip_addr *src, struct ip_addr *dest,
       u8_t proto, u16_t proto_len)
{
  u32_t acc;
  struct pbuf *q;
  u8_t swapped;

  acc = 0;
  swapped = 0;
  /* iterate through all pbuf in chain */
  for(q = p; q != NULL; q = q->next) {
//    LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
//      (void *)q, (void *)q->next));
    acc += lwip_chksum(q->payload, q->len);
    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%lx \n", acc));*/
    while (acc >> 16) {
      acc = (acc & 0xffffUL) + (acc >> 16);
    }
    if (q->len % 2 != 0) {
      swapped = 1 - swapped;
      acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
    }
    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%lx \n", acc));*/
  }

  if (swapped) {
    acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
  }
  acc += (src->addr & 0xffffUL);
  acc += ((src->addr >> 16) & 0xffffUL);
  acc += (dest->addr & 0xffffUL);
  acc += ((dest->addr >> 16) & 0xffffUL);
  acc += (u32_t)htons((u16_t)proto);
  acc += (u32_t)htons(proto_len);

  while (acc >> 16) {
    acc = (acc & 0xffffUL) + (acc >> 16);
  }
 // LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%lx\n", acc));
  return (u16_t)~(acc & 0xffffUL);
}
/**
 * Initializes the TCP layer.
 */
void tcp_init(void)
{
	  /* Clear globals. */
	  tcp_listen_pcbs.listen_pcbs = NULL;
	  tcp_active_pcbs = NULL;
	  tcp_tw_pcbs = NULL;
	  tcp_tmp_pcb = NULL;
	  
	  /* initialize timer */
	  tcp_ticks = 0;
	  tcp_timer = 0;
  
}

/**
 * Called periodically to dispatch TCP timers.
 *
 */
void tcp_tmr(void)
{
	  /* Call tcp_fasttmr() every 250 ms */
	  tcp_fasttmr();
	
	  if (++tcp_timer & 1) 
	  {
		    /* Call tcp_tmr() every 500 ms, i.e., every other timer
		       tcp_tmr() is called. */
		    tcp_slowtmr();
	  }
}

/**
 * Closes the connection held by the PCB.
 *
 */
err_t  tcp_close(struct tcp_pcb *pcb)
{
	  err_t err;
	  
	  switch (pcb->state) 
	  {
		  case CLOSED:
			    /* Closing a pcb in the CLOSED state might seem erroneous,
			     * however, it is in this state once allocated and as yet unused
			     * and the user needs some way to free it should the need arise.
			     * Calling tcp_close() with a pcb that has already been closed, (i.e. twice)
			     * or for a pcb that has been used and then entered the CLOSED state 
			     * is erroneous, but this should never happen as the pcb has in those cases
			     * been freed, and so any remaining handles are bogus. */
			    err = ERR_OK;
			    memp_free(MEMP_TCP_PCB, pcb);
			    pcb = NULL;
		        break;
		  case LISTEN:
			    err = ERR_OK;
			    tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs.pcbs, pcb);
			    memp_free(MEMP_TCP_PCB_LISTEN, pcb);
			    pcb = NULL;
			    break;
		  case SYN_SENT:
			    err = ERR_OK;
			    tcp_pcb_remove(&tcp_active_pcbs, pcb);
			    memp_free(MEMP_TCP_PCB, pcb);
			    pcb = NULL;
			    break;
		  case SYN_RCVD:
		        
		  case ESTABLISHED:
			    err = tcp_send_ctrl(pcb, TCP_FIN);
			    if (err == ERR_OK) 
			    {
				      pcb->state = FIN_WAIT_1;
			    }
			    break;
		  case CLOSE_WAIT:
			    err = tcp_send_ctrl(pcb, TCP_FIN);
			    if (err == ERR_OK) 
			    {
				      pcb->state = LAST_ACK;
			    }
			    break;
		  default:
			    /* Has already been closed, do nothing. */
			    err = ERR_OK;
			    pcb = NULL;
			    break;
	  }
	
	  if (pcb != NULL && err == ERR_OK) 
	  {
		    err = tcp_output(pcb);
	  }
	  return err;
}

/**
 * Aborts a connection by sending a RST to the remote host and deletes
 * the local protocol control block. This is done when a connection is
 * killed because of shortage of memory.
 *
 */
void tcp_abort(struct tcp_pcb *pcb)
{
	  u32_t seqno, ackno;
	  u16_t remote_port, local_port;
	  Uint32 remote_ip, local_ip;
	  void *errf_arg;
	
	  
	  /* Figure out on which TCP PCB list we are, and remove us. If we
	     are in an active state, call the receive function associated with
	     the PCB with a NULL argument, and send an RST to the remote end. */
	  if (pcb->state == TIME_WAIT) 
	  {
		    tcp_pcb_remove(&tcp_tw_pcbs, pcb);
		    memp_free(MEMP_TCP_PCB, pcb);
	  } 
	  else 
	  {
		    seqno = pcb->snd_nxt;
		    ackno = pcb->rcv_nxt;
		    local_ip=pcb->local_ip;
		    remote_ip=pcb->dest_ip;
		    local_port = pcb->local_port;
		    remote_port = pcb->remote_port;
		    errf_arg = pcb->callback_arg;
		    tcp_pcb_remove(&tcp_active_pcbs, pcb);
		    if (pcb->unacked != NULL) 
		    {
			      tcp_segs_free(pcb->unacked);
		    }
		    if (pcb->unsent != NULL) 
		    {
			      tcp_segs_free(pcb->unsent);
		    }
		    #if TCP_QUEUE_OOSEQ    
		    if (pcb->ooseq != NULL) 
		    {
			      tcp_segs_free(pcb->ooseq);
		    }
		    #endif /* TCP_QUEUE_OOSEQ */
		    memp_free(MEMP_TCP_PCB, pcb);
		    tcp_rst(seqno, ackno, local_ip, remote_ip, local_port, remote_port);
	  }
}

/**
 * Binds the connection to a local portnumber and IP address. If the
 * IP address is not given (i.e., ipaddr == NULL), the IP address of
 * the outgoing network interface is used instead.
 *
 */
err_t tcp_bind(struct tcp_pcb *pcb, Uint32 *ipaddr, u16_t port)
{
	  struct tcp_pcb *cpcb;
#if SO_REUSE
	  int reuse_port_all_set = 1;
#endif /* SO_REUSE */
	
	  if (port == 0) 
	  {
		    port = tcp_new_port();
	  }
	  
	  
#if SO_REUSE == 0
	  
	  /* Check if the address already is in use. */
	  for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs;cpcb != NULL; cpcb = cpcb->next) 
	  {
		    if (cpcb->local_port == port) 
		    {
			      if(ip_addr_isany((struct ip_addr *)&(cpcb->local_ip))||ip_addr_isany((struct ip_addr *)ipaddr) ||ip_addr_cmp((struct ip_addr *)&(cpcb->local_ip), (struct ip_addr *)ipaddr)) 
			      {
			          return ERR_USE;
			      }
		    }
	  }
	  for(cpcb = tcp_active_pcbs;cpcb != NULL; cpcb = cpcb->next) 
	  {
		    if (cpcb->local_port == port)
		    {
			      if (ip_addr_isany((struct ip_addr *)&(cpcb->local_ip))||ip_addr_isany((struct ip_addr *)ipaddr)||ip_addr_cmp((struct ip_addr *)&(cpcb->local_ip), (struct ip_addr *)ipaddr)) 
			      {
				        return ERR_USE;
			      }
		    }
	  }
	  
	  
#else /* SO_REUSE */
	  
	  
	  /* Search through list of PCB's in LISTEN state. 
	     
	  If there is a PCB bound to specified port and IP_ADDR_ANY another PCB can be bound to the interface IP
	  or to the loopback address on the same port if SOF_REUSEADDR is set. Any combination of PCB's bound to 
	  the same local port, but to one address out of {IP_ADDR_ANY, 127.0.0.1, interface IP} at a time is valid.
	  But no two PCB's bound to same local port and same local address is valid.
	  
	  If SOF_REUSEPORT is set several PCB's can be bound to same local port and same local address also. But then 
	  all PCB's must have the SOF_REUSEPORT option set.
	  
	  When the two options aren't set and specified port is already bound, ERR_USE is returned saying that 
	  address is already in use. */
	  for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; cpcb != NULL; cpcb = cpcb->next) 
	  {
		    if(cpcb->local_port == port) 
		    {
			      if(ip_addr_cmp(&(cpcb->local_ip), ipaddr)) 
			      {
				        if(pcb->so_options & SOF_REUSEPORT) 
				        {
					          LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in listening PCB's: SO_REUSEPORT set and same address.\n"));
					          reuse_port_all_set = (reuse_port_all_set && (cpcb->so_options & SOF_REUSEPORT));
				        }
				        else 
				        {
					          LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in listening PCB's: SO_REUSEPORT not set and same address.\n"));
					          return ERR_USE;
				        }
			      }
			      else if((ip_addr_isany(ipaddr) && !ip_addr_isany(&(cpcb->local_ip))) ||
			              (!ip_addr_isany(ipaddr) && ip_addr_isany(&(cpcb->local_ip)))) 
			      {
				        if(!(pcb->so_options & SOF_REUSEADDR) && !(pcb->so_options & SOF_REUSEPORT)) 
				        {
					          LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in listening PCB's SO_REUSEPORT or SO_REUSEADDR not set and not the same address.\n"));
					          return ERR_USE;
				        }      
				        else 
				        {
					          LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in listening PCB's SO_REUSEPORT or SO_REUSEADDR set and not the same address.\n"));
				        }     
			      }
		    }
	  }
	
	  /* Search through list of PCB's in a state in which they can accept or send data. Same decription as for 
	     PCB's in state LISTEN applies to this PCB's regarding the options SOF_REUSEADDR and SOF_REUSEPORT. */
	  for(cpcb = tcp_active_pcbs; cpcb != NULL; cpcb = cpcb->next) 
	  {
		    if(cpcb->local_port == port) 
		    {
			      if(ip_addr_cmp(&(cpcb->local_ip), ipaddr)) 
			      {
				        if(pcb->so_options & SOF_REUSEPORT) 
				        {
					          LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in active PCB's SO_REUSEPORT set and same address.\n"));
					          reuse_port_all_set = (reuse_port_all_set && (cpcb->so_options & SOF_REUSEPORT));
				        }
				        else 
				        {
					          LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in active PCB's SO_REUSEPORT not set and same address.\n"));
					          return ERR_USE;
				        }
			      }
			      else if((ip_addr_isany(ipaddr) && !ip_addr_isany(&(cpcb->local_ip))) ||
			              (!ip_addr_isany(ipaddr) && ip_addr_isany(&(cpcb->local_ip)))) 
			      {
				        if(!(pcb->so_options & SOF_REUSEADDR) && !(pcb->so_options & SOF_REUSEPORT)) 
				        {
					          LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in active PCB's SO_REUSEPORT or SO_REUSEADDR not set and not the same address.\n"));
					          return ERR_USE;
				        }   
				        else 
				        {
					          LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in active PCB's SO_REUSEPORT or SO_REUSEADDR set and not the same address.\n"));
				        }        
			      }
		    }
	  }
	
	  /* Search through list of PCB's in TIME_WAIT state. If SO_REUSEADDR is set a bound combination [IP, port} 
	     can be rebound. The same applies when SOF_REUSEPORT is set. 
	     
	     If SOF_REUSEPORT is set several PCB's can be bound to same local port and same local address also. But then 
	     all PCB's must have the SOF_REUSEPORT option set.
	     
	     When the two options aren't set and specified port is already bound, ERR_USE is returned saying that 
	     address is already in use. */
	  for(cpcb = tcp_tw_pcbs; cpcb != NULL; cpcb = cpcb->next) 
	  {
		    if(cpcb->local_port == port) 
		    {
			      if(ip_addr_cmp(&(cpcb->local_ip), ipaddr)) 
			      {
				        if(!(pcb->so_options & SOF_REUSEADDR) && !(pcb->so_options & SOF_REUSEPORT)) 
				        {
					          LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in TIME_WAIT PCB's SO_REUSEPORT or SO_REUSEADDR not set and same address.\n"));
					          return ERR_USE;
				        }
				        else if(pcb->so_options & SOF_REUSEPORT) 
				        {
					          LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in TIME_WAIT PCB's SO_REUSEPORT set and same address.\n"));
					          reuse_port_all_set = (reuse_port_all_set && (cpcb->so_options & SOF_REUSEPORT));
				        }
			      }
		    }
	  }
	
	  /* If SOF_REUSEPORT isn't set in all PCB's bound to specified port and local address specified then 
	     {IP, port} can't be reused. */
	  if(!reuse_port_all_set) 
	  {
		    LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: not all sockets have SO_REUSEPORT set.\n"));
		    return ERR_USE;
	  }
#endif /* SO_REUSE */
	
	  if (!ip_addr_isany((struct ip_addr *)ipaddr)) 
	  {
		    pcb->local_ip = *ipaddr;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -