uip_process分析
轉載地址:http://chenlaichang.blog.163.com/blog/static/58944355201031325323818/
uip_process(u8_t?flag)
(1)if(flag?==?UIP_UDP_SEND_CONN),若是則goto?udp_send;不是則向下執行;
(2)
if(flag?==?UIP_POLL_REQUEST)?
{
if(tcpstateflags==?UIP_ESTABLISHED?&&!uip_outstanding(uip_connr))如果處于穩定連接狀態且沒有數據在緩存中等待確認則:
{
①uip_flags?=?UIP_POLL;?
②UIP_APPCALL();
③goto?appsend;
}
goto?drop;
}
else?if(flag?==?UIP_TIMER)
{
?uip_len?=?0;
?uip_slen?=?0;
?如果連接處于等待超時關閉狀態則增加超時計數器,如果到達超時期限則關閉當前連 接tcpstateflags?=?UIP_CLOSED;
if(tcpstateflags?!=?UIP_CLOSED)?如果連接不處于關閉狀態
{
if(uip_outstanding(uip_connr)&&(timer--?==?0))?已經發送的數據包還未接收 到對其的ACK,超時計數器減一且超時計數器值為0
{
①如果到達所設定的重發次數則:
1、tcpstateflags?=?UIP_CLOSED;關閉當前連接
2、uip_flags?=?UIP_TIMEDOUT;通知應用程序超時;
3、UIP_APPCALL();
4、設置RST+ACK終止連接標志
5、goto?tcp_send_nodata;
②沒有到達設定的重發次數則重傳數據:
1、重置重傳計數器
2、?switch(tcpstateflags)根據連接處的不同狀態重發不同的數據包
case?UIP_SYN_RCVD:?
goto?tcp_send_synack;重新發送先前發送的SYN+ACK
case?UIP_SYN_SENT:
goto?tcp_send_syn;重發SYN請求連接
case?UIP_ESTABLISHED:
uip_flags?=?UIP_REXMIT;
UIP_APPCALL();?調用上層應用程序,通知重新生成數據重發
goto?apprexmit;進入重發階段
case?UIP_FIN_WAIT_1:
case?UIP_CLOSING:
??case?UIP_LAST_ACK:
??????goto?tcp_send_finack;重發FIN+ACK關閉連接
}
else?if(tcpstateflags)?==?UIP_ESTABLISHED)?處于穩定連接狀態且上次發送的數據 接收到正確的ACK,可以繼續發送新數據
{
①uip_flags?=?UIP_POLL;詢問應用程序是否有數據要發送
②UIP_APPCALL();調用應用程序產生數據
③goto?appsend;發送數據
}
??}
?goto?drop;
}
if(flag?==?UIP_UDP_TIMER)
{
當前連接的本地端口不為0則
{
①uip_len?=?uip_slen?=?0;
②uip_flags?=?UIP_POLL;詢問應用程序是否有數據要發送
③UIP_UDP_APPCALL();調用應用程序產生數據
④goto?udp_send;
}
本地端口為0,表明沒有建立DUP連接,則
{
goto?drop;
}
}
(3)檢查IP幀頭中的IP版本及IP頭長度是否符合要求:
①不符合:goto?drop;丟棄此包
②符合繼續向下執行
(4)檢查目的IP地址是否為本機地址:
①不是,goto?drop;丟棄此包
②是,向下繼續執行
?(5)if(BUF->proto?==?UIP_PROTO_TCP)IP上層協議是否為TCP協議
①是,goto?tcp_input;進入TCP數據處理模塊
②不是,繼續向下執行
(6)if(BUF->proto?==?UIP_PROTO_UDP)IP上層協議是否為UDP協議
? ①是,goto?udp_input;進入UDP數據處理模塊
②不是,繼續向下執行
(7)if(BUF->proto?!=?UIP_PROTO_ICMP)?不是TCP不是UDP也不是ICMP協議
①goto?drop;本機只處理UDP、TCP、ICMP數據包,其它包都將丟棄
(8)運行到此處,表明接收到的是ICMP數據包,繼續向下執行;
———————————————————————————————————————
icmp_input:
此處為ICMP數據包處理部分,比較簡單不做詳解。
此部分僅僅接收ECHO命令,若接收到別的命令,則將數據包丟棄。若接收到的是ECHO命令則返回包含ECHO_REPLY的ICMP數據包給遠方主機,主要是用來響應ping命令。
?
———————————————————————————————————————
udp_input:
(1)根據要求校驗UDP數據
(2)在UDP連接列表中尋找接收到的數據包是否屬于列表中的連接,若是則?goto?udp_found;
???如果不是則??goto?drop;
udp_found:
(1)接收到數據數設置uip_flags?=?UIP_NEWDATA;?將uip_sappdata?,uip_appdata指向接收到的UDP包的數據部分。
(2)調用UIP_UDP_APPCALL();使應用程序處理接收到的數據;
(3)繼續向下執行
udp_send:
(1)如果uip_slen?==?0表明沒有數據要發送,則直接goto?drop;
(2)計算UDP數據包長度,填充UDP、IP幀頭中的數據長度及相關選項;
(3)根據要求計算校驗和;
(4)goto?ip_send_nolen;發送UDP數據包;
?
———————————————————————————————————————tcp_input:
(1)檢查TCP校驗和,若正確向下繼續,若錯誤則丟棄此包直接返回;
(2)在TCP連接列表uip_conns中輪詢,檢查接收到的TCP數據包是否已經建立連接(通過逐個比較源端口、目的端口和源IP是否與鏈接列表中的相同)。
若找到goto?found;
沒有找到則檢查接收到的TCP數據包中是否含有SYN請求建立連接標志:
若沒有則goto?reset;發送RST+ACK斷開連接;
若有則檢查uip_listenports監聽列表,若TCP數據包目的端口在監聽列表中則goto?found_listen;若不在監聽列表中則向下執行,進入?reset;發送RST+ACK斷開連接;
reset:
(1)接收到的是RST斷開連接包,則直接丟包,返回;
(2)設置RST+ACK標志,填充適當的TCP幀頭;
(3)goto?tcp_send_noconn;發送TCP數據包;
found_listen:
(1)從鏈接列表中找出一個空鏈接或剩余生存時間最短的連接;
(2)將找到的鏈接列表根據接收到的TCP數據包進行初始化;
(3)設置TCP狀態為UIP_SYN_RCVD;
(4)向下執行,發送ACK
tcp_send_synack:
(1)設置ACK標志
(2)向下執行
tcp_send_syn:
(1)設置SYN標志
(2)填充TCP選項中最大報文段長度MSS
(3)?goto?tcp_send;
found:
(1)若接收到的是RST數據包,則將本連接狀態置為UIP_CLOSED,uip_flags?=?UIP_ABORT;,調用UIP_APPCALL()通知應用程序處理連接斷開請求。然后丟棄此包,直接返回;
(2)檢查接收到的數據包中的數據編號是否為自己等在等待的數據編號,若不是則goto?tcp_send_ack;發送自己期望的數據編號的數據,即請求重傳。若是則繼續向下;
(3)檢查接收到的數據包中是否包含ACK,
若是則:
①更新發送數據序列的編號,使之可以發送后續數據;
②計算RTT時間,重新設置RTT時間;
③uip_flags?=?UIP_ACKDATA;表明接收到ACK
④uip_connr->len?=?0;表明等待ACK的數據長度為0,即可以發送其它數據
⑤繼續向下;
若不是:繼續向下;
TCP狀態機
switch(tcpstateflags)
case?UIP_SYN_RCVD:
(1)檢查uip_flags==UIP_ACKDATA即是否接收到對自己發送SYN的ACK確認,
若是則:
①cpstateflags?=?UIP_ESTABLISHED;/*進入ESTABLISHED狀態*/
??uip_flags?=?UIP_CONNECTED;/*連接成功*
②檢查數據包長度是否包含數據部分,若是則uip_flags?|=?UIP_NEWDATA;
③調用UIP_APPCALL()處理剛建立的連接和新接收到數據;
⑤goto?appsend;
若不是則goto?drop;丟包返回;
case?UIP_SYN_SENT:
(1)如果接收到ACK且為SYN+ACK則:
①檢查TCP擴展選項,如果有擴展選項從中取出MSS信息;
②tcpstateflags?=?UIP_ESTABLISHED;進入ESTABLISHED狀態
③設置接收編號,uip_flags?=?UIP_CONNECTED?|?UIP_NEWDATA;調用UIP_APPCALL()處理剛建立的連接和新接收到數據;
④goto?appsend;
(2)沒有接收到ACK且為SYN+ACK則:
①uip_flags?=?UIP_ABORT;終止連接調用UIP_APPCALL();
②tcpstateflags?=?UIP_CLOSED;關閉TCP連接
③goto?reset;
case?UIP_ESTABLISHED:
(1)接收到遠方主機的FIN請求:
①?uip_flags?|=?UIP_CLOSE;關閉TCP連接
②如果接收到的數據包中還包含有數據則uip_flags?|=?UIP_NEWDATA;
③調用UIP_APPCALL()處理剛關閉的連接和新接收到數據;
④發送TCP_FIN?+TCP_ACK,關閉連接;
(2)如果接收到的數據狀態為UIP_NEWDATA?|?UIP_ACKDATA則:
①調用UIP_APPCALL();處理接收到的包;
②
appsend:
(1)如果(uip_flags?&?UIP_ABORT)終止連接則
①tcpstateflags?=?UIP_CLOSED;關閉TCP連接;
②發送RST+ACK關閉連接;
(2)如果(uip_flags?&?UIP_CLOSE)正常關閉連接則:
①tcpstateflags?=?UIP_FIN_WAIT_1;進入等待關閉狀態
②發送FIN+ACK告知對方關閉連接;
(3)如果uip_slen?>?0有數據要發送則設置發送數據的長度
apprexmit:
(1)如果(uip_slen?>?0?&&?uip_connr->len?>?0)則發送PSH_ACK數據包;
(2)如果(uip_flags?&?UIP_NEWDATA)僅僅是發送ACK,沒有數據要發送則發送對接收到數據的ACK;
(3)?goto?drop;
case?UIP_LAST_ACK:
(1)如果uip_flags?&?UIP_ACKDATA接收到對本機發送的FIN的ACK確認則:
①tcpstateflags?=?UIP_CLOSED;將連接置為關閉狀態
②uip_flags?=?UIP_CLOSE;調用UIP_APPCALL();通知應用程序連接已經斷開;
case?UIP_FIN_WAIT_1:
(1)此時本機已經關閉連接等待對方關閉連接,如果接收到數據并不處理,僅僅將接收到數據包數目加一;
(2)如果接收到FIN請求:
①如果(uip_flags?&?UIP_ACKDATA)接收到對本機發送FIN的確認則將連接狀態置為tcpstateflags?=?UIP_TIME_WAIT;
②否則的話則將連接狀態置為tcpstateflags?=?UIP_CLOSING;
③uip_flags?=?UIP_CLOSE;?調用UIP_APPCALL();通知應用程序有一方已經關閉連接
④goto?tcp_send_ack;
(2)如果(uip_flags?&?UIP_ACKDATA)僅僅接收到ACK則設置連接狀態標志tcpstateflags?=?UIP_FIN_WAIT_2;?進入等待對方關閉階段
(3)?如果(uip_len?>?0)表明接收到數據包則goto?tcp_send_ack;發送對接收到數據的確認ACK;
(4)goto?drop;
case?UIP_FIN_WAIT_2:
(1)此時本機已經關閉連接等待對方關閉連接,如果接收到數據并不處理,僅僅將接收到數據包數目加一;
(2)如果接收到對方發送的FIN請求。則
①設置tcpstateflags?=?UIP_TIME_WAIT;進入超時關閉狀態;
②uip_flags?=?UIP_CLOSE;?調用UIP_APPCALL();通知應用程序有一方已經關閉連接
③goto?tcp_send_ack;
(3)如果(uip_len?>?0)表明接收到數據包則goto?tcp_send_ack;發送對接收到數據的確認ACK;
(4)goto?drop;
case?UIP_TIME_WAIT:
(1)goto?tcp_send_ack;
case?UIP_CLOSING:
(1)如果(uip_flags?&?UIP_ACKDATA)接收到對FIN的ACK,連接進入超時等待狀態tcpstateflags?=?UIP_TIME_WAIT;
Endcase
———————————————————————————————————————
?
tcp_send_ack:
(1)設置ACK標志
?tcp_send_nodata:
(1)將長度設為幀頭長度,不包含數據
tcp_send_noopts:
(1)將選項長度設為0
tcp_send:
(1)填充TCP幀頭確認編號和發送編號,IP地址和端口號;
(2)如果tcpstateflags?&?UIP_STOPPED要求暫停發送數據則將接收窗口設為0;禁止對方往自己發送數據;
tcp_send_noconn:
(1)設置TCP包生存時間,傳送的數據的長度;
(2)計算TCP校驗和
ip_send_nolen:
(1)設置IP幀頭中的各個選項
(2)計算IP校驗和
send:
(1)將發送的數據包計數器加一;
(2)uip_flags?=?0;??return;
drop:
(1)uip_len?=?0;
(2)uip_flags?=?0;
(3)return;
總結
以上是生活随笔為你收集整理的uip_process分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Pod和容器设计模式
- 下一篇: 软件测试教程第2版(宫云战主编)