LWIP完全剖析详解之core/tcp.c

更多网络底层原创来自:http://blog.csdn.net/lizhiliang06/article/details/8708679微笑


#include "lwip/opt.h" //选项头文件,lwip一些配置的选项包含在opt.h,debug开启和内存大小等配置信息

#if LWIP_TCP /* don't build if not configured for use in lwipopts.h *//*如果在lwipopts.h没有配置LWIP_TCP这项,则不编译TCP这个文件*/

#include "lwip/def.h" //定义项头文件,包括一些宏
#include "lwip/mem.h" //内存头文件,包括一些宏,内存大小,申请内存,内存对齐
#include "lwip/memp.h" //内存池头文件,包含内存申请,内存释放
#include "lwip/snmp.h" //SNMP(Simple Network Management Protocol,简单网络管理协议),包含snmp的函数声明
#include "lwip/tcp.h" //包含tcp.c里面定义的函数声明和所用到的宏
#include "lwip/debug.h" //包含lwip debug的一些宏,开启debug

#include <string.h>

/* Incremented every coarse grained timer shot (typically every 500 ms). */
/* 增加每一个粗粒度的定时器拍摄(通常每500 ms一次)*/
u32_t tcp_ticks; //定义tcp的滴答数	
const u8_t tcp_backoff[13] =
    { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};
 /* Times per slowtmr hits */
 /*  */
const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 };

/* The TCP PCB lists. */
/* TCP PCB 列表	*/
/** List of all TCP PCBs bound but not yet (connected || listening) */
/** 所有的但是还没有(连接或者监听中的TCP PCB绑定)列表*/
struct tcp_pcb *tcp_bound_pcbs;  
/** List of all TCP PCBs in LISTEN state */

/** 所有在监听中的状态 TCP PCB列表*/
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. */
/*所有在accept或者send数据状态的TCP PCB列表 */
struct tcp_pcb *tcp_active_pcbs;  

/** List of all TCP PCBs in TIME-WAIT state */
/*所有在等待状态中的TCP PCB*/
struct tcp_pcb *tcp_tw_pcbs;

/*所有临时TCP PCB列表*/
struct tcp_pcb *tcp_tmp_pcb;

/*定义tcp计时器*/
static u8_t tcp_timer;

/*生成新的tcp本地端口*/
static u16_t tcp_new_port(void);

/**
 * Called periodically to dispatch TCP timers.
 *
 */
/*
 *定期调用派遣TCP定时器
 */
void
tcp_tmr(void)
{
  /* Call tcp_fasttmr() every 250 ms */
  /*每250ms调用一次tcp_fasttmr()*/
  tcp_fasttmr();

  if (++tcp_timer & 1) {//tcp_timer加1后与1
    /* Call tcp_tmr() every 500 ms, i.e., every other timer
       tcp_tmr() is called. */
	/*
	   每500ms调用一次tcp_tmr(),tcp_tmr被其他的定时器调用
	*/
    tcp_slowtmr();
  }
}

/**
 * Closes the connection held by the PCB.
 *
 * Listening pcbs are freed and may not be referenced any more.
 * Connection pcbs are freed if not yet connected and may not be referenced
 * any more. If a connection is established (at least SYN received or in
 * a closing state), the connection is closed, and put in a closing state.
 * The pcb is then automatically freed in tcp_slowtmr(). It is therefore
 * unsafe to reference it.
 *
 * @param pcb the tcp_pcb to close
 * @return ERR_OK if connection has been closed
 *         another err_t if closing failed and pcb is not freed
 */
/*
 *通过PCB关闭连接握手
 *监听中的pcb应该被释放的,也许永远也不会被使用了
 *连接的pcb应该被释放的,如果还没有连接或者再也没有被引用
 *如果一个连接被建立(至少SYN已经被接收或者在一个关闭中的状态)
 *连接被关闭了,而且输入了一个正在关闭的状态
 *pcb然后自动在tcp_slowtmr()释放,所以引用它是不安全的
 */
err_t
tcp_close(struct tcp_pcb *pcb)
{
  err_t err;

  //TCP debug信息,打印pcb的状态
#if TCP_DEBUG
  LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in "));
  tcp_debug_print_state(pcb->state);
#endif /* TCP_DEBUG */

  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. */

    /*在CLOSED状态下关闭一个pcb似乎是错误的,
	 *尽管如此,一但在这个状态下分配了而且还没有使用所以用户需要一些办法来释放它
	 *调用一个已经被关闭的pcb的tcp_close(),(即2次)或者一个已经被使用了之后,进入CLOSE状态是错误的
	 *但作为一个在这些情况下被释放的pcb是不会存在的,因此,任何剩余的句柄都是假的
	 */
    err = ERR_OK;//设定返回值
    TCP_RMV(&tcp_bound_pcbs, pcb);//从绑定的pcb列表中去掉pcb
    memp_free(MEMP_TCP_PCB, pcb);//在MEMP_TCP_PCB内存池设定释放掉的pcb对应的单元值,释放内存
    pcb = NULL; //设置pcb指针指向空
    break;
  case LISTEN:
    err = ERR_OK;//设定返回值
    tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs.pcbs, pcb);//在tcp PCB监听列表中删除对应的pcb
    memp_free(MEMP_TCP_PCB_LISTEN, pcb);//在MEMP_TCP_PCB_LISTEN对应的内存池中设定需要释放的pcb单元值
    pcb = NULL;//设置pcb指针指向空
    break;
  case SYN_SENT:
    err = ERR_OK;//设定返回值
    tcp_pcb_remove(&tcp_active_pcbs, pcb);//在所有accept或者send数据状态的TCP PCB列表的TCP PCB列表中删除对应的pcb
    memp_free(MEMP_TCP_PCB, pcb);//在MEMP_TCP_PCB内存池设定释放掉的pcb对应的单元值,释放内存
    pcb = NULL;//设置pcb指针指向空
    snmp_inc_tcpattemptfails();//tcp尝试失败
    break;
  case SYN_RCVD:
    err = tcp_send_ctrl(pcb, TCP_FIN);//通过pcb发送对应的TCP_FIN包,表示已完成
    if (err == ERR_OK) { //如果发回ERR_OK表明发送成功
      snmp_inc_tcpattemptfails();//tcp 尝试失败
      pcb->state = FIN_WAIT_1; //pcb进入FIN_WAIT_1状态
    }
    break;
  case ESTABLISHED:
    err = tcp_send_ctrl(pcb, TCP_FIN);//通过pcb发送对应的TCP_FIN包,表示已完成
    if (err == ERR_OK) {//如果发回ERR_OK表明发送成功
      snmp_inc_tcpestabresets();//tcp 建立连接复位
      pcb->state = FIN_WAIT_1; //pcb进入FIN_WAIT_1状态
    }
    break;
  case CLOSE_WAIT:
    err = tcp_send_ctrl(pcb, TCP_FIN);//通过pcb发送对应的TCP_FIN包,表示已完成
    if (err == ERR_OK) {//如果发回ERR_OK表明发送成功
      snmp_inc_tcpestabresets();//tcp 建立连接复位
      pcb->state = LAST_ACK;//pcb进入LAST_ACK状态
    }
    break;
  default:
    /* Has already been closed, do nothing. */
	/* 已经被关闭,什么也不做*/
    err = ERR_OK;//设置返回值
    pcb = NULL;//把pcb指向NULL
    break;
  }

  if (pcb != NULL && err == ERR_OK) {
    /* To ensure all data has been sent when tcp_close returns, we have
       to make sure tcp_output doesn't fail.
       Since we don't really have to ensure all data has been sent when tcp_close
       returns (unsent data is sent from tcp timer functions, also), we don't care
       for the return value of tcp_output for now. */
    /* @todo: When implementing SO_LINGER, this must be changed somehow:
       If SOF_LINGER is set, the data should be sent when tcp_close returns. */
	/*
		为了确认在tcp_close 返回的时候所有的数据已经被发送,我们必须确定tcp_output不是失败的,
		从我们还没有确定在tcp_close之前不是所有的数据都被发送(没有发送的数据是从tcp计时器函数发过来的),
		我们现在不在乎tcp_output的返回值
		todo:当正在实现SO_LINGER时,这个不知道怎么的必须被改变:
		如果SO_LINGER被设置了,数据应该在tcp_close的时候被发送
	*/
    tcp_output(pcb);//发送pcb对应的包
  }
  return err;
}

/**
 * Abandons a connection and optionally sends a RST to the remote
 * host.  Deletes the local protocol control block. This is done when
 * a connection is killed because of shortage of memory.
 *
 * @param pcb the tcp_pcb to abort
 * @param reset boolean to indicate whether a reset should be sent
 */
/*
 放弃一个连接和选择发送一个RST到远端主机
 当一个连接因为短命的内存而挂掉,删除远端协议控制块(PCB)是要做的
 @参数pcb:tcp_pcb终止
 @参数reset:布尔类型表明是否要发送复位
 */
void
tcp_abandon(struct tcp_pcb *pcb, int reset)
{
  u32_t seqno, ackno;//定义序列号,应答号
  u16_t remote_port, local_port;//远程端口,本地端口
  struct ip_addr remote_ip, local_ip;//远程IP地址结构体,本地IP地址结构体
#if LWIP_CALLBACK_API  //LWIP是否要使用回调API
  void (* errf)(void *arg, err_t err);//定义回调函数指针
#endif /* LWIP_CALLBACK_API */
  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. */
  /*
	找出我们的pcb在TCP PCB列表那个位置后删除,如果我们在一个激活状态,
	调用pcb NULL参数的接收函数协助处理,
	并发送一个RST到远程终端
  */
  if (pcb->state == TIME_WAIT) { //如果pcb状态值是TIME_WAIT
    tcp_pcb_remove(&tcp_tw_pcbs, pcb);//从time-wait等待状态列表中删除pcb
    memp_free(MEMP_TCP_PCB, pcb);//删除pcb内存
  } else {//否则
    seqno = pcb->snd_nxt;//序列号指向发送下一个
    ackno = pcb->rcv_nxt;//应答好指向接收到的下一个
    ip_addr_set(&local_ip, &(pcb->local_ip));//设置pcb中的本地地址
    ip_addr_set(&remote_ip, &(pcb->remote_ip));//设置pcb中的远端地址
    local_port = pcb->local_port;
    remote_port = pcb->remote_port;
#if LWIP_CALLBACK_API
    errf = pcb->errf;//指针指向回调函数
#endif /* LWIP_CALLBACK_API */
    errf_arg = pcb->callback_arg;//回调参数
    tcp_pcb_remove(&tcp_active_pcbs, pcb);//把pcb重激活的tcp pcb列表中删除
    if (pcb->unacked != NULL) {//发送还没有回答?
      tcp_segs_free(pcb->unacked);//释放未应答段
    }
    if (pcb->unsent != NULL) {//还没有发送?
      tcp_segs_free(pcb->unsent);//释放还没有发送段
    }
#if TCP_QUEUE_OOSEQ    //TCP队列乱序
    if (pcb->ooseq != NULL) {//队列乱?
      tcp_segs_free(pcb->ooseq);//释放乱队列
    }
#endif /* TCP_QUEUE_OOSEQ */
    memp_free(MEMP_TCP_PCB, pcb);//释放pcb
    TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);//调用回调函数,传入终止错误参数
    if (reset) {//复位?
      LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n"));//打印发送RST信息
      tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);//tcp发送复位信息包
    }
  }
}

/**
 * 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.
 *
 * @param pcb the tcp_pcb to bind (no check is done whether this pcb is
 *        already bound!)
 * @param ipaddr the local ip address to bind to (use IP_ADDR_ANY to bind
 *        to any local address
 * @param port the local port to bind to
 * @return ERR_USE if the port is already in use
 *         ERR_OK if bound
 */
/*绑定一个连接的本地IP和端口.如果IP地址没有,传出去的接口IP会被替代
 *
 *参数pcb:绑定的tcp_pcb(不检查是否这个pcb已经绑定)
 *参数ipaddr:本地IP地址绑定(用IP_ADDR_ANY绑定任何本地IP
 *参数port: 本地端口绑定
 *返回ERR_USE如果端口已经被使用,返回ERR_OK如果绑定好
 */
err_t
tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
{
  struct tcp_pcb *cpcb; //定义cpcb

  LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);

  if (port == 0) { //端口为0则从本地找一个端口
    port = tcp_new_port();
  }
  /* Check if the address already is in use. */
  /* Check the listen pcbs. */
  //检查是不是地址已经在使用
  for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs;
      cpcb != NULL; cpcb = cpcb->next) {
    if (cpcb->local_port == port) {//端口是否在使用
      if (ip_addr_isany(&(cpcb->local_ip)) ||
          ip_addr_isany(ipaddr) ||
          ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
        return ERR_USE;//返回在使用
      }
    }
  }
  /* Check the connected pcbs. */
  /*检查已连接的PCB*/
  for(cpcb = tcp_active_pcbs;
      cpcb != NULL; cpcb = cpcb->next) {
    if (cpcb->local_port == port) {//端口是否在使用
      if (ip_addr_isany(&(cpcb->local_ip)) ||
          ip_addr_isany(ipaddr) ||
          ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
        return ERR_USE;//返回在使用
      }
    }
  }
  /* Check the bound, not yet connected pcbs. */
  /* 检查绑定,但没有连接的PCB*/
  for(cpcb = tcp_bound_pcbs; cpcb != NULL; cpcb = cpcb->next) {
    if (cpcb->local_port == port) {//端口是否在使用
      if (ip_addr_isany(&(cpcb->local_ip)) ||
          ip_addr_isany(ipaddr) ||
          ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
        return ERR_USE;//返回在使用
      }
    }
  }
  /* @todo: until SO_REUSEADDR is implemented (see task #6995 on savannah),
   * we have to check the pcbs in TIME-WAIT state, also: */
  /*todo:直到SO_REUSEADDR被完成(看任务#6995),
  我们也必须检查pcb是不是在 TIME-WAIT状态
   */
  for(cpcb = tcp_tw_pcbs; cpcb != NULL; cpcb = cpcb->next) {
    if (cpcb->local_port == port) {//端口是否在使用
      if (ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
        return ERR_USE;//返回在使用
      }
    }
  }

  if (!ip_addr_isany(ipaddr)) {//检查是否为所有本地IP地址
    pcb->local_ip = *ipaddr;
  }
  pcb->local_port = port;//设定本地端口
  TCP_REG(&tcp_bound_pcbs, pcb);//注册绑定的pcb
  LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port));
  return ERR_OK;//返回绑定成功
}
#if LWIP_CALLBACK_API
/**
 * Default accept callback if no accept callback is specified by the user.
 */
/*
  *如果没有用户指定的接受回调,默认接受回调
  */
static err_t
tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err)
{
  LWIP_UNUSED_ARG(arg);//没使用的参数
  LWIP_UNUSED_ARG(pcb);//没使用的参数
  LWIP_UNUSED_ARG(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.
 *
 * @param pcb the original tcp_pcb
 * @param backlog the incoming connections queue limit
 * @return tcp_pcb used for listening, consumes less memory.
 *
 * @note The original tcp_pcb is freed. This function therefore has to be
 *       called like this:
 *             tpcb = tcp_listen(tpcb);
 */
/*
 *	设置连接状态来监听,这意味着它可以接受进来的连接,
 *	协议控制块重新分配是为了减少内存开销,
 *	设置连接来监听是一个不可逆的过程。
 */
struct tcp_pcb *
tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
{
  struct tcp_pcb_listen *lpcb;//定义监听协议控制块

  LWIP_UNUSED_ARG(backlog);//不用参数
  LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, return NULL);
  //判断pcb状态是否关闭

  /* already listening? */
  //已经在监听中?
  if (pcb->state == LISTEN) {
    return pcb;//返回
  }
  lpcb = memp_malloc(MEMP_TCP_PCB_LISTEN);//分配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;//Socket选项
  lpcb->so_options |= SOF_ACCEPTCONN;//socket 已经监听
  lpcb->ttl = pcb->ttl;//存活时间
  lpcb->tos = pcb->tos;//服务类型
  ip_addr_set(&lpcb->local_ip, &pcb->local_ip);//设置本地IP
  TCP_RMV(&tcp_bound_pcbs, pcb);//把pcb从tcp绑定列表中删除
  memp_free(MEMP_TCP_PCB, pcb);//释放空间
#if LWIP_CALLBACK_API
  lpcb->accept = tcp_accept_null; //设置接受函数为空
#endif /* LWIP_CALLBACK_API */
#if TCP_LISTEN_BACKLOG
  lpcb->accepts_pending = 0;//接受挂起清空
  lpcb->backlog = (backlog ? backlog : 1);//累积>0?否则1
#endif /* TCP_LISTEN_BACKLOG */
  TCP_REG(&tcp_listen_pcbs.listen_pcbs, lpcb);//注册lpcb进监听列表
  return (struct tcp_pcb *)lpcb;//返回监听的块
}

/** 
 * Update the state that tracks the available window space to advertise.
 *
 * Returns how much extra window would be advertised if we sent an
 * update now.
 */
/*
 *更新状态这个追踪了允许可用的窗口空间来发布 
 *如果我们现在开始发送一个更新将返回多少额外的窗体将发布
 */
u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb)//TCP 更新接收发布窗口
{
  u32_t new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd;//下一个序列号+接收窗口

  if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + pcb->mss)) {//比较是否越界
    /* we can advertise more window */
    /* 我们可以发布更多窗口*/
    pcb->rcv_ann_wnd = pcb->rcv_wnd;//接收发布窗口设置为接收窗口
    return new_right_edge - pcb->rcv_ann_right_edge;//得到剩下的发布窗口
  } else {
    if (TCP_SEQ_GT(pcb->rcv_nxt, pcb->rcv_ann_right_edge)) {//如果期待的下一个序列号大于发布边界
      /* Can happen due to other end sending out of advertised window,
       * but within actual available (but not yet advertised) window */
	  /*
	    可以发生在另一端发送超出发布窗口,但是在实际允许(但还没有发布的)窗口
	   */
      pcb->rcv_ann_wnd = 0;//发布窗口置0
    } else {
      /* keep the right edge of window constant */
      /*保持正确的不变窗口边界*/
      pcb->rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt;
    }
    return 0;
  }
}

/**
 * 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.
 *
 * @param pcb the tcp_pcb for which data is read
 * @param len the amount of bytes that have been read by the application
 */
/*
 *这个函数应该被已经处理数据的应用程序调用。目的是当数据已经被处理后发布更大的窗口
 *参数pcb:数据已经被读的tcp_pcb
 *参数len:已经被应用程序读取的数据量
 */
void
tcp_recved(struct tcp_pcb *pcb, u16_t len)
{
  int wnd_inflation;//定义窗口膨胀变量

  LWIP_ASSERT("tcp_recved: len would wrap rcv_wnd\n",
              len <= 0xffff - pcb->rcv_wnd );

  pcb->rcv_wnd += len;//接收到的窗口加len
  if (pcb->rcv_wnd > TCP_WND)//大于TCP_WND?
    pcb->rcv_wnd = TCP_WND;//职位最大的窗口值

  wnd_inflation = tcp_update_rcv_ann_wnd(pcb);//更新发布窗口,返回剩下的值

  /* If the change in the right edge of window is significant (default
   * watermark is TCP_WND/2), then send an explicit update now.
   * Otherwise wait for a packet to be sent in the normal course of
   * events (or more window to be available later) */
  /*如果在正确的窗口边缘出现改变是有意义的(默认的水印是TCP_WND/2),然后现在发送一个明确的更新。
   * 另外等待在正常情况事件下(或者在之后更多的可用窗口)发送一个包
   *
   */
  if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD) //返回的值大于TCP窗口更新的临界值
    tcp_ack_now(pcb);//tcp应答

  LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n",
         len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd));
}

/**
 * A nastly hack featuring 'goto' statements that allocates a
 * new TCP local port.
 *
 * @return a new (free) local TCP port number
 */
/*
 *声明一个分配新TCP本地端口,返回一个新的可用的本地TCP端口
 */
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.
 *
 * @param pcb the tcp_pcb used to establish the connection
 * @param ipaddr the remote ip address to connect to
 * @param port the remote tcp port to connect to
 * @param connected callback function to call when connected (or on error)
 * @return ERR_VAL if invalid arguments are given
 *         ERR_OK if connect request has been sent
 *         other err_t values if connect request couldn't be sent
 */
/*
 *连接到其他的主机,当连接已经建立,connected作为参数将被调用
 *@参数 pcb:被用来作为建立连接的tcp_pcb
 *@参数 ipaddr:连接到的远程IP地址
 *@参数 port:连接到的远程tcp端口
 *@参数 connected:当连接了(或者出错误)的回调函数
 *如果传入的是非法的参数返回ERR_VAL
 *如果连接请求已经发送放回ERR_OK
 *如果连接请求没有发送返回其他的err_t值
 */
err_t
tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port,
      err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err))
{
  err_t ret;
  u32_t iss;

  LWIP_ERROR("tcp_connect: can only connected from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);

  LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port));
  if (ipaddr != NULL) {//如果传入的地址不为空
    pcb->remote_ip = *ipaddr;//远程ip赋值
  } else {
    return ERR_VAL;//返回错误值
  }
  pcb->remote_port = port;//设置远程端口
  if (pcb->local_port == 0) {//本地端口为0
    pcb->local_port = tcp_new_port();//申请新端口
  } 
  iss = tcp_next_iss();//计算一个新的初始化序列号给新的连接
  pcb->rcv_nxt = 0;//接收的下一个为0
  pcb->snd_nxt = iss;//发送的下一个为初始化序列号
  pcb->lastack = iss - 1;//ack减一
  pcb->snd_lbb = iss - 1;// 下一个字节序列号缓冲
  pcb->rcv_wnd = TCP_WND;//接收窗口数
  pcb->rcv_ann_wnd = TCP_WND;//接收发布窗口数
  pcb->rcv_ann_right_edge = pcb->rcv_nxt;//发布正确边缘
  pcb->snd_wnd = TCP_WND;//发送窗口数
  /* As initial send MSS, we use TCP_MSS but limit it to 536.
     The send MSS is updated when an MSS option is received. */
  /* 作为初始化发送最大段大小,我们使用TCP_MSS但是限制在536.
     当一个 最大段大小选项被接收,发送的最大段大小就被更新*/
  pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;
#if TCP_CALCULATE_EFF_SEND_MSS
  pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr);//计算有效发送的最大段大小 
#endif /* TCP_CALCULATE_EFF_SEND_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_RMV(&tcp_bound_pcbs, pcb);//从绑定列表中删除pcb
  TCP_REG(&tcp_active_pcbs, pcb);//注册激活的pcb到激活列表

  snmp_inc_tcpactiveopens();//开启tcp激活
  
  //pcb假如tcp队列
  ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, TF_SEG_OPTS_MSS
#if LWIP_TCP_TIMESTAMPS
                    | TF_SEG_OPTS_TS
#endif
                    );
  if (ret == ERR_OK) { //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.
 *
 * Automatically called from tcp_tmr().
 */
/**
 *  每500ms调用和实施传播计时器,计时器删除已经足够时间在TIME-WAIT的PCB,
 *  这个也增加各种计时器,例如在每个PCB中的休止状态的计时器
 */
void
tcp_slowtmr(void)
{
  struct tcp_pcb *pcb, *pcb2, *prev;
  u16_t eff_wnd;// 有效窗口
  u8_t pcb_remove;      /* flag if a PCB should be removed *//*一个PCB应该被移除的标记*/
  err_t err;

  err = ERR_OK;

  ++tcp_ticks;//tcp滴答数+1

  /* Steps through all of the active PCBs. */
  /*所有激活中的PCB*/
  prev = NULL;
  pcb = tcp_active_pcbs;
  if (pcb == NULL) {
    LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n"));
  }
  while (pcb != NULL) {//遍历激活的pcb列表
    LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n"));
    LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED);
    LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN);
    LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT);

    pcb_remove = 0;

    if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) {//如果状态为SYN_SENT而且pcb传播编号是TCP_SYNMAXRTX
      ++pcb_remove;//移除计数加1
      LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n"));
    }
    else if (pcb->nrtx == TCP_MAXRTX) {//pcb传播编号是TCP_SYNMAXRTX
      ++pcb_remove;//移除计数加1
      LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n"));
    } else {
      if (pcb->persist_backoff > 0) {
        /* If snd_wnd is zero, use persist timer to send 1 byte probes
         * instead of using the standard retransmission mechanism. */
        /* 如果发送窗口是0,持续使用计时器发送1字节使用标准传播编号机制探索替代  */
        pcb->persist_cnt++;//持续计时器计数
        if (pcb->persist_cnt >= tcp_persist_backoff[pcb->persist_backoff-1]) {//tcp持续备值
          pcb->persist_cnt = 0;
          if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) {//如果pcb持续备值小雨tcp_persist_backoff的大小
            pcb->persist_backoff++;//加1
          }
          tcp_zero_window_probe(pcb);//发送持续计时器零窗口探头
        }
      } else {
        /* Increase the retransmission timer if it is running */
		/* 如果重传计数器在跑,则增加*/
        if(pcb->rtime >= 0)
          ++pcb->rtime;

        if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {//
          /* Time for a retransmission. */
	      /* 转播时间 */
          LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F
                                      " pcb->rto %"S16_F"\n",
                                      pcb->rtime, pcb->rto));

          /* Double retransmission time-out unless we are trying to
           * connect to somebody (i.e., we are in SYN_SENT). */
		  /*双重转播超时出发我们尝试连接到别人那里(也就是,我们在SYN_SENT状态)
		   *
		   */
          if (pcb->state != SYN_SENT) {//pcb不在SYN_SENT
            pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx];//计算出重发时间
          }

          /* Reset the retransmission timer. */
		  /*重置重发计时器*/
          pcb->rtime = 0;

          /* Reduce congestion window and ssthresh. */
		  /* 减少拥挤窗口和阀门值*/
          eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd);//计算有效窗口
          pcb->ssthresh = eff_wnd >> 1;//有效值右移1位
          if (pcb->ssthresh < pcb->mss) {//阀门值小于最大段大小?
            pcb->ssthresh = pcb->mss * 2;
          }
          pcb->cwnd = pcb->mss;//最大段大小赋给拥挤窗口
          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F
                                       " ssthresh %"U16_F"\n",
                                       pcb->cwnd, pcb->ssthresh));
 
          /* The following needs to be called AFTER cwnd is set to one
             mss - STJ */
		  /*在调用AFTER拥挤窗口被设置为一个最大段大小- STJ时下面需要被调用
		  */
          tcp_rexmit_rto(pcb);//为重发重新入队所有的未应答段
        }
      }
    }
    /* Check if this PCB has stayed too long in FIN-WAIT-2 */
    /* 检测如果这个PCB已经在FIN-WAIT-2状态下等太久了 */
    if (pcb->state == FIN_WAIT_2) {//检测状态
      if ((u32_t)(tcp_ticks - pcb->tmr) >
          TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) {//tcp滴答数减去计时器的计数 是否大于等待的时间除以粗粒超时?
        ++pcb_remove;//删除多一个pcb
        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n"));
      }
    }

    /* Check if KEEPALIVE should be sent */
    /* 检测如果KEEPALIVE被发送了*/
    if((pcb->so_options & SOF_KEEPALIVE) && 
       ((pcb->state == ESTABLISHED) || 
        (pcb->state == CLOSE_WAIT))) {//在SOF_KEEPALIVE的情况下且是ESTABLISHED或CLOSE_WAIT状态
#if LWIP_TCP_KEEPALIVE
      if((u32_t)(tcp_ticks - pcb->tmr) > 
         (pcb->keep_idle + (pcb->keep_cnt*pcb->keep_intvl))
         / TCP_SLOW_INTERVAL)//如果是KEEPALIVE被打开,允许计数keep alive的间隔
#else      
      if((u32_t)(tcp_ticks - pcb->tmr) > 
         (pcb->keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL)//最大的闲置Keep alive
#endif /* LWIP_TCP_KEEPALIVE */
      {
        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n",
                                ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
                                ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));
        
        tcp_abort(pcb);//终止pcb
      }
#if LWIP_TCP_KEEPALIVE
      else if((u32_t)(tcp_ticks - pcb->tmr) > 
              (pcb->keep_idle + pcb->keep_cnt_sent * pcb->keep_intvl)
              / TCP_SLOW_INTERVAL)//如果是KEEPALIVE被打开,允许发送计数keep alive的间隔
#else
      else if((u32_t)(tcp_ticks - pcb->tmr) > 
              (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEPINTVL_DEFAULT) 
              / TCP_SLOW_INTERVAL)//最大的闲置发送计数*默认Keep alive间隔
#endif /* LWIP_TCP_KEEPALIVE */
      {
        tcp_keepalive(pcb);//keepalive pcb
        pcb->keep_cnt_sent++;//计数加1
      }
    }

    /* 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). */
    /* 如果这个PCB 有队列超出序列的数据,但是已经不活跃太长一段时间了,
		将终止数据(它最终将被重传)*/
#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 */
    /* 检测如果这个PCB已经在SYN-RCVD状态太长时间了 */
    if (pcb->state == SYN_RCVD) {
      if ((u32_t)(tcp_ticks - pcb->tmr) >
          TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) {//超时了?
        ++pcb_remove;//移除加1
        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n"));
      }
    }

    /* Check if this PCB has stayed too long in LAST-ACK */
    /* 检测如果这个PCB已经在LAST-ACK太长时间了 */
    if (pcb->state == LAST_ACK) {
      if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {//超时了?
        ++pcb_remove;//移除数加1
        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n"));
      }
    }

    /* If the PCB should be removed, do it. */
    /* 如果PCB应该被移除,执行 */
    if (pcb_remove) {
      tcp_pcb_purge(pcb);      //清理一个TCP PCB
      /* Remove PCB from tcp_active_pcbs list. */
      /* 把PCB从激活列表里移除. */
      if (prev != NULL) {//前一个为空?
        LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs);
        prev->next = pcb->next;//下一个指向pcb的next
      } else {
        /* This PCB was the first. */
        /* 这个PCB是第一个. */
        LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb);
        tcp_active_pcbs = pcb->next;//直接把tcp_active_pcbs队列执行pcb的下一个
      }

      TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT);//TCP错误发生事件

      pcb2 = pcb->next;//pcb2指向pcb的next
      memp_free(MEMP_TCP_PCB, pcb);//释放pcb
      pcb = pcb2;//pcb指向往下的一个
    } else {

      /* We check if we should poll the connection. */
      /* 我们检测是否我们应该调查连接. */
      ++pcb->polltmr;//调查计时器加1
      if (pcb->polltmr >= pcb->pollinterval) {//计数器大于调查间隔
        pcb->polltmr = 0;//调查计数器置0
        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n"));
        TCP_EVENT_POLL(pcb, err);//TCP调查事件
        if (err == ERR_OK) {//错误?
          tcp_output(pcb);//发送pcb数据
        }
      }
      
      prev = pcb;//前一个指向pcb
      pcb = pcb->next;//pcb指向pcb的下一个
    }
  }
  
  /* Steps through all of the TIME-WAIT PCBs. */
  /* 遍历所有的TIME-WAI 状态的PCB. */
  prev = NULL;    
  pcb = tcp_tw_pcbs;//pcb指向time wait pcb列表
  while (pcb != NULL) {
    LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
    pcb_remove = 0;//移除计数设置0

    /* Check if this PCB has stayed long enough in TIME-WAIT */
    /* 检测是否这个PCB已经在TIME-WAIT状态足够长时间 */
    if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {
      ++pcb_remove;//pcb移除技术加1
    }
    

    /* If the PCB should be removed, do it. */
    /* 如果PCB应该被移除,动手吧. */
    if (pcb_remove) {
      tcp_pcb_purge(pcb); //清理pcb
      /* Remove PCB from tcp_tw_pcbs list. */
      /* 吧PCB从tcp_tw_pcbs列表中移除. */
      if (prev != NULL) {
        LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs);
        prev->next = pcb->next;//摘除pcb
      } else {
        /* This PCB was the first. */
        /* 这是第一个PCB. */
        LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb);
        tcp_tw_pcbs = pcb->next;//摘除
      }
      pcb2 = pcb->next;//pcb2指向pcb的下一个
      memp_free(MEMP_TCP_PCB, pcb);//释放pcb
      pcb = pcb2;
    } else {//否则不应该移除
      prev = pcb;//前面的指针指向pcb
      pcb = pcb->next;//pcb指向下一个
    }
  }
}

/**
 * Is called every TCP_FAST_INTERVAL (250 ms) and process data previously
 * "refused" by upper layer (application) and sends delayed ACKs.
 *
 * Automatically called from tcp_tmr().
 */
/**
 *  叫每个tcp快速区间(250毫秒)和过程数据之前“拒绝”,上层(应用程序)和发送延迟ack。
 *  每个TCP_FAST_INTERVAL (250 ms)和处理的数据之前被拒绝被上层(应用程序)和发送延迟ACK调用
 *
 *  自动从tcp_tmr()调用
 */
void
tcp_fasttmr(void)
{
  struct tcp_pcb *pcb;

  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { //遍历tcp_active_pcbs列表
    /* If there is data which was previously "refused" by upper layer */
    /* 如果有数据提前被上层拒绝   */
    if (pcb->refused_data != NULL) {
      /* Notify again application with data previously received. */
      /* 再次通知应用数据提前接收. */
	  err_t err;
      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_fasttmr: notify kept packet\n"));
      TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);//
      if (err == ERR_OK) {
        pcb->refused_data = NULL;//拒绝数据置空
      }
    }

    /* send delayed ACKs */  
    /* 发送延迟ACK */  
    if (pcb->flags & TF_ACK_DELAY) {
      LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n"));
      tcp_ack_now(pcb);//输出应答PCB包
      pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);//设置标志位,取消延迟ACK和立即ACK
    }
  }
}

/**
 * Deallocates a list of TCP segments (tcp_seg structures).
 *
 * @param seg tcp_seg list of TCP segments to free
 * @return the number of pbufs that were deallocated
 */
/**
 * 释放一个TCP段(tcp_seg结构)列表的分配
 *
 * @参数seg tcp_seg: 要十分的TCP段列表
 * @返回 一个被释放掉的phufs的数量
 */
u8_t
tcp_segs_free(struct tcp_seg *seg)
{
  u8_t count = 0;//置0
  struct tcp_seg *next;//tcp段下一个
  while (seg != NULL) {//段为空?
    next = seg->next;//下一个
    count += tcp_seg_free(seg);//释放,
    seg = next;//段指向下一个
  }
  return count;//返回计数
}

/**
 * Frees a TCP segment (tcp_seg structure).
 *
 * @param seg single tcp_seg to free
 * @return the number of pbufs that were deallocated
 */
/**
 *  释放一个TCP段(tcp_seg 结构)
 *
 * @参数 seg:单个要释放的tcp_seg
 * @返回 pbuf被释放的数量
 */
u8_t
tcp_seg_free(struct tcp_seg *seg)
{
  u8_t count = 0;
  
  if (seg != NULL) {//段为空?
    if (seg->p != NULL) {//seg->p这段buffer包括了数据+TCP头,为空?
      count = pbuf_free(seg->p);//释放
#if TCP_DEBUG
      seg->p = NULL;//置空
#endif /* TCP_DEBUG */
    }
    memp_free(MEMP_TCP_SEG, seg);//释放seg段
  }
  return count;//返回释放数量
}

/**
 * Sets the priority of a connection.
 *
 * @param pcb the tcp_pcb to manipulate
 * @param prio new priority
 */
/**
 * 设置连接的优先级
 *
 * @参数pcb:操作的tcp_pcb
 * @参数prio:新的优先级
 */
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.
 * The pbuf and data are not copied, only the pointers
 *
 * @param seg the old tcp_seg
 * @return a copy of seg
 */ 
/**
 * 返回一个传入TCP段的复制
 * pbuf与数据不复制,只是个指针 
 *
 * @参数seg:旧的tcp_seg
 * @返回段的复制
 */ 
struct tcp_seg *
tcp_seg_copy(struct tcp_seg *seg)
{
  struct tcp_seg *cseg;

  cseg = memp_malloc(MEMP_TCP_SEG);//分配空间
  if (cseg == NULL) {//分配失败?
    return NULL;返回
  }
  SMEMCPY((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg)); //copy一个段
  pbuf_ref(cseg->p);//增加pbuf的引用计数
  return cseg;
}
#endif

#if LWIP_CALLBACK_API
/**
 * Default receive callback that is called if the user didn't register
 * a recv callback for the pcb.
 */
/**
 * 默认的接收回调函数,如果用户没有给pcb注册一个接收回调函数
 */
static err_t
tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
  arg = arg;
  if (p != NULL) {//传入的pbuf为空?
    pbuf_free(p);//释放
  } else if (err == ERR_OK) {
    return tcp_close(pcb);//关闭tcp
  }
  return ERR_OK;
}
#endif /* LWIP_CALLBACK_API */

/**
 * Kills the oldest active connection that has lower priority than prio.
 *
 * @param prio minimum priority
 */
/**
 * 杀掉旧的比传入优先级低的激活链接
 *
 * @参数 prio:最小的优先级
 */
static void
tcp_kill_prio(u8_t prio)
{
  struct tcp_pcb *pcb, *inactive;
  u32_t inactivity;
  u8_t mprio;

  mprio = TCP_PRIO_MAX;//TCP最大的优先级
  
  /* We kill the oldest active connection that has lower priority than prio. */
  /* 我们杀掉最旧的比传入优先级低的激活链接. */
  inactivity = 0;
  inactive = NULL;
  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {//遍历激活列表
    if (pcb->prio <= prio &&
       pcb->prio <= mprio &&
       (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {//对比优先级且看是否处在激活状态
      inactivity = tcp_ticks - pcb->tmr;//计算静止时间
      inactive = pcb;//非激活
      mprio = pcb->prio;//获取优先级
    }
  }
  if (inactive != NULL) {//为空?非空则说明找到了
    LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n",
           (void *)inactive, inactivity));
    tcp_abort(inactive);//终止它
  }      
}

/**
 * Kills the oldest connection that is in TIME_WAIT state.
 * Called from tcp_alloc() if no more connections are available.
 */
/**
 * 杀掉最久的在TIME_WAIT状态的连接.
 * 如果没有更多连接可用则调用tcp_alloc.
 */
static void
tcp_kill_timewait(void)
{
  struct tcp_pcb *pcb, *inactive;
  u32_t inactivity;

  inactivity = 0;
  inactive = NULL;
  /* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */
  /* 遍历TIME_WAIT状态的pcb列表,得到最旧的pcb. */
  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
    if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {//是否在静止状态?否
      inactivity = tcp_ticks - pcb->tmr;//得到静止计时
      inactive = pcb;//静止指针指向pcb
    }
  }
  if (inactive != NULL) {//找到了?
    LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n",
           (void *)inactive, inactivity));
    tcp_abort(inactive);//终止
  }      
}

/**
 * Allocate a new tcp_pcb structure.
 *
 * @param prio priority for the new pcb
 * @return a new tcp_pcb that initially is in state CLOSED
 */
/**
 * 分配一个新的tcp_pcb结构.
 *
 * @参数prio:新pcb的优先级
 * @返回一个新的初始化在CLOSED状态的tcp_pcb
 */
struct tcp_pcb *
tcp_alloc(u8_t prio)
{
  struct tcp_pcb *pcb;
  u32_t iss;
  
  pcb = memp_malloc(MEMP_TCP_PCB);//分配一个MEMP_TCP_PCB
  if (pcb == NULL) {//分配成功?
    /* Try killing oldest connection in TIME-WAIT. */
    /* 尝试杀掉一个在TIME-WAIT状态下最旧的连接. */
    LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n"));
	tcp_kill_timewait();
    /* Try to allocate a tcp_pcb again. */
    /* 尝试再次分配一个tcp_pcb. */
    pcb = memp_malloc(MEMP_TCP_PCB);
    if (pcb == NULL) {
      /* Try killing active connections with lower priority than the new one. */
      /* 尝试杀掉比新块低优先级的激活的连接. */
      tcp_kill_prio(prio);
      /* Try to allocate a tcp_pcb again. */
      /* 再次尝试分配pcb. */
      pcb = memp_malloc(MEMP_TCP_PCB);
    }
  }
  if (pcb != NULL) {
    memset(pcb, 0, sizeof(struct tcp_pcb));//初始化内存置0
    pcb->prio = TCP_PRIO_NORMAL;//设置为普通优先级
    pcb->snd_buf = TCP_SND_BUF;//设置TCP发送的空间为256
    pcb->snd_queuelen = 0;//发送队列长度置0
    pcb->rcv_wnd = TCP_WND;//TCP结构窗口
    pcb->rcv_ann_wnd = TCP_WND;//TCP发布窗口
    pcb->tos = 0;//服务类型
    pcb->ttl = TCP_TTL;//默认存活时间
    /* As initial send MSS, we use TCP_MSS but limit it to 536.
       The send MSS is updated when an MSS option is received. */
    /* 作为初始化发送的MSS,我们用TCP_MSS但是最大限制在536.
	   当一个MSS选项被接收,发送的MSS会被更新		
	*/
    pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;//设置pcb的mss
    pcb->rto = 3000 / TCP_SLOW_INTERVAL;//设置重传超时
    pcb->sa = 0;//
    pcb->sv = 3000 / TCP_SLOW_INTERVAL;//
    pcb->rtime = -1;//重传计时器
    pcb->cwnd = 1;//拥挤避免
    iss = tcp_next_iss();//计算新的连接的初始化队列数
    pcb->snd_wl2 = iss;//最后的窗口更新序列和应答号
    pcb->snd_nxt = iss;//下一个发送的心的序列号
    pcb->lastack = iss;//最后的应答号
    pcb->snd_lbb = iss;//下一个字节的进入buffer的序列数   
    pcb->tmr = tcp_ticks;//计时器

    pcb->polltmr = 0;//池计时器

#if LWIP_CALLBACK_API
    pcb->recv = tcp_recv_null;//接收函数默认
#endif /* LWIP_CALLBACK_API */  
    
    /* Init KEEPALIVE timer */
    /* 初始化KEEPALIVE计时器 */
    pcb->keep_idle  = TCP_KEEPIDLE_DEFAULT;
    
#if LWIP_TCP_KEEPALIVE
    pcb->keep_intvl = TCP_KEEPINTVL_DEFAULT;//初始化KEEPALIVE默认时间间隔
    pcb->keep_cnt   = TCP_KEEPCNT_DEFAULT;//初始化KEEPALIVE计数
#endif /* LWIP_TCP_KEEPALIVE */

    pcb->keep_cnt_sent = 0;//发送计数置0
  }
  return pcb;//返回新生成的pcb
}

/**
 * Creates a new TCP protocol control block but doesn't place it on
 * any of the TCP PCB lists.
 * The pcb is not put on any list until binding using tcp_bind().
 *
 * @internal: Maybe there should be a idle TCP PCB list where these
 * PCBs are put on. Port reservation using tcp_bind() is implemented but
 * allocated pcbs that are not bound can't be killed automatically if wanting
 * to allocate a pcb with higher prio (@see tcp_kill_prio())
 *
 * @return a new tcp_pcb that initially is in state CLOSED
 */
/**
 *  生成新的TCP PCB但没有房子到任何TCP PCB的列表
 *  pcb没有放入任何列表直到使用tcp_bind绑定后
 *  
 *
 * @内部: 可能应该是一个闲置的TCP PCB列表哪里有PCB在里面
 * 使用tcp_bind() 实现端口预定但是分配pcb没有绑定不能自动杀掉,
 *  如果想分配一个pcb用更高的优先级(请看tcp_kill_prio())
 *  
 *
 * @返回一个新的初始化在CLOSED状态的tcp_pcb
 */
struct tcp_pcb *
tcp_new(void)
{
  return tcp_alloc(TCP_PRIO_NORMAL);//分配一个新的pcb
}

/**
 * Used to specify the argument that should be passed callback
 * functions.
 *
 * @param pcb tcp_pcb to set the callback argument
 * @param arg void pointer argument to pass to callback functions
 */ 
/**
 *  使用指定参数,这个参数应该被传到回调函数去
 *  
 *
 * @参数pcb: tcp_pcb设置的回调函数参数
 * @参数arg:一个void指针参数传到回调函数
 */ 
void
tcp_arg(struct tcp_pcb *pcb, void *arg)
{  
  pcb->callback_arg = arg;//设置回调函数参数
}
#if LWIP_CALLBACK_API

/**
 * Used to specify the function that should be called when a TCP
 * connection receives data.
 *
 * @param pcb tcp_pcb to set the recv callback
 * @param recv callback function to call for this pcb when data is received
 */ 
/**
 * 使用指定的函数,当一个TCP连接收到数据是这个函数应该被调用
 *
 * @参数pcb: 设置接收回调函数的tcp_pcb
 * @参数recv:当数据被接收了回调函数将为相应的pcb调用
 */ 
void
tcp_recv(struct tcp_pcb *pcb,
   err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err))
{
  pcb->recv = recv;//设置相应的接收回调函数
}

/**
 * Used to specify the function that should be called when TCP data
 * has been successfully delivered to the remote host.
 *
 * @param pcb tcp_pcb to set the sent callback
 * @param sent callback function to call for this pcb when data is successfully sent
 */ 
/**
 *  使用指定的函数,当TCP数据已经成功传送到远程主机,这个函数应该被调用
 *  
 *
 * @参数pcb: 设置发送回调函数的tcp_pcb
 * @参数send: 当数据已经成功送达,send回调函数将被调用
 */ 
void
tcp_sent(struct tcp_pcb *pcb,
   err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len))
{
  pcb->sent = sent;//设置相应的发送回调函数
}

/**
 * Used to specify the function that should be called when a fatal error
 * has occured on the connection.
 *
 * @param pcb tcp_pcb to set the err callback
 * @param errf callback function to call for this pcb when a fatal error
 *        has occured on the connection
 */ 
/**
 *  使用指定的函数,当一个致命错误发生在连接的时候,这个函数应该被调用
 * 
 *
 * @参数pcb: 设置错误的回调函数的tcp_pcb
 * @参数errf: 但一个致命错误发生在连接的时候,errf回调函数将被调用 
 */
void
tcp_err(struct tcp_pcb *pcb,
   void (* errf)(void *arg, err_t err))
{
  pcb->errf = errf;//设置致命错误回调函数
}

/**
 * Used for specifying the function that should be called when a
 * LISTENing connection has been connected to another host.
 *
 * @param pcb tcp_pcb to set the accept callback
 * @param accept callback function to call for this pcb when LISTENing
 *        connection has been connected to another host
 */ 
/**
 * 使用指定的函数,当一个监听中的连接已经连接到另外的主机上,这个函数应该被调用
 *
 * @参数pcb: 设置接受的回调函数的tcp_pcb
 * @参数accept: 当监听中的连接已经连接到其他的主机上,这个回调函数将被调用
 */ 
void
tcp_accept(struct tcp_pcb *pcb,
     err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err))
{
  pcb->accept = accept;//设置接受回调函数
}
#endif /* LWIP_CALLBACK_API */


/**
 * Used to specify the function that should be called periodically
 * from TCP. The interval is specified in terms of the TCP coarse
 * timer interval, which is called twice a second.
 *
 */ 
/**
 * 使用指定的函数,这个函数会定期的被TCP调用,时间间隔是指定在TCP粗糙的计时器间隔
 * 这个函数每秒会被调用2次
 */ 
void
tcp_poll(struct tcp_pcb *pcb,
   err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval)
{
#if LWIP_CALLBACK_API
  pcb->poll = poll;//设置回调函数
#endif /* LWIP_CALLBACK_API */  
  pcb->pollinterval = interval;//设置时间间隔
}

/**
 * Purges a TCP PCB. Removes any buffered data and frees the buffer memory
 * (pcb->ooseq, pcb->unsent and pcb->unacked are freed).
 *
 * @param pcb tcp_pcb to purge. The pcb itself is not deallocated!
 */
/**
 * 清理一个TCP PCB,移除所有的buffer数据和释放buffer内存(pcb->ooseq, pcb->unsent和pcb->unacked被释放 )
 * @参数pcb:清理tcp_pcb.pcb自己不被释放!
 */
void
tcp_pcb_purge(struct tcp_pcb *pcb)
{
  if (pcb->state != CLOSED &&
     pcb->state != TIME_WAIT &&
     pcb->state != LISTEN) {//看状态都否CLOSED,TIME_WAIT,LISTEN?

    LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n"));

#if TCP_LISTEN_BACKLOG
    if (pcb->state == SYN_RCVD) {//状态是否为SYN_RCVD
      /* Need to find the corresponding listen_pcb and decrease its accepts_pending */
      /* 需要找出相应的listen_pcb和减少它的接受等待*/
      struct tcp_pcb_listen *lpcb;
      LWIP_ASSERT("tcp_pcb_purge: pcb->state == SYN_RCVD but tcp_listen_pcbs is NULL",
        tcp_listen_pcbs.listen_pcbs != NULL);
	  //遍历监听的pcb列表
      for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
        if ((lpcb->local_port == pcb->local_port) &&
            (ip_addr_isany(&lpcb->local_ip) ||
             ip_addr_cmp(&pcb->local_ip, &lpcb->local_ip))) {
            /* port and address of the listen pcb match the timed-out pcb */
            /*监听pcb匹配超时的pcb端口和地址 */
			LWIP_ASSERT("tcp_pcb_purge: listen pcb does not have accepts pending",
              lpcb->accepts_pending > 0);
            lpcb->accepts_pending--;//接受挂起数减1
            break;
          }
      }
    }
#endif /* TCP_LISTEN_BACKLOG */


    if (pcb->refused_data != NULL) {//拒绝数据为空?
      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n"));
      pbuf_free(pcb->refused_data);//释放拒绝数据
      pcb->refused_data = NULL;//把指针指向空
    }
    if (pcb->unsent != NULL) {//未发送全部数据
      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n"));
    }
    if (pcb->unacked != NULL) {//未应答?
      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n"));
    }
#if TCP_QUEUE_OOSEQ /* LW */
    if (pcb->ooseq != NULL) {//接收超出队列段序列
      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n"));
    }

    /* Stop the retransmission timer as it will expect data on unacked
       queue if it fires */
    /* 停在重发计时器作为它将期待数据在为应答队列如果???*/
    pcb->rtime = -1;

    tcp_segs_free(pcb->ooseq);//释放接收超出队列段
    pcb->ooseq = NULL;
#endif /* TCP_QUEUE_OOSEQ */
    tcp_segs_free(pcb->unsent);//释放未发送段
    tcp_segs_free(pcb->unacked);//释放为应答段
    pcb->unacked = pcb->unsent = NULL;//置空
  }
}

/**
 * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first.
 *
 * @param pcblist PCB list to purge.
 * @param pcb tcp_pcb to purge. The pcb itself is also deallocated!
 */
/**
 *  清理PCB和吧pcb冲列表中移除.所有延迟的应答被首先发送
 * @参数pcblist:要清楚的PCB列表.
 * @参数pcb:要清理的tcp_pcb. pcb自己也释放!
 */
void
tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)
{
  TCP_RMV(pcblist, pcb);//移除pcb
  tcp_pcb_purge(pcb);//清理pcb
  
  /* if there is an outstanding delayed ACKs, send it */
  /* 如果有一个味解决的延迟应答,则发送*/
  if (pcb->state != TIME_WAIT &&
     pcb->state != LISTEN &&
     pcb->flags & TF_ACK_DELAY) {
    pcb->flags |= TF_ACK_NOW;//标记为应答
    tcp_output(pcb);//发送
  }

  if (pcb->state != LISTEN) {//如果不是监听状态
    LWIP_ASSERT("unsent segments leaking", pcb->unsent == NULL);
    LWIP_ASSERT("unacked segments leaking", pcb->unacked == NULL);
#if TCP_QUEUE_OOSEQ
    LWIP_ASSERT("ooseq segments leaking", pcb->ooseq == NULL);
#endif /* TCP_QUEUE_OOSEQ */
  }

  pcb->state = CLOSED;//pcb状态设为CLOSED

  LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane());
}

/**
 * Calculates a new initial sequence number for new connections.
 *
 * @return u32_t pseudo random sequence number
 */
/**
 * 给新连接计算新的初始化队列好.
 *
 * @返回一个冒充的32位随机队列号
 */
u32_t
tcp_next_iss(void)
{
  static u32_t iss = 6510;
  
  iss += tcp_ticks;       /* XXX *//*初始化随机设定的大于6510的一个序列号*/
  return iss;
}

#if TCP_CALCULATE_EFF_SEND_MSS
/**
 * Calcluates the effective send mss that can be used for a specific IP address
 * by using ip_route to determin the netif used to send to the address and
 * calculating the minimum of TCP_MSS and that netif's mtu (if set).
 */
/**
 *  计算有效的发送最大段大小,这样可以用来作为一个指定的IP地址
   通过使用ip_route来确定netif用来发送给的地址
   而且计算最小的TCP_MSS和这个netif的mtu(如果设置了)
 *  
 *  
 */
u16_t
tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr)
{
  u16_t mss_s;
  struct netif *outif;

  outif = ip_route(addr);//从适当的网络接口中找到匹配的netif
  if ((outif != NULL) && (outif->mtu != 0)) {//outif找到?最大的传送单元为0?
    mss_s = outif->mtu - IP_HLEN - TCP_HLEN;//最大传送单元减去IP头和TCP头
    /* RFC 1122, chap 4.2.2.6:
     * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize
     * We correct for TCP options in tcp_enqueue(), and don't support
     * IP options
     */
    /* RFC 1122, 4.2.2.6章:
     * 有效的发送最大段大小 = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize
     * 我们TCP选项在tcp_enqueue()是正确的,且没有支持IP选项
     */
    sendmss = LWIP_MIN(sendmss, mss_s);//最小的发送段大小
  }
  return sendmss;//得到有效的段大小 
}
#endif /* TCP_CALCULATE_EFF_SEND_MSS */

#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG
/**
 * Print a tcp header for debugging purposes.
 *
 * @param tcphdr pointer to a struct tcp_hdr
 */
/**
 * 为调试目的打印tcp头.
 *
 * @参数tcphdr:结构体tcp_hdr的指针
 */
void
tcp_debug_print(struct tcp_hdr *tcphdr)
{
  LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n"));
  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
  LWIP_DEBUGF(TCP_DEBUG, ("|    %5"U16_F"      |    %5"U16_F"      | (src port, dest port)\n",
         ntohs(tcphdr->src), ntohs(tcphdr->dest)));
  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
  LWIP_DEBUGF(TCP_DEBUG, ("|           %010"U32_F"          | (seq no)\n",
          ntohl(tcphdr->seqno)));
  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
  LWIP_DEBUGF(TCP_DEBUG, ("|           %010"U32_F"          | (ack no)\n",
         ntohl(tcphdr->ackno)));
  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
  LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" |   |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"|     %5"U16_F"     | (hdrlen, flags (",
       TCPH_HDRLEN(tcphdr),
         TCPH_FLAGS(tcphdr) >> 5 & 1,
         TCPH_FLAGS(tcphdr) >> 4 & 1,
         TCPH_FLAGS(tcphdr) >> 3 & 1,
         TCPH_FLAGS(tcphdr) >> 2 & 1,
         TCPH_FLAGS(tcphdr) >> 1 & 1,
         TCPH_FLAGS(tcphdr) & 1,
         ntohs(tcphdr->wnd)));
  tcp_debug_print_flags(TCPH_FLAGS(tcphdr));
  LWIP_DEBUGF(TCP_DEBUG, ("), win)\n"));
  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
  LWIP_DEBUGF(TCP_DEBUG, ("|    0x%04"X16_F"     |     %5"U16_F"     | (chksum, urgp)\n",
         ntohs(tcphdr->chksum), ntohs(tcphdr->urgp)));
  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
}

/**
 * Print a tcp state for debugging purposes.
 *
 * @param s enum tcp_state to print
 */
/**
 *为调试目的打印tcp状态.
 *
 * @参数s: 打印枚举tcp_state 
 */
void
tcp_debug_print_state(enum tcp_state s)
{
  LWIP_DEBUGF(TCP_DEBUG, ("State: "));
  switch (s) {
  case CLOSED:
    LWIP_DEBUGF(TCP_DEBUG, ("CLOSED\n"));
    break;
 case LISTEN:
   LWIP_DEBUGF(TCP_DEBUG, ("LISTEN\n"));
   break;
  case SYN_SENT:
    LWIP_DEBUGF(TCP_DEBUG, ("SYN_SENT\n"));
    break;
  case SYN_RCVD:
    LWIP_DEBUGF(TCP_DEBUG, ("SYN_RCVD\n"));
    break;
  case ESTABLISHED:
    LWIP_DEBUGF(TCP_DEBUG, ("ESTABLISHED\n"));
    break;
  case FIN_WAIT_1:
    LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_1\n"));
    break;
  case FIN_WAIT_2:
    LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_2\n"));
    break;
  case CLOSE_WAIT:
    LWIP_DEBUGF(TCP_DEBUG, ("CLOSE_WAIT\n"));
    break;
  case CLOSING:
    LWIP_DEBUGF(TCP_DEBUG, ("CLOSING\n"));
    break;
  case LAST_ACK:
    LWIP_DEBUGF(TCP_DEBUG, ("LAST_ACK\n"));
    break;
  case TIME_WAIT:
    LWIP_DEBUGF(TCP_DEBUG, ("TIME_WAIT\n"));
   break;
  }
}

/**
 * Print tcp flags for debugging purposes.
 *
 * @param flags tcp flags, all active flags are printed
 */
/**
 * 为调试目的打印tcp标示.
 *
 * @参数flags:tcp标示,打印所以激活的标示
 */
void
tcp_debug_print_flags(u8_t flags)
{
  if (flags & TCP_FIN) {
    LWIP_DEBUGF(TCP_DEBUG, ("FIN "));
  }
  if (flags & TCP_SYN) {
    LWIP_DEBUGF(TCP_DEBUG, ("SYN "));
  }
  if (flags & TCP_RST) {
    LWIP_DEBUGF(TCP_DEBUG, ("RST "));
  }
  if (flags & TCP_PSH) {
    LWIP_DEBUGF(TCP_DEBUG, ("PSH "));
  }
  if (flags & TCP_ACK) {
    LWIP_DEBUGF(TCP_DEBUG, ("ACK "));
  }
  if (flags & TCP_URG) {
    LWIP_DEBUGF(TCP_DEBUG, ("URG "));
  }
  if (flags & TCP_ECE) {
    LWIP_DEBUGF(TCP_DEBUG, ("ECE "));
  }
  if (flags & TCP_CWR) {
    LWIP_DEBUGF(TCP_DEBUG, ("CWR "));
  }
  LWIP_DEBUGF(TCP_DEBUG, ("\n"));
}

/**
 * Print all tcp_pcbs in every list for debugging purposes.
 */
/**
 * 为调试打印所有的tcp_pcb在每个列表里面.
 */
void
tcp_debug_print_pcbs(void)
{
  struct tcp_pcb *pcb;
  LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:\n"));
  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
    LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",
                       pcb->local_port, pcb->remote_port,
                       pcb->snd_nxt, pcb->rcv_nxt));
    tcp_debug_print_state(pcb->state);
  }    
  LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n"));
  for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {
    LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",
                       pcb->local_port, pcb->remote_port,
                       pcb->snd_nxt, pcb->rcv_nxt));
    tcp_debug_print_state(pcb->state);
  }    
  LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n"));
  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
    LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",
                       pcb->local_port, pcb->remote_port,
                       pcb->snd_nxt, pcb->rcv_nxt));
    tcp_debug_print_state(pcb->state);
  }    
}

/**
 * Check state consistency of the tcp_pcb lists.
 */
/**
 * 检测tcp_pcb列表状态兼容性.
 */
s16_t
tcp_pcbs_sane(void)
{
  struct tcp_pcb *pcb;
  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
    LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED);
    LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN);
    LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
  }
  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
    LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
  }
  return 1;
}
#endif /* TCP_DEBUG */

#endif /* LWIP_TCP */


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值