LWIP tcp_output Source Code Analysis

Source: Internet
Author: User

Prototype:

err_t
Tcp_output (struct TCP_PCB *PCB)

Description

Find the data you can send--send

The function may send a message segment on the unsent queue of a connected PCB control block field, or send only one ACK message segment. Process:

If the function is called, the flags field of the PCB

The TF_ACK_NOW flag is set and no data is sent, building an empty ACK segment and then sending (reason: either because the->unsent queue is empty or the window is not allowed);

  /* If the TF_ACK_NOW flag is set and no data would be sent (either== such as the Tf_ack_now flag is placed and there is nothing to send
   * because the->unsent q Ueue is empty or because the window does== (either because the->unsent queue is empty or the windows are not allowed) * not let
   it), construct an empty ACK segmen T and send it. Build an empty ACK segment and then send * if data is to be
   sent, we'll just piggyback the ACK (see below). = = If you want to send the data, we'll piggyback ACK (see below)
   */
  if (Pcb->flags & Tf_ack_now &&
     (seg = = NULL | | Unsent queue is empty
      Ntohl (seg->tcphdr->seqno)-pcb->lastack + Seg->len > Wnd)) {/* Window not allowed */
     return TCP_ Send_empty_ack (PCB);
  }

If the data is to be sent, we will piggyback the ACK and send the first message segment of the unsent queue (see below).

Unsent queue is not empty and the window is allowed to send messages with ACK

  /* Data available and window allows it to be sent? = = data and windows are allowed to be sent? *
  /while (seg! = NULL &&
         ntohl (seg->tcphdr->seqno)-Pcb->lastack + Seg->len & Lt;= wnd) {

Period, there is a process: if the sent message segment length is not 0, or with SYN, FIN, then put in the unacknowledged queue unacked, so that time-out retransmission. If the current unacked queue is not empty, the current message needs to be organized in sequence in the queue, which is handled as follows:

/* Put segment on unacknowledged list if length > 0 if the sent message segment is not 0 or with SYN, FIN, it is placed in the unacknowledged queue unacked so that time-out retransmission */if (tcp_t  Cplen (SEG) > 0) {seg->next = null;//empty message segment next Field/* unacked list is empty? */if (pcb->unacked = = null) {//unacked is empty pcb->unacked = seg;//directly to, that is, tail useg = seg;//useg points to unacked tail */unacked lis T is not empty? ==unacked non-empty, the current message needs to be organized in sequence in the queue */} else {/* In the case of fast retransmit, the packet should not go to the tail== in the case of fast retransmission, the package should not be inserted into Unacked's team tail * of the unacked queue, but rather somewhere before it. We need to check for== instead of somewhere before, * this case. -stj Jul 27, 2004 = = This condition needs to be checked */if (Tcp_seq_lt (Ntohl (seg->tcphdr->seqno), Ntohl (useg->tcphdr->seqno))) {//Set up/* Add segment to before tail of unacked list, keeping the list sorted = = Find the right place to insert to keep sort */Struc
          T tcp_seg **cur_seg = & (pcb->unacked); while (*cur_seg && tcp_sEq_lt (Ntohl ((*cur_seg)->tcphdr->seqno), Ntohl (seg->tcphdr->seqno))) {cur_seg = & ((*cur_seg)
          ->next);//Find the insertion position, insert} Seg->next = (*cur_seg);
        (*cur_seg) = seg;
          } else {/* add segment to tail of unacked list = = directly into the end of the queue is */useg->next = SEG;
        Useg = useg->next;
    }}/* does not queue empty segments on the unacked list */} else {tcp_seg_free (SEG);//Message length 0, no retransmission required, delete }


If the sending window is filled and cannot be sent, a 0 window probe is initiated to ensure that the receiver's window notification is received accurately:

if (seg! = NULL && Pcb->persist_backoff = = 0 &&/* If the sending window is filled and cannot be sent, the 0 window probe is initiated to ensure that the receiver's window notification is received accurately */
      Ntohl (seg->tcphdr->seqno)-pcb->lastack + Seg->len > Pcb->snd_wnd) {/
    * prepare for persist timer== ready to stick Timer */
    pcb->persist_cnt = 0;
    Pcb->persist_backoff = 1;
  }

The complete source code is as follows:

/** * Find out what we can send and send it== find a message to send * * @param PCB Protocol control block for the TCP connection T o Send data * @return ERR_OK if data have been sent or nothing to send * another err_t On Error */err_t tcp_out
  Put (struct TCP_PCB *pcb) {struct tcp_seg *seg, *useg;
u32_t Wnd, SND_NXT;
#if tcp_cwnd_debug s16_t i = 0;
     #endif/* Tcp_cwnd_debug */* First, check if we are invoked by the TCP input processing== Firstly, checking if we are called to process code via TCP input Code. If So, we does not output anything. Instead, we rely on the== if this is the case, nothing will do. Input processing code to call us when input processing is do with.
  Instead, we rely on the input processing code to call us when the input processing is complete */if (TCP_INPUT_PCB = = PCB) {return ERR_OK;

  } WND = Lwip_min (Pcb->snd_wnd, Pcb->cwnd); SEG = pcb->unsent;//Message Segment Queue/* If the TF_ACK_NOW flag is set and no data would be sent (either== as Tf_ack_now flag and no
Data sent * Because the->unsent queue is empty or because the window does== (either because the->unsent queue is empty or the window does not allow)   * not allow it), construct an empty ACK segment and send it. Build an empty ACK segment and then send * If data is to be sent, we'll jus  T piggyback the ACK (see below). = = If you want to send the data, we will piggyback the ACK (below) */if (Pcb->flags & Tf_ack_now && (seg = = NULL | | Unsent queue is empty Ntohl (seg->tcphdr->seqno)-pcb->lastack + Seg->len > Wnd)) {/* Window not allowed */return TCP_
  Send_empty_ack (PCB);
  }/* Useg should point to last segment on unacked queue== "useg should refer to the final paragraph on the unacked queue (Team tail) */useg = pcb->unacked;
  if (useg! = null) {//traverse looking for tail for (; Useg->next! = null; useg = Useg->next);
                                   } #if tcp_output_debug if (seg = = NULL) {LWIP_DEBUGF (Tcp_output_debug, ("Tcp_output:nothing to send (%p) \ n",
  (void*) pcb->unsent)); } #endif/* tcp_output_debug */#if tcp_cwnd_debug if (seg = = NULL) {LWIP_DEBUGF (Tcp_cwnd_debug, ("Tcp_output:snd_
                 Wnd% "U16_f", CWnd% "U16_f", wnd% "U32_f                ", seg = = NULL, ack%" U32_f "\ n", Pcb->snd_wnd, Pcb->cwnd, WND, pcb-
  >lastack));
                 } else {LWIP_DEBUGF (Tcp_cwnd_debug, ("Tcp_output:snd_wnd%" u16_f ", CWND%" u16_f ", wnd%" U32_f
                 ", Effwnd%" u32_f ", seq%" u32_f ", ack%" U32_f "\ n", Pcb->snd_wnd, Pcb->cwnd, WND, Ntohl (seg->tcphdr->seqno)-Pcb->lastack + Seg->len, Ntohl (seg->tcphdr->seqn
  o), pcb->lastack)); } #endif/* tcp_cwnd_debug */* Data available and window allows it to is sent? = = data and windows are allowed to be sent? */while (seg! = NULL && Ntohl (seg->tcphdr->seqno)-Pcb->lastack + Seg->len &
    lt;= wnd) {Lwip_assert ("RST not expected here!", (Tcph_flags (SEG->TCPHDR) & tcp_rst) = = 0); /* Stop sending if the Nagle algorithm would prevent it== as the Nagle algorithm blocks, then stops sending * Don ' t stop://the condition *-if Tcp_w Rite had a memory error before (prevent delayed ACK timeout) or *-if FIN was already enqueued for the This PCB (SYN be always alone in a seg
     ment-* either seg->next! = NULL or pcb->unacked = = null;
     * RST is no sent using Tcp_write/tcp_output. */if ((Tcp_do_output_nagle (PCB) = = 0) && ((Pcb->flags & (Tf_naglememerr |
    Tf_fin)) (= 0)) {break; } #if tcp_cwnd_debug LWIP_DEBUGF (Tcp_cwnd_debug, ("Tcp_output:snd_wnd%" u16_f ", CWND%" u16_f ", wnd%" u32_f ", Effwnd%
                            "U32_f", seq% "u32_f", ack% "u32_f", I% "S16_f" \ 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;//pcb->unsent refers to the next node = = Remove the current if from the Send buffer queue (Pcb->sta Te! = syn_sent) {Tcph_set_flag (seg->TCPHDR, Tcp_ack);//The ACK flag in the fill header pcb->flags &= ~ (Tf_ack_delay |  Tf_ack_now);//clear Flag bit} tcp_output_segment (SEG, PCB);//Send delivery section = = "submitted to IP layer SND_NXT = Ntohl (seg->tcphdr->seqno) + Tcp_tcplen (SEG);/* Calculates snd_nxt== next data sequence to be sent */if (TCP_SEQ_LT (PCB->SND_NXT, SND_NXT)) {/* update next data sequence to be sent */PCB
    ->SND_NXT = SND_NXT; }/* Put segment on unacknowledged list if length > 0 if the packet sent out is not 0, or with SYN, FIN, it is placed in the unacknowledged queue unacked so that time-out retransmission */if (Tcp_tcplen (SEG) > 0) {//Nonzero seg->next = null;//Empty message segment next Field/* unacked list is empty? */if (pcb->unacked = = NULL) {//u Nacked is empty pcb->unacked = seg;//direct To, that is, tail useg = seg;//useg point to unacked team Tail/* unacked list is not empty ? ==unacked non-empty, the current message needs to be organized in sequence in the queue */} else {/* In the case of fast retransmit, the packet should not go to the tail== in the case of fast retransmission, the package should not be inserted into Unacked's team tail * of the unacked queue, but rather somewhere before it.
     We need to check for== but somewhere before,    * This case. -stj Jul 27, 2004 = = This condition needs to be checked */if (Tcp_seq_lt (Ntohl (seg->tcphdr->seqno), Ntohl (useg->tcphdr->seqno))) {//Set up/* Add segment to before tail of unacked list, keeping the list sorted = = Find the right place to insert to keep sort */Struc
          T tcp_seg **cur_seg = & (pcb->unacked); while (*cur_seg && tcp_seq_lt (Ntohl (*cur_seg)->tcphdr->seqno), Ntohl (seg->tcphdr->seqno))
          {cur_seg = & ((*cur_seg)->next);//Find insertion position, insert} Seg->next = (*cur_seg);
        (*cur_seg) = seg;
          } else {//message length bit 0/* Add segment to tail of unacked list = = directly into the end of the queue is */useg->next = SEG;
        Useg = useg->next;
    }}/* does not queue empty segments on the unacked list */} else {tcp_seg_free (SEG);//Message length 0, no retransmission required, delete } SEG = pcb->unsent;//Next} #if tcp_oversize if (pcb->unsent = = NULL) {/* Last unsent have been Remo VED, reset unsEnt_oversize */pcb->unsent_oversize = 0; } #endif/* tcp_oversize */if (seg! = NULL && Pcb->persist_backoff = = 0 &&/* If the sending window is filled and cannot be sent, start 0 windows
    Ntohl (seg->tcphdr->seqno)-pcb->lastack + Seg->len > Pcb->snd_wnd), to ensure accurate receipt of the receiver's window notification */
    /* Prepare for persist timer== ready to stick timer */pcb->persist_cnt = 0;
  Pcb->persist_backoff = 1;
  } pcb->flags &= ~tf_naglememerr;
return ERR_OK; }

Summarize:

By appeal: Tcp_output just checks to see if a message satisfies the condition being sent and then calls

The Tcp_output_segment function sends out the message segment, which needs to fill in the rest of the required fields in the message, and then calls the IP layer output function Ip_output send the paper.

Tcp_output_segment source code See the next chapter.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.