您的位置:首页 > 其它

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)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: