Quantcast
Channel: CSDN博客推荐文章
Viewing all articles
Browse latest Browse all 35570

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

$
0
0
更多网络底层原创来自: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指向下一个
    }
  }
}

(稍后待续)
作者:lizhiliang06 发表于2013-3-23 0:11:28 原文链接
阅读:137 评论:0 查看评论

Viewing all articles
Browse latest Browse all 35570

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>