📄 tcp_out.c
字号:
else { if(useg == NULL) { pcb->unsent = queue; } else { useg->next = queue; } } if((flags & TCP_SYN) || (flags & TCP_FIN)) { ++len; } pcb->snd_lbb += len; pcb->snd_buf -= len; pcb->snd_queuelen = queuelen; DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d (after enqueued)\n", pcb->snd_queuelen)); if(pcb->snd_queuelen != 0) { LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL || pcb->unsent != NULL); } /* Set the PSH flag in the last segment that we enqueued, but only if the segment has data (indicated by seglen > 0). */ if(seg != NULL && seglen > 0 && seg->tcphdr != NULL) { TCPH_FLAGS_SET(seg->tcphdr, TCPH_FLAGS(seg->tcphdr) | TCP_PSH); } return ERR_OK; memerr:#ifdef TCP_STATS ++lwip_stats.tcp.memerr;#endif /* TCP_STATS */ if(queue != NULL) { tcp_segs_free(queue); } if(pcb->snd_queuelen != 0) { LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL || pcb->unsent != NULL); } DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d (with mem err)\n", pcb->snd_queuelen)); return ERR_MEM;}/*-----------------------------------------------------------------------------------*//* find out what we can send and send it */err_ttcp_output(struct tcp_pcb *pcb){ struct pbuf *p; struct tcp_hdr *tcphdr; struct tcp_seg *seg, *useg; u32_t wnd;#if TCP_CWND_DEBUG int i = 0;#endif /* TCP_CWND_DEBUG */ /* First, check if we are invoked by the TCP input processing code. If so, we do not output anything. Instead, we rely on the input processing code to call us when input processing is done with. */ if(tcp_input_pcb == pcb) { return ERR_OK; } wnd = MIN(pcb->snd_wnd, pcb->cwnd); seg = pcb->unsent; /* If the TF_ACK_NOW flag is set, we check if there is data that is to be sent. If data is to be sent out, we'll just piggyback our acknowledgement with the outgoing segment. If no data will be sent (either because the ->unsent queue is empty or because the window doesn't allow it) we'll have to construct an empty ACK segment and send it. */ if(pcb->flags & TF_ACK_NOW && (seg == NULL || ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) { pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); if(p == NULL) { DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n")); return ERR_BUF; } DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: sending ACK for %lu\n", pcb->rcv_nxt)); tcphdr = p->payload; tcphdr->src = htons(pcb->local_port); tcphdr->dest = htons(pcb->remote_port); tcphdr->seqno = htonl(pcb->snd_nxt); tcphdr->ackno = htonl(pcb->rcv_nxt); TCPH_FLAGS_SET(tcphdr, TCP_ACK); tcphdr->wnd = htons(pcb->rcv_wnd); tcphdr->urgp = 0; TCPH_OFFSET_SET(tcphdr, 5 << 4); tcphdr->chksum = 0; tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip), IP_PROTO_TCP, p->tot_len); ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), TCP_TTL, IP_PROTO_TCP); pbuf_free(p); return ERR_OK; } #if TCP_OUTPUT_DEBUG if(seg == NULL) { DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", pcb->unsent)); }#endif /* TCP_OUTPUT_DEBUG */#if TCP_CWND_DEBUG if(seg == NULL) { DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %lu, cwnd %lu, wnd %lu, seg == NULL, ack %lu\n", pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack)); } else { DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %lu, cwnd %lu, wnd %lu, effwnd %lu, seq %lu, ack %lu\n", pcb->snd_wnd, pcb->cwnd, wnd, ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len, ntohl(seg->tcphdr->seqno), pcb->lastack)); }#endif /* TCP_CWND_DEBUG */ while(seg != NULL && ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {#if TCP_CWND_DEBUG DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %lu, cwnd %lu, wnd %lu, effwnd %lu, seq %lu, ack %lu, i%d\n", pcb->snd_wnd, pcb->cwnd, wnd, ntohl(seg->tcphdr->seqno) + seg->len - pcb->lastack, ntohl(seg->tcphdr->seqno), pcb->lastack, i)); ++i;#endif /* TCP_CWND_DEBUG */ pcb->unsent = seg->next; if(pcb->state != SYN_SENT) { TCPH_FLAGS_SET(seg->tcphdr, TCPH_FLAGS(seg->tcphdr) | TCP_ACK); pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); } tcp_output_segment(seg, pcb); pcb->snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg); if(TCP_SEQ_LT(pcb->snd_max, pcb->snd_nxt)) { pcb->snd_max = pcb->snd_nxt; } /* put segment on unacknowledged list if length > 0 */ if(TCP_TCPLEN(seg) > 0) { seg->next = NULL; if(pcb->unacked == NULL) { pcb->unacked = seg; } else { for(useg = pcb->unacked; useg->next != NULL; useg = useg->next); useg->next = seg; } } else { tcp_seg_free(seg); } seg = pcb->unsent; } return ERR_OK;}/*-----------------------------------------------------------------------------------*/static voidtcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb){ u16_t len; struct netif *netif; /* The TCP header has already been constructed, but the ackno and wnd fields remain. */ seg->tcphdr->ackno = htonl(pcb->rcv_nxt); /* silly window avoidance */ if(pcb->rcv_wnd < pcb->mss) { seg->tcphdr->wnd = 0; } else { /* advertise our receive window size in this TCP segment */ seg->tcphdr->wnd = htons(pcb->rcv_wnd); } /* If we don't have a local IP address, we get one by calling ip_route(). */ if(ip_addr_isany(&(pcb->local_ip))) { netif = ip_route(&(pcb->remote_ip)); if(netif == NULL) { return; } ip_addr_set(&(pcb->local_ip), &(netif->ip_addr)); } pcb->rtime = 0; if(pcb->rttest == 0) { pcb->rttest = tcp_ticks; pcb->rtseq = ntohl(seg->tcphdr->seqno); DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %lu\n", pcb->rtseq)); } DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %lu:%lu\n", htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) + seg->len)); 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; seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip), &(pcb->remote_ip), IP_PROTO_TCP, seg->p->tot_len);#ifdef TCP_STATS ++lwip_stats.tcp.xmit;#endif /* TCP_STATS */ ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), TCP_TTL, IP_PROTO_TCP);}/*-----------------------------------------------------------------------------------*/voidtcp_rst(u32_t seqno, u32_t ackno, struct ip_addr *local_ip, struct ip_addr *remote_ip, u16_t local_port, u16_t remote_port){ struct pbuf *p; struct tcp_hdr *tcphdr; p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); if(p == NULL) { DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n")); return; } tcphdr = p->payload; tcphdr->src = htons(local_port); tcphdr->dest = htons(remote_port); tcphdr->seqno = htonl(seqno); tcphdr->ackno = htonl(ackno); TCPH_FLAGS_SET(tcphdr, TCP_RST | TCP_ACK); tcphdr->wnd = htons(TCP_WND); tcphdr->urgp = 0; TCPH_OFFSET_SET(tcphdr, 5 << 4); tcphdr->chksum = 0; tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip, IP_PROTO_TCP, p->tot_len);#ifdef TCP_STATS ++lwip_stats.tcp.xmit;#endif /* TCP_STATS */ ip_output(p, local_ip, remote_ip, TCP_TTL, IP_PROTO_TCP); pbuf_free(p); DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %lu ackno %lu.\n", seqno, ackno));}/*-----------------------------------------------------------------------------------*/voidtcp_rexmit(struct tcp_pcb *pcb){ struct tcp_seg *seg; if(pcb->unacked == NULL) { return; } /* Move all unacked segments to the unsent queue. */ for(seg = pcb->unacked; seg->next != NULL; seg = seg->next); seg->next = pcb->unsent; pcb->unsent = pcb->unacked; pcb->unacked = NULL; pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno); ++pcb->nrtx; /* Don't take any rtt measurements after retransmitting. */ pcb->rttest = 0; /* Do the actual retransmission. */ tcp_output(pcb);}#endif /* LWIP_TCP */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -