学习笔记9中对SIP消息如何从传输层获得,又如何从传输层发送出去有了一个大致的了解
SIP消息从传输层到 pjsip_endpoint的两个重要接口, 实际上是两个回调函数:
1) mgr->on_rx_msg(mgr->endpt, PJ_SUCCESS, rdata)
2) mgr->on_tx_msg(mgr->endpt, PJ_SUCCESS, rdata)
pjsip_endpoint是SIP协议栈的调度器,下面分析SIP消息协议栈是如何驱动SIP协议栈栈工作的。
一) SIP incoming消息预处理
SIP数据到来时,udp_on_read_complete调用抽象层pjsip_tpmgr_receive_packet()对数据进行SIP解析处理。
pjsip_tpmgr_receive_packet 入口参数为struct pjsip_rx_data*, 结构体定义如下:
struct pjsip_rx_data
{
struct {
pj_pool_t *pool;
pjsip_transport *transport;
void *tp_data;
pjsip_rx_data_op_key op_key;
} tp_info; //-------------------用户套接子数据接收阶段,传输层标识区
struct{
pj_time_val timestamp;
char packet[PJSIP_MAX_PKT_LEN];
pj_uint32_t zero;
pj_ssize_t len;
pj_sockaddr src_addr;
int src_addr_len;
char src_name[PJ_INET6_ADDRSTRLEN];
int src_port;
} pkt_info;//-------------------incoming 消息的原始数据缓存区, 包括数据来源, 接收时间
struct {
char *msg_buf; /** Start of msg buffer. */
int len; /** Length fo message. */
pjsip_msg *msg; //msg = pjsip_parse_rdata( current_pkt, msg_fragment_size, rdata);
/** Short description about the message.
* Application should use #pjsip_rx_data_get_info() instead.
*/
char *info;
pjsip_cid_hdr *cid; /** The Call-ID header as found in the message. */
pjsip_from_hdr *from; /** The From header as found in the message. */
pjsip_to_hdr *to; /** The To header as found in the message. */
pjsip_via_hdr *via; /** The topmost Via header as found in the message. */
pjsip_cseq_hdr *cseq; /** The CSeq header as found in the message. */
pjsip_max_fwd_hdr *max_fwd; /** Max forwards header. */
pjsip_route_hdr *route; /** The first route header. */
pjsip_rr_hdr *record_route;/** The first record-route header. */
pjsip_ctype_hdr *ctype; /** Content-type header. */
pjsip_clen_hdr *clen; /** Content-length header. */
pjsip_require_hdr *require; /** "Require" header or NULL. */
pjsip_supported_hdr *supported; /** Supported headers found in the message, or NULL. */
pjsip_parser_err_report parse_err; /** The list of parser error */
} msg_info; //------------------SIP paraser 解析结果区
//endpt_info is initialized by endpoint after this buffer reaches endpoint.*/
struct {
void *mod_data[PJSIP_MAX_MODULE]; /** Data attached by modules to this message. */
} endpt_info; //----------------SIP协议栈木快信息
};
struct pjsip_rx_data内部定义了多个结构体, 用于SIP消息在协议栈的处理的不同阶段
pjsip_tpmgr_receive_packet()的SIP消息解析:
rdata->msg_info.msg = pjsip_parse_rdata( current_pkt, msg_fragment_size, rdata);
mgr->on_rx_msg(mgr->endpt, PJ_SUCCESS, rdata);
on_rx_msg回调函数指向sip_endpoint.c定义的endpt_on_rx_msg()
二) incoming SIP 消息处理机制
endpt_on_rx_msg() 函数中两段关于检查response消息的via头部的IP:port验证代码, 被注释掉了,原因也在注释中加以了说明, 可以帮助我们理解via头部
/* The RFC says that we should drop response when sent-by
* address mismatch. But it could happen (e.g. with SER) when
* endpoint with private IP is sending request to public
* server.
*/
/* Port or address mismatch, we should discard response */
/* But we saw one implementation (we don't want to name it to
* protect the innocence) which put wrong sent-by port although
* the "rport" parameter is correct.
* So we discard the response only if the port doesn't match
* both the port in sent-by and rport. We try to be lenient here!
*/
SIP消息协议栈的入口函数在这里:pjsip_endpt_process_rx_data(endpt, rdata, &proc_prm, &handled);
该函数主要代码摘抄如下:
PJ_DEF(pj_status_t) pjsip_endpt_process_rx_data( pjsip_endpoint *endpt, pjsip_rx_data *rdata,
pjsip_process_rdata_param *p,pj_bool_t *p_handled)
{
。。。
msg = rdata->msg_info.msg;
。。。
mod = endpt->module_list.next; //根据module_list定义的注释,module_list已经是进行了优先级排序
/* Distribute SIP协议栈的核心在这里*/
if (msg->type == PJSIP_REQUEST_MSG) {
do {
if (mod->on_rx_request)
handled = (*mod->on_rx_request)(rdata);
if (handled) break; //--------------------------注意当回调函数返回PJ_TRUE时间, SIP消息处理结束
mod = mod->next;
} while (mod != &endpt->module_list);
} else {
do {
if (mod->on_rx_response)
handled = (*mod->on_rx_response)(rdata);
if (handled) break;//--------------------------注意当回调函数返回PJ_TRUE时间, SIP消息处理结束
mod = mod->next;
} while (mod != &endpt->module_list);
}
。。。
}
可见, PJSIP使用预先排好优先级的模块链表,依次调用模块on_rx_request或on_rx_request处理收到SIP消息,模块采用统一的回调接口
三) outgoing SIP 消息处理机制
我们再来看看outgoing SIP 消息处理机制, 前面讲过:pjsip_transport_send()函数在数据进入套接字前,调用用on_tx_msg回调函数
on_tx_msg回调函数指向sip_endpoint.c定义的endpt_on_tx_msg(), 该函数主要代码摘录如下:
static pj_status_t endpt_on_tx_msg( pjsip_endpoint *endpt, pjsip_tx_data *tdata )
{
。。。
mod = endpt->module_list.prev;
if (tdata->msg->type == PJSIP_REQUEST_MSG) {
while (mod != &endpt->module_list) {
if (mod->on_tx_request)
status = (*mod->on_tx_request)(tdata);
if (status != PJ_SUCCESS) break; //--------------------------注意当回调函数返回PJ_TRUE时间, SIP消息处理结束
mod = mod->prev;
}
} else {
while (mod != &endpt->module_list) {
if (mod->on_tx_response)
status = (*mod->on_tx_response)(tdata);
if (status != PJ_SUCCESS) break;//--------------------------注意当回调函数返回PJ_SUCCESS时间, SIP消息处理结束
mod = mod->prev;
}
}
。。。
}
该函数按照module_list优先级逆序的方式, 调用模块的on_tx_request()/on_tx_response()回调接口
------ SIP传输层也被定义成一个模块,不过看模块名称字面意思,只是用来打印SIP消息,你可以在传输抽先层中找到on_tx_request()和on_tx_response()的回调接口,如下:
static pjsip_module mod_msg_print =
{
NULL, NULL, /* prev and next */
{ "mod-msg-print", 13}, /* Name. */
-1, /* Id */
PJSIP_MOD_PRIORITY_TRANSPORT_LAYER, /* Priority */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
NULL, /* unload() */
NULL, /* on_rx_request() */
NULL, /* on_rx_response() */
&mod_on_tx_msg, /* on_tx_request() */=========================在这里
&mod_on_tx_msg, /* on_tx_response() */=========================在这里
NULL, /* on_tsx_state() */
};
三) pjsip提供的模块, 参考以下来自于pjsip提供的例程simple_pjsua.c启动时的打印消息
11:03:13.594 sip_endpoint.c .Module "mod-msg-print" registered
11:03:13.594 sip_endpoint.c .Module "mod-pjsua-log" registered
11:03:13.594 sip_endpoint.c .Module "mod-tsx-layer" registered SIP事务层
11:03:13.594 sip_endpoint.c .Module "mod-stateful-util" registered SIP事务状态机
11:03:13.594 sip_endpoint.c .Module "mod-ua" registered SIP用户代理 libpjsip
11:03:13.594 sip_endpoint.c .Module "mod-100rel" registered //RFC3262,除100trying外的1XX消息如果带着100rel参数,对端会发PRACK进行中间状态的确认
11:03:13.594 sip_endpoint.c .Module "mod-pjsua" registered SIP 用户代理 libpjua
11:03:13.594 sip_endpoint.c .Module "mod-invite" registered SIP invite
11:03:13.595 sip_endpoint.c .Module "mod-evsub" registered
11:03:13.595 sip_endpoint.c .Module "mod-presence" registered
11:03:13.595 sip_endpoint.c .Module "mod-mwi" registered
11:03:13.595 sip_endpoint.c .Module "mod-refer" registered
11:03:13.595 sip_endpoint.c .Module "mod-pjsua-pres" registered
11:03:13.595 sip_endpoint.c .Module "mod-pjsua-im" registered
11:03:13.595 sip_endpoint.c .Module "mod-pjsua-options" registered
11:03:13.595 sip_endpoint.c .Module "mod-unsolicited-mwi" registered
MWI(Messege Waiting Indicator)通常情况下语音信箱或者其他形式的信息的声音或视频信号在等待时,比如不完整的语音,闪现的通话,震动产生的信号,周期性的特殊信号等等。
对于SIP MWI,它的实现是在NOTIFY方式下进行的。
SIP消息从传输层到 pjsip_endpoint的两个重要接口, 实际上是两个回调函数:
1) mgr->on_rx_msg(mgr->endpt, PJ_SUCCESS, rdata)
2) mgr->on_tx_msg(mgr->endpt, PJ_SUCCESS, rdata)
pjsip_endpoint是SIP协议栈的调度器,下面分析SIP消息协议栈是如何驱动SIP协议栈栈工作的。
一) SIP incoming消息预处理
SIP数据到来时,udp_on_read_complete调用抽象层pjsip_tpmgr_receive_packet()对数据进行SIP解析处理。
pjsip_tpmgr_receive_packet 入口参数为struct pjsip_rx_data*, 结构体定义如下:
struct pjsip_rx_data
{
struct {
pj_pool_t *pool;
pjsip_transport *transport;
void *tp_data;
pjsip_rx_data_op_key op_key;
} tp_info; //-------------------用户套接子数据接收阶段,传输层标识区
struct{
pj_time_val timestamp;
char packet[PJSIP_MAX_PKT_LEN];
pj_uint32_t zero;
pj_ssize_t len;
pj_sockaddr src_addr;
int src_addr_len;
char src_name[PJ_INET6_ADDRSTRLEN];
int src_port;
} pkt_info;//-------------------incoming 消息的原始数据缓存区, 包括数据来源, 接收时间
struct {
char *msg_buf; /** Start of msg buffer. */
int len; /** Length fo message. */
pjsip_msg *msg; //msg = pjsip_parse_rdata( current_pkt, msg_fragment_size, rdata);
/** Short description about the message.
* Application should use #pjsip_rx_data_get_info() instead.
*/
char *info;
pjsip_cid_hdr *cid; /** The Call-ID header as found in the message. */
pjsip_from_hdr *from; /** The From header as found in the message. */
pjsip_to_hdr *to; /** The To header as found in the message. */
pjsip_via_hdr *via; /** The topmost Via header as found in the message. */
pjsip_cseq_hdr *cseq; /** The CSeq header as found in the message. */
pjsip_max_fwd_hdr *max_fwd; /** Max forwards header. */
pjsip_route_hdr *route; /** The first route header. */
pjsip_rr_hdr *record_route;/** The first record-route header. */
pjsip_ctype_hdr *ctype; /** Content-type header. */
pjsip_clen_hdr *clen; /** Content-length header. */
pjsip_require_hdr *require; /** "Require" header or NULL. */
pjsip_supported_hdr *supported; /** Supported headers found in the message, or NULL. */
pjsip_parser_err_report parse_err; /** The list of parser error */
} msg_info; //------------------SIP paraser 解析结果区
//endpt_info is initialized by endpoint after this buffer reaches endpoint.*/
struct {
void *mod_data[PJSIP_MAX_MODULE]; /** Data attached by modules to this message. */
} endpt_info; //----------------SIP协议栈木快信息
};
struct pjsip_rx_data内部定义了多个结构体, 用于SIP消息在协议栈的处理的不同阶段
pjsip_tpmgr_receive_packet()的SIP消息解析:
rdata->msg_info.msg = pjsip_parse_rdata( current_pkt, msg_fragment_size, rdata);
mgr->on_rx_msg(mgr->endpt, PJ_SUCCESS, rdata);
on_rx_msg回调函数指向sip_endpoint.c定义的endpt_on_rx_msg()
二) incoming SIP 消息处理机制
endpt_on_rx_msg() 函数中两段关于检查response消息的via头部的IP:port验证代码, 被注释掉了,原因也在注释中加以了说明, 可以帮助我们理解via头部
/* The RFC says that we should drop response when sent-by
* address mismatch. But it could happen (e.g. with SER) when
* endpoint with private IP is sending request to public
* server.
*/
/* Port or address mismatch, we should discard response */
/* But we saw one implementation (we don't want to name it to
* protect the innocence) which put wrong sent-by port although
* the "rport" parameter is correct.
* So we discard the response only if the port doesn't match
* both the port in sent-by and rport. We try to be lenient here!
*/
SIP消息协议栈的入口函数在这里:pjsip_endpt_process_rx_data(endpt, rdata, &proc_prm, &handled);
该函数主要代码摘抄如下:
PJ_DEF(pj_status_t) pjsip_endpt_process_rx_data( pjsip_endpoint *endpt, pjsip_rx_data *rdata,
pjsip_process_rdata_param *p,pj_bool_t *p_handled)
{
。。。
msg = rdata->msg_info.msg;
。。。
mod = endpt->module_list.next; //根据module_list定义的注释,module_list已经是进行了优先级排序
/* Distribute SIP协议栈的核心在这里*/
if (msg->type == PJSIP_REQUEST_MSG) {
do {
if (mod->on_rx_request)
handled = (*mod->on_rx_request)(rdata);
if (handled) break; //--------------------------注意当回调函数返回PJ_TRUE时间, SIP消息处理结束
mod = mod->next;
} while (mod != &endpt->module_list);
} else {
do {
if (mod->on_rx_response)
handled = (*mod->on_rx_response)(rdata);
if (handled) break;//--------------------------注意当回调函数返回PJ_TRUE时间, SIP消息处理结束
mod = mod->next;
} while (mod != &endpt->module_list);
}
。。。
}
可见, PJSIP使用预先排好优先级的模块链表,依次调用模块on_rx_request或on_rx_request处理收到SIP消息,模块采用统一的回调接口
三) outgoing SIP 消息处理机制
我们再来看看outgoing SIP 消息处理机制, 前面讲过:pjsip_transport_send()函数在数据进入套接字前,调用用on_tx_msg回调函数
on_tx_msg回调函数指向sip_endpoint.c定义的endpt_on_tx_msg(), 该函数主要代码摘录如下:
static pj_status_t endpt_on_tx_msg( pjsip_endpoint *endpt, pjsip_tx_data *tdata )
{
。。。
mod = endpt->module_list.prev;
if (tdata->msg->type == PJSIP_REQUEST_MSG) {
while (mod != &endpt->module_list) {
if (mod->on_tx_request)
status = (*mod->on_tx_request)(tdata);
if (status != PJ_SUCCESS) break; //--------------------------注意当回调函数返回PJ_TRUE时间, SIP消息处理结束
mod = mod->prev;
}
} else {
while (mod != &endpt->module_list) {
if (mod->on_tx_response)
status = (*mod->on_tx_response)(tdata);
if (status != PJ_SUCCESS) break;//--------------------------注意当回调函数返回PJ_SUCCESS时间, SIP消息处理结束
mod = mod->prev;
}
}
。。。
}
该函数按照module_list优先级逆序的方式, 调用模块的on_tx_request()/on_tx_response()回调接口
------ SIP传输层也被定义成一个模块,不过看模块名称字面意思,只是用来打印SIP消息,你可以在传输抽先层中找到on_tx_request()和on_tx_response()的回调接口,如下:
static pjsip_module mod_msg_print =
{
NULL, NULL, /* prev and next */
{ "mod-msg-print", 13}, /* Name. */
-1, /* Id */
PJSIP_MOD_PRIORITY_TRANSPORT_LAYER, /* Priority */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
NULL, /* unload() */
NULL, /* on_rx_request() */
NULL, /* on_rx_response() */
&mod_on_tx_msg, /* on_tx_request() */=========================在这里
&mod_on_tx_msg, /* on_tx_response() */=========================在这里
NULL, /* on_tsx_state() */
};
三) pjsip提供的模块, 参考以下来自于pjsip提供的例程simple_pjsua.c启动时的打印消息
11:03:13.594 sip_endpoint.c .Module "mod-msg-print" registered
11:03:13.594 sip_endpoint.c .Module "mod-pjsua-log" registered
11:03:13.594 sip_endpoint.c .Module "mod-tsx-layer" registered SIP事务层
11:03:13.594 sip_endpoint.c .Module "mod-stateful-util" registered SIP事务状态机
11:03:13.594 sip_endpoint.c .Module "mod-ua" registered SIP用户代理 libpjsip
11:03:13.594 sip_endpoint.c .Module "mod-100rel" registered //RFC3262,除100trying外的1XX消息如果带着100rel参数,对端会发PRACK进行中间状态的确认
11:03:13.594 sip_endpoint.c .Module "mod-pjsua" registered SIP 用户代理 libpjua
11:03:13.594 sip_endpoint.c .Module "mod-invite" registered SIP invite
11:03:13.595 sip_endpoint.c .Module "mod-evsub" registered
11:03:13.595 sip_endpoint.c .Module "mod-presence" registered
11:03:13.595 sip_endpoint.c .Module "mod-mwi" registered
11:03:13.595 sip_endpoint.c .Module "mod-refer" registered
11:03:13.595 sip_endpoint.c .Module "mod-pjsua-pres" registered
11:03:13.595 sip_endpoint.c .Module "mod-pjsua-im" registered
11:03:13.595 sip_endpoint.c .Module "mod-pjsua-options" registered
11:03:13.595 sip_endpoint.c .Module "mod-unsolicited-mwi" registered
MWI(Messege Waiting Indicator)通常情况下语音信箱或者其他形式的信息的声音或视频信号在等待时,比如不完整的语音,闪现的通话,震动产生的信号,周期性的特殊信号等等。
对于SIP MWI,它的实现是在NOTIFY方式下进行的。