注册发起
//初始化注册
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 (UINT32 i = 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_NS CUARegistration);
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, "Digest username=\"%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, TO msgBody);
注册超时
//当前没有板子调试,协议栈没有源码,猜测当前流程从此入口进入。
1、callctrl事件回调
SIPCB::EvFailedA
RegistrationState(pRegistration, eState, pPacket);
switch (FSM_(eState, callgcb.reg[uRegIdx]->regState))
//正在注册过程中,收到eREGISTRATION_REQUEST_TIMEOUT事件
case FSM(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)
case CCEVT_STATUS:
switch( reason )
case CCRSN_REG_TIMEOUT:
//获取cmEndpt控制块
endpt = cmFindEndptFromRegId( cid );
//取消注册超时探测定时器
cmEndpt[endpt].regActTimerMs = 0;
//映射为CMEVT_STATUS事件
cnxevent = cmMapById( cmCallEvtMap, reason);
if ((cnxevent == CMEVT_STATUS) && (endpt != UNKNOWN))
switch (reason)
case CCRSN_REG_TIMEOUT:
//如果已处于在线状态
if( cmEndpt[endpt].inservice == TRUE )
//复位在线状态
cmEndpt[endpt].inservice = FALSE;
//更新是否在线状态显示
cmDisplay( endpt, UNKNOWN, CMLCD_SERVER);
switch ( msgtype)
case CMLCD_SERVER:
cmEndptNotify( endpt, UNKNOWN, CMEVT_INSERVICE,
cmEndpt[endpt].inservice);
cmEndptStateEngine( endpt, cid, event, data );
case FSM( 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_NS CSipPacket*)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))
//在正在注册状态下收到注册成功
case FSM(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)
case CCEVT_STATUS:
switch( reason )
case CCRSN_REG_OK:
//获取cmEndpt控制块
endpt = cmFindEndptFromRegId( cid );
//取消注册超时探测定时器
cmEndpt[endpt].regActTimerMs = 0;
//映射为CMEVT_STATUS事件
cnxevent = cmMapById( cmCallEvtMap, reason);
if ((cnxevent == CMEVT_STATUS) && (endpt != UNKNOWN))
switch (reason)
case CCRSN_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 ))
case FSM( CMEVT_STATUS, CMSUBSTATE_IDLE ):
switch( reason )
case CCRSN_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 )