深入浅出asterisk(三):chan_sip代码分析(下)

来源:互联网 发布:windows怎样编辑照片 编辑:程序博客网 时间:2024/05/16 07:49

转载自:http://blog.csdn.net/colinchan/article/details/1805306


现在回过头来把焦点转移到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, (struct sockaddr *)&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 staticint handle_request(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int *recount, int *nounlock);
01504 staticint 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 staticint handle_request_refer(struct sip_pvt *p, struct sip_request *req, int debug, int ignore, int seqno, int *nounlock);
01506 staticint handle_request_bye(struct sip_pvt *p, struct sip_request *req);
01507 staticint handle_request_register(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, char *e);
01508 staticint handle_request_cancel(struct sip_pvt *p, struct sip_request *req);
01509 staticint handle_request_message(struct sip_pvt *p, struct sip_request *req);
01510 staticint handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, char *e);
01511 staticvoid handle_request_info(struct sip_pvt *p, struct sip_request *req);
01512 staticint handle_request_options(struct sip_pvt *p, struct sip_request *req);
01513 staticint handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, int debug, int ignore, int seqno, struct sockaddr_in *sin);
01514 staticint handle_request_notify(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, char *e);
01515 staticint local_attended_transfer(struct sip_pvt *transferer, struct sip_dual *current, struct sip_request *req, int seqno);
01516 
01517 /*------Response handling functions */
01518 staticvoid handle_response_invite(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno);
01519 staticvoid handle_response_refer(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno);
01520 staticint handle_response_register(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int ignore, int seqno);
01521 staticvoid 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 staticconststruct 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的帧。

原创粉丝点击