一、模塊
2.1 模塊框架
模塊框架的主要作用是在應用程序組件之間分發SIP消息,PJSIP的所有的組件,包括dialog和transaction都是以模塊方式實現的,沒有模塊,核心協議棧將不知道如何處理SIP消息。
模塊架構思基於簡單但是非常強大的接口抽象,對於到達的消息,Endpoint 按照優先級向所有的模塊分發消息,直到其中一個模塊告知已經處理這個消息。對於出去的消息,endpoint分發消息到所有模塊,在消息未到達網絡之前,允許任何模塊對消息做最后的修改。
2.1.1 模塊聲明
模塊接口再<pjsip/sip_module.h>中聲明,如下:
/**
* The declaration for SIP module. This structure would be passed to
* #pjsip_endpt_register_module() to register the module to PJSIP.
*/
struct pjsip_module
{
/** To allow chaining of modules in the endpoint. */
PJ_DECL_LIST_MEMBER(struct pjsip_module);
/**
* Module name to identify the module.
*
* This field MUST be initialized before registering the module.
*/
pj_str_t name;
/**
* Module ID. Application must initialize this field with -1 before
* registering the module to PJSIP. After the module is registered,
* this field will contain a unique ID to identify the module.
*/
int id;
/**
* Integer number to identify module initialization and start order with
* regard to other modules. Higher number will make the module gets
* initialized later.
*
* This field MUST be initialized before registering the module.
*/
int priority;
/**
* Optional function to be called to initialize the module. This function
* will be called by endpoint during module registration. If the value
* is NULL, then it's equal to returning PJ_SUCCESS.
*
* @param endpt The endpoint instance.
* @return Module should return PJ_SUCCESS to indicate success.
*/
pj_status_t (*load)(pjsip_endpoint *endpt);
/**
* Optional function to be called to start the module. This function
* will be called by endpoint during module registration. If the value
* is NULL, then it's equal to returning PJ_SUCCESS.
*
* @return Module should return zero to indicate success.
*/
pj_status_t (*start)(void);
/**
* Optional function to be called to deinitialize the module before
* it is unloaded. This function will be called by endpoint during
* module unregistration. If the value is NULL, then it's equal to
* returning PJ_SUCCESS.
*
* @return Module should return PJ_SUCCESS to indicate success.
*/
pj_status_t (*stop)(void);
/**
* Optional function to be called to deinitialize the module before
* it is unloaded. This function will be called by endpoint during
* module unregistration. If the value is NULL, then it's equal to
* returning PJ_SUCCESS.
*
* @param mod The module.
*
* @return Module should return PJ_SUCCESS to indicate success.
*/
pj_status_t (*unload)(void);
/**
* Optional function to be called to process incoming request message.
*
* @param rdata The incoming message.
*
* @return Module should return PJ_TRUE if it handles the request,
* or otherwise it should return PJ_FALSE to allow other
* modules to handle the request.
*/
pj_bool_t (*on_rx_request)(pjsip_rx_data *rdata);
/**
* Optional function to be called to process incoming response message.
*
* @param rdata The incoming message.
*
* @return Module should return PJ_TRUE if it handles the
* response, or otherwise it should return PJ_FALSE to
* allow other modules to handle the response.
*/
pj_bool_t (*on_rx_response)(pjsip_rx_data *rdata);
/**
* Optional function to be called when transport layer is about to
* transmit outgoing request message.
*
* @param tdata The outgoing request message.
*
* @return Module should return PJ_SUCCESS in all cases.
* If non-zero (or PJ_FALSE) is returned, the message
* will not be sent.
*/
pj_status_t (*on_tx_request)(pjsip_tx_data *tdata);
/**
* Optional function to be called when transport layer is about to
* transmit outgoing response message.
*
* @param tdata The outgoing response message.
*
* @return Module should return PJ_SUCCESS in all cases.
* If non-zero (or PJ_FALSE) is returned, the message
* will not be sent.
*/
pj_status_t (*on_tx_response)(pjsip_tx_data *tdata);
/**
* Optional function to be called when this module is acting as
* transaction user for the specified transaction, when the
* transaction's state has changed.
*
* @param tsx The transaction.
* @param event The event which has caused the transaction state
* to change.
*/
void (*on_tsx_state)(pjsip_transaction *tsx, pjsip_event *event);
};
所有回調函數的指針都是可選的,如果沒有被指定,被默認為返回成功。
Load, start, stop, unload這四個函數指針被enpoint調用,控制模塊的狀態,下面的圖展示了模塊狀態的生命周期:
其中on_rx_request( ) 和 on_rx_response( ) 主要作用是從sip_endpoint或其他的模塊接收SIP消息。Callback函數的返回值非常重要,如果返回非0(相當於true),意味這個模塊已經處理消息,這時,endpoint將停止分發消息到其他的模塊。2.1.3 節呼入消息的處理將會詳細描述。
On_tx_request( ) 和 on_tx_response( )在消息被廣播前通過transport manager調用,這給了一些類型模塊(比如:sigcomp 、 message signing)最后修改消息的機會。所有的模塊必須都要返回PJ_SUCCESS(ie zero)。否則分發將會被取消,外出的消息,將會在2.1.4的將會詳細描述。
On_tsx_state() 函數用來接收事務狀態改變的通知,比如:接收消息、發送消息、定時器事件、傳輸錯誤事件都可能引起通知,在2.1.5節將會詳細的介紹
2.1.2 模塊的優先級
通過優先級指定回調調用的順序,高優先級模塊將首先調用on_rx_request 和 on_rx_response。最后調用on_tx_request 和 on_tx_response
下面是模塊優先級的標准
/**
* Module priority guidelines.
*/
enum pjsip_module_priority
{
/**
* This is the priority used by transport layer.
*/
PJSIP_MOD_PRIORITY_TRANSPORT_LAYER = 8,
/**
* This is the priority used by transaction layer.
*/
PJSIP_MOD_PRIORITY_TSX_LAYER = 16,
/**
* This is the priority used by the user agent and proxy layer.
*/
PJSIP_MOD_PRIORITY_UA_PROXY_LAYER = 32,
/**
* This is the priority used by the dialog usages.
*/
PJSIP_MOD_PRIORITY_DIALOG_USAGE = 48,
/**
* This is the recommended priority to be used by applications.
*/
PJSIP_MOD_PRIORITY_APPLICATION = 64
};
注意: 數字越小優先級越高
PJSIP_MOD_PRIORITY_TRANSPORT_LAYER 被用於傳輸管理模塊,優先級當前只是被用來控制消息的傳送。低優先級的模塊將在傳輸層調用on_tx_request/on_tx_response回調函數之前調用。高優先級的模塊,將在傳輸層處理之后調用這兩個函數。2.1 4 將詳細介紹outgoing的細節。
PJSIP_MOD_PRIORITY_TSX_LAYER 是Transaction layer擁有的優先級,事務層接收所有屬於事務層輸入的消息。
PJSIP_MOD_PRIORITY_UA_PROXY_LAYER 是UA layer(dialog framework )或 proxy layer 擁有的權限,UA layer 接收所有輸入dialog的消息
PJSIP_MOD_PRIORITY_DIALOG_USAGE 是dialog的擁有的優先級,目前,PJSIP實現兩個類型dilalog usage: invite session 和 event subscription(包括refer)。Dialog usage 接收同一個對話的屬於特定session的所有消息。
PJSIP_MOD_PRIORITY_APPLICATION 是應用模塊和合適的值,當他采用transaction、dialogs 和 dislog usage時。
2.1.3 處理呼入消息的模塊
當Incoming Message到達時,提供接收消息的緩存區(結構體:pjsip_rx_data,參考第5章的 “Recive Data Buffer”)傳輸管理模塊解析消息,並且把解析的數據結構存放在緩沖區中,把消息傳遞到endpoint.
Endpoint 分發接收的消息到每一個注冊模塊,調用on_rx_request和on_rx_response的回調。從高優先級的模塊開始,直到有一個模塊返回非0。當模塊返回非0時, endpoint 不再發送消息到剩余的模塊,因為它假定這個模塊關心該消息的處理。
處理消息的模塊可能分發消息到其他模塊,舉例:事務模塊接收到匹配的消息,處理該消息然后再分發到其他到事務用戶(本身也是一個模塊)。Transction傳遞消息,通過回調 on_rx_request 和 on_rx_response 傳遞消息到transction user,在設置transction接收緩沖區以便transction user模塊能其區分transction內部消息和外部消息。
下圖顯示模塊的如何重疊調用其他的模塊
2.1.4 模塊處理呼出消息
出去的請求和響應消息由transmit data buffer(pjsip_tx_data)處理,包含了消息結構體本身、內存池、連續的buffer 和 transport info。
Pjsip_transport_send( ) 被調用發送一個消息,transport manager 調用on_tx_request 或 on_tx_response 為所有的模塊,處理順序是優先級的低先接收消息。當回調被調用時,消息可能已經或還沒有被transport layer處理。Transport layer 主要負責管理transimit buffer。
l Transport info
l 打印結構和連續 buffer的結構體
低於PJSIP_MOD_PRIORITY_TRANSPORT_LAYER優先級的模塊,將會接收消息,在這些信息被獲取到之前,這就意味着目標地址沒有被計算出來並且消息還沒有被輸出到連續buffer。
如果模塊准備改變消息結構體在打印buffer之前,他一定設置他的優先級高於transport layer的優先級,如果模塊先看真實的packet bytes,再它被傳送到網絡之前,它應該設置優先級低於transport layer。
在所有的情況下,模塊一定要返回PJ_SUCCESS. 如果模塊返回錯誤碼,transmission 將被取消,並且錯誤碼將會返回到調用者pjsip_transport_send.
2.1.5 事務用戶及狀態回調
回調函數on_tsx_state被用來接收特定事務的通知,當事務狀態發生改變時,回調是唯一的通知路徑。但是transcation的事務改變也可能會因為非消息的事件引起的。比如:超時或者傳輸錯誤
當模塊注冊為事務用戶,才擁有這個回調,在一個事務中,只允許有一個事務用戶,transaction user 能夠被設置為事務再每一個transction基礎上。
在dialog創建的事務,transaction user 被設置為 UA layer 模塊,當應用程序手工創建事務時,他們作為事務用戶設置。
On_tsx_state回調收到retransmissions的request 和 response消息時,回調將不會再被調用。注意:發送和接收臨時的響應將不會被認為重傳。臨時消息的接收和重傳將會導致回調被調用。