2016年9月29日 星期四

TDI Operations - V

Making an Endpoint-to-Endpoint Connection

TDI客戶端在不同的網路節點與他各自的傳輸共同合作,在他們彼此之間建立點對點的連接。而在試圖嘗試連接之前,每一個客戶對它的在節點必須做下列的處理:
1.  開啟一個傳輸位址,同Opening a Transport Address
2.  開啟一個連結端點,同Opening a Connection Endpoint
3. 透過TDI_ASSOCIATE_ADDRESS關聯開啟的連與位址。

然後,其中一個客戶端對其他人建立一個連接,通常其他人都處於被動的聆聽(listen)連接到來。

如果客戶端對它底層傳輸註冊了它的ClientEventConnect。則當有任何來自於遠端節點的連接,則傳輸驅動會調用ClientEventConnect

Requesting a Connection to a Remote Node

下圖示範一個本地端節點的TDI客戶如何對遠端節點啟動一個連接處理。


本地端節點客戶透過提交一個TDI_CONNECT請求來對遠端節點建立一個連接處理,客戶可以透過TdiBuildConnect來封裝這個請求。

本地端節點傳輸從它的客戶端那裏確定遠端節點的位址,並且與遠端節點傳輸合作傳輸連結工作。

如果在之前遠端節點的客戶端有提交一個TDI_LISTEN請求或是註冊ClientEventConnect處理程序,則當有一個連接請求進入時,遠端節點傳輸會通知它的客戶。

如果遠端節點客戶沒有聆聽(listen)或是沒有回應,則本地端節點傳輸會得到連接失敗的結果。遠端節點可以接受或是拒絕連結,如果傳輸支援delayed-connection acceptance,在稍後會有描述。

Accepting a Connection Offer from a Remote Node

下圖示範一個本地端節點客戶如何聆聽一個來自於遠端節點的連接處理。

要建立一個點對點連接,一個客戶會提出一個連接請求,然後其他客戶會對它底層傳輸示意等待一個連接請求的來臨。

本地端節點客戶可以透過提交一個TDI_LISTEN請求來被動地聆聽一個正要進入的連結,客戶可以透過TdiBuildListen來封裝這個請求。當客戶在設定聆聽(listen)IRP時,可以指定可以接收請求發生的遠端節點傳輸位址。如果傳輸支援delayed-connection acceptances,則客戶端可以指定傳輸立即的接收來自於遠端節點的連接,或是允許客戶檢這個請求並且決定是否要接收。

當傳輸接收一個TDI_LISTEN請求,它會監視來自於遠端節點的連接。當它接收到一個遠端位址的連接,傳輸會複製交易的訊息到本地客戶端配置的緩衝區,並且會完成IRP給監聽的客戶端。

接收一個連接有更簡單的方式,如果本地端客戶使用事件處理函式。當傳輸接收一個來自遠端節點的連接,則傳輸會調用客戶端註冊的ClientEventConnect處理函式。ClientEventConnect接者會接收或是否決這個請求。

2016年9月26日 星期一

TDI Operations - IV

Setting and Querying Information

下圖示範一個TDI客戶如何詢問底層傳輸的特徵或是對底層傳輸設定狀態數據。

一個TDI客戶可以詢問某些傳輸驅動的資訊,例如連接狀態的訊息,在一個特定傳輸位址的激活,數據報大小與數量的限制,驅動統計,以及內部收發緩衝區的大小。一個客戶也可以對底層傳輸設定一些狀態訊息,雖然這不能透過發送設定請求來覆寫底層傳輸所定義的某些限制大小值。

如果一個客戶希望詢問有關一個開傳輸位址或是一個連接端點的訊息,它可以提交一個TDI_QUERY_INFORMATION請求,客戶可以透過TdiBuildQueryInformation來封裝請求給底層傳輸。當它使用這個巨集,客戶會使用位址或是連接端點的檔案物件指標以及客戶所配置的緩衝區(用於接收底層傳輸回傳資訊)作為參數。

要設定傳輸訊息,客戶端發布一個TDI_SET_INFORMATION請求,並且透過TdiBuildSetInformation來封裝。

對於每一個操作,客戶也通過一個系統定義的TDI_QUERY_XXX作為 TdiBuild..巨集的參數。QType或是SType分別決定可以詢問以及設定的訊息類型。

查詢或是設定訊息並沒有特別關注一個位址或是一個連接端點,客戶在查詢/設定訊息請求前首先必須開啟一個控制通道。舉例來說,一個客戶端為了無連接傳輸詢問有關底層廣播位址的訊息使用一個控制通道。

要開啟一個控制通道,客戶端調用ZwCreateFile 並且帶有一個空的EaBuffer 指標。客戶端調用ZwCreateFile 使得I/O管理員建立一個代表控制通道的檔案物件並且調用底層的TdiDispatchCreate例程TdiDispatchCreate 注意到沒有EA訊息,以及傳輸端為了開啟的控制通道設置內部狀態。

作為代表一個控制通道的檔案物件,客戶端可以調用 IoGetDeviceObjectPointer 來得到符合的檔案物件的裝置物件指標。

在成功調用ZwCreateFile 後,會得到一個file handle,並且客戶端可以透過ObReferenceObjectByHandle來獲得檔案物件的指標,現在客戶端已經準備好使用TDI_QUERY_INFORMATION或是TDI_SET_INFORMATION IOCTL請求。

當詢問或是設定訊息的操作完成,客戶端必須使用ZwClose 關閉一個開的控制通道,在稍後的Closing a Transport Address or Control Channel會介紹。


2016年9月22日 星期四

TDI Operations - III

Packaging and Submitting IOCTL Requests


下圖示範了TDI客戶如何封裝以及提交TDI_XXX IOCTL要求給他底層的TDI傳輸驅動。


核心模式客戶端會準備他自己的IOCTL IRPs,可以使用TdiBuildXxx 巨集來建立,詳細的介紹在TDI Routines, Macros, and Callbacks。客戶端可以從網路更高層或是調用TdiBuildInternalDeviceControlIrp來為自己配置一個IRP

隨後調用一個TdiBuildXxx 巨集,在IRP內的MinorFunctionCode 欄位設定適當的TDI_ XXX 碼,並且在IRP內設定MajorFunctionCode IRP_MJ_INTERNAL_DEVICE_CONTROL,同時也對每一個IRP設定客戶端支援的IOCTL特定參數。例如,上一節提到的有關如何設定TDI_ASSOCIATE_ADDRESS要求,當使用 TdiBuildAccept,客戶端會提交一個代表連接端點的檔案物件以及代表傳輸位址檔案物件的handle

IRP設定好以後,客戶端可以調用 IoCallDriver 來提交他的IOCTL請求給他的底層傳輸驅動。傳輸驅動的TdiDispatchInternalDeviceControl例程收到來自於客戶端的IRP,並且將命令轉接給內部驅動函式作更進一步的處理。當完成客戶端請求以後,傳輸驅動會對 IRP 設定 I/O statsus block,然後調用TdiCompleteRequest(或 IoCompleteRequest)來返回操作的結果。

如果客戶端在調用 TdiBuildXxx 巨集的時候有設定 IoCompletion,則當傳輸驅動完成操作請求並且調用Io/TdiCompleteRequest 後,會調用客戶端註冊的 IoCompletion 例程。

TDI Operations - II

Opening a Connection Endpoint


下圖示範了一個核心模式客戶端如何對它底層傳輸驅動開一個連接端點(connection endpoint)


如果一個本地端節點客戶需要建立一個連線導向的網路傳輸,則本地端節點客戶首先必須開一個傳輸位址(transport address)並且對它的底層傳輸驅動開一個連接端點(connection endpoint)。客戶端會調用兩次ZwCreateFile,第一次開一個位址,接著再開一個連接端點。

當開一個連接端點時,客戶端在EA(extended attributes)緩衝區內傳送一個客戶-支援內容參數給ZwCreateFile,客戶端設定EaName為系統所定義的TdiConnectionContext 

客戶端調用ZwCreateFile 會讓I/O管理員建立一個客戶端程序指定的檔案物件並且會調用TDI傳輸驅動的TdiDispatchCreate例程。TdiDispatchCreate會解析EA的資訊,並且如果調用成功的時候,傳輸驅動會對開的連接終端設定內部的狀態。

在成功調用 ZwCreateFile 以後,接者傳輸端驅動程式會回傳客戶端一個 file handle,並且客戶端可以透過 ObReferenceObjectByHandle 來獲得檔案物件的指標,此時客戶端已經準備好創建某些 TDI_XXX IOCTL 請求來對遠端節點建立一個點對點的連接。

首先,客戶端必須透過提交一個TDI_ASSOCIATE_ADDRESS請求來關聯這個連接端點與他的傳輸位址,可以使用TdiBuildAssociateAddress來封裝一個IRP

如何封裝設定一個TDI_XXX IOCTL IRPs,可以參考Packaging and Submitting IOCTL Requests。而更多有關如何建立一個點對點的連接,可以參考Making an Endpoint-to-Endpoint Connection.

當點對點連接已經斷線時,並且客戶端不在使用任何的連線導向傳輸,客戶端必須關閉連接端點,透過先前ZwCreateFile 得到的檔案handel作為參數來使用ZwClose,在 Closing a Connection Endpoint有描述這個部分。