freeswitch系列31注册流程

  1. freeswitch中的sip架构

 

freeswitch的结构图如上,蓝色箭头是调用,绿色箭头是回调。最底层的是第三方库,一个sip协议栈,实现sip信令协议,构造sip当中的各个字段。核心层主要维护跟会话,通路相关的信息,它不依赖于sip,但是会被逻辑层用到。mod_sofia是一个端点模块,它可以理解为逻辑层,实现注册、呼叫等业务,它一方面跟sip协议栈交互,调用sip协议栈去发送信令,提供回调,用于接收信令、状态变化。另一方面,它也通过核心层,构建session和channel,并且还是通过设置回调,监控通道的状态改变。

 

  1. 注册信令流程

 

 

注册的信令交互比较简单,就四步:

  1. sip客户端代理UA先发送register注册请求;
  2. freeswitch检查还未认证,回复401表示未认证,同时生成一个认证摘要(WWW-Authenticate),一起发送给UA。认证机制原理,暂不研究。
  3. UA收到401后,根据自己的用户名和密码,以及认证摘要,生成认证信息,然后再次发起注册请求;
  4. freeswitch检查通过后,回复200OK,注册成功。
  1. register请求
    1. register信令

 

register表示这是一条注册消息;

via表示sip消息的路由,如果经过多个代理服务器转发,这里会有多条记录

from表示请求端地址

to表示目的端地址

call-id表示本次会话的标识

contact表示联系人信息

cseq表示消息序号

allow表示所支持的功能

max-forwards表示可以转发多少次,防止死循环,类似TTL

user-agent表示UA的型号

expires表示本次注册的有效期,单位为秒

content-length表示消息体长度,这里0表示没有后续消息体

    1. sofia协议栈

    1. 应用层mod_sofia

之前说过,sip协议栈通知应用是通过回调sofia_event_callback

  1. void sofia_event_callback(nua_event_t event,  
  2.                           int status,  
  3.                           char const *phrase,  
  4.                           nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,  
  5.                           tagi_t tags[])  
  6. {  
  7.     sofia_dispatch_event_t *de;  
  8.   
  9.     //sip消息是一系列nua_开头的,nua_i表示Indications消息,还有一类nua_r表示Responses消息  
  10.     switch(event) {  
  11.     case nua_i_terminated:  
  12.     case nua_i_invite:  
  13.     case nua_i_register:  
  14.     case nua_i_options:  
  15.     case nua_i_notify:  
  16.     case nua_i_info:  
  17.         ...  
  18.     }  
  19.   
  20.     //invite消息,则要创建session,同时也是创建channel  
  21.     if (event == nua_i_invite && !sofia_private) {  
  22.         session = switch_core_session_request_uuid(sofia_endpoint_interface,...);  
  23.         switch_core_session_thread_launch(session)  
  24.     }  
  25.       
  26.     //最后把sip消息投入到消息队列mod_sofia_globals.msg_queue  
  27.     sofia_queue_message(de);  

 

这里虽然对消息有一些判断,但是没有具体去处理,只有invite这个消息,会去创建session,最后是投递到消息队列mod_sofia_globals.msg_queue 。

 

以前讲过,这个队列主要在消息线程sofia_msg_thread_run处理,不断地从队列取出消息,然后调用sofia_process_dispatch_event去处理,这个函数里面又调用our_sofia_event_callback。

 

  1. our_sofia_event_callback()  
  2. {  
  3.     switch (event) {  
  4.     case nua_i_register:  
  5.         //nua_respond(nh, SIP_200_OK, SIPTAG_CONTACT(sip->sip_contact), NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());  
  6.         //nua_handle_destroy(nh);  
  7.         sofia_reg_handle_sip_i_register(nua, profile, nh, &sofia_private, sip, de, tags);  
  8.         break;  
  9.         ...  
  10.     }  
  11. }  

 

our_sofia_event_callback只是个事件分发器,每个消息对应一个处理函数,这里我们只关心register相关的,调用sofia_reg_handle_sip_i_register处理注册消息。这个函数在sofia_reg.c,该文件专门处理注册相关。

 

  1. void sofia_reg_handle_sip_i_register()  
  2. {  
  3.     //处理一些特殊的情况,比如不允许注册,则回复403,调用nua_respond可以给客户端UA发送反馈。  
  4.     if (!(profile->mflags & MFLAG_REGISTER)) {  
  5.         nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());  
  6.         goto end;  
  7.     }  
  8.   
  9.     //正常流程进入到这个函数  
  10.     sofia_reg_handle_register_token();  

 

我们从协议包反推,这里应该在哪个地方判断没有认证,然后回复401,所以可以搜索SIP_401_UNAUTHORIZED,这个宏,可以找到三处,然后进行log跟踪,就可以知道在哪里判断未认证了。这里应该是判断有没有authorization字段,调用sofia_reg_auth_challenge,在该函数回复401。

这就是注册的第一阶段,收到register消息后,创建session,判断未认证,回复401。

  1. 回复01 unauthorized
    1. 401信令

 

status-code:服务器回复401表示未认证

WWW-Authenticate:服务端会生成认证摘要,一起发送给UA。

    1. 应用层mod_sofia

 

  1. void sofia_reg_auth_challenge(sofia_profile_t *profile, nua_handle_t *nh, sofia_dispatch_event_t *de,  
  2.                               sofia_regtype_t regtype, const char *realm, int stale, long exptime)  
  3. {  
  4.     switch_uuid_t uuid;  
  5.     char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];  
  6.     char *sql, *auth_str;  
  7.     msg_t *msg = NULL;  
  8.   
  9.     sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);  
  10.   
  11.     auth_str = switch_mprintf("Digest realm=\"%q\", nonce=\"%q\",%s algorithm=MD5, qop=\"auth\"", realm, uuid_str, stale ? " stale=true," : "");  
  12.   
  13.     if (regtype == REG_REGISTER) {  
  14.         nua_respond(nh, SIP_401_UNAUTHORIZED, TAG_IF(msg, NUTAG_WITH_THIS_MSG(msg)), SIPTAG_WWW_AUTHENTICATE_STR(auth_str), TAG_END());  
  15.     } else if (regtype == REG_INVITE) {  
  16.         nua_respond(nh, SIP_407_PROXY_AUTH_REQUIRED,   
  17.                     TAG_IF(msg, NUTAG_WITH_THIS_MSG(msg)),   
  18.                     SIPTAG_PROXY_AUTHENTICATE_STR(auth_str), TAG_END());  
  19.     }  
  20.   
  21.     switch_safe_free(auth_str);  

 

这里除了回复401给客户端UA,还要插入数据表sip_authentication。

    1. 协议栈

  1. 带认证register
    1. 协议

 

UA收到401后,重新发起注册请求,并带上根据摘要和用户名、密码生成的认证信息。

 

    1. mod_sofia
  1. sofia_reg_handle_register_token()  
  2. {  
  3.     authorization = sip->sip_authorization;  
  4.   
  5.     if (authorization) {  
  6.         char *v_contact_str = NULL;  
  7.         const char *username = "unknown";  
  8.         const char *realm = reg_host;  
  9.         if ((auth_res = sofia_reg_parse_auth(profile, authorization, sip, de, sip->sip_request->rq_method_name,  
  10.                                              key, keylen, network_ip, network_port, v_event, exptime, regtype, to_user, &auth_params, ®_count, user_xml)) == AUTH_STALE) {  
  11.             stale = 1;  
  12.   
  13.         if (auth_res != AUTH_OK && auth_res != AUTH_RENEWED && !stale) {  
  14.             if (auth_res == AUTH_FORBIDDEN) {  
  15.                 nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());  
  16.                 forbidden = 1;  
  17.             } else {  
  18.                 nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());  
  19.             }  
  20.         }  
  21.   
  22.         nua_respond(nh, SIP_200_OK...)  

 

收到带认证的register消息,流程大体一样,只是到了这里对认证进行校验。认证成功后回复200OK。如果认证不通过,则回复403 forbidden。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值