⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcp_out.c

📁 lwip-1.4.0
💻 C
📖 第 1 页 / 共 4 页
字号:
    optflags = TF_SEG_OPTS_MSS;  }#if LWIP_TCP_TIMESTAMPS  if ((pcb->flags & TF_TIMESTAMP)) {    optflags |= TF_SEG_OPTS_TS;  }#endif /* LWIP_TCP_TIMESTAMPS */  optlen = LWIP_TCP_OPT_LENGTH(optflags);  /* tcp_enqueue_flags is always called with either SYN or FIN in flags.   * We need one available snd_buf byte to do that.   * This means we can't send FIN while snd_buf==0. A better fix would be to   * not include SYN and FIN sequence numbers in the snd_buf count. */  if (pcb->snd_buf == 0) {    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: no send buffer available\n"));    TCP_STATS_INC(tcp.memerr);    return ERR_MEM;  }  /* Allocate pbuf with room for TCP header + options */  if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {    pcb->flags |= TF_NAGLEMEMERR;    TCP_STATS_INC(tcp.memerr);    return ERR_MEM;  }  LWIP_ASSERT("tcp_enqueue_flags: check that first pbuf can hold optlen",              (p->len >= optlen));  /* Allocate memory for tcp_seg, and fill in fields. */  if ((seg = tcp_create_segment(pcb, p, flags, pcb->snd_lbb, optflags)) == NULL) {    pcb->flags |= TF_NAGLEMEMERR;    TCP_STATS_INC(tcp.memerr);    return ERR_MEM;  }  LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);  LWIP_ASSERT("tcp_enqueue_flags: invalid segment length", seg->len == 0);  LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE,              ("tcp_enqueue_flags: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n",               ntohl(seg->tcphdr->seqno),               ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),               (u16_t)flags));  /* Now append seg to pcb->unsent queue */  if (pcb->unsent == NULL) {    pcb->unsent = seg;  } else {    struct tcp_seg *useg;    for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);    useg->next = seg;  }#if TCP_OVERSIZE  /* The new unsent tail has no space */  pcb->unsent_oversize = 0;#endif /* TCP_OVERSIZE */  /* SYN and FIN bump the sequence number */  if ((flags & TCP_SYN) || (flags & TCP_FIN)) {    pcb->snd_lbb++;    /* optlen does not influence snd_buf */    pcb->snd_buf--;  }  if (flags & TCP_FIN) {    pcb->flags |= TF_FIN;  }  /* update number of segments on the queues */  pcb->snd_queuelen += pbuf_clen(seg->p);  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: %"S16_F" (after enqueued)\n", pcb->snd_queuelen));  if (pcb->snd_queuelen != 0) {    LWIP_ASSERT("tcp_enqueue_flags: invalid queue length",      pcb->unacked != NULL || pcb->unsent != NULL);  }  return ERR_OK;} #if LWIP_TCP_TIMESTAMPS/* Build a timestamp option (12 bytes long) at the specified options pointer) * * @param pcb tcp_pcb * @param opts option pointer where to store the timestamp option */static voidtcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts){  /* Pad with two NOP options to make everything nicely aligned */  opts[0] = PP_HTONL(0x0101080A);  opts[1] = htonl(sys_now());  opts[2] = htonl(pcb->ts_recent);}#endif/** Send an ACK without data. * * @param pcb Protocol control block for the TCP connection to send the ACK */err_ttcp_send_empty_ack(struct tcp_pcb *pcb){  struct pbuf *p;  struct tcp_hdr *tcphdr;  u8_t optlen = 0;#if LWIP_TCP_TIMESTAMPS  if (pcb->flags & TF_TIMESTAMP) {    optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);  }#endif  p = tcp_output_alloc_header(pcb, optlen, 0, htonl(pcb->snd_nxt));  if (p == NULL) {    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));    return ERR_BUF;  }  tcphdr = (struct tcp_hdr *)p->payload;  LWIP_DEBUGF(TCP_OUTPUT_DEBUG,               ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt));  /* remove ACK flags from the PCB, as we send an empty ACK now */  pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);  /* NB. MSS option is only sent on SYNs, so ignore it here */#if LWIP_TCP_TIMESTAMPS  pcb->ts_lastacksent = pcb->rcv_nxt;  if (pcb->flags & TF_TIMESTAMP) {    tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1));  }#endif #if CHECKSUM_GEN_TCP  tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),        IP_PROTO_TCP, p->tot_len);#endif#if LWIP_NETIF_HWADDRHINT  ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,      IP_PROTO_TCP, &(pcb->addr_hint));#else /* LWIP_NETIF_HWADDRHINT*/  ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,      IP_PROTO_TCP);#endif /* LWIP_NETIF_HWADDRHINT*/  pbuf_free(p);  return ERR_OK;}/** * Find out what we can send and send it * * @param pcb Protocol control block for the TCP connection to send data * @return ERR_OK if data has been sent or nothing to send *         another err_t on error */err_ttcp_output(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     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;  /* If the TF_ACK_NOW flag is set and no data will be sent (either   * because the ->unsent queue is empty or because the window does   * not allow it), construct an empty ACK segment and send it.   *   * If data is to be sent, we will just piggyback the ACK (see below).   */  if (pcb->flags & TF_ACK_NOW &&     (seg == NULL ||      ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {     return tcp_send_empty_ack(pcb);  }  /* useg should point to last segment on unacked queue */  useg = pcb->unacked;  if (useg != NULL) {    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->seqno), pcb->lastack));  }#endif /* TCP_CWND_DEBUG */  /* data available and window allows it to be sent? */  while (seg != NULL &&         ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {    LWIP_ASSERT("RST not expected here!",                 (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0);    /* Stop sending if the nagle algorithm would prevent it     * Don't stop:     * - if tcp_write had a memory error before (prevent delayed ACK timeout) or     * - if FIN was already enqueued for this PCB (SYN is always alone in a segment -     *   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;    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);    snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);    if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) {      pcb->snd_nxt = snd_nxt;    }    /* put segment on unacknowledged list if length > 0 */    if (TCP_TCPLEN(seg) > 0) {      seg->next = NULL;      /* unacked list is empty? */      if (pcb->unacked == NULL) {        pcb->unacked = seg;        useg = seg;      /* unacked list is not empty? */      } else {        /* In the case of fast retransmit, the packet should not go to the tail         * of the unacked queue, but rather somewhere before it. We need to check for         * this case. -STJ Jul 27, 2004 */        if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))) {          /* add segment to before tail of unacked list, keeping the list sorted */          struct 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 );          }          seg->next = (*cur_seg);          (*cur_seg) = seg;        } else {          /* add segment to tail of unacked list */          useg->next = seg;          useg = useg->next;        }      }    /* do not queue empty segments on the unacked list */    } else {      tcp_seg_free(seg);    }    seg = pcb->unsent;  }#if TCP_OVERSIZE  if (pcb->unsent == NULL) {    /* last unsent has been removed, reset unsent_oversize */    pcb->unsent_oversize = 0;  }#endif /* TCP_OVERSIZE */  if (seg != NULL && pcb->persist_backoff == 0 &&       ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) {    /* prepare for persist timer */    pcb->persist_cnt = 0;    pcb->persist_backoff = 1;  }  pcb->flags &= ~TF_NAGLEMEMERR;  return ERR_OK;}/** * Called by tcp_output() to actually send a TCP segment over 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. */  seg->tcphdr->ackno = htonl(pcb->rcv_nxt);  /* advertise our receive window size in this TCP segment */  seg->tcphdr->wnd = htons(pcb->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 */  LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);  opts = (u32_t *)(void *)(seg->tcphdr + 1);  if (seg->flags & TF_SEG_OPTS_MSS) {    TCP_BUILD_MSS_OPTION(*opts);    opts += 1;  }#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. */  if (pcb->rtime == -1) {    pcb->rtime = 0;  }  /* 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_copy(pcb->local_ip, netif->ip_addr);  }  if (pcb->rttest == 0) {    pcb->rttest = tcp_ticks;    pcb->rtseq = ntohl(seg->tcphdr->seqno);    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) +

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -