[cpp] #include "lwip/opt.h" //選項頭文件,lwip一些配置的選項包含在opt.h,debug開啟和內存大小等配置信息 #if LWIP_TCP /* don't build if not configured for use in lwipopts.h *//*如果在lwipopts.h沒有配置LWIP_TCP這項,則不編譯TCP這個文件*/ #include "lwip/def.h" //定義項頭文件,包括一些宏 #include "lwip/mem.h" //內存頭文件,包括一些宏,內存大小,申請內存,內存對齊 #include "lwip/memp.h" //內存池頭文件,包含內存申請,內存釋放 #include "lwip/snmp.h" //SNMP(Simple Network Management Protocol,簡單網絡管理協議),包含snmp的函數聲明 #include "lwip/tcp.h" //包含tcp.c裡面定義的函數聲明和所用到的宏 #include "lwip/debug.h" //包含lwip debug的一些宏,開啟debug #include <string.h> /* Incremented every coarse grained timer shot (typically every 500 ms). */ /* 增加每一個粗粒度的定時器拍攝(通常每500 ms一次)*/ u32_t tcp_ticks; //定義tcp的滴答數 const u8_t tcp_backoff[13] = { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7}; /* Times per slowtmr hits */ /* */ const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 }; /* The TCP PCB lists. */ /* TCP PCB 列表 */ /** List of all TCP PCBs bound but not yet (connected || listening) */ /** 所有的但是還沒有(連接或者監聽中的TCP PCB綁定)列表*/ struct tcp_pcb *tcp_bound_pcbs; /** List of all TCP PCBs in LISTEN state */ /** 所有在監聽中的狀態 TCP PCB列表*/ union tcp_listen_pcbs_t tcp_listen_pcbs; /** List of all TCP PCBs that are in a state in which * they accept or send data. */ /*所有在accept或者send數據狀態的TCP PCB列表 */ struct tcp_pcb *tcp_active_pcbs; /** List of all TCP PCBs in TIME-WAIT state */ /*所有在等待狀態中的TCP PCB*/ struct tcp_pcb *tcp_tw_pcbs; /*所有臨時TCP PCB列表*/ struct tcp_pcb *tcp_tmp_pcb; /*定義tcp計時器*/ static u8_t tcp_timer; /*生成新的tcp本地端口*/ static u16_t tcp_new_port(void); /** * Called periodically to dispatch TCP timers. * */ /* *定期調用派遣TCP定時器 */ void tcp_tmr(void) { /* Call tcp_fasttmr() every 250 ms */ /*每250ms調用一次tcp_fasttmr()*/ tcp_fasttmr(); if (++tcp_timer & 1) {//tcp_timer加1後與1 /* Call tcp_tmr() every 500 ms, i.e., every other timer tcp_tmr() is called. */ /* 每500ms調用一次tcp_tmr(),tcp_tmr被其他的定時器調用 */ tcp_slowtmr(); } } /** * Closes the connection held by the PCB. * * Listening pcbs are freed and may not be referenced any more. * Connection pcbs are freed if not yet connected and may not be referenced * any more. If a connection is established (at least SYN received or in * a closing state), the connection is closed, and put in a closing state. * The pcb is then automatically freed in tcp_slowtmr(). It is therefore * unsafe to reference it. * * @param pcb the tcp_pcb to close * @return ERR_OK if connection has been closed * another err_t if closing failed and pcb is not freed */ /* *通過PCB關閉連接握手 *監聽中的pcb應該被釋放的,也許永遠也不會被使用了 *連接的pcb應該被釋放的,如果還沒有連接或者再也沒有被引用 *如果一個連接被建立(至少SYN已經被接收或者在一個關閉中的狀態) *連接被關閉了,而且輸入了一個正在關閉的狀態 *pcb然後自動在tcp_slowtmr()釋放,所以引用它是不安全的 */ err_t tcp_close(struct tcp_pcb *pcb) { err_t err; //TCP debug信息,打印pcb的狀態 #if TCP_DEBUG LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in ")); tcp_debug_print_state(pcb->state); #endif /* TCP_DEBUG */ switch (pcb->state) { case CLOSED: /* Closing a pcb in the CLOSED state might seem erroneous, * however, it is in this state once allocated and as yet unused * and the user needs some way to free it should the need arise. * Calling tcp_close() with a pcb that has already been closed, (i.e. twice) * or for a pcb that has been used and then entered the CLOSED state * is erroneous, but this should never happen as the pcb has in those cases * been freed, and so any remaining handles are bogus. */ /*在CLOSED狀態下關閉一個pcb似乎是錯誤的, *盡管如此,一但在這個狀態下分配了而且還沒有使用所以用戶需要一些辦法來釋放它 *調用一個已經被關閉的pcb的tcp_close(),(即2次)或者一個已經被使用了之後,進入CLOSE狀態是錯誤的 *但作為一個在這些情況下被釋放的pcb是不會存在的,因此,任何剩余的句柄都是假的 */ err = ERR_OK;//設定返回值 TCP_RMV(&tcp_bound_pcbs, pcb);//從綁定的pcb列表中去掉pcb memp_free(MEMP_TCP_PCB, pcb);//在MEMP_TCP_PCB內存池設定釋放掉的pcb對應的單元值,釋放內存 pcb = NULL; //設置pcb指針指向空 break; case LISTEN: err = ERR_OK;//設定返回值 tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs.pcbs, pcb);//在tcp PCB監聽列表中刪除對應的pcb memp_free(MEMP_TCP_PCB_LISTEN, pcb);//在MEMP_TCP_PCB_LISTEN對應的內存池中設定需要釋放的pcb單元值 pcb = NULL;//設置pcb指針指向空 break; case SYN_SENT: err = ERR_OK;//設定返回值 tcp_pcb_remove(&tcp_active_pcbs, pcb);//在所有accept或者send數據狀態的TCP PCB列表的TCP PCB列表中刪除對應的pcb memp_free(MEMP_TCP_PCB, pcb);//在MEMP_TCP_PCB內存池設定釋放掉的pcb對應的單元值,釋放內存 pcb = NULL;//設置pcb指針指向空 snmp_inc_tcpattemptfails();//tcp嘗試失敗 break; case SYN_RCVD: err = tcp_send_ctrl(pcb, TCP_FIN);//通過pcb發送對應的TCP_FIN包,表示已完成 if (err == ERR_OK) { //如果發回ERR_OK表明發送成功 snmp_inc_tcpattemptfails();//tcp 嘗試失敗 pcb->state = FIN_WAIT_1; //pcb進入FIN_WAIT_1狀態 } break; case ESTABLISHED: err = tcp_send_ctrl(pcb, TCP_FIN);//通過pcb發送對應的TCP_FIN包,表示已完成 if (err == ERR_OK) {//如果發回ERR_OK表明發送成功 snmp_inc_tcpestabresets();//tcp 建立連接復位 pcb->state = FIN_WAIT_1; //pcb進入FIN_WAIT_1狀態 } break; case CLOSE_WAIT: err = tcp_send_ctrl(pcb, TCP_FIN);//通過pcb發送對應的TCP_FIN包,表示已完成 if (err == ERR_OK) {//如果發回ERR_OK表明發送成功 snmp_inc_tcpestabresets();//tcp 建立連接復位 pcb->state = LAST_ACK;//pcb進入LAST_ACK狀態 } break; default: /* Has already been closed, do nothing. */ /* 已經被關閉,什麼也不做*/ err = ERR_OK;//設置返回值 pcb = NULL;//把pcb指向NULL break; } if (pcb != NULL && err == ERR_OK) { /* To ensure all data has been sent when tcp_close returns, we have to make sure tcp_output doesn't fail. Since we don't really have to ensure all data has been sent when tcp_close returns (unsent data is sent from tcp timer functions, also), we don't care for the return value of tcp_output for now. */ /* @todo: When implementing SO_LINGER, this must be changed somehow: If SOF_LINGER is set, the data should be sent when tcp_close returns. */ /* 為了確認在tcp_close 返回的時候所有的數據已經被發送,我們必須確定tcp_output不是失敗的, 從我們還沒有確定在tcp_close之前不是所有的數據都被發送(沒有發送的數據是從tcp計時器函數發過來的), 我們現在不在乎tcp_output的返回值 todo:當正在實現SO_LINGER時,這個不知道怎麼的必須被改變: 如果SO_LINGER被設置了,數據應該在tcp_close的時候被發送 */ tcp_output(pcb);//發送pcb對應的包 } return err; } /** * Abandons a connection and optionally sends a RST to the remote * host. Deletes the local protocol control block. This is done when * a connection is killed because of shortage of memory. * * @param pcb the tcp_pcb to abort * @param reset boolean to indicate whether a reset should be sent */ /* 放棄一個連接和選擇發送一個RST到遠端主機 當一個連接因為短命的內存而掛掉,刪除遠端協議控制塊(PCB)是要做的 @參數pcb:tcp_pcb終止 @參數reset:布爾類型表明是否要發送復位 */ void tcp_abandon(struct tcp_pcb *pcb, int reset) { u32_t seqno, ackno;//定義序列號,應答號 u16_t remote_port, local_port;//遠程端口,本地端口 struct ip_addr remote_ip, local_ip;//遠程IP地址結構體,本地IP地址結構體 #if LWIP_CALLBACK_API //LWIP是否要使用回調API void (* errf)(void *arg, err_t err);//定義回調函數指針 #endif /* LWIP_CALLBACK_API */ void *errf_arg; /* Figure out on which TCP PCB list we are, and remove us. If we are in an active state, call the receive function associated with the PCB with a NULL argument, and send an RST to the remote end. */ /* 找出我們的pcb在TCP PCB列表那個位置後刪除,如果我們在一個激活狀態, 調用pcb NULL參數的接收函數協助處理, 並發送一個RST到遠程終端 */ if (pcb->state == TIME_WAIT) { //如果pcb狀態值是TIME_WAIT tcp_pcb_remove(&tcp_tw_pcbs, pcb);//從time-wait等待狀態列表中刪除pcb memp_free(MEMP_TCP_PCB, pcb);//刪除pcb內存 } else {//否則 seqno = pcb->snd_nxt;//序列號指向發送下一個 ackno = pcb->rcv_nxt;//應答好指向接收到的下一個 ip_addr_set(&local_ip, &(pcb->local_ip));//設置pcb中的本地地址 ip_addr_set(&remote_ip, &(pcb->remote_ip));//設置pcb中的遠端地址 local_port = pcb->local_port; remote_port = pcb->remote_port; #if LWIP_CALLBACK_API errf = pcb->errf;//指針指向回調函數 #endif /* LWIP_CALLBACK_API */ errf_arg = pcb->callback_arg;//回調參數 tcp_pcb_remove(&tcp_active_pcbs, pcb);//把pcb重激活的tcp pcb列表中刪除 if (pcb->unacked != NULL) {//發送還沒有回答? tcp_segs_free(pcb->unacked);//釋放未應答段 } if (pcb->unsent != NULL) {//還沒有發送? tcp_segs_free(pcb->unsent);//釋放還沒有發送段 } #if TCP_QUEUE_OOSEQ //TCP隊列亂序 if (pcb->ooseq != NULL) {//隊列亂? tcp_segs_free(pcb->ooseq);//釋放亂隊列 } #endif /* TCP_QUEUE_OOSEQ */ memp_free(MEMP_TCP_PCB, pcb);//釋放pcb TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);//調用回調函數,傳入終止錯誤參數 if (reset) {//復位? LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n"));//打印發送RST信息 tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);//tcp發送復位信息包 } } } /** * Binds the connection to a local portnumber and IP address. If the * IP address is not given (i.e., ipaddr == NULL), the IP address of * the outgoing network interface is used instead. * * @param pcb the tcp_pcb to bind (no check is done whether this pcb is * already bound!) * @param ipaddr the local ip address to bind to (use IP_ADDR_ANY to bind * to any local address * @param port the local port to bind to * @return ERR_USE if the port is already in use * ERR_OK if bound */ /*綁定一個連接的本地IP和端口.如果IP地址沒有,傳出去的接口IP會被替代 * *參數pcb:綁定的tcp_pcb(不檢查是否這個pcb已經綁定) *參數ipaddr:本地IP地址綁定(用IP_ADDR_ANY綁定任何本地IP *參數port: 本地端口綁定 *返回ERR_USE如果端口已經被使用,返回ERR_OK如果綁定好 */ err_t tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) { struct tcp_pcb *cpcb; //定義cpcb LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); if (port == 0) { //端口為0則從本地找一個端口 port = tcp_new_port(); } /* Check if the address already is in use. */ /* Check the listen pcbs. */ //檢查是不是地址已經在使用 for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; cpcb != NULL; cpcb = cpcb->next) { if (cpcb->local_port == port) {//端口是否在使用 if (ip_addr_isany(&(cpcb->local_ip)) || ip_addr_isany(ipaddr) || ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { return ERR_USE;//返回在使用 } } } /* Check the connected pcbs. */ /*檢查已連接的PCB*/ for(cpcb = tcp_active_pcbs; cpcb != NULL; cpcb = cpcb->next) { if (cpcb->local_port == port) {//端口是否在使用 if (ip_addr_isany(&(cpcb->local_ip)) || ip_addr_isany(ipaddr) || ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { return ERR_USE;//返回在使用 } } } /* Check the bound, not yet connected pcbs. */ /* 檢查綁定,但沒有連接的PCB*/ for(cpcb = tcp_bound_pcbs; cpcb != NULL; cpcb = cpcb->next) { if (cpcb->local_port == port) {//端口是否在使用 if (ip_addr_isany(&(cpcb->local_ip)) || ip_addr_isany(ipaddr) || ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { return ERR_USE;//返回在使用 } } } /* @todo: until SO_REUSEADDR is implemented (see task #6995 on savannah), * we have to check the pcbs in TIME-WAIT state, also: */ /*todo:直到SO_REUSEADDR被完成(看任務#6995), 我們也必須檢查pcb是不是在 TIME-WAIT狀態 */ for(cpcb = tcp_tw_pcbs; cpcb != NULL; cpcb = cpcb->next) { if (cpcb->local_port == port) {//端口是否在使用 if (ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { return ERR_USE;//返回在使用 } } } if (!ip_addr_isany(ipaddr)) {//檢查是否為所有本地IP地址 pcb->local_ip = *ipaddr; } pcb->local_port = port;//設定本地端口 TCP_REG(&tcp_bound_pcbs, pcb);//注冊綁定的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_t tcp_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); //判斷pcb狀態是否關閉 /* already listening? */ //已經在監聽中? if (pcb->state == LISTEN) { return pcb;//返回 } lpcb = memp_malloc(MEMP_TCP_PCB_LISTEN);//分配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->so_options = pcb->so_options;//Socket選項 lpcb->so_options |= SOF_ACCEPTCONN;//socket 已經監聽 lpcb->ttl = pcb->ttl;//存活時間 lpcb->tos = pcb->tos;//服務類型 ip_addr_set(&lpcb->local_ip, &pcb->local_ip);//設置本地IP TCP_RMV(&tcp_bound_pcbs, pcb);//把pcb從tcp綁定列表中刪除 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);//累積>0?否則1 #endif /* TCP_LISTEN_BACKLOG */ TCP_REG(&tcp_listen_pcbs.listen_pcbs, lpcb);//注冊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)//TCP 更新接收發布窗口 { u32_t new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd;//下一個序列號+接收窗口 if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + 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;//發布窗口置0 } else { /* keep the right edge of window constant */ /*保持正確的不變窗口邊界*/ pcb->rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt; } 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 */ /* *這個函數應該被已經處理數據的應用程序調用。目的是當數據已經被處理後發布更大的窗口 *參數pcb:數據已經被讀的tcp_pcb *參數len:已經被應用程序讀取的數據量 */ void tcp_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;//接收到的窗口加len if (pcb->rcv_wnd > TCP_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/2), 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) */ /*如果在正確的窗口邊緣出現改變是有意義的(默認的水印是TCP_WND/2),然後現在發送一個明確的更新。 * 另外等待在正常情況事件下(或者在之後更多的可用窗口)發送一個包 * */ if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD) //返回的值大於TCP窗口更新的臨界值 tcp_ack_now(pcb);//tcp應答 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 */ /* *聲明一個分配新TCP本地端口,返回一個新的可用的本地TCP端口 */ static u16_t tcp_new_port(void) { struct tcp_pcb *pcb; #ifndef TCP_LOCAL_PORT_RANGE_START #define TCP_LOCAL_PORT_RANGE_START 4096//端口范圍開始 #define TCP_LOCAL_PORT_RANGE_END 0x7fff//端口范圍結束 #endif static u16_t port = TCP_LOCAL_PORT_RANGE_START;//開始端口 again: if (++port > TCP_LOCAL_PORT_RANGE_END) {//是否超出范圍 port = TCP_LOCAL_PORT_RANGE_START;//超出,則回到開始 } 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. * * @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 */ /* *連接到其他的主機,當連接已經建立,connected作為參數將被調用 *@參數 pcb:被用來作為建立連接的tcp_pcb *@參數 ipaddr:連接到的遠程IP地址 *@參數 port:連接到的遠程tcp端口 *@參數 connected:當連接了(或者出錯誤)的回調函數 *如果傳入的是非法的參數返回ERR_VAL *如果連接請求已經發送放回ERR_OK *如果連接請求沒有發送返回其他的err_t值 */ err_t tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port, err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err)) { err_t ret; u32_t iss; LWIP_ERROR("tcp_connect: can only connected 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;//遠程ip賦值 } else { return ERR_VAL;//返回錯誤值 } pcb->remote_port = port;//設置遠程端口 if (pcb->local_port == 0) {//本地端口為0 pcb->local_port = tcp_new_port();//申請新端口 } iss = tcp_next_iss();//計算一個新的初始化序列號給新的連接 pcb->rcv_nxt = 0;//接收的下一個為0 pcb->snd_nxt = iss;//發送的下一個為初始化序列號 pcb->lastack = iss - 1;//ack減一 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. */ /* 作為初始化發送最大段大小,我們使用TCP_MSS但是限制在536. 當一個 最大段大小選項被接收,發送的最大段大小就被更新*/ 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;//控制值 pcb->state = SYN_SENT;//設置同步發送 #if LWIP_CALLBACK_API pcb->connected = connected;//連接回調函數 #endif /* LWIP_CALLBACK_API */ TCP_RMV(&tcp_bound_pcbs, pcb);//從綁定列表中刪除pcb TCP_REG(&tcp_active_pcbs, pcb);//注冊激活的pcb到激活列表 snmp_inc_tcpactiveopens();//開啟tcp激活 //pcb假如tcp隊列 ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, TF_SEG_OPTS_MSS #if LWIP_TCP_TIMESTAMPS | TF_SEG_OPTS_TS #endif ); if (ret == ERR_OK) { //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. * * Automatically called from tcp_tmr(). */ /** * 每500ms調用和實施傳播計時器,計時器刪除已經足夠時間在TIME-WAIT的PCB, * 這個也增加各種計時器,例如在每個PCB中的休止狀態的計時器 */ void tcp_slowtmr(void) { struct tcp_pcb *pcb, *pcb2, *prev; u16_t eff_wnd;// 有效窗口 u8_t pcb_remove; /* flag if a PCB should be removed *//*一個PCB應該被移除的標記*/ err_t err; err = ERR_OK; ++tcp_ticks;//tcp滴答數+1 /* Steps through all of the active PCBs. */ /*所有激活中的PCB*/ prev = NULL; pcb = tcp_active_pcbs; if (pcb == NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n")); } while (pcb != NULL) {//遍歷激活的pcb列表 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) {//如果狀態為SYN_SENT而且pcb傳播編號是TCP_SYNMAXRTX ++pcb_remove;//移除計數加1 LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n")); } else if (pcb->nrtx == TCP_MAXRTX) {//pcb傳播編號是TCP_SYNMAXRTX ++pcb_remove;//移除計數加1 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. */ /* 如果發送窗口是0,持續使用計時器發送1字節使用標准傳播編號機制探索替代 */ pcb->persist_cnt++;//持續計時器計數 if (pcb->persist_cnt >= tcp_persist_backoff[pcb->persist_backoff-1]) {//tcp持續備值 pcb->persist_cnt = 0; if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) {//如果pcb持續備值小雨tcp_persist_backoff的大小 pcb->persist_backoff++;//加1 } 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). */ /*雙重轉播超時出發我們嘗試連接到別人那裡(也就是,我們在SYN_SENT狀態) * */ if (pcb->state != SYN_SENT) {//pcb不在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;//有效值右移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 */ /*在調用AFTER擁擠窗口被設置為一個最大段大小- STJ時下面需要被調用 */ tcp_rexmit_rto(pcb);//為重發重新入隊所有的未應答段 } } } /* Check if this PCB has stayed too long in FIN-WAIT-2 */ /* 檢測如果這個PCB已經在FIN-WAIT-2狀態下等太久了 */ if (pcb->state == FIN_WAIT_2) {//檢測狀態 if ((u32_t)(tcp_ticks - pcb->tmr) > TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) {//tcp滴答數減去計時器的計數 是否大於等待的時間除以粗粒超時? ++pcb_remove;//刪除多一個pcb LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n")); } } /* Check if KEEPALIVE should be sent */ /* 檢測如果KEEPALIVE被發送了*/ if((pcb->so_options & SOF_KEEPALIVE) && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) {//在SOF_KEEPALIVE的情況下且是ESTABLISHED或CLOSE_WAIT狀態 #if LWIP_TCP_KEEPALIVE if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keep_idle + (pcb->keep_cnt*pcb->keep_intvl)) / TCP_SLOW_INTERVAL)//如果是KEEPALIVE被打開,允許計數keep alive的間隔 #else if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL)//最大的閒置Keep alive #endif /* LWIP_TCP_KEEPALIVE */ { 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);//終止pcb } #if LWIP_TCP_KEEPALIVE else if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keep_idle + pcb->keep_cnt_sent * pcb->keep_intvl) / TCP_SLOW_INTERVAL)//如果是KEEPALIVE被打開,允許發送計數keep alive的間隔 #else else if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEPINTVL_DEFAULT) / TCP_SLOW_INTERVAL)//最大的閒置發送計數*默認Keep alive間隔 #endif /* LWIP_TCP_KEEPALIVE */ { tcp_keepalive(pcb);//keepalive pcb pcb->keep_cnt_sent++;//計數加1 } } /* 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). */ /* 如果這個PCB 有隊列超出序列的數據,但是已經不活躍太長一段時間了, 將終止數據(它最終將被重傳)*/ #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 */ /* 檢測如果這個PCB已經在SYN-RCVD狀態太長時間了 */ if (pcb->state == SYN_RCVD) { if ((u32_t)(tcp_ticks - pcb->tmr) > TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) {//超時了? ++pcb_remove;//移除加1 LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n")); } } /* Check if this PCB has stayed too long in LAST-ACK */ /* 檢測如果這個PCB已經在LAST-ACK太長時間了 */ if (pcb->state == LAST_ACK) { if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {//超時了? ++pcb_remove;//移除數加1 LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n")); } } /* If the PCB should be removed, do it. */ /* 如果PCB應該被移除,執行 */ if (pcb_remove) { tcp_pcb_purge(pcb); //清理一個TCP PCB /* Remove PCB from tcp_active_pcbs list. */ /* 把PCB從激活列表裡移除. */ if (prev != NULL) {//前一個為空? LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs); prev->next = pcb->next;//下一個指向pcb的next } else { /* This PCB was the first. */ /* 這個PCB是第一個. */ LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb); tcp_active_pcbs = pcb->next;//直接把tcp_active_pcbs隊列執行pcb的下一個 } TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT);//TCP錯誤發生事件 pcb2 = pcb->next;//pcb2指向pcb的next memp_free(MEMP_TCP_PCB, pcb);//釋放pcb pcb = pcb2;//pcb指向往下的一個 } else { /* We check if we should poll the connection. */ /* 我們檢測是否我們應該調查連接. */ ++pcb->polltmr;//調查計時器加1 if (pcb->polltmr >= pcb->pollinterval) {//計數器大於調查間隔 pcb->polltmr = 0;//調查計數器置0 LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n")); TCP_EVENT_POLL(pcb, err);//TCP調查事件 if (err == ERR_OK) {//錯誤? tcp_output(pcb);//發送pcb數據 } } prev = pcb;//前一個指向pcb pcb = pcb->next;//pcb指向pcb的下一個 } } /* Steps through all of the TIME-WAIT PCBs. */ /* 遍歷所有的TIME-WAI 狀態的PCB. */ prev = NULL; pcb = tcp_tw_pcbs;//pcb指向time wait pcb列表 while (pcb != NULL) { LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); pcb_remove = 0;//移除計數設置0 /* Check if this PCB has stayed long enough in TIME-WAIT */ /* 檢測是否這個PCB已經在TIME-WAIT狀態足夠長時間 */ if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { ++pcb_remove;//pcb移除技術加1 } /* If the PCB should be removed, do it. */ /* 如果PCB應該被移除,動手吧. */ if (pcb_remove) { tcp_pcb_purge(pcb); //清理pcb /* Remove PCB from tcp_tw_pcbs list. */ /* 吧PCB從tcp_tw_pcbs列表中移除. */ if (prev != NULL) { LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs); prev->next = pcb->next;//摘除pcb } else { /* This PCB was the first. */ /* 這是第一個PCB. */ LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb); tcp_tw_pcbs = pcb->next;//摘除 } pcb2 = pcb->next;//pcb2指向pcb的下一個 memp_free(MEMP_TCP_PCB, pcb);//釋放pcb pcb = pcb2; } else {//否則不應該移除 prev = pcb;//前面的指針指向pcb pcb = pcb->next;//pcb指向下一個 } } } /** * Is called every TCP_FAST_INTERVAL (250 ms) and process data previously * "refused" by upper layer (application) and sends delayed ACKs. * * Automatically called from tcp_tmr(). */ /** * 叫每個tcp快速區間(250毫秒)和過程數據之前“拒絕”,上層(應用程序)和發送延遲ack。 * 每個TCP_FAST_INTERVAL (250 ms)和處理的數據之前被拒絕被上層(應用程序)和發送延遲ACK調用 * * 自動從tcp_tmr()調用 */ void tcp_fasttmr(void) { struct tcp_pcb *pcb; for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { //遍歷tcp_active_pcbs列表 /* If there is data which was previously "refused" by upper layer */ /* 如果有數據提前被上層拒絕 */ if (pcb->refused_data != NULL) { /* Notify again application with data previously received. */ /* 再次通知應用數據提前接收. */ err_t err; LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_fasttmr: notify kept packet\n")); TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);// if (err == ERR_OK) { pcb->refused_data = NULL;//拒絕數據置空 } } /* send delayed ACKs */ /* 發送延遲ACK */ if (pcb->flags & TF_ACK_DELAY) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n")); tcp_ack_now(pcb);//輸出應答PCB包 pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);//設置標志位,取消延遲ACK和立即ACK } } } /** * Deallocates a list of TCP segments (tcp_seg structures). * * @param seg tcp_seg list of TCP segments to free * @return the number of pbufs that were deallocated */ /** * 釋放一個TCP段(tcp_seg結構)列表的分配 * * @參數seg tcp_seg: 要十分的TCP段列表 * @返回 一個被釋放掉的phufs的數量 */ u8_t tcp_segs_free(struct tcp_seg *seg) { u8_t count = 0;//置0 struct tcp_seg *next;//tcp段下一個 while (seg != NULL) {//段為空? next = seg->next;//下一個 count += tcp_seg_free(seg);//釋放, seg = next;//段指向下一個 } return count;//返回計數 } /** * Frees a TCP segment (tcp_seg structure). * * @param seg single tcp_seg to free * @return the number of pbufs that were deallocated */ /** * 釋放一個TCP段(tcp_seg 結構) * * @參數 seg:單個要釋放的tcp_seg * @返回 pbuf被釋放的數量 */ u8_t tcp_seg_free(struct tcp_seg *seg) { u8_t count = 0; if (seg != NULL) {//段為空? if (seg->p != NULL) {//seg->p這段buffer包括了數據+TCP頭,為空? count = pbuf_free(seg->p);//釋放 #if TCP_DEBUG seg->p = NULL;//置空 #endif /* TCP_DEBUG */ } memp_free(MEMP_TCP_SEG, seg);//釋放seg段 } return count;//返回釋放數量 } /** * Sets the priority of a connection. * * @param pcb the tcp_pcb to manipulate * @param prio new priority */ /** * 設置連接的優先級 * * @參數pcb:操作的tcp_pcb * @參數prio:新的優先級 */ void tcp_setprio(struct tcp_pcb *pcb, u8_t prio) { pcb->prio = prio;//設置新的優先級 } #if TCP_QUEUE_OOSEQ /** * Returns a copy of the given TCP segment. * The pbuf and data are not copied, only the pointers * * @param seg the old tcp_seg * @return a copy of seg */ /** * 返回一個傳入TCP段的復制 * pbuf與數據不復制,只是個指針 * * @參數seg:舊的tcp_seg * @返回段的復制 */ 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;返回 } SMEMCPY((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg)); //copy一個段 pbuf_ref(cseg->p);//增加pbuf的引用計數 return cseg; } #endif #if LWIP_CALLBACK_API /** * Default receive callback that is called if the user didn't register * a recv callback for the pcb. */ /** * 默認的接收回調函數,如果用戶沒有給pcb注冊一個接收回調函數 */ static err_t tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) { arg = arg; if (p != NULL) {//傳入的pbuf為空? pbuf_free(p);//釋放 } else if (err == ERR_OK) { return tcp_close(pcb);//關閉tcp } return ERR_OK; } #endif /* LWIP_CALLBACK_API */ /** * Kills the oldest active connection that has lower priority than prio. * * @param prio minimum priority */ /** * 殺掉舊的比傳入優先級低的激活鏈接 * * @參數 prio:最小的優先級 */ static void tcp_kill_prio(u8_t prio) { struct tcp_pcb *pcb, *inactive; u32_t inactivity; u8_t mprio; mprio = TCP_PRIO_MAX;//TCP最大的優先級 /* 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);//終止它 } } /** * Kills the oldest connection that is in TIME_WAIT state. * Called from tcp_alloc() if no more connections are available. */ /** * 殺掉最久的在TIME_WAIT狀態的連接. * 如果沒有更多連接可用則調用tcp_alloc. */ static void tcp_kill_timewait(void) { struct tcp_pcb *pcb, *inactive; u32_t inactivity; inactivity = 0; inactive = NULL; /* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */ /* 遍歷TIME_WAIT狀態的pcb列表,得到最舊的pcb. */ for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {//是否在靜止狀態?否 inactivity = tcp_ticks - pcb->tmr;//得到靜止計時 inactive = pcb;//靜止指針指向pcb } } if (inactive != NULL) {//找到了? LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n", (void *)inactive, inactivity)); tcp_abort(inactive);//終止 } } /** * Allocate a new tcp_pcb structure. * * @param prio priority for the new pcb * @return a new tcp_pcb that initially is in state CLOSED */ /** * 分配一個新的tcp_pcb結構. * * @參數prio:新pcb的優先級 * @返回一個新的初始化在CLOSED狀態的tcp_pcb */ struct tcp_pcb * tcp_alloc(u8_t prio) { struct tcp_pcb *pcb; u32_t iss; pcb = memp_malloc(MEMP_TCP_PCB);//分配一個MEMP_TCP_PCB if (pcb == NULL) {//分配成功? /* Try killing oldest connection in TIME-WAIT. */ /* 嘗試殺掉一個在TIME-WAIT狀態下最舊的連接. */ LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n")); tcp_kill_timewait(); /* Try to allocate a tcp_pcb again. */ /* 嘗試再次分配一個tcp_pcb. */ pcb = memp_malloc(MEMP_TCP_PCB); if (pcb == NULL) { /* Try killing active connections with lower priority than the new one. */ /* 嘗試殺掉比新塊低優先級的激活的連接. */ tcp_kill_prio(prio); /* Try to allocate a tcp_pcb again. */ /* 再次嘗試分配pcb. */ pcb = memp_malloc(MEMP_TCP_PCB); } } if (pcb != NULL) { memset(pcb, 0, sizeof(struct tcp_pcb));//初始化內存置0 pcb->prio = TCP_PRIO_NORMAL;//設置為普通優先級 pcb->snd_buf = TCP_SND_BUF;//設置TCP發送的空間為256 pcb->snd_queuelen = 0;//發送隊列長度置0 pcb->rcv_wnd = TCP_WND;//TCP結構窗口 pcb->rcv_ann_wnd = TCP_WND;//TCP發布窗口 pcb->tos = 0;//服務類型 pcb->ttl = TCP_TTL;//默認存活時間 /* As initial send MSS, we use TCP_MSS but limit it to 536. The send MSS is updated when an MSS option is received. */ /* 作為初始化發送的MSS,我們用TCP_MSS但是最大限制在536. 當一個MSS選項被接收,發送的MSS會被更新 */ pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;//設置pcb的mss pcb->rto = 3000 / TCP_SLOW_INTERVAL;//設置重傳超時 pcb->sa = 0;// pcb->sv = 3000 / TCP_SLOW_INTERVAL;// pcb->rtime = -1;//重傳計時器 pcb->cwnd = 1;//擁擠避免 iss = tcp_next_iss();//計算新的連接的初始化隊列數 pcb->snd_wl2 = iss;//最後的窗口更新序列和應答號 pcb->snd_nxt = iss;//下一個發送的心的序列號 pcb->lastack = iss;//最後的應答號 pcb->snd_lbb = iss;//下一個字節的進入buffer的序列數 pcb->tmr = tcp_ticks;//計時器 pcb->polltmr = 0;//池計時器 #if LWIP_CALLBACK_API pcb->recv = tcp_recv_null;//接收函數默認 #endif /* LWIP_CALLBACK_API */ /* Init KEEPALIVE timer */ /* 初始化KEEPALIVE計時器 */ pcb->keep_idle = TCP_KEEPIDLE_DEFAULT; #if LWIP_TCP_KEEPALIVE pcb->keep_intvl = TCP_KEEPINTVL_DEFAULT;//初始化KEEPALIVE默認時間間隔 pcb->keep_cnt = TCP_KEEPCNT_DEFAULT;//初始化KEEPALIVE計數 #endif /* LWIP_TCP_KEEPALIVE */ pcb->keep_cnt_sent = 0;//發送計數置0 } return pcb;//返回新生成的pcb } /** * Creates a new TCP protocol control block but doesn't place it on * any of the TCP PCB lists. * The pcb is not put on any list until binding using tcp_bind(). * * @internal: Maybe there should be a idle TCP PCB list where these * PCBs are put on. Port reservation using tcp_bind() is implemented but * allocated pcbs that are not bound can't be killed automatically if wanting * to allocate a pcb with higher prio (@see tcp_kill_prio()) * * @return a new tcp_pcb that initially is in state CLOSED */ /** * 生成新的TCP PCB但沒有房子到任何TCP PCB的列表 * pcb沒有放入任何列表直到使用tcp_bind綁定後 * * * @內部: 可能應該是一個閒置的TCP PCB列表哪裡有PCB在裡面 * 使用tcp_bind() 實現端口預定但是分配pcb沒有綁定不能自動殺掉, * 如果想分配一個pcb用更高的優先級(請看tcp_kill_prio()) * * * @返回一個新的初始化在CLOSED狀態的tcp_pcb */ struct tcp_pcb * tcp_new(void) { return tcp_alloc(TCP_PRIO_NORMAL);//分配一個新的pcb } /** * Used to specify the argument that should be passed callback * functions. * * @param pcb tcp_pcb to set the callback argument * @param arg void pointer argument to pass to callback functions */ /** * 使用指定參數,這個參數應該被傳到回調函數去 * * * @參數pcb: tcp_pcb設置的回調函數參數 * @參數arg:一個void指針參數傳到回調函數 */ void tcp_arg(struct tcp_pcb *pcb, void *arg) { pcb->callback_arg = arg;//設置回調函數參數 } #if LWIP_CALLBACK_API /** * Used to specify the function that should be called when a TCP * connection receives data. * * @param pcb tcp_pcb to set the recv callback * @param recv callback function to call for this pcb when data is received */ /** * 使用指定的函數,當一個TCP連接收到數據是這個函數應該被調用 * * @參數pcb: 設置接收回調函數的tcp_pcb * @參數recv:當數據被接收了回調函數將為相應的pcb調用 */ void tcp_recv(struct tcp_pcb *pcb, err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)) { pcb->recv = recv;//設置相應的接收回調函數 } /** * Used to specify the function that should be called when TCP data * has been successfully delivered to the remote host. * * @param pcb tcp_pcb to set the sent callback * @param sent callback function to call for this pcb when data is successfully sent */ /** * 使用指定的函數,當TCP數據已經成功傳送到遠程主機,這個函數應該被調用 * * * @參數pcb: 設置發送回調函數的tcp_pcb * @參數send: 當數據已經成功送達,send回調函數將被調用 */ void tcp_sent(struct tcp_pcb *pcb, err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len)) { pcb->sent = sent;//設置相應的發送回調函數 } /** * Used to specify the function that should be called when a fatal error * has occured on the connection. * * @param pcb tcp_pcb to set the err callback * @param errf callback function to call for this pcb when a fatal error * has occured on the connection */ /** * 使用指定的函數,當一個致命錯誤發生在連接的時候,這個函數應該被調用 * * * @參數pcb: 設置錯誤的回調函數的tcp_pcb * @參數errf: 但一個致命錯誤發生在連接的時候,errf回調函數將被調用 */ void tcp_err(struct tcp_pcb *pcb, void (* errf)(void *arg, err_t err)) { pcb->errf = errf;//設置致命錯誤回調函數 } /** * Used for specifying the function that should be called when a * LISTENing connection has been connected to another host. * * @param pcb tcp_pcb to set the accept callback * @param accept callback function to call for this pcb when LISTENing * connection has been connected to another host */ /** * 使用指定的函數,當一個監聽中的連接已經連接到另外的主機上,這個函數應該被調用 * * @參數pcb: 設置接受的回調函數的tcp_pcb * @參數accept: 當監聽中的連接已經連接到其他的主機上,這個回調函數將被調用 */ void tcp_accept(struct tcp_pcb *pcb, err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err)) { pcb->accept = accept;//設置接受回調函數 } #endif /* LWIP_CALLBACK_API */ /** * Used to specify the function that should be called periodically * from TCP. The interval is specified in terms of the TCP coarse * timer interval, which is called twice a second. * */ /** * 使用指定的函數,這個函數會定期的被TCP調用,時間間隔是指定在TCP粗糙的計時器間隔 * 這個函數每秒會被調用2次 */ void tcp_poll(struct tcp_pcb *pcb, err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval) { #if LWIP_CALLBACK_API pcb->poll = poll;//設置回調函數 #endif /* LWIP_CALLBACK_API */ pcb->pollinterval = interval;//設置時間間隔 } /** * Purges a TCP PCB. Removes any buffered data and frees the buffer memory * (pcb->ooseq, pcb->unsent and pcb->unacked are freed). * * @param pcb tcp_pcb to purge. The pcb itself is not deallocated! */ /** * 清理一個TCP PCB,移除所有的buffer數據和釋放buffer內存(pcb->ooseq, pcb->unsent和pcb->unacked被釋放 ) * @參數pcb:清理tcp_pcb.pcb自己不被釋放! */ void tcp_pcb_purge(struct tcp_pcb *pcb) { if (pcb->state != CLOSED && pcb->state != TIME_WAIT && pcb->state != LISTEN) {//看狀態都否CLOSED,TIME_WAIT,LISTEN? LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n")); #if TCP_LISTEN_BACKLOG if (pcb->state == SYN_RCVD) {//狀態是否為SYN_RCVD /* Need to find the corresponding listen_pcb and decrease its accepts_pending */ /* 需要找出相應的listen_pcb和減少它的接受等待*/ struct tcp_pcb_listen *lpcb; LWIP_ASSERT("tcp_pcb_purge: pcb->state == SYN_RCVD but tcp_listen_pcbs is NULL", tcp_listen_pcbs.listen_pcbs != NULL); //遍歷監聽的pcb列表 for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { if ((lpcb->local_port == pcb->local_port) && (ip_addr_isany(&lpcb->local_ip) || ip_addr_cmp(&pcb->local_ip, &lpcb->local_ip))) { /* port and address of the listen pcb match the timed-out pcb */ /*監聽pcb匹配超時的pcb端口和地址 */ LWIP_ASSERT("tcp_pcb_purge: listen pcb does not have accepts pending", lpcb->accepts_pending > 0); lpcb->accepts_pending--;//接受掛起數減1 break; } } } #endif /* TCP_LISTEN_BACKLOG */ if (pcb->refused_data != NULL) {//拒絕數據為空? LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n")); pbuf_free(pcb->refused_data);//釋放拒絕數據 pcb->refused_data = NULL;//把指針指向空 } if (pcb->unsent != NULL) {//未發送全部數據 LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n")); } if (pcb->unacked != NULL) {//未應答? LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n")); } #if TCP_QUEUE_OOSEQ /* LW */ if (pcb->ooseq != NULL) {//接收超出隊列段序列 LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n")); } /* Stop the retransmission timer as it will expect data on unacked queue if it fires */ /* 停在重發計時器作為它將期待數據在為應答隊列如果???*/ pcb->rtime = -1; tcp_segs_free(pcb->ooseq);//釋放接收超出隊列段 pcb->ooseq = NULL; #endif /* TCP_QUEUE_OOSEQ */ tcp_segs_free(pcb->unsent);//釋放未發送段 tcp_segs_free(pcb->unacked);//釋放為應答段 pcb->unacked = pcb->unsent = NULL;//置空 } } /** * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first. * * @param pcblist PCB list to purge. * @param pcb tcp_pcb to purge. The pcb itself is also deallocated! */ /** * 清理PCB和吧pcb沖列表中移除.所有延遲的應答被首先發送 * @參數pcblist:要清楚的PCB列表. * @參數pcb:要清理的tcp_pcb. pcb自己也釋放! */ void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb) { TCP_RMV(pcblist, pcb);//移除pcb tcp_pcb_purge(pcb);//清理pcb /* if there is an outstanding delayed ACKs, send it */ /* 如果有一個味解決的延遲應答,則發送*/ if (pcb->state != TIME_WAIT && pcb->state != LISTEN && pcb->flags & TF_ACK_DELAY) { pcb->flags |= TF_ACK_NOW;//標記為應答 tcp_output(pcb);//發送 } if (pcb->state != LISTEN) {//如果不是監聽狀態 LWIP_ASSERT("unsent segments leaking", pcb->unsent == NULL); LWIP_ASSERT("unacked segments leaking", pcb->unacked == NULL); #if TCP_QUEUE_OOSEQ LWIP_ASSERT("ooseq segments leaking", pcb->ooseq == NULL); #endif /* TCP_QUEUE_OOSEQ */ } pcb->state = CLOSED;//pcb狀態設為CLOSED LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane()); } /** * Calculates a new initial sequence number for new connections. * * @return u32_t pseudo random sequence number */ /** * 給新連接計算新的初始化隊列好. * * @返回一個冒充的32位隨機隊列號 */ u32_t tcp_next_iss(void) { static u32_t iss = 6510; iss += tcp_ticks; /* XXX *//*初始化隨機設定的大於6510的一個序列號*/ return iss; } #if TCP_CALCULATE_EFF_SEND_MSS /** * Calcluates the effective send mss that can be used for a specific IP address * by using ip_route to determin the netif used to send to the address and * calculating the minimum of TCP_MSS and that netif's mtu (if set). */ /** * 計算有效的發送最大段大小,這樣可以用來作為一個指定的IP地址 通過使用ip_route來確定netif用來發送給的地址 而且計算最小的TCP_MSS和這個netif的mtu(如果設置了) * * */ u16_t tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr) { u16_t mss_s; struct netif *outif; outif = ip_route(addr);//從適當的網絡接口中找到匹配的netif if ((outif != NULL) && (outif->mtu != 0)) {//outif找到?最大的傳送單元為0? mss_s = outif->mtu - IP_HLEN - TCP_HLEN;//最大傳送單元減去IP頭和TCP頭 /* RFC 1122, chap 4.2.2.6: * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize * We correct for TCP options in tcp_enqueue(), and don't support * IP options */ /* RFC 1122, 4.2.2.6章: * 有效的發送最大段大小 = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize * 我們TCP選項在tcp_enqueue()是正確的,且沒有支持IP選項 */ sendmss = LWIP_MIN(sendmss, mss_s);//最小的發送段大小 } return sendmss;//得到有效的段大小 } #endif /* TCP_CALCULATE_EFF_SEND_MSS */ #if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG /** * Print a tcp header for debugging purposes. * * @param tcphdr pointer to a struct tcp_hdr */ /** * 為調試目的打印tcp頭. * * @參數tcphdr:結構體tcp_hdr的指針 */ void tcp_debug_print(struct tcp_hdr *tcphdr) { LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n")); LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(TCP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n", ntohs(tcphdr->src), ntohs(tcphdr->dest))); LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (seq no)\n", ntohl(tcphdr->seqno))); LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (ack no)\n", ntohl(tcphdr->ackno))); LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" | |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"| %5"U16_F" | (hdrlen, flags (", TCPH_HDRLEN(tcphdr), TCPH_FLAGS(tcphdr) >> 5 & 1, TCPH_FLAGS(tcphdr) >> 4 & 1, TCPH_FLAGS(tcphdr) >> 3 & 1, TCPH_FLAGS(tcphdr) >> 2 & 1, TCPH_FLAGS(tcphdr) >> 1 & 1, TCPH_FLAGS(tcphdr) & 1, ntohs(tcphdr->wnd))); tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); LWIP_DEBUGF(TCP_DEBUG, ("), win)\n")); LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(TCP_DEBUG, ("| 0x%04"X16_F" | %5"U16_F" | (chksum, urgp)\n", ntohs(tcphdr->chksum), ntohs(tcphdr->urgp))); LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); } /** * Print a tcp state for debugging purposes. * * @param s enum tcp_state to print */ /** *為調試目的打印tcp狀態. * * @參數s: 打印枚舉tcp_state */ void tcp_debug_print_state(enum tcp_state s) { LWIP_DEBUGF(TCP_DEBUG, ("State: ")); switch (s) { case CLOSED: LWIP_DEBUGF(TCP_DEBUG, ("CLOSED\n")); break; case LISTEN: LWIP_DEBUGF(TCP_DEBUG, ("LISTEN\n")); break; case SYN_SENT: LWIP_DEBUGF(TCP_DEBUG, ("SYN_SENT\n")); break; case SYN_RCVD: LWIP_DEBUGF(TCP_DEBUG, ("SYN_RCVD\n")); break; case ESTABLISHED: LWIP_DEBUGF(TCP_DEBUG, ("ESTABLISHED\n")); break; case FIN_WAIT_1: LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_1\n")); break; case FIN_WAIT_2: LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_2\n")); break; case CLOSE_WAIT: LWIP_DEBUGF(TCP_DEBUG, ("CLOSE_WAIT\n")); break; case CLOSING: LWIP_DEBUGF(TCP_DEBUG, ("CLOSING\n")); break; case LAST_ACK: LWIP_DEBUGF(TCP_DEBUG, ("LAST_ACK\n")); break; case TIME_WAIT: LWIP_DEBUGF(TCP_DEBUG, ("TIME_WAIT\n")); break; } } /** * Print tcp flags for debugging purposes. * * @param flags tcp flags, all active flags are printed */ /** * 為調試目的打印tcp標示. * * @參數flags:tcp標示,打印所以激活的標示 */ void tcp_debug_print_flags(u8_t flags) { if (flags & TCP_FIN) { LWIP_DEBUGF(TCP_DEBUG, ("FIN ")); } if (flags & TCP_SYN) { LWIP_DEBUGF(TCP_DEBUG, ("SYN ")); } if (flags & TCP_RST) { LWIP_DEBUGF(TCP_DEBUG, ("RST ")); } if (flags & TCP_PSH) { LWIP_DEBUGF(TCP_DEBUG, ("PSH ")); } if (flags & TCP_ACK) { LWIP_DEBUGF(TCP_DEBUG, ("ACK ")); } if (flags & TCP_URG) { LWIP_DEBUGF(TCP_DEBUG, ("URG ")); } if (flags & TCP_ECE) { LWIP_DEBUGF(TCP_DEBUG, ("ECE ")); } if (flags & TCP_CWR) { LWIP_DEBUGF(TCP_DEBUG, ("CWR ")); } LWIP_DEBUGF(TCP_DEBUG, ("\n")); } /** * Print all tcp_pcbs in every list for debugging purposes. */ /** * 為調試打印所有的tcp_pcb在每個列表裡面. */ void tcp_debug_print_pcbs(void) { struct tcp_pcb *pcb; LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:\n")); for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", pcb->local_port, pcb->remote_port, pcb->snd_nxt, pcb->rcv_nxt)); tcp_debug_print_state(pcb->state); } LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n")); for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) { LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", pcb->local_port, pcb->remote_port, pcb->snd_nxt, pcb->rcv_nxt)); tcp_debug_print_state(pcb->state); } LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n")); for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", pcb->local_port, pcb->remote_port, pcb->snd_nxt, pcb->rcv_nxt)); tcp_debug_print_state(pcb->state); } } /** * Check state consistency of the tcp_pcb lists. */ /** * 檢測tcp_pcb列表狀態兼容性. */ s16_t tcp_pcbs_sane(void) { struct tcp_pcb *pcb; for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED); LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN); LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); } for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); } return 1; } #endif /* TCP_DEBUG */ #endif /* LWIP_TCP */