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

📄 tcp_in.c

📁 超轻量级TCP/IP协议栈源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
 */static err_ttcp_listen_input(struct tcp_pcb_listen *pcb){  struct tcp_pcb *npcb;  u32_t optdata;  /* In the LISTEN state, we check for incoming SYN segments,     creates a new PCB, and responds with a SYN|ACK. */  if (flags & TCP_ACK) {    /* For incoming segments with the ACK flag set, respond with a       RST. */    LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));    tcp_rst(ackno + 1, seqno + tcplen,      &(iphdr->dest), &(iphdr->src),      tcphdr->dest, tcphdr->src);  } else if (flags & TCP_SYN) {    LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %u -> %u.\n", tcphdr->src, tcphdr->dest));    npcb = tcp_alloc(pcb->prio);    /* If a new PCB could not be created (probably due to lack of memory),       we don't do anything, but rely on the sender will retransmit the       SYN at a time when we have more memory available. */    if (npcb == NULL) {      LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n"));      TCP_STATS_INC(tcp.memerr);      return ERR_MEM;    }    /* Set up the new PCB. */    ip_addr_set(&(npcb->local_ip), &(iphdr->dest));    npcb->local_port = pcb->local_port;    ip_addr_set(&(npcb->remote_ip), &(iphdr->src));    npcb->remote_port = tcphdr->src;    npcb->state = SYN_RCVD;    npcb->rcv_nxt = seqno + 1;    npcb->snd_wnd = tcphdr->wnd;    npcb->ssthresh = npcb->snd_wnd;    npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */    npcb->callback_arg = pcb->callback_arg;#if LWIP_CALLBACK_API    npcb->accept = pcb->accept;#endif /* LWIP_CALLBACK_API */    /* inherit socket options */    npcb->so_options = pcb->so_options & (SOF_DEBUG|SOF_DONTROUTE|SOF_KEEPALIVE|SOF_OOBINLINE|SOF_LINGER);    /* Register the new PCB so that we can begin receiving segments       for it. */    TCP_REG(&tcp_active_pcbs, npcb);    /* Parse any options in the SYN. */    tcp_parseopt(npcb);    /* Build an MSS option. */    optdata = htonl(((u32_t)2 << 24) |        ((u32_t)4 << 16) |        (((u32_t)npcb->mss / 256) << 8) |        (npcb->mss & 255));    /* Send a SYN|ACK together with the MSS option. */    tcp_enqueue(npcb, NULL, 0, TCP_SYN | TCP_ACK, 0, (u8_t *)&optdata, 4);    return tcp_output(npcb);  }  return ERR_OK;}/* tcp_timewait_input(): * * Called by tcp_input() when a segment arrives for a connection in * TIME_WAIT. */static err_ttcp_timewait_input(struct tcp_pcb *pcb){  if (TCP_SEQ_GT(seqno + tcplen, pcb->rcv_nxt)) {    pcb->rcv_nxt = seqno + tcplen;  }  if (tcplen > 0) {    tcp_ack_now(pcb);  }  return tcp_output(pcb);}/* tcp_process * * Implements the TCP state machine. Called by tcp_input. In some * states tcp_receive() is called to receive data. The tcp_seg * argument will be freed by the caller (tcp_input()) unless the * recv_data pointer in the pcb is set. */static err_ttcp_process(struct tcp_pcb *pcb){  struct tcp_seg *rseg;  u8_t acceptable = 0;  err_t err;  err = ERR_OK;  /* Process incoming RST segments. */  if (flags & TCP_RST) {    /* First, determine if the reset is acceptable. */    if (pcb->state == SYN_SENT) {      if (ackno == pcb->snd_nxt) {  acceptable = 1;      }    } else {      if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&   TCP_SEQ_LEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {  acceptable = 1;      }    }    if (acceptable) {      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));      LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);      recv_flags = TF_RESET;      pcb->flags &= ~TF_ACK_DELAY;      return ERR_RST;    } else {      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %lu rcv_nxt %lu\n",       seqno, pcb->rcv_nxt));      LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %lu rcv_nxt %lu\n",       seqno, pcb->rcv_nxt));      return ERR_OK;    }  }  /* Update the PCB (in)activity timer. */  pcb->tmr = tcp_ticks;  pcb->keep_cnt = 0;  /* Do different things depending on the TCP state. */  switch (pcb->state) {  case SYN_SENT:    LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %lu pcb->snd_nxt %lu unacked %lu\n", ackno,     pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));    if ((flags & TCP_ACK) && (flags & TCP_SYN)        && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {      pcb->rcv_nxt = seqno + 1;      pcb->lastack = ackno;      pcb->snd_wnd = tcphdr->wnd;      pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */      pcb->state = ESTABLISHED;      pcb->cwnd = pcb->mss;      --pcb->snd_queuelen;      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %u\n", (unsigned int)pcb->snd_queuelen));      rseg = pcb->unacked;      pcb->unacked = rseg->next;      tcp_seg_free(rseg);      /* Parse any options in the SYNACK. */      tcp_parseopt(pcb);      /* Call the user specified function to call when sucessfully       * connected. */      TCP_EVENT_CONNECTED(pcb, ERR_OK, err);      tcp_ack(pcb);    }    break;  case SYN_RCVD:    if (flags & TCP_ACK &&       !(flags & TCP_RST)) {      if (TCP_SEQ_LT(pcb->lastack, ackno) &&          TCP_SEQ_LEQ(ackno, pcb->snd_nxt)) {        pcb->state = ESTABLISHED;        LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %u -> %u.\n", inseg.tcphdr->src, inseg.tcphdr->dest));#if LWIP_CALLBACK_API        LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL);#endif        /* Call the accept function. */        TCP_EVENT_ACCEPT(pcb, ERR_OK, err);        if (err != ERR_OK) {          /* If the accept function returns with an error, we abort           * the connection. */          tcp_abort(pcb);          return ERR_ABRT;        }        /* If there was any data contained within this ACK,         * we'd better pass it on to the application as well. */        tcp_receive(pcb);        pcb->cwnd = pcb->mss;      }    }    break;  case CLOSE_WAIT:    /* FALLTHROUGH */  case ESTABLISHED:    tcp_receive(pcb);    if (flags & TCP_FIN) {      tcp_ack_now(pcb);      pcb->state = CLOSE_WAIT;    }    break;  case FIN_WAIT_1:    tcp_receive(pcb);    if (flags & TCP_FIN) {      if (flags & TCP_ACK && ackno == pcb->snd_nxt) {        LWIP_DEBUGF(TCP_DEBUG,         ("TCP connection closed %d -> %d.\n", inseg.tcphdr->src, inseg.tcphdr->dest));  tcp_ack_now(pcb);  tcp_pcb_purge(pcb);  TCP_RMV(&tcp_active_pcbs, pcb);  pcb->state = TIME_WAIT;  TCP_REG(&tcp_tw_pcbs, pcb);      } else {  tcp_ack_now(pcb);  pcb->state = CLOSING;      }    } else if (flags & TCP_ACK && ackno == pcb->snd_nxt) {      pcb->state = FIN_WAIT_2;    }    break;  case FIN_WAIT_2:    tcp_receive(pcb);    if (flags & TCP_FIN) {      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %u -> %u.\n", inseg.tcphdr->src, inseg.tcphdr->dest));      tcp_ack_now(pcb);      tcp_pcb_purge(pcb);      TCP_RMV(&tcp_active_pcbs, pcb);      pcb->state = TIME_WAIT;      TCP_REG(&tcp_tw_pcbs, pcb);    }    break;  case CLOSING:    tcp_receive(pcb);    if (flags & TCP_ACK && ackno == pcb->snd_nxt) {      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %u -> %u.\n", inseg.tcphdr->src, inseg.tcphdr->dest));      tcp_ack_now(pcb);      tcp_pcb_purge(pcb);      TCP_RMV(&tcp_active_pcbs, pcb);      pcb->state = TIME_WAIT;      TCP_REG(&tcp_tw_pcbs, pcb);    }    break;  case LAST_ACK:    tcp_receive(pcb);    if (flags & TCP_ACK && ackno == pcb->snd_nxt) {      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %u -> %u.\n", inseg.tcphdr->src, inseg.tcphdr->dest));      pcb->state = CLOSED;      recv_flags = TF_CLOSED;    }    break;  default:    break;  }  return ERR_OK;}/* tcp_receive: * * Called by tcp_process. Checks if the given segment is an ACK for outstanding * data, and if so frees the memory of the buffered data. Next, is places the * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until * i it has been removed from the buffer. * * If the incoming segment constitutes an ACK for a segment that was used for RTT * estimation, the RTT is estimated here as well. */static voidtcp_receive(struct tcp_pcb *pcb){  struct tcp_seg *next;#if TCP_QUEUE_OOSEQ  struct tcp_seg *prev, *cseg;#endif  struct pbuf *p;  s32_t off;  int m;  u32_t right_wnd_edge;  if (flags & TCP_ACK) {    right_wnd_edge = pcb->snd_wnd + pcb->snd_wl1;    /* Update window. */    if (TCP_SEQ_LT(pcb->snd_wl1, seqno) ||       (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) ||       (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) {      pcb->snd_wnd = tcphdr->wnd;      pcb->snd_wl1 = seqno;      pcb->snd_wl2 = ackno;      LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %lu\n", pcb->snd_wnd));#if TCP_WND_DEBUG    } else {      if (pcb->snd_wnd != tcphdr->wnd) {        LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: no window update lastack %lu snd_max %lu ackno %lu wl1 %lu seqno %lu wl2 %lu\n",                               pcb->lastack, pcb->snd_max, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2));      }#endif /* TCP_WND_DEBUG */    }    if (pcb->lastack == ackno) {      pcb->acked = 0;      if (pcb->snd_wl1 + pcb->snd_wnd == right_wnd_edge){  ++pcb->dupacks;  if (pcb->dupacks >= 3 && pcb->unacked != NULL) {    if (!(pcb->flags & TF_INFR)) {      /* This is fast retransmit. Retransmit the first unacked segment. */      LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupacks %u (%lu), fast retransmit %lu\n",          (unsigned int)pcb->dupacks, pcb->lastack,          ntohl(pcb->unacked->tcphdr->seqno)));      tcp_rexmit(pcb);      /* Set ssthresh to max (FlightSize / 2, 2*SMSS) */      pcb->ssthresh = LWIP_MAX((pcb->snd_max -          pcb->lastack) / 2,         2 * pcb->mss);      pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;      pcb->flags |= TF_INFR;    } else {      /* Inflate the congestion window, but not if it means that         the value overflows. */      if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {        pcb->cwnd += pcb->mss;      }    }  }      } else {  LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %lu %lu\n",            pcb->snd_wl1 + pcb->snd_wnd, right_wnd_edge));      }    } else if (TCP_SEQ_LT(pcb->lastack, ackno) &&              TCP_SEQ_LEQ(ackno, pcb->snd_max)) {      /* We come here when the ACK acknowledges new data. */      /* Reset the "IN Fast Retransmit" flag, since we are no longer         in fast retransmit. Also reset the congestion window to the         slow start threshold. */      if (pcb->flags & TF_INFR) {  pcb->flags &= ~TF_INFR;  pcb->cwnd = pcb->ssthresh;      }      /* Reset the number of retransmissions. */      pcb->nrtx = 0;      /* Reset the retransmission time-out. */      pcb->rto = (pcb->sa >> 3) + pcb->sv;      /* Update the send buffer space. */      pcb->acked = ackno - pcb->lastack;      pcb->snd_buf += pcb->acked;      /* Reset the fast retransmit variables. */      pcb->dupacks = 0;      pcb->lastack = ackno;      /* Update the congestion control variables (cwnd and         ssthresh). */      if (pcb->state >= ESTABLISHED) {        if (pcb->cwnd < pcb->ssthresh) {    if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {      pcb->cwnd += pcb->mss;    }          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %u\n", pcb->cwnd));        } else {    u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);    if (new_cwnd > pcb->cwnd) {      pcb->cwnd = new_cwnd;    }          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %u\n", pcb->cwnd));        }      }      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %lu, unacked->seqno %lu:%lu\n",                               ackno,                               pcb->unacked != NULL?                               ntohl(pcb->unacked->tcphdr->seqno): 0,                               pcb->unacked != NULL?                               ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));      /* Remove segment from the unacknowledged list if the incoming   ACK acknowlegdes them. */      while (pcb->unacked != NULL &&      TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +      TCP_TCPLEN(pcb->unacked), ackno)) {  LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %lu:%lu from pcb->unacked\n",         ntohl(pcb->unacked->tcphdr->seqno),         ntohl(pcb->unacked->tcphdr->seqno) +         TCP_TCPLEN(pcb->unacked)));  next = pcb->unacked;  pcb->unacked = pcb->unacked->next;  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %u ... ", (unsigned int)pcb->snd_queuelen));  pcb->snd_queuelen -= pbuf_clen(next->p);  tcp_seg_free(next);  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%u (after freeing unacked)\n", (unsigned int)pcb->snd_queuelen));  if (pcb->snd_queuelen != 0) {    LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||     pcb->unsent != NULL);  }      }      pcb->polltmr = 0;    }      /* We go through the ->unsent list to see if any of the segments         on the list are acknowledged by the ACK. This may seem         strange since an "unsent" segment shouldn't be acked. The

⌨️ 快捷键说明

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