lwip tcp_output_segment源码解析

来源:互联网 发布:精通qt4编程 第2版 编辑:程序博客网 时间:2024/06/05 16:05

原型:

static void
tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)

功能:被tcp_output()调用来 发送TCP报文给IP层

实现:


源码如下:

/** * Called by tcp_output() to actually send a TCP segment over IP.被tcp_output()调用,实际的发送TCP报文给IP层 * * @param seg the tcp_seg to send * @param pcb the tcp_pcb for the TCP connection used to send the segment */static voidtcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb){  u16_t len;  struct netif *netif;  u32_t *opts;  /** @bug Exclude retransmitted segments from this count. */  snmp_inc_tcpoutsegs();  /* The TCP header has already been constructed, but the ackno and   wnd fields remain.==TCP报头已经构建,但ackno和wnd字段需要保存 */  seg->tcphdr->ackno = htonl(pcb->rcv_nxt);  /* advertise our receive window size in this TCP segment==在这个报文段中将要向对方通告我们接受窗口允许大小 */  seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd);  /*更新rcv_ann_right_edge 上一次窗口通告时,窗口的右边缘值==rcv_nxt(下一个期望接收到的字节序号)+rcv_ann_wnd*/  pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;  /* Add any requested options.  NB MSS option is only set on SYN     packets, so ignore it here --MSS选项只当SYN包中设置,所以不再seg结构中体现*/  LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);  opts = (u32_t *)(void *)(seg->tcphdr + 1);/*+1 为sizeof(*(seg->tcphdr))*/  if (seg->flags & TF_SEG_OPTS_MSS) {    TCP_BUILD_MSS_OPTION(*opts);//MSS选项    opts += 1;//u32  }#if LWIP_TCP_TIMESTAMPS  pcb->ts_lastacksent = pcb->rcv_nxt;  if (seg->flags & TF_SEG_OPTS_TS) {    tcp_build_timestamp_option(pcb, opts);    opts += 3;  }#endif  /* Set retransmission timer running if it is not currently enabled      This must be set before checking the route.设置重传定时器使能,必须在检查route前设置 */  if (pcb->rtime == -1) {    pcb->rtime = 0;  }  /* If we don't have a local IP address, we get one by     calling ip_route().==没有本地IP,获取一个 */  if (ip_addr_isany(&(pcb->local_ip))) {    netif = ip_route(&(pcb->remote_ip));    if (netif == NULL) {      return;    }    ip_addr_copy(pcb->local_ip, netif->ip_addr);  }  if (pcb->rttest == 0) {/*如果要求进行往返时间的估算,初始化相关参数*/    pcb->rttest = tcp_ticks;//RRT估值时,以500ms周期递增    pcb->rtseq = ntohl(seg->tcphdr->seqno);//用于测试RRT报文段序号    LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq));  }  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n",          htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +          seg->len));  /*调整报文段pbuf的payload指针,使他指向报文首部*/  len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);  seg->p->len -= len;  seg->p->tot_len -= len;  seg->p->payload = seg->tcphdr;  seg->tcphdr->chksum = 0;#if CHECKSUM_GEN_TCP#if TCP_CHECKSUM_ON_COPY  {    u32_t acc;#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK    u16_t chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip),           &(pcb->remote_ip),           IP_PROTO_TCP, seg->p->tot_len);#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */    if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) {      LWIP_ASSERT("data included but not checksummed",        seg->p->tot_len == (TCPH_HDRLEN(seg->tcphdr) * 4));    }    /* rebuild TCP header checksum (TCP header changes for retransmissions!) */    acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip),             &(pcb->remote_ip),             IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4);    /* add payload checksum */    if (seg->chksum_swapped) {      seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum);      seg->chksum_swapped = 0;    }    acc += (u16_t)~(seg->chksum);    seg->tcphdr->chksum = FOLD_U32T(acc);#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK    if (chksum_slow != seg->tcphdr->chksum) {      LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING,                  ("tcp_output_segment: calculated checksum is %"X16_F" instead of %"X16_F"\n",                  seg->tcphdr->chksum, chksum_slow));      seg->tcphdr->chksum = chksum_slow;    }#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */  }#else /* TCP_CHECKSUM_ON_COPY *//*校验和相关*/  seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip),         &(pcb->remote_ip),         IP_PROTO_TCP, seg->p->tot_len);#endif /* TCP_CHECKSUM_ON_COPY */#endif /* CHECKSUM_GEN_TCP */  TCP_STATS_INC(tcp.xmit);#if LWIP_NETIF_HWADDRHINT  ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,      IP_PROTO_TCP, &(pcb->addr_hint));#else /* LWIP_NETIF_HWADDRHINT*/  ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,      IP_PROTO_TCP);//IP层发送接口#endif /* LWIP_NETIF_HWADDRHINT*/}


0 0
原创粉丝点击