📄 tcp_out.c
字号:
TCPH_SET_FLAG(seg->tcphdr, TCP_PSH); } return ERR_OK; memerr: TCP_STATS_INC(tcp.memerr); 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); } LWIP_DEBUGF(TCP_QLEN_DEBUG | DBG_STATE, ("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 = LWIP_MIN(pcb->snd_wnd, pcb->cwnd); seg = pcb->unsent; /* useg should point to last segment on unacked queue */ useg = pcb->unacked; if (useg != NULL) { for (; useg->next != NULL; useg = useg->next); } /* 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) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n")); return ERR_BUF; } LWIP_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_HDRLEN_SET(tcphdr, 5); 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), pcb->ttl, pcb->tos, IP_PROTO_TCP); pbuf_free(p); return ERR_OK; }#if TCP_OUTPUT_DEBUG if (seg == NULL) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", pcb->unsent)); }#endif /* TCP_OUTPUT_DEBUG */#if TCP_CWND_DEBUG if (seg == NULL) { LWIP_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 { LWIP_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 LWIP_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_SET_FLAG(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; useg = seg; } else { useg->next = seg; useg = useg->next; } } 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); LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %lu\n", pcb->rtseq)); } LWIP_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); TCP_STATS_INC(tcp.xmit); ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, 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) { LWIP_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_HDRLEN_SET(tcphdr, 5); tcphdr->chksum = 0; tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip, IP_PROTO_TCP, p->tot_len); TCP_STATS_INC(tcp.xmit); /* Send output with hardcoded TTL since we have no access to the pcb */ ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP); pbuf_free(p); LWIP_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);}voidtcp_keepalive(struct tcp_pcb *pcb){ struct pbuf *p; struct tcp_hdr *tcphdr; LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %u.%u.%u.%u\n", ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip), ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip))); LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %ld pcb->tmr %ld pcb->keep_cnt %ld\n", tcp_ticks, pcb->tmr, pcb->keep_cnt)); p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); if(p == NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: could not allocate memory for pbuf\n")); return; } tcphdr = p->payload; tcphdr->src = htons(pcb->local_port); tcphdr->dest = htons(pcb->remote_port); tcphdr->seqno = htonl(pcb->snd_nxt - 1); tcphdr->ackno = htonl(pcb->rcv_nxt); tcphdr->wnd = htons(pcb->rcv_wnd); tcphdr->urgp = 0; TCPH_HDRLEN_SET(tcphdr, 5); tcphdr->chksum = 0; tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, IP_PROTO_TCP, p->tot_len); TCP_STATS_INC(tcp.xmit); /* Send output to IP */ ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP); pbuf_free(p); LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_keepalive: seqno %lu ackno %lu.\n", pcb->snd_nxt - 1, pcb->rcv_nxt));}#endif /* LWIP_TCP */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -