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

📄 tcp.c

📁 lwip-1.4.0
💻 C
📖 第 1 页 / 共 4 页
字号:
     we have to check the pcbs in TIME-WAIT state, also.     We do not dump TIME_WAIT pcb's; they can still be matched by incoming     packets using both local and remote IP addresses and ports to distinguish.   */  if ((pcb->so_options & SOF_REUSEADDR) != 0) {    max_pcb_list = NUM_TCP_PCB_LISTS_NO_TIME_WAIT;  }#endif /* SO_REUSE */  if (port == 0) {    port = tcp_new_port();  }  /* Check if the address already is in use (on all lists) */  for (i = 0; i < max_pcb_list; i++) {    for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) {      if (cpcb->local_port == port) {#if SO_REUSE        /* Omit checking for the same port if both pcbs have REUSEADDR set.           For SO_REUSEADDR, the duplicate-check for a 5-tuple is done in           tcp_connect. */        if (((pcb->so_options & SOF_REUSEADDR) == 0) ||          ((cpcb->so_options & SOF_REUSEADDR) == 0))#endif /* SO_REUSE */        {          if (ip_addr_isany(&(cpcb->local_ip)) ||              ip_addr_isany(ipaddr) ||              ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {            return ERR_USE;          }        }      }    }  }  if (!ip_addr_isany(ipaddr)) {    pcb->local_ip = *ipaddr;  }  pcb->local_port = port;  TCP_REG(&tcp_bound_pcbs, pcb);  LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port));  return ERR_OK;}#if LWIP_CALLBACK_API/** * Default accept callback if no accept callback is specified by the user. */static err_ttcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err){  LWIP_UNUSED_ARG(arg);  LWIP_UNUSED_ARG(pcb);  LWIP_UNUSED_ARG(err);  return ERR_ABRT;}#endif /* LWIP_CALLBACK_API *//** * Set the state of the connection to be LISTEN, which means that it * is able to accept incoming connections. The protocol control block * is reallocated in order to consume less memory. Setting the * connection to LISTEN is an irreversible process. * * @param pcb the original tcp_pcb * @param backlog the incoming connections queue limit * @return tcp_pcb used for listening, consumes less memory. * * @note The original tcp_pcb is freed. This function therefore has to be *       called like this: *             tpcb = tcp_listen(tpcb); */struct tcp_pcb *tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog){  struct tcp_pcb_listen *lpcb;  LWIP_UNUSED_ARG(backlog);  LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, return NULL);  /* already listening? */  if (pcb->state == LISTEN) {    return pcb;  }#if SO_REUSE  if ((pcb->so_options & SOF_REUSEADDR) != 0) {    /* Since SOF_REUSEADDR allows reusing a local address before the pcb's usage       is declared (listen-/connection-pcb), we have to make sure now that       this port is only used once for every local IP. */    for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {      if (lpcb->local_port == pcb->local_port) {        if (ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) {          /* this address/port is already used */          return NULL;        }      }    }  }#endif /* SO_REUSE */  lpcb = (struct tcp_pcb_listen *)memp_malloc(MEMP_TCP_PCB_LISTEN);  if (lpcb == NULL) {    return NULL;  }  lpcb->callback_arg = pcb->callback_arg;  lpcb->local_port = pcb->local_port;  lpcb->state = LISTEN;  lpcb->prio = pcb->prio;  lpcb->so_options = pcb->so_options;  lpcb->so_options |= SOF_ACCEPTCONN;  lpcb->ttl = pcb->ttl;  lpcb->tos = pcb->tos;  ip_addr_copy(lpcb->local_ip, pcb->local_ip);  if (pcb->local_port != 0) {    TCP_RMV(&tcp_bound_pcbs, pcb);  }  memp_free(MEMP_TCP_PCB, pcb);#if LWIP_CALLBACK_API  lpcb->accept = tcp_accept_null;#endif /* LWIP_CALLBACK_API */#if TCP_LISTEN_BACKLOG  lpcb->accepts_pending = 0;  lpcb->backlog = (backlog ? backlog : 1);#endif /* TCP_LISTEN_BACKLOG */  TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb);  return (struct tcp_pcb *)lpcb;}/**  * Update the state that tracks the available window space to advertise. * * Returns how much extra window would be advertised if we sent an * update now. */u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb){  u32_t new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd;  if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + LWIP_MIN((TCP_WND / 2), pcb->mss))) {    /* we can advertise more window */    pcb->rcv_ann_wnd = pcb->rcv_wnd;    return new_right_edge - pcb->rcv_ann_right_edge;  } else {    if (TCP_SEQ_GT(pcb->rcv_nxt, pcb->rcv_ann_right_edge)) {      /* Can happen due to other end sending out of advertised window,       * but within actual available (but not yet advertised) window */      pcb->rcv_ann_wnd = 0;    } else {      /* keep the right edge of window constant */      u32_t new_rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt;      LWIP_ASSERT("new_rcv_ann_wnd <= 0xffff", new_rcv_ann_wnd <= 0xffff);      pcb->rcv_ann_wnd = (u16_t)new_rcv_ann_wnd;    }    return 0;  }}/** * This function should be called by the application when it has * processed the data. The purpose is to advertise a larger window * when the data has been processed. * * @param pcb the tcp_pcb for which data is read * @param len the amount of bytes that have been read by the application */voidtcp_recved(struct tcp_pcb *pcb, u16_t len){  int wnd_inflation;  LWIP_ASSERT("tcp_recved: len would wrap rcv_wnd\n",              len <= 0xffff - pcb->rcv_wnd );  pcb->rcv_wnd += len;  if (pcb->rcv_wnd > TCP_WND) {    pcb->rcv_wnd = TCP_WND;  }  wnd_inflation = tcp_update_rcv_ann_wnd(pcb);  /* If the change in the right edge of window is significant (default   * watermark is TCP_WND/4), then send an explicit update now.   * Otherwise wait for a packet to be sent in the normal course of   * events (or more window to be available later) */  if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD) {    tcp_ack_now(pcb);    tcp_output(pcb);  }  LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n",         len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd));}/** * A nastly hack featuring 'goto' statements that allocates a * new TCP local port. * * @return a new (free) local TCP port number */static u16_ttcp_new_port(void){  int i;  struct tcp_pcb *pcb;#ifndef TCP_LOCAL_PORT_RANGE_START/* From http://www.iana.org/assignments/port-numbers:   "The Dynamic and/or Private Ports are those from 49152 through 65535" */#define TCP_LOCAL_PORT_RANGE_START  0xc000#define TCP_LOCAL_PORT_RANGE_END    0xffff#endif  static u16_t port = TCP_LOCAL_PORT_RANGE_START;   again:  if (port++ >= TCP_LOCAL_PORT_RANGE_END) {    port = TCP_LOCAL_PORT_RANGE_START;  }  /* Check all PCB lists. */  for (i = 0; i < NUM_TCP_PCB_LISTS; i++) {    for(pcb = *tcp_pcb_lists[i]; pcb != NULL; pcb = pcb->next) {      if (pcb->local_port == port) {        goto again;      }    }  }  return port;}/** * Connects to another host. The function given as the "connected" * argument will be called when the connection has been established. * * @param pcb the tcp_pcb used to establish the connection * @param ipaddr the remote ip address to connect to * @param port the remote tcp port to connect to * @param connected callback function to call when connected (or on error) * @return ERR_VAL if invalid arguments are given *         ERR_OK if connect request has been sent *         other err_t values if connect request couldn't be sent */err_ttcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,      tcp_connected_fn connected){  err_t ret;  u32_t iss;  u16_t old_local_port;  LWIP_ERROR("tcp_connect: can only connect from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);  LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port));  if (ipaddr != NULL) {    pcb->remote_ip = *ipaddr;  } else {    return ERR_VAL;  }  pcb->remote_port = port;  /* check if we have a route to the remote host */  if (ip_addr_isany(&(pcb->local_ip))) {    /* no local IP address set, yet. */    struct netif *netif = ip_route(&(pcb->remote_ip));    if (netif == NULL) {      /* Don't even try to send a SYN packet if we have no route         since that will fail. */      return ERR_RTE;    }    /* Use the netif's IP address as local address. */    ip_addr_copy(pcb->local_ip, netif->ip_addr);  }  old_local_port = pcb->local_port;  if (pcb->local_port == 0) {    pcb->local_port = tcp_new_port();  }#if SO_REUSE  if ((pcb->so_options & SOF_REUSEADDR) != 0) {    /* Since SOF_REUSEADDR allows reusing a local address, we have to make sure       now that the 5-tuple is unique. */    struct tcp_pcb *cpcb;    int i;    /* Don't check listen- and bound-PCBs, check active- and TIME-WAIT PCBs. */    for (i = 2; i < NUM_TCP_PCB_LISTS; i++) {      for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) {        if ((cpcb->local_port == pcb->local_port) &&            (cpcb->remote_port == port) &&            ip_addr_cmp(&cpcb->local_ip, &pcb->local_ip) &&            ip_addr_cmp(&cpcb->remote_ip, ipaddr)) {          /* linux returns EISCONN here, but ERR_USE should be OK for us */          return ERR_USE;        }      }    }  }#endif /* SO_REUSE */  iss = tcp_next_iss();  pcb->rcv_nxt = 0;  pcb->snd_nxt = iss;  pcb->lastack = iss - 1;  pcb->snd_lbb = iss - 1;  pcb->rcv_wnd = TCP_WND;  pcb->rcv_ann_wnd = TCP_WND;  pcb->rcv_ann_right_edge = pcb->rcv_nxt;  pcb->snd_wnd = TCP_WND;  /* As initial send MSS, we use TCP_MSS but limit it to 536.     The send MSS is updated when an MSS option is received. */  pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;#if TCP_CALCULATE_EFF_SEND_MSS  pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr);#endif /* TCP_CALCULATE_EFF_SEND_MSS */  pcb->cwnd = 1;  pcb->ssthresh = pcb->mss * 10;#if LWIP_CALLBACK_API  pcb->connected = connected;#else /* LWIP_CALLBACK_API */    LWIP_UNUSED_ARG(connected);#endif /* LWIP_CALLBACK_API */  /* Send a SYN together with the MSS option. */  ret = tcp_enqueue_flags(pcb, TCP_SYN);  if (ret == ERR_OK) {    /* SYN segment was enqueued, changed the pcbs state now */    pcb->state = SYN_SENT;    if (old_local_port != 0) {      TCP_RMV(&tcp_bound_pcbs, pcb);    }    TCP_REG(&tcp_active_pcbs, pcb);    snmp_inc_tcpactiveopens();    tcp_output(pcb);  }  return ret;}/** * Called every 500 ms and implements the retransmission timer and the timer that * removes PCBs that have been in TIME-WAIT for enough time. It also increments * various timers such as the inactivity timer in each PCB. * * Automatically called from tcp_tmr(). */voidtcp_slowtmr(void){  struct tcp_pcb *pcb, *prev;  u16_t eff_wnd;  u8_t pcb_remove;      /* flag if a PCB should be removed */  u8_t pcb_reset;       /* flag if a RST should be sent when removing */  err_t err;  err = ERR_OK;  ++tcp_ticks;  /* Steps through all of the active PCBs. */  prev = NULL;  pcb = tcp_active_pcbs;  if (pcb == NULL) {    LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n"));  }  while (pcb != NULL) {    LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n"));    LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED);    LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN);    LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT);    pcb_remove = 0;    pcb_reset = 0;    if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) {      ++pcb_remove;      LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n"));    }    else if (pcb->nrtx == TCP_MAXRTX) {      ++pcb_remove;      LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n"));    } else {      if (pcb->persist_backoff > 0) {        /* If snd_wnd is zero, use persist timer to send 1 byte probes         * instead of using the standard retransmission mechanism. */        pcb->persist_cnt++;        if (pcb->persist_cnt >= tcp_persist_backoff[pcb->persist_backoff-1]) {          pcb->persist_cnt = 0;          if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) {            pcb->persist_backoff++;          }          tcp_zero_window_probe(pcb);        }      } else {        /* Increase the retransmission timer if it is running */        if(pcb->rtime >= 0)          ++pcb->rtime;        if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {          /* Time for a retransmission. */          LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F                                      " pcb->rto %"S16_F"\n",                                      pcb->rtime, pcb->rto));          /* Double retransmission time-out unless we are trying to           * connect to somebody (i.e., we are in SYN_SENT). */          if (pcb->state != SYN_SENT) {            pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx];          }          /* Reset the retransmission timer. */          pcb->rtime = 0;          /* Reduce congestion window and ssthresh. */          eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd);          pcb->ssthresh = eff_wnd >> 1;

⌨️ 快捷键说明

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