BCM VOIP 注册流程分析
2013-11-27 23:03
357 查看
注册发起
//初始化注册 callRegSetup(®Id,&pu[i]); //分配一个注册控制块 regIdx=CreateRegIdx(); //将用户参数保存到注册控制块中 //callgcb.reg[i]->suser.username //callgcb.reg[i]->suser.display //callgcb.reg[i]->suser.authname //callgcb.reg[i]->suser.password //callgcb.reg[i]->suser.realmlist.realm[k].realm //callgcb.reg[i]->suser.realmlist.realm[k].username //callgcb.reg[i]->suser.realmlist.realm[k].password //callgcb.reg[i]->suser.registrar.addr //callgcb.reg[i]->suser.aorHostport.addr //callgcb.reg[i]->suser.mohserver.addr //callgcb.reg[i]->suser.mohserver.display //callgcb.reg[i]->suser.routeSet.route[k].addr.addr //callgcb.reg[i]->suser.mohserver.scheme=CCURITYPE_SIP; //callgcb.reg[i]->suser.mohserver.params=NULL; //callgcb.reg[i]->aorValid //callgcb.reg[i]->registrarEnabled //callgcb.reg[i]->routeSetEnabled SetSuserParm(regIdx,suser); //初始状态为CCSTS_UNREGISTERED reg->regState=CCSTS_UNREGISTERED; //无源码,不太清楚 reg->pUAAuthentication->SetManager(&sipcb); reg->pUAAuthentication->ReleaseIfRef(); //如果当前用户配置了realm参数,则调用协议栈接口添加鉴权凭证 for(UINT32i=0;i<realmlist->num;i++) realm=realmlist->realm[i].realm; user=realmlist->realm[i].username; password=realmlist->realm[i].password; reg->pUAAuthentication->AddCredentialsA(realm,user,password); if(reg->registrarEnabled) //如果用户配置了路由集,则转化为MT5内部格式 if(reg->routeSetEnabled) SetRoute(regIdx,reg->suser.registrar.addr,reg->suser.registrar.port,GO preloadRoute); //格式化From头域地址 FormAddrOfRecord(regIdx,addressOfRecord); //格式化Request-URI //格式化Contact头域 //调用协议栈句柄,初始化注册管理控制块 reg->pUARegistration=BRCM_NEW(MX_NSCUARegistration); reg->pUARegistration->Initialize(&sipcb,&sipcb,&addressOfRecord,&contactHdrs, &localContactHdrs,&sipUri,&addressOfRecord,&serverLocatorListModifierCb, (mxt_opaque)serverLocOpaque,serverLocatorPrevListModifierCb, serverLocPrevOpaque,preloadRoute); //调用协议栈句柄,设置一些通用头域 SetGenHeaders(*rid,NULL); //将鉴权模块附加到注册控制块中 reg->pUARegistration->SetAuthenticationS(reg->pUAAuthentication,callgcb.mutex); //没有源码,不太清楚 reg->pUARegistration->SetOpaqueS((mxt_opaque)(*rid),callgcb.mutex); reg->pUAAuthentication->SetOpaqueS((mxt_opaque)(*rid),callgcb.mutex); //将注册控制块索引关联到cmEndpt中 cmEndpt[i].regId=regId; if(cmEndpt[i].registrarEnabled) //向注册对象中添加Authorization和Supported头 sprintf(hdrValue,"Digestusername=\"%s\",realm=\"%s\",nonce=\"\",uri=\"sip:%s\",response=\"\",algorithm=MD5",pu[i].authname,pu[i].registrar.addr,pu[i].registrar.addr); headers.list[headers.num].type=CCHDR_GENERIC; headers.list[headers.num].hdr.generic.name=CHDR_AUTHORIZATION_NAME; headers.list[headers.num].hdr.generic.value=hdrValue; headers.map[headers.num]=CCHDRMAP_REQ_ONLY; headers.num++; headers.list[headers.num].type=CCHDR_GENERIC; headers.list[headers.num].hdr.generic.name=CHDR_SUPPORTED_NAME; headers.list[headers.num].hdr.generic.value=CHDR_SUPPORTED_VALUE; headers.map[headers.num]=CCHDRMAP_REQ_ONLY; headers.num++; callSetParm(regId,CCPARM_GENHDRS,(void*)&headers); //重置注册超时定时器 cmEndpt[i].regRetryTimerMs=0; cmEndpt[i].regActTimerMs=EPT_REGACT_TIMER; //发起注册 callRegister(regId,NULL); //仅在未注册或者已经注册成功的最终状态下,才处理注册请求 if((reg->regState==CCSTS_UNREGISTERED)||(reg->regState==CCSTS_REGISTERED)) //注册控制块状态迁为CCSTS_REGINPROGRESS reg->regState=CCSTS_REGINPROGRESS; //构建Contact头域 FormRegistrationContacts(regIdx,localContactHdrs); //当前content为空,不处理 FormatContent(content,msgBody); //调用协议栈句柄,发起注册请求 reg->pUARegistration->RegisterA(&localContactHdrs,TOmsgBody);
注册超时
//当前没有板子调试,协议栈没有源码,猜测当前流程从此入口进入。
1、callctrl事件回调
SIPCB::EvFailedA
RegistrationState(pRegistration,eState,pPacket);
switch(FSM_(eState,callgcb.reg[uRegIdx]->regState))
//正在注册过程中,收到eREGISTRATION_REQUEST_TIMEOUT事件
caseFSM(eREGISTRATION_REQUEST_TIMEOUT,CCSTS_REGINPROGRESS):
//当前注册控制块状态迁为CCSTS_UNREGISTERED
callgcb.reg[uRegIdx]->regState=CCSTS_UNREGISTERED;
//给callmgr发送CCEVT_STATUS/CCRSN_REG_TIMEOUT事件
GCBEVTSTATUS(rid,CCRSN_REG_TIMEOUT,pp);
2、callmgr处理从callctrl发来的CCEVT_STATUS/CCRSN_REG_TIMEOUT事件
cmProcessCallEvent
switch(event)
caseCCEVT_STATUS:
switch(reason)
caseCCRSN_REG_TIMEOUT:
//获取cmEndpt控制块
endpt=cmFindEndptFromRegId(cid);
//取消注册超时探测定时器
cmEndpt[endpt].regActTimerMs=0;
//映射为CMEVT_STATUS事件
cnxevent=cmMapById(cmCallEvtMap,reason);
if((cnxevent==CMEVT_STATUS)&&(endpt!=UNKNOWN))
switch(reason)
caseCCRSN_REG_TIMEOUT:
//如果已处于在线状态
if(cmEndpt[endpt].inservice==TRUE)
//复位在线状态
cmEndpt[endpt].inservice=FALSE;
//更新是否在线状态显示
cmDisplay(endpt,UNKNOWN,CMLCD_SERVER);
switch(msgtype)
caseCMLCD_SERVER:
cmEndptNotify(endpt,UNKNOWN,CMEVT_INSERVICE,
cmEndpt[endpt].inservice);
cmEndptStateEngine(endpt,cid,event,data);
caseFSM(CMEVT_INSERVICE,CMST_ONHOOK):
//这里主要调用了cmPublishEvent,当然该函数的回调
//中没有对CMEVT_INSERVICE事件的处理。
//更新cmEndpt关联兄弟控制块的inservice
cmUpdateRegSib(endpt);
//检查SIP报文是否含有Retry-Afterr头域,如果有则将当前线路的重新注
//册时间更新为该值。当前超时流程不会有报文存在,所以不执行此流程。
if(headers&&headers->num)
for(i=0;i<(int)headers->num;i++)
if(headers->list[i].type==CCHDR_RETRY_AFTER)
cmEndpt[endpt].regRetryTimerMs=
headers->list[i].hdr.retry.deltasec*1000;
//设置重新注册时间为用户配置的值
if(!cmEndpt[endpt].regRetryTimerMs)
cmEndpt[endpt].regRetryTimerMs=
cmProvisionGet(PROVIS_SIP_REGRETRY_TIMER,endpt))*1000
//当前没有对CCEVT_STATUS/CCRSN_REG_TIMEOUT事件的处理
cmProtProcessCallEvent(endpt,cnxevent,reason,packet);
注册成功
1、callctrl事件回调
SIPCB::EvRegisteredA
//从sip报文中获取Allow-Events头域字段,并存储到注册控制块中reg->allowevts
GetAllowEvents(reg->allowevts,(MX_NSCSipPacket*)pPacket);
RegistrationState(pRegistration,IUARegistrationMgr::eREGISTERED,pPacket);
//提取应答码,并将SIP包转化成callctrl格式
if(pPacket&&pPacket->IsResponse())
uStatus=pPacketCopy->GetStatusLine()->GetCode();
strPhrase=pPacketCopy->GetStatusLine()->GetPhrase();
GetPacket(*pPacketCopy,outPacket);
pp=(outPacket.content!=NULL||outPacket.hdrs!=NULL)?&outPacket:NULL;
switch(FSM_(eState,callgcb.reg[uRegIdx]->regState))
//在正在注册状态下收到注册成功
caseFSM(eREGISTERED,CCSTS_REGINPROGRESS):
//注册控制块状态迁为CCSTS_REGISTERED
callgcb.reg[uRegIdx]->regState=CCSTS_REGISTERED;
//给callmgr发送CCEVT_STATUS/CCRSN_REG_OK事件
GCBEVTSTATUS(rid,CCRSN_REG_OK,pp);
2、callmgr处理从callctrl发来的CCEVT_STATUS/CCRSN_REG_OK事件
cmProcessCallEvent
switch(event)
caseCCEVT_STATUS:
switch(reason)
caseCCRSN_REG_OK:
//获取cmEndpt控制块
endpt=cmFindEndptFromRegId(cid);
//取消注册超时探测定时器
cmEndpt[endpt].regActTimerMs=0;
//映射为CMEVT_STATUS事件
cnxevent=cmMapById(cmCallEvtMap,reason);
if((cnxevent==CMEVT_STATUS)&&(endpt!=UNKNOWN))
switch(reason)
caseCCRSN_REG_OK:
if(cmEndpt[endpt].inservice==FALSE)
//在cmEndpt控制块中记载当前已经在线
cmEndpt[endpt].inservice=TRUE;
//该函数最终触发cmPublishEvent回调,但该回调中没有对应事件处理
cmDisplay(endpt,UNKNOWN,CMLCD_SERVER);
//将关联的兄弟cmEndpt也标记为在线
cmUpdateRegSib(endpt);
cmProtProcessCallEvent(endpt,cnxevent,reason,packet);
if(cnxevent==CMEVT_STATUS&&(endpt!=UNKNOWN))
if(reason==CCRSN_REG_OK)
//如果注册应答报文中含有Service-Route头域,则记录到cmEndpt控制块
if(headers&&headers->num)
for(i=0;i<headers->num;i++)
if(headers->list[i].type==CCHDR_SERVICE_ROUTE)
strcpy(cmEndpt[endpt].srAddr,
headers->list[i].hdr.route.service.addr);
cmEndpt[endpt].srPort=
headers->list[i].hdr.route.service.port;
//发送MWI消息订阅
cmMwiSubscribe(endpt);
//用户开启了订阅服务
if(cmEndpt[endpt].explicitMwi.enabled)
//构造to字段
cmSetCalledParty(endpt,&calledparty,to);
//分配呼叫控制块,并初始化用户配置参数
callSetup(&cid,cmEndpt[endpt].regId,CCCIDTYPE_MWI,
&calledparty);
//将消处订阅类型的呼叫控制块索引关联到cmEndpt中
cmEndpt[endpt].explicitMwi.mwiCid=cid;
//设置PREFERRED_ID头域
callSetParm(cid,CCPARM_PREFERRED_ID,(void*)&prefId);
//如果本地配有outband服务器,或者注册应答中含有
//Service-Route头域,则当前注册包加入Route头域
cmSetServiceRoute(cid,endpt);
//调用协议栈句柄发起Subscribe请求
callSubscribe(cmEndpt[endpt].explicitMwi.mwiCid,
SUBSCRIBTION_TIMEOUT_SECS,NULL,NULL);
//cmCnx控制块关联cmEndpt控制块
cmCnx[cid].endpt=endpt;
//MWI状态机变迁为CMMWI_SUBSCRIBING
cmEndpt[endpt].explicitMwi.mwiState=CMMWI_SUBSCRIBING;
//发送注册订阅
cmRegEvtPkgStateEngine(endpt,UNKNOWN,cnxevent,CCRSN_REG_OK);
ep=&cmEndpt[endpt];
regevt=&cmRegEvtPkg.regEvtProfBlk[endpt];
switch(FSM(event,state))
caseFSM(CMEVT_STATUS,CMSUBSTATE_IDLE):
switch(reason)
caseCCRSN_REG_OK:
//发起订阅
cmRegEvtPkgSubscribe(UNKNOWN,regevt);
//创建一个呼叫控制块,并初始化并初始化用户配置
//参数
callSetup(&cid,cmEndpt[endpt].regId,
CCCIDTYPE_EVENT,&to)
//注册订阅控制块关联呼叫控制块,并初始化状态
cmCnx[cid].endpt=pRegEvt->endpt;
cmCnx[cid].state=CMST_IDLE;
pRegEvt->reqId.cid=cid;
pRegEvt->reqId.state=CMSUBSTATE_SUBSCRIBING;
//设置PREFERRED_ID头域
callSetParm(cid,CCPARM_PREFERRED_ID,(void*)&to);
//设置Accept:application/reginfo+xml头域
sprintf(display,"Accept");
sprintf(eventValue,"%s/%s",
CMREGEVT_ACCEPT_HEADER_TYPE_APP,
CMREGEVT_ACCEPT_HEADER_SUBTYPE_REGINFO);
headers.list[headers.num].type=CCHDR_GENERIC;
headers.list[headers.num].hdr.generic.name=display;
headers.list[headers.num].hdr.generic.value=
eventValue;
headers.map[headers.num]=CCHDRMAP_ALWAYS;
headers.num++;
callSetParm(cid,CCPARM_GENHDRS,(void*)&headers);
//如果本地配有outband服务器,或者注册应答中含有
//Service-Route头域,则当前注册包加入Route头域
cmSetServiceRoute(cid,endpt);
//调用协议栈句柄发起Subscribe请求
callSubscribe(cid,SUBSCRIBTION_TIMEOUT_SECS,
eventValue,NULL)
相关文章推荐
- BCM VOIP 基本呼叫流程分析
- 今天我以fb设备的注册过程来分析platform设备的添加流程
- BCM VOIP 应用程序编译分析
- 从注册流程 分析如何安全退出多个Activity 多种方式(附DEMO)
- SNS、微博网站“注册流程”对比分析?
- Android广播管理二--广播注册(registerReceiver)流程分析
- BCM VOIP EPON二层链路状态改变分析
- i2c驱动注册流程实例分析
- netty源码分析(十五)Channel注册流程深度解读
- 基于linux 3.10.49内核 从dts文件里注册platform_device流程分析
- BCM VOIP 启动分析
- 从注册流程 分析如何安全退出多个Activity 多种方式(附DEMO)
- i2c_add_driver:i2c驱动注册流程分析
- 网站注册流程的分析与研究
- BCM VOIP 线路统计分析
- 从注册流程 分析如何安全退出多个Activity 多种方式(附DEMO)
- Openfire注册流程代码分析(转)
- 从注册流程 分析如何安全退出多个Activity 多种方式(附DEMO)
- 基于GBT28181:SIP协议组件开发-----------第三篇SIP注册流程分析实现
- BCM VOIP 数图算法分析