Asterisk 1.8 sip 协议栈分析(2)
2013-08-26 12:53
330 查看
从handle_request_invite入口,invite请求此处处理replace请求头,如果为replace则认为是咨询,此时不会
创建新的通道,而是找到一个通道植入(masqued),大多数情况下是根据invite创建新的请求,所以此处我们从这里开始,不考虑咨询情况
首先检查此请求是否为重复请求,if (!req->ignore)
,接下来调用check_via检查via头域,这个函数涉及到nat穿越问题,此函数解析rport头域参数,如果via头域有rport=
,则设置标记此请求包含rport 域标志,同时检查maddr= 域是否存在,如果此处rport=存在则设置nat mode 为
nat,否则为no nat, 至此check_via结束。
返回 invite函数,这里 invite 有两种情况,一个为
call-id已经存在,则asterisk认为此请求是re-invite(!p->owner),否则认为是一个新的invite,关于re-
invite有很多故事,涉及到asterisk是b2bua还是proxy的问题,下面先讨论非 re-invite请求。
从打印信息看到
ast_verbose("Using INVITE request as basis request - %s/n",
p->callid);
Using INVITE request as basis request -
ZjRiYjZkYzYzZDNjNDRmMjhmMmNlNzdmODE4NTYzZmE.
如果开启sip history 可以看到会调用,
append_history(p, "Invite", "New call: %s",
p->callid);
接下来调用parse_ok_contact ()函数保存 此invite的contact头域,以备将来做响应(200
ok,bye, re-invite)
fullcontact 变量保存 全部cantact头域,用来做bye,re-invite,okcontacturi保存uri
of acks, bye, re-invite.
接下来调用 下面代码:
if (!p->lastinvite
&& !req->ignore
&& !p->owner)
{
// 全新invite
int cc_recall_core_id = -1;
set_pvt_allowed_methods(p, req);
res = check_user_full(p, req, SIP_INVITE, e,
XMIT_RELIABLE, addr, &authpeer);
if (res == AUTH_CHALLENGE_SENT) {
p->invitestate
= INV_COMPLETED;
res = 0;
goto
request_invite_cleanup;
}
对于第一次请求会做验证,调用check_user_full,下面分析一下此函数。
此函数用 请求的 from 头域 的usr name 和 peer的 ip/port做匹配,check_user_full
调用get_calleridname 从from头域分理出
callid_name,最终调用 check_peer_ok ,check_peer_ok内部查找 peer name 是否在
peers 链表中存在。这里先尝试用
from 头域中的 user name查找,找不到则用 ip/port查找。
这里找到后 输出如下。
if (debug)
ast_verbose("Found peer '%s' for '%s' from
%s/n",
peer->name, of,
ast_sockaddr_stringify(&p->recv));
Found peer '1501159973' for '1501159973' from
10.10.10.84:59584
然后 把peer 相关属性拷贝到为此peer创建的channle中,如
acc,language,amaflags。callgroup,fullcontact等,
设置定时器管理 事务。。。
接下来调用 dialog_initialize_rtp函数初始化此peer的rtp信息。
是否peer有RTP,有则设置编码。设置RTP 引擎,这里需要说明的是
asterisk1.8开始RTP协议栈改动很大,默认使用Asteirsk提供的rtp协议栈,开发者可以自己嵌入其他rtp协议栈。
设置完协议栈后设置此peer 建立rtp会话的默认编码规则。
Found peer '1501159973' for '1501159973' from
10.10.10.84:59584
[Dec 21 15:30:13] DEBUG[28437]: rtp_engine.c:344
ast_rtp_instance_new: Using engine 'asterisk' for RTP instance
'0xc1c0078'
[Dec 21 15:30:13] DEBUG[28437]: res_rtp_asterisk.c:472 ast_rtp_new:
Allocated port 18084 for RTP instance '0xc1c0078'
[Dec 21 15:30:13] DEBUG[28437]: rtp_engine.c:353
ast_rtp_instance_new: RTP instance '0xc1c0078' is setup and ready
to go
[Dec 21 15:30:13] DEBUG[28437]: res_rtp_asterisk.c:2370
ast_rtp_prop_set: Setup RTCP on RTP instance '0xc1c0078'
此处路线:
check_peer_ok->dialog_initialize_rtp->ast_rtp_instance_new->ast_rtp_instance_set_timeout
ast_rtp_instance_set_hold_timeout
ast_rtp_instance_set_prop
ast_rtp_instance_set_qos
do_setnat
上面为一些列调用过程,初始化此peer的RTP信息,包括 qos,nat
mode,rtcp,dtmf几项任务。check_peer_ok函数做了很多工作哇。。。。
至此 验证通过,RTP信息也初始化完毕,返回 handl_request_invite函数 ,开始处理 SDP啦。。。。
if (find_sdp(req)) {
if (process_sdp(p, req, SDP_T38_INITIATE)) {
if
(!ast_strlen_zero(get_header(req, "Content-Encoding"))) {
transmit_response_reliable(p, "415 Unsupported Media type",
req);
} else
{
transmit_response_reliable(p, "488 Not acceptable here",
req);
}
。。。。
可以看到,开始处理SDP...
首先当然是从invite请求中找sdp 了,,调用find_sdp (),
static int find_sdp(struct sip_request *req)
此处当然是找到了。。
调用 process_sdp 处理SDP,
static int process_sdp(struct sip_pvt *p, struct sip_request *req,
int t38action)
解析SDP包头。。。
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8197 process_sdp:
Processing session-level SDP v=0... UNSUPPORTED.
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8197 process_sdp:
Processing session-level SDP o=- 0 2 IN IP4 10.10.10.84...
UNSUPPORTED.
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8197 process_sdp:
Processing session-level SDP s=CounterPath X-Lite 3.0...
UNSUPPORTED.
[Dec 21 15:30:13] DEBUG[28437]: netsock2.c:125
ast_sockaddr_split_hostport: Splitting '10.10.10.84' gives...
[Dec 21 15:30:13] DEBUG[28437]: netsock2.c:155
ast_sockaddr_split_hostport: ...host '10.10.10.84' and port
'(null)'.
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8197 process_sdp:
Processing session-level SDP c=IN IP4 10.10.10.84... OK.
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8197 process_sdp:
Processing session-level SDP t=0 0... UNSUPPORTED.
首先扫描 m=头域,media stream
这里包含一些SDP 信息,解释如下
SDP Data from Example SDP Parameter
Parameter Name
v=0
Version number
o=Tesla 2890844526 2890844526 IN IP4 lab.high-voltage.org
Origin containing name
s=Phone Call
Subject
c=IN IP4 100.101.102.103
Connection
t=0 0
Time
m=audio 49170 RTP/AVP 0
Media
a=rtpmap:0 PCMU/8000
Attributes
•Connection IP address (100.101.102.103);
•Media format (audio);
•Port number (49170);
•Media transport protocol (RTP);
•Media encoding (PCM μ Law);
•Sampling rate (8,000 Hz).
每个SDP头域包含 m,o,c,等对不同SDP头域的处理,
每种类型调用 process_sdp_类型 函数处理,
如 连接地址 处理函数process_sdp_c,这里最重要的是
process_sdp_a_媒体类型,此函数处理SDP包的属性,如音频,则为
process_sdp_a_audio,关于SDP处理的核心位置都在这个函数中。。。process_sdp根据SDP包属性(媒体编码类型)匹配支持的编码类型。
[Dec 21 15:30:13] DEBUG[28437]: rtp_engine.c:535
ast_rtp_codecs_payloads_set_m_type: Setting payload 98 based on m
type on 0xb7b30490
Found RTP audio format 8
[Dec 21 15:30:13] DEBUG[28437]: rtp_engine.c:535
ast_rtp_codecs_payloads_set_m_type: Setting payload 8 based on m
type on 0xb7b30490
Found RTP audio format 101
[Dec 21 15:30:13] DEBUG[28437]: rtp_engine.c:535
ast_rtp_codecs_payloads_set_m_type: Setting payload 101 based on m
type on 0xb7b30490
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8384 process_sdp:
Processing media-level (audio) SDP a=alt:1 1 : Bwd30+5D C9DdG2tq
10.10.10.84 50946... UNSUPPORTED.
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8384 process_sdp:
Processing media-level (audio) SDP a=fmtp:101 0-15...
UNSUPPORTED.
Found audio description format BV32 for ID 107
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8384 process_sdp:
Processing media-level (audio) SDP a=rtpmap:107 BV32/16000...
OK.
Found audio description format BV32-FEC for ID 119
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8384 process_sdp:
Processing media-level (audio) SDP a=rtpmap:119 BV32-FEC/16000...
OK.
Found audio description format SPEEX for ID 100
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8384 process_sdp:
Processing media-level (audio) SDP a=rtpmap:100 SPEEX/16000...
OK.
Found audio description format SPEEX-FEC for ID 106
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8384 process_sdp:
Processing media-level (audio) SDP a=rtpmap:106 SPEEX-FEC/16000...
OK.
Found audio description format SPEEX-FEC for ID 105
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8384 process_sdp:
Processing media-level (audio) SDP a=rtpmap:105 SPEEX-FEC/8000...
OK.
Found audio description format iLBC for ID 98
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8384 process_sdp:
Processing media-level (audio) SDP a=rtpmap:98 iLBC/8000...
OK.
Found audio description format telephone-event for ID 101
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8384 process_sdp:
Processing media-level (audio) SDP a=rtpmap:101
telephone-event/8000... OK.
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8384 process_sdp:
Processing media-level (audio) SDP a=sendrecv... OK.
至此,关于此peer的 SDP信息及 RTP信息都已初始化完毕。
回到 handle_request_invite()
ast_debug(1, "Checking SIP call limits for
device %s/n", p->username);
开始 检查 peer的 call-limit
如果此peer达到 上限,则返回 480 Temporarily Unavailable (Call
limit)响应。。。所以当调试时返回此响应我们应该猜测到 此设备已经达到并发上限。。。。
接下来 调用get_destination(),我们得给此请求 送到哪????
此函数用 invite请求的 to 头域 作为请求地址,
根据请求的peer name@ip
查找请求的peerr是否在我这check_sip_domain()。。。找不到则到dialplan中查找。。。。。
if
(!ast_test_flag(&p->flags[1],
SIP_PAGE2_HAVEPEERCONTEXT) &&
!ast_strlen_zero(domain_context)) {
ast_string_field_set(p,
context, domain_context);
}
这里是当 我们在sip config 里设置润许guest invite时设置 context为默认。。
当在dialplan中找到对应分机时我们得给此SIP 请求 创建 channle啦。。
调用 sip_new()...这里,sip_new函数是真正创建sip通道的地方,此函数
在呼入请求,及外呼请求时调用,分别为函数
sip_request_call及handle_request_invite函数。。。
sip_new函用 sip_pvt结构创建sip structuer, 设置此通道的编码类型,dtfm, caller
id等信息。。。
调用ast_channel_alloc 宏(channel.c)创建sip
channle,创建细节在__ast_channel_alloc_ap 函数中,channle的分配用
ao2_alloc函数,同时指定了析构函数释放通道,申请channel内存后设置
管道句柄初始状态,创建此channle调度器上下文,
1.8新增了 caller party information
统计信息,所以此处先初始化这些结构,接下来申请channle无名管道,
if (pipe(tmp->alertpipe)) {
ast_log(LOG_WARNING, "Channel
allocation failed: Can't create alert pipe! Try increasing max file
descriptors with ulimit -n/n");
return
ast_channel_unref(tmp);
} else {
flags =
fcntl(tmp->alertpipe[0], F_GETFL);
if
(fcntl(tmp->alertpipe[0], F_SETFL, flags |
O_NONBLOCK) < 0) {
ast_log(LOG_WARNING, "Channel allocation failed: Unable to set
alertpipe nonblocking! (%d: %s)/n", errno, strerror(errno));
return
ast_channel_unref(tmp);
}
flags =
fcntl(tmp->alertpipe[1], F_GETFL);
if
(fcntl(tmp->alertpipe[1], F_SETFL, flags |
O_NONBLOCK) < 0) {
ast_log(LOG_WARNING, "Channel allocation failed: Unable to set
alertpipe nonblocking! (%d: %s)/n", errno, strerror(errno));
return
ast_channel_unref(tmp);
}
}
把创建的管道加入fd列表监听。。。。这里channle fd数量是有限制的,默认一个channle最大10个。
ast_channel_set_fd(tmp, AST_ALERT_FD,
tmp->alertpipe[0]);
ast_channel_set_fd(tmp, AST_TIMING_FD,
tmp->timingfd);
接下来初始化uniqueid,linkeid,这里uniqueid
最大150个字符,包括系统名字(最大127)+unix时间戳+递增序列。。。
初始化channle的amaflags,accountcode,context以便于计费使用(cdr)。
接下来 开始 分配此 channle cdr 结构并初始化。。
tmp->cdr = ast_cdr_alloc();// 分配
ast_cdr_init(tmp->cdr,
tmp);//初始化
ast_cdr_start(tmp->cdr); //设置起始
时间,,,cdr->start..
ast_cel_report_event(tmp,
AST_CEL_CHANNEL_START, NULL, NULL, NULL);// cdel引擎启动。。发channle
start事件。。
1.8多了个CEL ,也是在这里 初始化。。把channle放到 channles 容内部器。。
channle建立完毕,,,发送ami事件 Newchannel。。完毕后返回 创建channle 到sip_new
sip为一种通道类型,实际创建为channle.c中的ast_channle 结构,此结构为众多通道的接口层,。。
这里 设置
SIPURI,SIPDOMAIN,parkinglot,accountcode,language,等全局数据,初始化 fd
事件,值得注意的是 asterisk 1.8中 支持了 epoll
异步Io,在一些情况下对系统的并发应该提高很多。
接下来 SIP_new 对于有rtp的peer,则初始化 jt引擎(rtp 抖动),
然后,此函数调用 Ast_pbx_start进入Asterisk内核。。。。ast_pbx_start
启动新的线程处理此channle..
返回后,调用build_route(),记录 record_Route头域,此处作用是记录路由路径作为未来的请求。
ast_debug(2, "%s: New call is still down.... Trying... /n",
c->name);
至此,channle 已经建立完成,发个临时响应吧。。。transmit_provisional_response(p,
"100 Trying", req, 0);
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:21609
handle_request_invite: SIP/1501159973-0000000b: New call is still
down.... Trying..
<--- Transmitting (no NAT) to 10.10.10.84:59584
--->
SIP/2.0 100 Trying
Via: SIP/2.0/UDP
10.10.10.84:59584;branch=z9hG4bK-d87543-7c6375234a299e1c-1--d87543-;received=10.10.10.84;rport=59584
From:
"1501159973"<sip:1501159973@10.10.10.182>;tag=e648a101
To: "6969
(Softphone)"<sip:6969@10.10.10.182>
Call-ID: ZjRiYjZkYzYzZDNjNDRmMjhmMmNlNzdmODE4NTYzZmE.
CSeq: 2 INVITE
Server: Asterisk PBX 1.8.2-rc1
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY,
INFO, PUBLISH
Supported: replaces, timer
Contact:
<sip:6969@10.10.10.182:5060>
Content-Length: 0
这里,我们可以看到,via头域多了一个received及rport有值了,解决nat穿透。。。
同时记住 100 trying没有 sdp信息。。 调用 顺
序,sip_xmit<-send_response<--transmit_response<---transmit_provisional_response<--Handle_request_response.
接下来 执行 dialplan.......至此 一次呼入系统的请求 基本完成
创建新的通道,而是找到一个通道植入(masqued),大多数情况下是根据invite创建新的请求,所以此处我们从这里开始,不考虑咨询情况
首先检查此请求是否为重复请求,if (!req->ignore)
,接下来调用check_via检查via头域,这个函数涉及到nat穿越问题,此函数解析rport头域参数,如果via头域有rport=
,则设置标记此请求包含rport 域标志,同时检查maddr= 域是否存在,如果此处rport=存在则设置nat mode 为
nat,否则为no nat, 至此check_via结束。
返回 invite函数,这里 invite 有两种情况,一个为
call-id已经存在,则asterisk认为此请求是re-invite(!p->owner),否则认为是一个新的invite,关于re-
invite有很多故事,涉及到asterisk是b2bua还是proxy的问题,下面先讨论非 re-invite请求。
从打印信息看到
ast_verbose("Using INVITE request as basis request - %s/n",
p->callid);
Using INVITE request as basis request -
ZjRiYjZkYzYzZDNjNDRmMjhmMmNlNzdmODE4NTYzZmE.
如果开启sip history 可以看到会调用,
append_history(p, "Invite", "New call: %s",
p->callid);
接下来调用parse_ok_contact ()函数保存 此invite的contact头域,以备将来做响应(200
ok,bye, re-invite)
fullcontact 变量保存 全部cantact头域,用来做bye,re-invite,okcontacturi保存uri
of acks, bye, re-invite.
接下来调用 下面代码:
if (!p->lastinvite
&& !req->ignore
&& !p->owner)
{
// 全新invite
int cc_recall_core_id = -1;
set_pvt_allowed_methods(p, req);
res = check_user_full(p, req, SIP_INVITE, e,
XMIT_RELIABLE, addr, &authpeer);
if (res == AUTH_CHALLENGE_SENT) {
p->invitestate
= INV_COMPLETED;
res = 0;
goto
request_invite_cleanup;
}
对于第一次请求会做验证,调用check_user_full,下面分析一下此函数。
此函数用 请求的 from 头域 的usr name 和 peer的 ip/port做匹配,check_user_full
调用get_calleridname 从from头域分理出
callid_name,最终调用 check_peer_ok ,check_peer_ok内部查找 peer name 是否在
peers 链表中存在。这里先尝试用
from 头域中的 user name查找,找不到则用 ip/port查找。
这里找到后 输出如下。
if (debug)
ast_verbose("Found peer '%s' for '%s' from
%s/n",
peer->name, of,
ast_sockaddr_stringify(&p->recv));
Found peer '1501159973' for '1501159973' from
10.10.10.84:59584
然后 把peer 相关属性拷贝到为此peer创建的channle中,如
acc,language,amaflags。callgroup,fullcontact等,
设置定时器管理 事务。。。
接下来调用 dialog_initialize_rtp函数初始化此peer的rtp信息。
是否peer有RTP,有则设置编码。设置RTP 引擎,这里需要说明的是
asterisk1.8开始RTP协议栈改动很大,默认使用Asteirsk提供的rtp协议栈,开发者可以自己嵌入其他rtp协议栈。
设置完协议栈后设置此peer 建立rtp会话的默认编码规则。
Found peer '1501159973' for '1501159973' from
10.10.10.84:59584
[Dec 21 15:30:13] DEBUG[28437]: rtp_engine.c:344
ast_rtp_instance_new: Using engine 'asterisk' for RTP instance
'0xc1c0078'
[Dec 21 15:30:13] DEBUG[28437]: res_rtp_asterisk.c:472 ast_rtp_new:
Allocated port 18084 for RTP instance '0xc1c0078'
[Dec 21 15:30:13] DEBUG[28437]: rtp_engine.c:353
ast_rtp_instance_new: RTP instance '0xc1c0078' is setup and ready
to go
[Dec 21 15:30:13] DEBUG[28437]: res_rtp_asterisk.c:2370
ast_rtp_prop_set: Setup RTCP on RTP instance '0xc1c0078'
此处路线:
check_peer_ok->dialog_initialize_rtp->ast_rtp_instance_new->ast_rtp_instance_set_timeout
ast_rtp_instance_set_hold_timeout
ast_rtp_instance_set_prop
ast_rtp_instance_set_qos
do_setnat
上面为一些列调用过程,初始化此peer的RTP信息,包括 qos,nat
mode,rtcp,dtmf几项任务。check_peer_ok函数做了很多工作哇。。。。
至此 验证通过,RTP信息也初始化完毕,返回 handl_request_invite函数 ,开始处理 SDP啦。。。。
if (find_sdp(req)) {
if (process_sdp(p, req, SDP_T38_INITIATE)) {
if
(!ast_strlen_zero(get_header(req, "Content-Encoding"))) {
transmit_response_reliable(p, "415 Unsupported Media type",
req);
} else
{
transmit_response_reliable(p, "488 Not acceptable here",
req);
}
。。。。
可以看到,开始处理SDP...
首先当然是从invite请求中找sdp 了,,调用find_sdp (),
static int find_sdp(struct sip_request *req)
此处当然是找到了。。
调用 process_sdp 处理SDP,
static int process_sdp(struct sip_pvt *p, struct sip_request *req,
int t38action)
解析SDP包头。。。
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8197 process_sdp:
Processing session-level SDP v=0... UNSUPPORTED.
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8197 process_sdp:
Processing session-level SDP o=- 0 2 IN IP4 10.10.10.84...
UNSUPPORTED.
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8197 process_sdp:
Processing session-level SDP s=CounterPath X-Lite 3.0...
UNSUPPORTED.
[Dec 21 15:30:13] DEBUG[28437]: netsock2.c:125
ast_sockaddr_split_hostport: Splitting '10.10.10.84' gives...
[Dec 21 15:30:13] DEBUG[28437]: netsock2.c:155
ast_sockaddr_split_hostport: ...host '10.10.10.84' and port
'(null)'.
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8197 process_sdp:
Processing session-level SDP c=IN IP4 10.10.10.84... OK.
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8197 process_sdp:
Processing session-level SDP t=0 0... UNSUPPORTED.
首先扫描 m=头域,media stream
这里包含一些SDP 信息,解释如下
SDP Data from Example SDP Parameter
Parameter Name
v=0
Version number
o=Tesla 2890844526 2890844526 IN IP4 lab.high-voltage.org
Origin containing name
s=Phone Call
Subject
c=IN IP4 100.101.102.103
Connection
t=0 0
Time
m=audio 49170 RTP/AVP 0
Media
a=rtpmap:0 PCMU/8000
Attributes
•Connection IP address (100.101.102.103);
•Media format (audio);
•Port number (49170);
•Media transport protocol (RTP);
•Media encoding (PCM μ Law);
•Sampling rate (8,000 Hz).
每个SDP头域包含 m,o,c,等对不同SDP头域的处理,
每种类型调用 process_sdp_类型 函数处理,
如 连接地址 处理函数process_sdp_c,这里最重要的是
process_sdp_a_媒体类型,此函数处理SDP包的属性,如音频,则为
process_sdp_a_audio,关于SDP处理的核心位置都在这个函数中。。。process_sdp根据SDP包属性(媒体编码类型)匹配支持的编码类型。
[Dec 21 15:30:13] DEBUG[28437]: rtp_engine.c:535
ast_rtp_codecs_payloads_set_m_type: Setting payload 98 based on m
type on 0xb7b30490
Found RTP audio format 8
[Dec 21 15:30:13] DEBUG[28437]: rtp_engine.c:535
ast_rtp_codecs_payloads_set_m_type: Setting payload 8 based on m
type on 0xb7b30490
Found RTP audio format 101
[Dec 21 15:30:13] DEBUG[28437]: rtp_engine.c:535
ast_rtp_codecs_payloads_set_m_type: Setting payload 101 based on m
type on 0xb7b30490
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8384 process_sdp:
Processing media-level (audio) SDP a=alt:1 1 : Bwd30+5D C9DdG2tq
10.10.10.84 50946... UNSUPPORTED.
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8384 process_sdp:
Processing media-level (audio) SDP a=fmtp:101 0-15...
UNSUPPORTED.
Found audio description format BV32 for ID 107
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8384 process_sdp:
Processing media-level (audio) SDP a=rtpmap:107 BV32/16000...
OK.
Found audio description format BV32-FEC for ID 119
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8384 process_sdp:
Processing media-level (audio) SDP a=rtpmap:119 BV32-FEC/16000...
OK.
Found audio description format SPEEX for ID 100
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8384 process_sdp:
Processing media-level (audio) SDP a=rtpmap:100 SPEEX/16000...
OK.
Found audio description format SPEEX-FEC for ID 106
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8384 process_sdp:
Processing media-level (audio) SDP a=rtpmap:106 SPEEX-FEC/16000...
OK.
Found audio description format SPEEX-FEC for ID 105
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8384 process_sdp:
Processing media-level (audio) SDP a=rtpmap:105 SPEEX-FEC/8000...
OK.
Found audio description format iLBC for ID 98
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8384 process_sdp:
Processing media-level (audio) SDP a=rtpmap:98 iLBC/8000...
OK.
Found audio description format telephone-event for ID 101
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8384 process_sdp:
Processing media-level (audio) SDP a=rtpmap:101
telephone-event/8000... OK.
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:8384 process_sdp:
Processing media-level (audio) SDP a=sendrecv... OK.
至此,关于此peer的 SDP信息及 RTP信息都已初始化完毕。
回到 handle_request_invite()
ast_debug(1, "Checking SIP call limits for
device %s/n", p->username);
开始 检查 peer的 call-limit
如果此peer达到 上限,则返回 480 Temporarily Unavailable (Call
limit)响应。。。所以当调试时返回此响应我们应该猜测到 此设备已经达到并发上限。。。。
接下来 调用get_destination(),我们得给此请求 送到哪????
此函数用 invite请求的 to 头域 作为请求地址,
根据请求的peer name@ip
查找请求的peerr是否在我这check_sip_domain()。。。找不到则到dialplan中查找。。。。。
if
(!ast_test_flag(&p->flags[1],
SIP_PAGE2_HAVEPEERCONTEXT) &&
!ast_strlen_zero(domain_context)) {
ast_string_field_set(p,
context, domain_context);
}
这里是当 我们在sip config 里设置润许guest invite时设置 context为默认。。
当在dialplan中找到对应分机时我们得给此SIP 请求 创建 channle啦。。
调用 sip_new()...这里,sip_new函数是真正创建sip通道的地方,此函数
在呼入请求,及外呼请求时调用,分别为函数
sip_request_call及handle_request_invite函数。。。
sip_new函用 sip_pvt结构创建sip structuer, 设置此通道的编码类型,dtfm, caller
id等信息。。。
调用ast_channel_alloc 宏(channel.c)创建sip
channle,创建细节在__ast_channel_alloc_ap 函数中,channle的分配用
ao2_alloc函数,同时指定了析构函数释放通道,申请channel内存后设置
管道句柄初始状态,创建此channle调度器上下文,
1.8新增了 caller party information
统计信息,所以此处先初始化这些结构,接下来申请channle无名管道,
if (pipe(tmp->alertpipe)) {
ast_log(LOG_WARNING, "Channel
allocation failed: Can't create alert pipe! Try increasing max file
descriptors with ulimit -n/n");
return
ast_channel_unref(tmp);
} else {
flags =
fcntl(tmp->alertpipe[0], F_GETFL);
if
(fcntl(tmp->alertpipe[0], F_SETFL, flags |
O_NONBLOCK) < 0) {
ast_log(LOG_WARNING, "Channel allocation failed: Unable to set
alertpipe nonblocking! (%d: %s)/n", errno, strerror(errno));
return
ast_channel_unref(tmp);
}
flags =
fcntl(tmp->alertpipe[1], F_GETFL);
if
(fcntl(tmp->alertpipe[1], F_SETFL, flags |
O_NONBLOCK) < 0) {
ast_log(LOG_WARNING, "Channel allocation failed: Unable to set
alertpipe nonblocking! (%d: %s)/n", errno, strerror(errno));
return
ast_channel_unref(tmp);
}
}
把创建的管道加入fd列表监听。。。。这里channle fd数量是有限制的,默认一个channle最大10个。
ast_channel_set_fd(tmp, AST_ALERT_FD,
tmp->alertpipe[0]);
ast_channel_set_fd(tmp, AST_TIMING_FD,
tmp->timingfd);
接下来初始化uniqueid,linkeid,这里uniqueid
最大150个字符,包括系统名字(最大127)+unix时间戳+递增序列。。。
初始化channle的amaflags,accountcode,context以便于计费使用(cdr)。
接下来 开始 分配此 channle cdr 结构并初始化。。
tmp->cdr = ast_cdr_alloc();// 分配
ast_cdr_init(tmp->cdr,
tmp);//初始化
ast_cdr_start(tmp->cdr); //设置起始
时间,,,cdr->start..
ast_cel_report_event(tmp,
AST_CEL_CHANNEL_START, NULL, NULL, NULL);// cdel引擎启动。。发channle
start事件。。
1.8多了个CEL ,也是在这里 初始化。。把channle放到 channles 容内部器。。
channle建立完毕,,,发送ami事件 Newchannel。。完毕后返回 创建channle 到sip_new
sip为一种通道类型,实际创建为channle.c中的ast_channle 结构,此结构为众多通道的接口层,。。
这里 设置
SIPURI,SIPDOMAIN,parkinglot,accountcode,language,等全局数据,初始化 fd
事件,值得注意的是 asterisk 1.8中 支持了 epoll
异步Io,在一些情况下对系统的并发应该提高很多。
接下来 SIP_new 对于有rtp的peer,则初始化 jt引擎(rtp 抖动),
然后,此函数调用 Ast_pbx_start进入Asterisk内核。。。。ast_pbx_start
启动新的线程处理此channle..
返回后,调用build_route(),记录 record_Route头域,此处作用是记录路由路径作为未来的请求。
ast_debug(2, "%s: New call is still down.... Trying... /n",
c->name);
至此,channle 已经建立完成,发个临时响应吧。。。transmit_provisional_response(p,
"100 Trying", req, 0);
[Dec 21 15:30:13] DEBUG[28437]: chan_sip.c:21609
handle_request_invite: SIP/1501159973-0000000b: New call is still
down.... Trying..
<--- Transmitting (no NAT) to 10.10.10.84:59584
--->
SIP/2.0 100 Trying
Via: SIP/2.0/UDP
10.10.10.84:59584;branch=z9hG4bK-d87543-7c6375234a299e1c-1--d87543-;received=10.10.10.84;rport=59584
From:
"1501159973"<sip:1501159973@10.10.10.182>;tag=e648a101
To: "6969
(Softphone)"<sip:6969@10.10.10.182>
Call-ID: ZjRiYjZkYzYzZDNjNDRmMjhmMmNlNzdmODE4NTYzZmE.
CSeq: 2 INVITE
Server: Asterisk PBX 1.8.2-rc1
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY,
INFO, PUBLISH
Supported: replaces, timer
Contact:
<sip:6969@10.10.10.182:5060>
Content-Length: 0
这里,我们可以看到,via头域多了一个received及rport有值了,解决nat穿透。。。
同时记住 100 trying没有 sdp信息。。 调用 顺
序,sip_xmit<-send_response<--transmit_response<---transmit_provisional_response<--Handle_request_response.
接下来 执行 dialplan.......至此 一次呼入系统的请求 基本完成
相关文章推荐
- Asterisk 1.8 sip 协议栈分析(1)…
- asterisk chan_sip.c代码分析(转…
- Asterisk 1.8 sip 协议栈分析 2
- Asterisk 1.8 sip 协议栈分析
- Asterisk 1.8 sip 协议栈分析
- Asterisk 1.8 sip 协议栈分析(1)
- Asterisk 1.8 sip 协议栈分析(2)
- Asterisk 1.8 sip 协议栈分析(一)
- USB协议深入分析 设备描述符配置包…
- SD 卡驱动程序分析
- Nios II的Boot过程分析(转载)
- 使用 class-dump-z 分析支付宝 App
- Web App框架发展趋势及现状分析
- Doubango voip 框架分析之tinysip 协议栈
- Ubuntu&nbsp;init启动流程分析
- Linux&nbsp;sar分析网卡流量
- asterisk chan_sip.c代码分析 分享
- USB 协议分析 设置USB地址 和 配置…
- S3C6410的启动代码分析 一
- mysqlsla 分析mysql慢查询日志