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

📄 tcp.c

📁 DM642上的TCP/IP代码 LWIP 是TCP/ IP 在嵌入式系统中应用很多的代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	  }
	  pcb->local_port = port;
	  return ERR_OK;
}


#if LWIP_CALLBACK_API
static err_t tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err)
{
	  (void)arg;
	  (void)pcb;
	  (void)err;
	
	  return ERR_ABRT;
}
#endif /* LWIP_CALLBACK_API */

/**
 * Set the state of the connection to be LISTEN, which means that it
 * is able to accept incoming connections. The protocol control block
 * is reallocated in order to consume less memory. Setting the
 * connection to LISTEN is an irreversible process.
 *
 */
struct tcp_pcb *tcp_listen(struct tcp_pcb *pcb)
{
	  struct tcp_pcb_listen *lpcb;
	  /* already listening? */
	  if (pcb->state == LISTEN) 
	  {
		    return pcb;
	  }
	  lpcb = memp_malloc(MEMP_TCP_PCB_LISTEN);
	  if (lpcb == NULL) 
	  {
		    return NULL;
	  }
	  lpcb->callback_arg = pcb->callback_arg;
	  lpcb->local_port = pcb->local_port;
	  lpcb->state = LISTEN;
//	  lpcb->so_options = pcb->so_options;
//	  lpcb->so_options |= SOF_ACCEPTCONN;
//	  lpcb->ttl = pcb->ttl;
//	  lpcb->tos = pcb->tos;
	  lpcb->local_ip=pcb->local_ip;
	  memp_free(MEMP_TCP_PCB, pcb);
	  #if LWIP_CALLBACK_API
	  lpcb->accept = tcp_accept_null;
	  #endif /* LWIP_CALLBACK_API */
	  TCP_REG(&tcp_listen_pcbs.listen_pcbs, lpcb);
	  return (struct tcp_pcb *)lpcb;
}

/**
 * This function should be called by the application when it has
 * processed the data. The purpose is to advertise a larger window
 * when the data has been processed.
 *
 */
void tcp_recved(struct tcp_pcb *pcb, u16_t len)
{
	  if ((u32_t)pcb->rcv_wnd + len > TCP_WND) 
	  {
		    pcb->rcv_wnd = TCP_WND;
	  } 
	  else 
	  {
		    pcb->rcv_wnd += len;
	  }
	  if (!(pcb->flags & TF_ACK_DELAY) &&
	     !(pcb->flags & TF_ACK_NOW)) 
	  {
		    /*
		     * We send an ACK here (if one is not already pending, hence
		     * the above tests) as tcp_recved() implies that the application
		     * has processed some data, and so we can open the receiver's
		     * window to allow more to be transmitted.  This could result in
		     * two ACKs being sent for each received packet in some limited cases
		     * (where the application is only receiving data, and is slow to
		     * process it) but it is necessary to guarantee that the sender can
		     * continue to transmit.
		     */
		    tcp_ack(pcb);
	  }
}

/**
 * A nastly hack featuring 'goto' statements that allocates a
 * new TCP local port.
 */
static u16_t tcp_new_port(void)
{
	  struct tcp_pcb *pcb;
	  #ifndef TCP_LOCAL_PORT_RANGE_START
	  #define TCP_LOCAL_PORT_RANGE_START 4096
	  #define TCP_LOCAL_PORT_RANGE_END   0x7fff
	  #endif
	  
	  static u16_t port = TCP_LOCAL_PORT_RANGE_START;
	  
	  again:
	  if (++port > TCP_LOCAL_PORT_RANGE_END) 
	  {
		    port = TCP_LOCAL_PORT_RANGE_START;
	  }	  
	  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) 
	  {
		    if (pcb->local_port == port) 
		    {
			      goto again;
		    }
	  }
	  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) 
	  {
		    if (pcb->local_port == port) 
		    {
			      goto again;
		    }
	  }
	  for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) 
	  {
		    if (pcb->local_port == port) 
		    {
			      goto again;
		    }
	  }
	  return port;
}

/**
 * Connects to another host. The function given as the "connected"
 * argument will be called when the connection has been established.
 *
 */
err_t  tcp_connect(struct tcp_pcb *pcb, Uint32 *ipaddr, u16_t port,
                   err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err))
{
	  u32_t optdata;
	  err_t ret;
	  u32_t iss;
	
	  if (ipaddr != NULL) 
	  {
		    pcb->dest_ip = *ipaddr;
	  } 
	  else 
	  {
		    return ERR_VAL;
	  }
	  pcb->remote_port = port;
	  if (pcb->local_port == 0) 
	  {
		    pcb->local_port = tcp_new_port();
	  }
	  iss = tcp_next_iss();
	  pcb->rcv_nxt = 0;
	  pcb->snd_nxt = iss;
	  pcb->lastack = iss - 1;
	  pcb->snd_lbb = iss - 1;
	  pcb->rcv_wnd = TCP_WND;
	  pcb->snd_wnd = TCP_WND;
	  pcb->mss = TCP_MSS;
	  pcb->cwnd = 1;
	  pcb->ssthresh = pcb->mss * 10;
	  pcb->state = SYN_SENT;
	  #if LWIP_CALLBACK_API  
	  pcb->connected = connected;
	  #endif /* LWIP_CALLBACK_API */  
	  TCP_REG(&tcp_active_pcbs, pcb);
	  
	  /* Build an MSS option */
	  optdata = htonl(((u32_t)2 << 24) | 
	      ((u32_t)4 << 16) | 
	      (((u32_t)pcb->mss / 256) << 8) |
	      (pcb->mss & 255));
	
	  ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, (u8_t *)&optdata, 4);
	  if (ret == ERR_OK) { 
	    tcp_output(pcb);
	  }
	  return ret;
} 

/**
 * Called every 500 ms and implements the retransmission timer and the timer that
 * removes PCBs that have been in TIME-WAIT for enough time. It also increments
 * various timers such as the inactivity timer in each PCB.
 */
void
tcp_slowtmr(void)
{
     struct tcp_pcb *pcb, *pcb2, *prev;
     u32_t  eff_wnd;
     u8_t   pcb_remove;      /* flag if a PCB should be removed */
     err_t  err;

     err = ERR_OK;

     ++tcp_ticks;

     /* Steps through all of the active PCBs. */
     prev = NULL;
     pcb = tcp_active_pcbs;
     if (pcb == NULL) 
     {
     }
     while (pcb != NULL) 
     {

         pcb_remove = 0;

         if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) 
         {
              ++pcb_remove;
         }
         else if (pcb->nrtx == TCP_MAXRTX) 
         {
              ++pcb_remove;
//              LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n"));
         } 
         else 
         {
              ++pcb->rtime;
              if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) 
              {

//                   /* Time for a retransmission. */
//                   LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %u pcb->rto %u\n",\
//                               pcb->rtime, pcb->rto));

                   /* Double retransmission time-out unless we are trying to
                    * connect to somebody (i.e., we are in SYN_SENT). */
                   if (pcb->state != SYN_SENT) 
                   {
                         pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx];
                   }
                   tcp_rexmit(pcb);
                   /* Reduce congestion window and ssthresh. */
                   eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd);
                   pcb->ssthresh = eff_wnd >> 1;
                   if (pcb->ssthresh < pcb->mss) 
                   {
                         pcb->ssthresh = pcb->mss * 2;
                   }
                   pcb->cwnd = pcb->mss;
//                   LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %u ssthresh %u\n",
//                               pcb->cwnd, pcb->ssthresh));
              }
          }
          /* Check if this PCB has stayed too long in FIN-WAIT-2 */
          if (pcb->state == FIN_WAIT_2) 
          {
               if ((u32_t)(tcp_ticks - pcb->tmr) >TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) 
               {
                     ++pcb_remove;
//                     LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n"));
               }
          }

          /* Check if KEEPALIVE should be sent */
//          if((pcb->so_options & SOF_KEEPALIVE)&&((pcb->state == ESTABLISHED)||(pcb->state == CLOSE_WAIT))) 
          if(((pcb->state == ESTABLISHED)||(pcb->state == CLOSE_WAIT))) 
          {
                if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keepalive + TCP_MAXIDLE) / TCP_SLOW_INTERVAL)  
                {
//                     LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %u.%u.%u.%u.\n",
//                                 ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
//                                 ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));

                     tcp_abort(pcb);
                }
                else if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keepalive + pcb->keep_cnt * TCP_KEEPINTVL) / TCP_SLOW_INTERVAL) 
                {
                     tcp_keepalive(pcb);
                     pcb->keep_cnt++;
                }
          }

          /* If this PCB has queued out of sequence data, but has been
             inactive for too long, will drop the data (it will eventually
             be retransmitted). */
          #if TCP_QUEUE_OOSEQ    
          if (pcb->ooseq != NULL && (u32_t)tcp_ticks - pcb->tmr >=pcb->rto * TCP_OOSEQ_TIMEOUT)
          {
                tcp_segs_free(pcb->ooseq);
                pcb->ooseq = NULL;
//                LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n"));
          }
          #endif /* TCP_QUEUE_OOSEQ */

          /* Check if this PCB has stayed too long in SYN-RCVD */
          if (pcb->state == SYN_RCVD) 
          {
               if ((u32_t)(tcp_ticks - pcb->tmr)>TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) 
               {
                    ++pcb_remove;
//                    LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n"));
               }
          }


          /* If the PCB should be removed, do it. */
          if (pcb_remove) 
          {
               tcp_pcb_purge(pcb);      
               /* Remove PCB from tcp_active_pcbs list. */
               if (prev != NULL) 
               {
//                    LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs);
                    prev->next = pcb->next;
               } 
               else 
               {
                    /* This PCB was the first. */
//                    LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb);
                    tcp_active_pcbs = pcb->next;
               }

//               TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT);

               pcb2 = pcb->next;
               memp_free(MEMP_TCP_PCB, pcb);
               pcb = pcb2;
          } 
          else 
          {
               /* We check if we should poll the connection. */
               ++pcb->polltmr;
               if (pcb->polltmr >= pcb->pollinterval) 
               {
                    pcb->polltmr = 0;
//                    LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n"));
                    TCP_EVENT_POLL(pcb, err);
                    if (err == ERR_OK) 
                    {
                          tcp_output(pcb);
                    }
               }
      
               prev = pcb;
               pcb = pcb->next;
          }
     }

  
     /* Steps through all of the TIME-WAIT PCBs. */
     prev = NULL;    
     pcb = tcp_tw_pcbs;
     while (pcb != NULL) 
     {
//           LWIP_ASSERT("tcp_slowtmr: 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 - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) 
           {
               ++pcb_remove;
           }
    
           /* If the PCB should be removed, do it. */
           if (pcb_remove) 
           {
               tcp_pcb_purge(pcb);      
               /* Remove PCB from tcp_tw_pcbs list. */
               if (prev != NULL) 
               {
//                    LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs);
                    prev->next = pcb->next;
               } 
               else 
               {
                    /* This PCB was the first. */
//                    LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb);
                    tcp_tw_pcbs = pcb->next;
               }
               pcb2 = pcb->next;
               memp_free(MEMP_TCP_PCB, pcb);
               pcb = pcb2;
          } 
          else 
          {
               prev = pcb;
               pcb = pcb->next;
          }
      }
}

/**
 * Is called every TCP_FAST_INTERVAL (250 ms) and sends delayed ACKs.
 */
void tcp_fasttmr(void)
{
     struct tcp_pcb *pcb;

     /* send delayed ACKs */  
     for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) 
     {   
          if (pcb->flags & TF_ACK_DELAY) 
          {
                tcp_ack_now(pcb);
                pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
          }
     }
}

/**
 * Deallocates a list of TCP segments (tcp_seg structures).
 *
 */
u8_t tcp_segs_free(struct tcp_seg *seg)
{
	  u8_t count = 0;
	  struct tcp_seg *next;
	  while (seg != NULL) 
	  {
	    next = seg->next;
	    count += tcp_seg_free(seg);
	    seg = next;
	  }
	  return count;
}

/**
 * Frees a TCP segment.
 *
 */
u8_t tcp_seg_free(struct tcp_seg *seg)
{
	  u8_t count = 0;
	  
	  if (seg != NULL) 
	  {
		    if (seg->p != NULL) 
		    {
			      count = pbuf_free(seg->p);
			      #if TCP_DEBUG
			      seg->p = NULL;
			      #endif /* TCP_DEBUG */
		    }
		    memp_free(MEMP_TCP_SEG, seg);
	  }
	  return count;
}

/**
 * Sets the priority of a connection.
 *
 */
void tcp_setprio(struct tcp_pcb *pcb, u8_t prio)
{
	  pcb->prio = prio;
}

#if TCP_QUEUE_OOSEQ
/**
 * Returns a copy of the given TCP segment.
 *
 */ 
struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg)
{
  struct tcp_seg *cseg;

⌨️ 快捷键说明

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