李江寶
(江蘇自動化研究所,江蘇連云港 222061)
DDS(Data Distribution Service)是對象管理組織OMG發布的關于分布式實時系統中數據發布的規范,該規范標準化了分布式實時系統中數據發布、傳遞和接收的接口和行為,定義了以數據為中心的發布-訂閱機制,提供了一個與平臺無關的數據模型。DDS將分布式網絡中傳輸的數據定義為主題(Topic),將數據的產生和接收對象分別定義為發布者(Publisher)和訂閱者(Subscriber),從而構成數據的發布/訂閱傳輸模型。各個節點在邏輯上無主從關系,點與點之間都是對等關系,通信方式可以是點對點、點對多、多對多等,在QoS的控制下建立連接,自動發現和配置網絡參數[1]。RTPS(Real-Time Publish-Subscribe)協議是對DDS規范的實時發布-訂閱協議規范,該規范確保使用一個供應商的DDS實現發布的某個主題的信息可供相同或不同供應商DDS實現的一個或多個訂閱者使用。
基于可提供低延遲、高吞吐量、可控傳輸性能、數據為中心等優點,目前DDS已越來越多的應用于航空、國防、工業自動化等多個領域[2-4]。隨著DDS在各行業中的應用越來越多,產品開發調試過程中需要輔助開發調試,測試工具。目前產品中使用較多的DDS中間件有RTI-DDS、OpenDDS等,這些中間件雖然提供了一些工具輔助進行調試診斷、排除故障等,但是購買費用較高,需要合適的工具進行定制。
以RTI-DDS為例,其軟件套件中雖然提供了通信報文解析分析工具,但是只能基于結構化的IDL接口定義,對于序列化報文中的自定義數據結構無法進行解析,而實際項目使用中,需通信的信息結構數量較多,不可能逐一定義為IDL接口,更多的是使用序列化傳輸數據方式,在序列化傳輸的數據之下應用協議,由收發雙方程序根據協議組織或解析。這種使用方式下由DDS供應商提供的工具就無法解析序列化數據中的應用協議結構;并且開發商提供的通信報文解析分析工具也不支持二次開發,無法將網絡報文中的序列化應用數據傳遞出來,由開發人員分析其中的自定義數據是否符合協議。
應用數據協議報文解析工具對于開發調試以及軟件接口測試是必需的,尤其是大系統中多個不同廠家生產的設備之間使用DDS通信時,為進行接口對接更需要一個合適的工具來輔助調試開發。RTPS協議雖然是基于TCP/IP的網絡協議,但是為了支持規范要求的各項功能,實際網絡傳輸的應用數據之前封裝了不定長的復雜控制數據,無法采用傳統的網絡抓包分析方法來輔助調試分析報文內容。開發人員根據RTPS規范開發一套解析軟件又不現實,而開源網絡封包軟件Wireshark支持對RTPS協議的封包解析,可以從中提取出相應的協議解析代碼嵌入到應用數據協議解析工具中。
Wireshark是跨平臺的開源網絡封包分析軟件,在GNU GPL通用許可證的保障范圍內,使用者可以免費取得軟件與源代碼,并擁有針對其源代碼修改及定制化的權利。其底層使用Winpcap/libpcap作為網絡數據包捕獲接口,可實時顯示數據包的詳細協議信息,并支持其他常用抓包軟件的包數據文件導入和導出。其支持700多種協議的解析,幾乎包含所有的公開網絡協議,并可支持自定義協議解析器的擴展。Wireshark的系統結構如圖1所示[5]。
網絡數據包經由WinPcap/libpcap捕獲之后,經抓包引擎Dumpcap傳入接口模塊Capture中,Capture模塊將數據傳入數據包分析引擎Epan解析或者傳入Wiretap保存到磁盤中;GUI作為圖形界面,處理所有用戶的輸入/輸出;Core則負責將其他模塊組織起來。
網絡協議解析的核心代碼在Epan(Enhanced Packet ANalyzer)模塊,源碼在epan目錄下。其主要包括4個子模塊[6]:
Protocol-Tree:保存數據包的協議信息。Wireshark的協議結構采用樹形結構,解析協議報文時只需從根節點通過函數句柄依次調用各層解析函數即可;
Dissectors:在epan/dissector目錄下的各種協議解析器。支持700多種協議解析,對于每種協議,解碼器都能識別出協議字段(field),并顯示出字段值(field value)。由于網絡協議種類很多,為了使協議和協議間層次關系明顯,對數據流里的各個層次的協議能夠逐層處理,Wireshark采用了協議樹的方式;
Dissector-Plugins:以插件形式實現的協議解析器,源碼在plugins目錄;
Display-Filters:顯示過濾引擎,源碼在epan/dfilter目錄。
Wireshark的協議解析開發由內置型和插件型構成。插件型協議解析開發相對容易編寫,因為它不需要知道系統的整個框架結構以及整個程序的詳細流程,只需要根據接口的相關說明直接調用就可以。內置型的協議解析開發對比插件方式而言,需要了解Wireshark的組織架構、哪些協議解析本身是以內置型的方式開發的、源文件存放位置、程序編譯和運行信息,需要十分熟悉整個Wireshark的開發。其在編寫完解析器之后需要對整個工程進行編譯,工作量較大。
雖然通過開發應用協議解析插件方式實現對應用協議數據的解析,但考慮到使用時需要安裝整個Wireshark軟件并且通過上述分析Wireshark的工作原理可知:其采用協議樹逐層解析方式,各種協議解析器之間基本沒有相互關聯,可以比較方便的將所需協議解析代碼從整體代碼中剝離出來。所以可采用將RTPS協議解析代碼剝離為獨立模塊嵌入協議解析軟件中使用的方式來達到協議解析目的,遠遠小于開發Wireshark插件所需的工作量,而且還可以根據需要隨時修改。
Wireshark源代碼中實現對RTPS協議解析的代碼是Epan/dissectors目錄下的packet-rtps.h和packet-rtps.c兩個文件。由于Wireshark的dissectors采用的是協議樹逐層解析的方式,與其他網絡協議解析器無關聯,并且RTPS協議是在TCP/IP層上進行的封裝,所以通過將RTPS協議解析代碼從Wireshark剝離為獨立的模塊具備可行性。下面介紹如何將RTPS協議解析相關代碼剝離形成獨立于Wireshark的模塊。
由于Wireshark中使用了glib庫中的大量結構作為基礎元素,特別是作為基礎數據類型、鏈表、字符串等,所以首先需要完成對該庫的處理。因為glib庫是跨平臺的基礎庫,支持Linux、Windows等多個平臺[7],并且提供編譯好的二進制庫,所以可直接下載使用,不需要剝離移植等,只需要針對使用平臺下載對應的頭文件和庫文件,使用時進行鏈接即可。
Wireshark使用了GTK/Qt來開發圖形界面,因為僅需要實現網絡數據報文的解析,不需要圖形界面,所以與圖形界面相關的代碼等也不需要移植。但是源文件中跟界面顯示相關的代碼以及結構體中的相關字段需要進行去除處理。
Wireshark中的內存管理模塊叫wmem,在epan/wmem目錄下。該模塊除使用了glib庫之外,不依賴于其他模塊,可以獨立出來,所以可將其剝離并編譯為一個庫使用。
packet-rtps.h和packet-rtps.c兩個代碼文件包含的其他頭文件雖然不多,但是代碼中卻使用了Wireshark的很多基礎數據結構和輔助函數,所以要實現這兩個代碼文件的剝離獨立,必須把其代碼中使用的相關數據結構和輔助函數一起剝離獨立出來,才能實現整個協議解析功能代碼的完全獨立。
代碼中使用的基礎數據結構主要有:frame-data,tvbuff-t、packet-info、proto-node等;
frame-data結構用于存儲單個網絡報文,雖然該結構中有較多成員,但基本都是基礎數據類型或glib中的數據類型,所以代碼剝離簡單,不需特別處理。
packet-info 結構中除基礎數據類型和glib數據類型外,還有一些其他外部數據結構字段,如struct epan-column-info *cinfo,struct wtap-pkthdr *phdr等,由于在RTPS協議解析中并不需要,所以將這些結構的字段直接去除。
proto-node為協議樹節點,其中的field-info類型的字段在協議解析中并不需要,將其去除。
tvbuff-t結構是具體的網絡數據,struct tvb-ops *ops字段也不需要,直接去除。
將以上主要的結構從Wireshark中剝離后,組合成一個協議解析模塊的獨立結構定義頭文件public-defines.h,并包含到packet-rtps.h中。
協議解析中使用的輔助函數主要是從報文中提取不同類型數據的函數和一些異常處理函數,主要有從報文中取不同類型數據的函數(其中N可以是8、16、32、64):
guintN tvb-get-guintN(tvbuff-t *tvb, const gint offset, const guint encoding);
guint32 tvb-get-ntohl(tvbuff-t *tvb, const gint offset);
guint16 tvb-get-ntohs(tvbuff-t *tvb, const gint offset);
以及檢測報文長度的函數:
gint tvb-reported-length-remaining(const tvbuff-t *tvb, const gint offset);
由于檢測報文長度函數中使用了異常處理,所以還需將異常處理的except.h和except.c兩個文件一起進行移植剝離。這兩個異常處理文件并未依賴其他文件,可以直接從代碼中剝離。
將以上關聯輔助函數從Wireshark中剝離組成單獨的協議解析模塊輔助函數頭文件和源文件。
由于RTPS協議解析代碼已經從Wireshark中剝離,不需要協議樹的注冊等,所以將packet-rtps.c文件中的proto-register-rtps函數去除;
由于在數據結構packet-info中已經刪除了cinfo字段,所以解析代碼中所有與其相關的代碼都需去掉。
packet-rtps.c文件中以proto-tree-和proto-item-開頭的所有的函數調用也都可以刪除。
最后對packet-rtps.c以及依賴代碼文件中與剝離協議封裝頭無關的代碼進行注釋,去除對其他文件的依賴,最終實現協議解析代碼從Wireshark中的剝離。
剝離出的代碼主要包含packet-rtps.c、packet-rtps.h、wmem模塊,以及定義基礎結構的頭文件public-defines.h和定義提取函數的tvbuf.h,tvbuf.c和定義異常處理函數的except.h,except.c。
為方便嵌入其他代碼模塊中,將整個RTPS協議解析代碼封裝為獨立模塊,僅通過如下幾個函數接口進行調用:
模塊初始化接口,進行協議解析模塊的內存分配及初始化等,void rtps-init(void);
(1)
協議解析接口;gboolean dissect-rtps(tvbuff-t *tvb, packet-info *pinfo, proto-tree *tree, void *data);
(2)
應用層數據解析回調函數設置接口,其中回調函數定義如(4)所示。
void set-rtps-dissector(dissect-rtps-func-ptr ptr);
(3)
typedef int (*dissect-rtps-func-ptr)(const char *topic, const char *data, int len, int *param);
(4)
使用時按照接口(2)規定的格式將獲取的RTPS網絡數據包輸入函數接口中就可以實現對RTPS協議的解析,剝離RTPS協議封裝數據,最終應用層數據將被傳入外部定義的應用數據處理回調函數中,輸出的參數包括數據的主題號、應用數據、長度和自定義的用戶參數,方便其他軟件模塊對應用數據的解析分析。
為驗證RTPS協議解析代碼剝離后的有效性,設計了一個簡單的應用數據協議分析軟件,嵌入剝離出的RTPS協議解析模塊,實現對使用DDS通信的應用協議數據報文的解析,同時驗證RTPS協議解析模塊的有效性。
軟件包含3個模塊,如圖2所示,其中網絡抓包模塊負責從網絡抓取數據包,采用Winpcap/libpcap的網絡抓包庫實現,主要負責打開網卡,并抓取網絡通信數據包,送入后續處理模塊;協議解析模塊負責將網絡數據預處理后,根據數據包的不同類型調用不同的解析模塊進行協議的解析,上節中剝離出的RTPS協議解析功能代碼模塊將嵌入此模塊中,進行RTPS協議的解析和協議封裝頭的去除;人機交互模塊主要負責將抓取的數據包以及解析結果顯示出來。下面重點介紹協議解析模塊的處理流程。

圖2 協議分析軟件模塊組成
協議解析模塊的處理流程如圖3所示。從網絡抓包模塊中接收網絡數據后,首先進行網絡層協議解析,判斷是否需進行IP組包。由于使用DDS通信時,發送方底層會將待發送的長RTPS協議數據報文或控制報文進行IP層拆包發送,然后由接收方底層組包后再進行解析。收包不全時無法解析出完整內容,所以需對網絡層IP封裝頭部進行解析,判斷是否需進行組包處理。
組包完后再經傳輸層協議解析判斷后,再判斷是否是RTPS協議包。對于是使用DDS通信的報文,則進行RTPS協議解析,去除協議封包數據后,由應用協議解析子模塊進行應用協議數據的解析,最后將解析結果輸出至下一個模塊。為支持非DDS通信應用數據報文的解析,在判斷報文是非RTPS協議報后,直接將數據送入應用協議解析子模塊中進行判斷解析處理。

圖3 協議解析模塊處理流程
為進行協議解析驗證,假設使用DDS通信的序列化數據報文傳輸的應用數據協議接口結構定義如CGRAM所示,發送信息主題號為TEST-TOPIC。使用兩臺計算機點對點互通方式驗證,發送信息內容填充為發送方計算機日期和時間。
typedef struct tagCGRAM
{
unsigned short wTLen;
unsigned short wYear;
unsigned char ucMonth;
unsigned char ucDay;
unsigned char ucHour;
unsigned char ucMin;
unsigned char ucSec;
unsigned char ucMday;
char strName[100];
}CGRAM;
為做對比分析,同時使用Wireshark軟件和應用數據協議分析軟件進行抓包。選取一個完整DDS通信數據包,如圖4所示為Wireshark軟件中的數據包。Wireshark軟件會自動識別DDS通信數據包并執行RTPS協議解析,去除協議封裝之后的應用數據如圖5所示。由于采用序列化傳輸方式,所以Wireshark軟件無法解析傳輸的數據是什么結構,各字段的值是多少。在同步運行的應用數據協議分析軟件中選擇同一個報文進行應用層解析后,如圖6所示給出了應用數據中各字段的值。可見解析軟件中嵌入的RTPS協議解析模塊成功剝離了RTPS協議封裝數據,給出了完整的應用數據,而應用協議解析模塊也成功對應用數據協議進行了解析,給出了各字段的值。

圖4 Wireshark捕獲的RTPS數據包

圖5 Wireshark對RTPS數據包的解析

圖6 協議分析軟件對數據包的解析結果
本文針對使用DDS通信的應用程序進行調試、測試時應用數據無法解析的問題進行了分析,并在分析開源網絡封包分析軟件Wireshark工作原理的基礎上,研究實現了剝離其RTPS協議解析代碼的方法,最后將剝離出的協議解析代碼嵌入到設計的應用協議分析軟件中,驗證實現了對使用DDS通信的應用協議數據的解析,為進行設備信息互通和接口測試提供了工具,對實現類似基于開源軟件的功能代碼移植有一定的參考意義。