本文介紹TCP的用戶請求處理函數tcp_usrreq,它被協議的pr_usrreq函數調用,處理各種與tcp插口有關的系統調用,此外,
還將介紹tcp_ctloutput,應用進程調用setsockopt設定tcp插口選項時會用到它。
TCP的用戶請求函數用於處理多種操作,主要由tcp_usrreq函數完成,函數的對各個請求的大概處理如下:
1.PRU_ATTACH請求。應用程序調用socket系統調用,或者監聽服務器收到連接其你去,調用sonewconn函數,都會發出
PRU_ATTACH請求。如果插口結構已經指向某個PCB,則返回錯誤,調用tcp_attach完成處理:分配並初始化Internet PCB
和TCP控制塊。
2.PRU_DETACH請求。close系統調用在PRU_DISCONNECT請求失敗後,將發送PRU_DETACH請求,如果尚未建立連接,
則無需向對端發送任何信息,但如果連接已經建立,則調用tcp_disconnect初始化TCP的連接關閉過程。(發送所有緩存中
的數據,之後發送FIN)
3.PRU_BIND請求的處理只是簡單地調用in_pcbbind。
4.對於PRU_LISTEN請求,如果插口還沒有綁定到某個本地端口上,在調用in_pcbbind自動爲其分配一個。連接狀態變遷
到LISTEN,完成了listen調用的主要目的:設定插口的狀態,以便接收到達的連接請求。
5.PRU_CONNECT請求。connect系統調用發起該請求,處理的大概流程如下:
a.分配臨時端口。
b.連接PCB。
c.初始化IP和TCP首部。
d.計算窗口縮放因子。
e.設定插口和連接的狀態。
f.初始化序號。
g.發送初始SYN。
5.PRU_CONNECT2請求。來自於socketpair系統調用,對TCP協議無效。
6.close系統調用會發送PRU_DISCONNECT請求。如果連接已經建立,應調用tcp_disconnect,發送FIN,執行正常的TCP
關閉操作。
7.與accept系統調用有關的工作全部由插口層和協議層完成。PRU_ACCEPT請求只簡單地嚮應用進程返回對端的IP地址
和端口號。
8.PRU_SHUTDOWN請求。應用進程調用shutdown,禁止更多的輸出時,soshutdown會發送PRU_SHUTDOWN請求。
調用socantsendmore置位插口標誌,禁止繼續發送報文段,接着調用tcp_usrclosed,設定正確的連接狀態。
9.PRU_RCVD請求。應用進程從插口的接收緩存中讀取數據後,soreceive會發送這個請求。此時接收緩存已擴大,也許
會有足夠的空間,讓TCP發送更大的窗口通告。tcp_output會決定是否需要發送窗口更新報文段。
10.PRU_SEND請求。調用sbappend,向插口的發送緩存中添加數據,並調用tcp_output發送新報文段(如果條件允許)。
11.PRU_ABORT請求。如果插口是監聽插口,並且存在等待建立的連接,例如已發送初始SYN或已完成三次握手過程,但
還未被服務器accept的連接,調用soclose會導致發送PRU_ABORT請求。如果連接已同步,tcp_drop將發送RST。
12.PRU_SENSE請求。fastat系統調用會生成PRU_SENSE請求。TCP返回發送緩存的大小,保存在stat結構的成員變量中。
13.PRU_RCVOOB請求。當應用進程設置MSG_OOB標誌,試圖讀取帶外數據時,soreceive會發送這一請求。大概流程如下:
a.判斷能否讀取帶外數據。
b.判斷是否有帶外數據到達。
c.返回帶外數據字節。
d.更新標誌。
e.確認發送緩存中有足夠空間並添加新數據。
f.計算緊急指針。
g.強制TCP輸出。
14.PRU_SOCKADDR請求。getsockname系統調用會發送該請求,調用in_setsockaddr函數。
15.PRU_PEERADDR請求。getpeername系統調用會發送該請求,調用in_setpeeraddr函數。調用in_setsockaddr和
in_setpeeraddr函數,從PCB中獲取需要信息,存儲在addr參數中。
16.執行tcp_slowtimo會發送PRU_SLOWTIMO函數。