1. 代码简介:
Chan_sip.c是SIP协议(RFC3261)的实现代码,它没有实现对S/MIME, TCP and TLS的支持,对应的配置文件是sip.conf,代码所在的分组是:通道驱动类(channel_drivers)。
SIP通道处理各种类型的Sip sessions和dialogs(注意:并不是所有的dialogs都是“电话呼叫”),主要包括:
* - Incoming calls that will be sent to the PBX core
* - Outgoing calls, generated by the PBX
* - SIP subscriptions and notifications of states and voicemail messages
* - SIP registrations, both inbound and outbound
* - SIP peer management (peerpoke, OPTIONS)
* - SIP text messages
在SIP通道中,通常会有一列活跃的SIP dialogs,CLI下的命令sip show channels可以显示出大部分dialogs,除了订阅类的(它们可以用命令sip show subscriptions显示出来)。
CLI命令sip show channels的示例:
debian120*CLI> sip show channels
Peer User/ANR Call ID Seq (Tx/Rx) Form Hold Last Message
211.150.115.116 0132364499 51e8b037316 00102/00000 alaw No Init: INVITE
202.108.12.94 0000123456 76ad6e55-e0 00101/00001 alaw No Rx: ACK
211.150.115.116 0216252766 29df5b95633 00102/00000 alaw No Init: INVITE
202.108.12.94 0000123456 76ad6e55-2c 00101/00001 alaw No Rx: ACK
211.150.115.116 0137587006 720c5ecb32e 00102/00000 alaw No Tx: ACK
202.108.12.94 0000123456 76ad6e55-bf 00101/00001 alaw No Rx: ACK
211.150.115.116 0138797950 6d96c21a580 00102/00000 alaw No Tx: ACK
202.108.12.94 0000123456 76ad6e55-a5 00101/00001 alaw No Rx: ACK
211.150.115.116 0578708822 617679d2699 00102/00000 alaw No Tx: ACK
202.108.12.94 0000123456 76ad6e55-20 00101/00001 alaw No Rx: ACK
211.150.115.116 0512534057 6049a06e77d 00102/00000 alaw No Tx: ACK
202.108.12.94 0000123456 76ad6e55-b7 00101/00001 alaw No Rx: ACK
211.150.115.116 0132684273 4224f333507 00102/00000 alaw No Tx: ACK
202.108.12.94 0000123456 76ad6e55-95 00101/00001 alaw No Rx: ACK
2. 代码剖析:(注意:由于word自动更正某些代码中的首单词的首字母为大写,这儿可能与你在asterisk代码包中看到的代码不一致,请见谅)
chan_sip模块注册了load_module()函数作为asterisk在加载本模块时的入口函数。
17818 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Session Initiation Protocol (SIP)",
17819 .load = load_module,
17820 .unload = unload_module,
17821 .reload = reload,
17822 );
load_module()函数读取配置文件sip.conf,并且注册一个通道驱动类型,即sip,具体见sip_tech中的结构内容。
17696 if(reload_config(sip_reloadreason)) /* Load the configuration from sip.conf */
17697 return AST_MODULE_LOAD_DECLINE;
17698
17699 /* Make sure we can register our sip channel type */
17700 if (ast_channel_register(&sip_tech)) {
17701 ast_log(LOG_ERROR, "Unable to register channel type 'SIP'/n");
17702 io_context_destroy(io);
17703 sched_context_destroy(sched);
17704 return AST_MODULE_LOAD_FAILURE;
17705 }
Load_module最后调用restart_monitor()来启动sip监听。restart_monitor另外还有两处会被调用,在sip_request_call()和sip_reload()函数体内。
17735 /* And start the monitor for the first time */
17736 restart_monitor();
restart_monitor调用pthread接口启动一个独立的监听线程,线程id记录在monitor_thread,线程入口函数是do_monitor()
15399 if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
15400 ast_mutex_unlock(&monlock);
15401 ast_log(LOG_ERROR, "Unable to start monitor thread./n");
15402 return -1;
15403 }
do_monitor()给SIP UDP socket添加事件处理器,sipsock_read负责读取socket收到的数据。
15233 /* Add an I/O event to our SIP UDP socket */
15234 if (sipsock > -1)
15235 sipsock_read_id = ast_io_add(io, sipsock, sipsock_read, AST_IO_IN, NULL);
do_monitor ()函数然后进入一个for()循环中,这个循环不断检测是否需要reload sip模块,并且遍历sip session列表检查是否有需要kill的session。它是怎么遍历的呢?原来是chan_sip维护了一个sip_pvt结构的列表,头指针保存在全局变量iflist中,通过sip_pvt的next域进行遍历。每个sip_pvt结构记录了一个session的全部信息。
变量t表示现在的时间,sip->lastrtptx表示上次发送rtp包的时间,如果两者之差大于keep alive间隔,则说明需要发送keep alive包了。
15272 if (sip->lastrtptx &&
15273 ast_rtp_get_rtpkeepalive(sip->rtp) &&
15274 (t > sip->lastrtptx + ast_rtp_get_rtpkeepalive(sip->rtp))) {
15275 /* Need to send an empty RTP packet */
15276 sip->lastrtptx = time(NULL);
15277 ast_rtp_sendcng(sip->rtp, 0);
15278 }
变量t表示现在的时间,sip->lastrtprx表示上次收到rtp包的时间,如果两者之差大于rpt的timeout间隔,则说明已经超时了。
这两个超时参数可以在sip.conf中配置,分别如下:
rtptimeout=60
;rtpholdtimeout=300
15279 if (sip->lastrtprx &&
15280 (ast_rtp_get_rtptimeout(sip->rtp) ||ast_rtp_get_rtpholdtimeout(sip->rtp)) &&
15281 (t > sip->lastrtprx + ast_rtp_get_rtptimeout(sip->rtp))) {
15282 /* Might be a timeout now -- see if we're on hold */
此时再检测holdtimeout,并对channel上锁,ast_channel_trylock(sip->owner)。如果不是bridged channel,则调用soft hangup。
15301 /* Issue a softhangup */
15302 ast_softhangup_nolock(sip->owner,AST_SOFTHANGUP_DEV);
相关的重要数据结构:
sip_pvt: PVT structures are used for each SIP dialog, ie. a call, a registration, a subscribe
sip_pvt这个结构维护了一个sip session的重要数据信息,关键字段如下:
struct sip_pvt* next
Next dialog in chain。指向链上的下一个sip_pvt结构
struct ast_channel* owner
Who owns us (if we have an owner)。指向了拥有这个结构的通道的指针
struct sip_pkt* packets
Packets scheduled for re-transmission。维护待重传的sip packet
int pendinginvite
Any pending invite ? (seqno of this)。如果有等待的邀请包,则在这里记下这个包序号
struct ast_rtp* rtp
RTP Session,指向RTP Session的指针
int rtptimeout
RTP timeout time, RTP的超时时间
struct sockaddr_in sa
Our peer,对方的地址信息
char tag[11]
Our tag for this session,比如:tag=965531f1-52721549
现在回过头来把焦点转移到sipsock_read()函数。所有到来的sip包都在这里开始处理,在处理sip包期间,sipsock_read需要对sip的拥有者channel上锁,sipsock_read成功则返回0,失败则返回1。它解析sip包并且找到所在的dialog,或者创建新的dialog。并且把解析好的包交给handle_request()处理。
sipsock_read第一步接收socket数据,存到结构sip_request的data域中。
15062 res = recvfrom(sipsock, req.data, sizeof(req.data) - 1, 0, (structsockaddr *)&sin, &len);
解析SIP包,获取sip request method,如INVITE, BYE等
15086 parse_request(&req);
15087 req.method = find_sip_method(req.rlPart1);
随后找到对应的sip_pvt结构,或者创建新的sip_pvt结构,结构指针返回到变量p中。
15099 /* Find the active SIP dialog or create a new one */
15100 p = find_call(&req, &sin, req.method); /* returns p locked */
在进一步操作之前,需要对p->owner上锁,这个操作会最多尝试100次直至成功。
15107 /* Go ahead and lock the owner if it has one -- we may need it */
15108 /* becaues this is deadlock-prone, we need to try and unlock if failed */
15109 if (!p->owner || !ast_channel_trylock(p->owner))
15110 break; /* locking succeeded */
如果上锁操作失败,将会返回503 sip消息。
15127 if (req.method != SIP_ACK)
15128 transmit_response(p, "503 Server error", &req); /* We must respond according to RFC 3261 sec 12.2 */
15129 /* XXX We could add retry-after to make sure they come back */
15130 append_history(p, "LockFail", "Owner lock failed, transaction failed.");
15131 return 1;
更深一步的解析处理操作交给handle_request()函数处理,完了之后就是释放channel的锁。
15134 if (handle_request(p, &req, &sin, &recount, &nounlock) == -1) {
15135 /* Request failed */
15136 if (option_debug)
15137 ast_log(LOG_DEBUG, "SIP message could not be handled, bad request: %-70.70s/n", p->callid[0] ? p->callid : "<no callid>");
15138 }
15139
15140 if (p->owner && !nounlock)
15141 ast_channel_unlock(p->owner);
函数handle_request()视数据包的类型而处理,如果是对外出包的回应,则交给handle_response()处理,如果是一个请求包,则视请求类型(INVITE, OPTIONS, REFER, BYE, CANCEL etc)交给不同的函数处理。如果是一个INVITE包,则交给handle_request_invite()处理,在那里将会创建一个新的channel,这个通道随后会执行一个单独的通道线程。这就是一个来电呼叫。如果这个呼叫被应答,则一个桥接通道或者PBX本身会回调sip_answer()函数。而真正的媒体数据,音频或者视频,则会在RTP子系统中处理,具体见rtp.c
Outbound calls
Outbound calls are set up by the PBX through the sip_request_call() function. After that, they are activated by sip_call().
Hanging up
The PBX issues a hangup on both incoming and outgoing calls through the sip_hangup() function
01502 /*------Request handling functions */
01503 static int handle_request(struct sip_pvt *p, struct sip_request *req,struct sockaddr_in *sin, int *recount, int *nounlock);
01504 static int handle_request_invite(struct sip_pvt *p, struct sip_request*req, int debug, int seqno, struct sockaddr_in *sin, int *recount, char *e, int*nounlock);
01505 static int handle_request_refer(struct sip_pvt *p, struct sip_request*req, int debug, int ignore, int seqno, int *nounlock);
01506 static int handle_request_bye(struct sip_pvt *p, struct sip_request *req);
01507 static int handle_request_register(struct sip_pvt *p, struct sip_request*req, struct sockaddr_in *sin, char *e);
01508 static int handle_request_cancel(struct sip_pvt *p, struct sip_request*req);
01509 static int handle_request_message(struct sip_pvt *p, struct sip_request*req);
01510 static int handle_request_subscribe(struct sip_pvt *p, struct sip_request*req, struct sockaddr_in *sin, int seqno, char *e);
01511 static void handle_request_info(struct sip_pvt *p, struct sip_request*req);
01512 static int handle_request_options(struct sip_pvt *p, struct sip_request*req);
01513 static int handle_invite_replaces(struct sip_pvt *p, struct sip_request*req, int debug, int ignore, int seqno, struct sockaddr_in *sin);
01514 static int handle_request_notify(struct sip_pvt *p, struct sip_request*req, struct sockaddr_in *sin, int seqno, char *e);
01515 static int local_attended_transfer(struct sip_pvt *transferer, structsip_dual *current, struct sip_request *req, int seqno);
01516
01517 /*------Response handling functions */
01518 static void handle_response_invite(struct sip_pvt *p, int resp, char*rest, struct sip_request *req, int seqno);
01519 static void handle_response_refer(struct sip_pvt *p, int resp, char *rest,struct sip_request *req, int seqno);
01520 static int handle_response_register(struct sip_pvt *p, int resp, char*rest, struct sip_request *req, int ignore, int seqno);
01521 static void handle_response(struct sip_pvt *p, int resp, char *rest,struct sip_request *req, int ignore, int seqno);
现在回顾一下注册SIP通道驱动时,我们注册了一系列通道驱动的回调函数,这些有什么用呢?比如当需要发出一个outbound call时,则会调用sip_request_call()。而当需要hangup时,则调用sip_hangup()。
01541 /*! /brief Definition of this channel for PBX channel registration */
01542 static const struct ast_channel_tech sip_tech = {
01543 .type = "SIP",
01544 .description = "Session Initiation Protocol (SIP)",
01545 .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
01546 .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
01547 .requester = sip_request_call,
01548 .devicestate = sip_devicestate,
01549 .call = sip_call,
01550 .hangup = sip_hangup,
01551 .answer = sip_answer,
01552 .read = sip_read,
01553 .write = sip_write,
01554 .write_video = sip_write,
01555 .indicate = sip_indicate,
01556 .transfer = sip_transfer,
01557 .fixup = sip_fixup,
01558 .send_digit_begin = sip_senddigit_begin,
01559 .send_digit_end = sip_senddigit_end,
01560 .bridge = ast_rtp_bridge,
01561 .send_text = sip_sendtext,
01562 .func_channel_read = acf_channel_read,
01563 };
现在开始分析handle_request_invite()函数。If the INVITE has a Replaces header, it is part of an attended transfer. If so, we do not go through the dial plan but tries to find the active call and masquerade into it。(不是很明白?)
检查invite包的headers中是否有Require。最好是没有,如果有的话也必须是Replaces,其它的不支持一律不予处理。
13394 /* Find out what they require */
13395 required = get_header(req, "Require");
13396 if (!ast_strlen_zero(required)) {
13397 required_profile = parse_sip_options(NULL, required);
13398 if (required_profile && required_profile != SIP_OPT_REPLACES) {
13399 /* At this point we only support REPLACES */
13400 transmit_response_with_unsupported(p, "420 Bad extension (unsupported)", req, required);
13401 ast_log(LOG_WARNING,"Received SIP INVITE with unsupported required extension: %s/n", required);
13402 p->invitestate = INV_COMPLETED;
13403 if (!p->lastinvite)
13404 sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
13405 return -1;
13406 }
13407 }
接下来检查headers中是否有Replaces,如果有则做相关处理。由于商业项目中很少涉及这种需求,则略过。
开始验证sip user的合法性,check_user()调用check_user_full()函数,该函数从heades中的from中取出用户名并在sip user list 和 sip peer list中匹配,如果没找着,再查看是否允许guest,如果不允许,则认证通不过。
13584 /* This is a new invite */
13585 /* Handle authentication if this is our first invite */
13586 res = check_user(p, req, SIP_INVITE, e, XMIT_RELIABLE, sin);
检查sip包中是否有SDP信息,如: application/sdp 。SDP(Session Description Protocol)是指会话描述协议,SIP包中使用它来描述语音流协议的细节,比如某端所支持的介质编码(这些编码使用RTP进行传输)。
13558 /* Handle SDP here if we already have an owner */
13559 if (find_sdp(req)) {
13560 if (process_sdp(p, req)) {
13561 transmit_response(p, "488 Not acceptable here", req);
13562 if (!p->lastinvite)
13563 sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
13564 return -1;
13565 }
检查该用户的并行拨打电话数有没有达到上限。
13633 /* Check number of concurrent calls -vs- incoming limit HERE */
13634 if (option_debug)
13635 ast_log(LOG_DEBUG, "Checking SIP call limits for device %s/n", p->username);
13636 if ((res = update_call_counter(p, INC_CALL_LIMIT))) {
13637 if (res < 0) {
13638 ast_log(LOG_NOTICE, "Failed to place call for user %s, too many calls/n", p->username);
13639 transmit_response_reliable(p, "480 Temporarily Unavailable (Call limit) ", req);
13640 sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
13641 p->invitestate = INV_COMPLETED;
13642 }
13643 return 0;
13644 }
查找对应的extension,如果没有对应的extension,则从extension s开始执行(extension s是默认的extension,s表示start)
13645 gotdest = get_destination(p, NULL); /* Get destination right away */
调用sip_new()创建channel,这时候是incoming call。当调用dial application发起outbound call时asterisk pbx根据注册的回调函数sip_request_call()同样进入到sip_new中创建channel。
13672 /* First invitation - create the channel */
13673 c = sip_new(p, AST_STATE_DOWN, S_OR(p->username, NULL));
调用ast_pbx_start(),该函数启动一个独立线程负责这个channel,线程函数是pbx_thread(),pbx_thread()调用__ast_pbx_run()函数。
13717 res = ast_pbx_start(c);
__ast_pbx_run()函数allocate 一个pbx结构和cdr结构,并把它们的指针保存到ast_channel结构的pbx域和cdr域。随后进入for循环逐个执行application。具体见./main/pbx.c。
02385 /* loop on priorities in this context/exten */
02386 while (ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
02387 found = 1;
02388 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
02389 /* Something bad happened, or a hangup has been requested. */
下面再来分析下handle_request_bye()函数,这个函数比较简单,它在收到BYE包时被触发,首先记录下rtp, vrtp的qos到channel内置变量,调用stop_media_flows(p)结束rtp流,调用ast_queue_hangup(p->owner)进行挂断操作,调用transmit_response(p, "200 OK", req)返回200 OK消息。其中ast_queue_hangup()调用ast_queue_frame()在ast_channel机构的ast_frame队列里插入一个HANGUP的帧。