?? tcp.c
字號:
DEBUGF(TCP_DEBUG, ("tcp_connect to port %d\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; pcb->connected = connected; TCP_REG(&tcp_active_pcbs, pcb); /* 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;} /*-----------------------------------------------------------------------------------*//* * tcp_slowtmr(): * * 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){ static struct tcp_pcb *pcb, *pcb2, *prev; static struct tcp_seg *seg, *useg; static u32_t eff_wnd; static u8_t pcb_remove; /* flag if a PCB should be removed */ ++tcp_ticks; /* Steps through all of the active PCBs. */ prev = NULL; pcb = tcp_active_pcbs; while(pcb != NULL) { ASSERT("tcp_timer_coarse: active pcb->state != CLOSED", pcb->state != CLOSED); ASSERT("tcp_timer_coarse: active pcb->state != LISTEN", pcb->state != LISTEN); ASSERT("tcp_timer_coarse: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); pcb_remove = 0; if(pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) { ++pcb_remove; } else if(pcb->nrtx == TCP_MAXRTX) { ++pcb_remove; } else { ++pcb->rtime; seg = pcb->unacked; if(seg != NULL && pcb->rtime >= pcb->rto) { DEBUGF(TCP_RTO_DEBUG, ("tcp_timer_coarse: rtime %ld pcb->rto %d\n", tcp_ticks - 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]; } /* Move all other unacked segments to the unsent queue. */ if(seg->next != NULL) { for(useg = seg->next; useg->next != NULL; useg = useg->next); /* useg now points to the last segment on the unacked queue. */ useg->next = pcb->unsent; pcb->unsent = seg->next; seg->next = NULL; pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno); } /* Do the actual retransmission. */ tcp_rexmit_seg(pcb, seg); /* Reduce congestion window and ssthresh. */ eff_wnd = 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; DEBUGF(TCP_CWND_DEBUG, ("tcp_rexmit_seg: cwnd %u ssthresh %u\n", pcb->cwnd, pcb->ssthresh)); } } /* 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; } } /* 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; }#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; } } /* 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) { ASSERT("tcp_timer_coarse: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs); prev->next = pcb->next; } else { /* This PCB was the first. */ ASSERT("tcp_timer_coarse: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb); tcp_active_pcbs = pcb->next; } if(pcb->errf != NULL) { 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->poll != NULL) { pcb->polltmr = 0; pcb->poll(pcb->callback_arg, pcb); 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) { ASSERT("tcp_timer_coarse: 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) { ASSERT("tcp_timer_coarse: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs); prev->next = pcb->next; } else { /* This PCB was the first. */ ASSERT("tcp_timer_coarse: 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; } }}/*-----------------------------------------------------------------------------------*//* * tcp_fasttmr(): * * Is called every TCP_FINE_TIMEOUT (100 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) { DEBUGF(TCP_DEBUG, ("tcp_timer_fine: delayed ACK\n")); tcp_ack_now(pcb); pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); } }}/*-----------------------------------------------------------------------------------*//* * tcp_segs_free(): * * 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; again: if(seg != NULL) { next = seg->next; count += tcp_seg_free(seg); seg = next; goto again; } return count;}/*-----------------------------------------------------------------------------------*//* * tcp_seg_free(): * * Frees a TCP segment. * *//*-----------------------------------------------------------------------------------*/u8_ttcp_seg_free(struct tcp_seg *seg){ u8_t count = 0; if(seg != NULL) { if(seg->p == NULL) { memp_free(MEMP_TCP_SEG, seg); } else { count = pbuf_free(seg->p);#if TCP_DEBUG seg->p = NULL;#endif /* TCP_DEBUG */ memp_free(MEMP_TCP_SEG, seg); } } return count;}/*-----------------------------------------------------------------------------------*//* * tcp_seg_copy(): * * 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; } bcopy(seg, cseg, sizeof(struct tcp_seg)); pbuf_ref(cseg->p); return cseg;}/*-----------------------------------------------------------------------------------*//* * tcp_new(): * * Creates a new TCP protocol control block but doesn't place it on * any of the TCP PCB lists. * *//*-----------------------------------------------------------------------------------*/struct tcp_pcb *tcp_new(void){ struct tcp_pcb *pcb; u32_t iss; pcb = memp_malloc2(MEMP_TCP_PCB); if(pcb != NULL) { bzero(pcb, sizeof(struct tcp_pcb)); pcb->snd_buf = TCP_SND_BUF; pcb->snd_queuelen = 0; pcb->rcv_wnd = TCP_WND; pcb->mss = TCP_MSS; pcb->rto = 3000 / TCP_SLOW_INTERVAL; pcb->sa = 0; pcb->sv = 3000 / TCP_SLOW_INTERVAL; pcb->rtime = 0; pcb->cwnd = 1; iss = tcp_next_iss(); pcb->snd_wl2 = iss; pcb->snd_nxt = iss; pcb->snd_max = iss; pcb->lastack = iss; pcb->snd_lbb = iss; pcb->tmr = tcp_ticks; pcb->polltmr = 0; return pcb; } return NULL;}/*-----------------------------------------------------------------------------------*//* * tcp_mem_reclaim(): * * Tries to free up TCP memory. This function is called from the memory manager * when memory is scarce. * *//*-----------------------------------------------------------------------------------*/#if MEM_RECLAIMstatic mem_size_ttcp_mem_reclaim(void *arg, mem_size_t size){ static struct tcp_pcb *pcb, *inactive; static u32_t inactivity; static mem_size_t reclaimed; reclaimed = 0; /* Kill the oldest active connection, hoping that there may be memory associated with it. */ inactivity = 0; inactive = NULL; for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { if((u32_t)(tcp_ticks - pcb->tmr) > inactivity) { inactivity = tcp_ticks - pcb->tmr; inactive = pcb; } } if(inactive != NULL) { DEBUGF(TCP_DEBUG, ("tcp_mem_reclaim: killing oldest PCB 0x%p (%ld)\n", inactive, inactivity)); tcp_abort(inactive); } return reclaimed;}#endif /* MEM_RECLAIM *//*-----------------------------------------------------------------------------------*//* * tcp_memp_reclaim(): * * Tries to free up TCP memory. This function is called from the * memory pool manager when memory is scarce. * */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -