lwip tcp_output_segment源码解析

2019-07-14 10:55发布

原型: 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 void tcp_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" ", pcb->rtseq)); } LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F" ", 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" ", 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*/ }