📄 tcp.c
字号:
for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { if (pcb->local_port == port) { goto again; } } for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { if (pcb->local_port == port) { goto again; } } for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; 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. * */err_ttcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port, err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err)){ u32_t optdata; err_t ret; u32_t iss; 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; if (pcb->local_port == 0) { pcb->local_port = tcp_new_port(); } 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->snd_wnd = TCP_WND; pcb->mss = TCP_MSS; pcb->cwnd = 1; pcb->ssthresh = pcb->mss * 10; pcb->state = SYN_SENT;#if LWIP_CALLBACK_API pcb->connected = connected;#endif /* LWIP_CALLBACK_API */ TCP_REG(&tcp_active_pcbs, pcb); snmp_inc_tcpactiveopens(); /* Build an MSS option */ optdata = htonl(((u32_t)2 << 24) | ((u32_t)4 << 16) | (((u32_t)pcb->mss / 256) << 8) | (pcb->mss & 255)); ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, (u8_t *)&optdata, 4); if (ret == ERR_OK) { 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. */voidtcp_slowtmr(void){ struct tcp_pcb *pcb, *pcb2, *prev; u32_t eff_wnd; u8_t pcb_remove; /* flag if a PCB should be removed */ 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; 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 { ++pcb->rtime; if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) { /* Time for a retransmission. */ LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"U16_F" pcb->rto %"U16_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]; } /* Reduce congestion window and ssthresh. */ eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd); pcb->ssthresh = eff_wnd >> 1; if (pcb->ssthresh < pcb->mss) { pcb->ssthresh = pcb->mss * 2; } pcb->cwnd = pcb->mss; LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F" ssthresh %"U16_F"\n", pcb->cwnd, pcb->ssthresh)); /* The following needs to be called AFTER cwnd is set to one mss - STJ */ tcp_rexmit_rto(pcb); } } /* Check if this PCB has stayed too long in FIN-WAIT-2 */ if (pcb->state == FIN_WAIT_2) { if ((u32_t)(tcp_ticks - pcb->tmr) > TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) { ++pcb_remove; LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n")); } } /* Check if KEEPALIVE should be sent */ if((pcb->so_options & SOF_KEEPALIVE) && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) { if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keepalive + TCP_MAXIDLE) / TCP_SLOW_INTERVAL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n", ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip), ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip))); tcp_abort(pcb); } else if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keepalive + pcb->keep_cnt * TCP_KEEPINTVL) / TCP_SLOW_INTERVAL) { tcp_keepalive(pcb); pcb->keep_cnt++; } } /* If this PCB has queued out of sequence data, but has been inactive for too long, will drop the data (it will eventually be retransmitted). */#if TCP_QUEUE_OOSEQ if (pcb->ooseq != NULL && (u32_t)tcp_ticks - pcb->tmr >= pcb->rto * TCP_OOSEQ_TIMEOUT) { tcp_segs_free(pcb->ooseq); pcb->ooseq = NULL; LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n")); }#endif /* TCP_QUEUE_OOSEQ */ /* Check if this PCB has stayed too long in SYN-RCVD */ if (pcb->state == SYN_RCVD) { if ((u32_t)(tcp_ticks - pcb->tmr) > TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) { ++pcb_remove; LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n")); } } /* Check if this PCB has stayed too long in LAST-ACK */ if (pcb->state == LAST_ACK) { if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { ++pcb_remove; LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n")); } } /* If the PCB should be removed, do it. */ if (pcb_remove) { tcp_pcb_purge(pcb); /* Remove PCB from tcp_active_pcbs list. */ if (prev != NULL) { LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs); prev->next = pcb->next; } else { /* This PCB was the first. */ LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb); tcp_active_pcbs = pcb->next; } TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT); pcb2 = pcb->next; memp_free(MEMP_TCP_PCB, pcb); pcb = pcb2; } else { /* We check if we should poll the connection. */ ++pcb->polltmr; if (pcb->polltmr >= pcb->pollinterval) { pcb->polltmr = 0; LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n")); TCP_EVENT_POLL(pcb, err); if (err == ERR_OK) { tcp_output(pcb); } } prev = pcb; pcb = pcb->next; } } /* Steps through all of the TIME-WAIT PCBs. */ prev = NULL; pcb = tcp_tw_pcbs; while (pcb != NULL) { LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); pcb_remove = 0; /* Check if this PCB has stayed long enough in TIME-WAIT */ if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { ++pcb_remove; } /* If the PCB should be removed, do it. */ if (pcb_remove) { tcp_pcb_purge(pcb); /* Remove PCB from tcp_tw_pcbs list. */ if (prev != NULL) { LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs); prev->next = pcb->next; } else { /* This PCB was the first. */ LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb); tcp_tw_pcbs = pcb->next; } pcb2 = pcb->next; memp_free(MEMP_TCP_PCB, pcb); pcb = pcb2; } else { prev = pcb; pcb = pcb->next; } }}/** * Is called every TCP_FAST_INTERVAL (250 ms) and sends delayed ACKs. */voidtcp_fasttmr(void){ struct tcp_pcb *pcb; /* send delayed ACKs */ for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { if (pcb->flags & TF_ACK_DELAY) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n")); tcp_ack_now(pcb); pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); } }}/** * Deallocates a list of TCP segments (tcp_seg structures). * */u8_ttcp_segs_free(struct tcp_seg *seg){ u8_t count = 0; struct tcp_seg *next; while (seg != NULL) { next = seg->next; count += tcp_seg_free(seg); seg = next; } return count;}/** * Frees a TCP segment. * */u8_ttcp_seg_free(struct tcp_seg *seg){ u8_t count = 0; if (seg != NULL) { if (seg->p != NULL) { count = pbuf_free(seg->p);#if TCP_DEBUG seg->p = NULL;#endif /* TCP_DEBUG */ } memp_free(MEMP_TCP_SEG, seg); } return count;}/** * Sets the priority of a connection. * */voidtcp_setprio(struct tcp_pcb *pcb, u8_t prio){ pcb->prio = prio;}#if TCP_QUEUE_OOSEQ/** * Returns a copy of the given TCP segment. * */ struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg){ struct tcp_seg *cseg; cseg = memp_malloc(MEMP_TCP_SEG); if (cseg == NULL) { return NULL; } memcpy((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg)); pbuf_ref(cseg->p); return cseg;}#endif#if LWIP_CALLBACK_APIstatic err_ttcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err){ arg = arg; if (p != NULL) { pbuf_free(p); } else if (err == ERR_OK) { return tcp_close(pcb); } return ERR_OK;}#endif /* LWIP_CALLBACK_API */static voidtcp_kill_prio(u8_t prio){ struct tcp_pcb *pcb, *inactive; u32_t inactivity; u8_t mprio; mprio = TCP_PRIO_MAX; /* We kill the oldest active connection that has lower priority than prio. */ inactivity = 0; inactive = NULL; for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { if (pcb->prio <= prio && pcb->prio <= mprio && (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { inactivity = tcp_ticks - pcb->tmr; inactive = pcb; mprio = pcb->prio; } } if (inactive != NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n", (void *)inactive, inactivity)); tcp_abort(inactive); } }static void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -