一、 发送Refer请求
//创建订阅对象
RvSipSubsMgrCreateSubscription(g_hSubsMgr,hCallLeg,NULL,&hSubs)
//如果当前订阅对象是关联对话框的,则需要校验此对话框必须是一个早期对话框,或
//者是已完成的对话框,即有to-tag标记
if(hCallLeg != NULL)
rv = RvSipCallLegGetCurrentState(hCallLeg, &eDialogState);
if(eDialogState == RVSIP_CALL_LEG_STATE_IDLE ||
RV_FALSE == IsDialogEstablished(hCallLeg, pMgr->pLogSrc))
return RV_ERROR_ILLEGAL_ACTION;
//订阅对象创建
SubsMgrSubscriptionCreate(hSubsMgr, hCallLeg, hAppSubs, RVSIP_SUBS_TYPE_SUBSCRIBER, RV_FALSE, phSubs);
//如果这个订阅对象没有和基它已存在对话框关联,则这里创建隐性对话框,但当
//前例子提供了已存在的对话框,所以不执行这个流程。
if(hCallLeg == NULL)
//XXX
//创建订阅对象
SubsMgrSubscriptionObjCreate(pMgr, hSubsCallLeg, hAppSubs, eSubsType,
bOutOfBand, phSubs);
//从订阅管理对象中申请一个订阅对象资源
RLIST_InsertTail(pMgr->hSubsListPool,pMgr->hSubsList,&listItem);
pSubscription = (Subscription*)listItem;
//对订阅对象进行初始化
SubsInitialize(pSubscription, hAppSubs, hCallLeg, pMgr, eSubsType, bOutOfBand,
hSubsPage)
pSubs->alertTimeout = pMgr->alertTimeout;
pSubs->noNotifyTimeout = pMgr->noNotifyTimeout;
pSubs->bDisableRefer3515Behavior= pMgr->bDisableRefer3515Behavior;
pSubs->autoRefresh = pMgr->autoRefresh;
pSubs->bOutOfBand = isOutOfBand; //false
pSubs->hCallLeg = hCallLeg;
pSubs->eState = RVSIP_SUBS_STATE_IDLE;
……
// eType = RVSIP_SUBS_TYPE_SUBSCRIBER
pSubs->eSubsType = eType;
……
//将订阅对象句柄加入到对话框对象的订阅列表中pCallLeg->hSubsList
SipCallLegSubsAddSubscription(hCallLeg, (RvSipSubsHandle)pSubscription,
&(pSubscription->hItemInCallLegList));
CallLegSubsAddSubscription(hCallLeg, hSubs, phItem);
//开启对话框Fork支持,pCallLeg->bForkingEnabled
SipCallLegSetSubsForkingEnabledFlag(hSubsCallLeg, RV_TRUE );
//初始化Refer参数
RvSipSubsReferInitStr(hSubs, g_pReferToAddr, NULL,NULL)
SubsReferInit(hSubs, NULL, NULL, strReferTo, strReferredBy, strReplaces)
//如果用户传入了referTo字符串,则进行referTo头域对象构造,并将字符串解析
//到头域对象中
if(strReferTo != NULL)
RvSipReferToHeaderConstruct(pSubscription->pMgr->hMsgMgr,
hpool, pSubscription->hPage, &hReferTo);
RvSipReferToHeaderParse(hReferTo, strReferTo);
//如果用户传入了referBy字符串,则进行referBy头域对象构造,并将字符串解析
//到头域对象中
if(strReferredBy != NULL)
RvSipReferredByHeaderConstruct(pSubscription->pMgr->hMsgMgr,
hpool, pSubscription->hPage, &hReferredBy);
RvSipReferredByHeaderParse(hReferredBy, strReferredBy)
//使用前面构造的头域对象初始化refer参数
SubsReferSetInitialReferParams(pSubscription, hReferTo, hReferredBy);
//初始化referInfo块
InitSubsReferInfo(pSubs);
pSubs->pReferInfo->eReferResultObjType =
RVSIP_COMMON_STACK_OBJECT_TYPE_UNDEFINED;
pSubs->pReferInfo->referFinalStatus = 0;
//设置订阅含有Event:refer头域
RvSipEventHeaderSetEventPackage(pSubs->hEvent, "refer");
//标记当前Refer是对话框中第一个
pSubs->pReferInfo->bFirstReferSubsInDialog = RV_TRUE;
//pCallLeg->bFirstReferExists = RV_TRUE;
SipCallLegSetFirstReferExists(pSubs->hCallLeg);
//将之前构造的referTo头域对象设置到pSubs->pReferInfo->hReferTo
SubsReferSetReferToHeader(pSubs, hReferTo)
//将之前构造的referTo头域对象设置到pSubs->pReferInfo->hReferredBy
SubsReferSetReferredByHeader(pSubs, hReferredBy)
//如果用户传入了replaces字符串,并且当前对话管理对象支持replace处理,则
//设置replace头域对象到pSubs->pReferInfo->hReferTo->hReplacesHeader中
if((strReplaces != NULL) &&
(SipCallLegMgrGetReplacesStatus(pSubscription->pMgr->hCallLegMgr) !=
RVSIP_CALL_LEG_REPLACES_UNDEFINED))
SubsReferSetReplacesInReferToHeader(pSubscription, strReplaces)
//发送Refer请求
RvSipSubsRefer(hSubs)
SubsSubscribe(pSubs, RV_TRUE);
//发送请求
SubsSendRequest(pSubs, pSubs->expirationVal, bRefer, RV_TRUE);
eMethod = SIP_TRANSACTION_METHOD_REFER
//构建Refer事务
SubsPrepareSubscribeTransc(pSubs, expiresVal, bRefer, bCreateNewTransc);
//构造一个事务对象到pSubs->hActiveTransc中
SipCallLegCreateTransaction(pSubs->hCallLeg, RV_FALSE,
&(pSubs->hActiveTransc))
//将新的事务对象加入到pSubs->hTranscList列表中
SubsAddTranscToList(pSubs,pSubs->hActiveTransc)
//分配外发消息资源
RvSipTransactionGetOutboundMsg(pSubs->hActiveTransc, &hMsg);
//设置事件ID,并将refer-to、referred-by头域设置到消息对象中
SubsReferSetRequestParamsInMsg(pSubs, pSubs->hActiveTransc, hMsg);
// 将订阅对象指针设置到事务对象中pTransc->pSubsInfo
SipTransactionSetSubsInfo(pSubs->hActiveTransc, (void*)pSubs)
//将对话框对象句柄加入对对话框管理对象的HASH表中
SipCallLegSubsInsertCallToHash(pSubs->hCallLeg, RV_FALSE)
//将Refer请求发送出去
SipCallLegSendRequest(pSubs->hCallLeg,pSubs->hActiveTransc,eMethod,NULL);
CallLegSendRequest((CallLeg*)hCallLeg,hTransc, eRequestMethod,
strMethod)
//订阅状态更新通知
SubsChangeState(pSubs, RVSIP_SUBS_STATE_SUBS_SENT,
RVSIP_SUBS_REASON_UNDEFINED);
pSubs->ePrevState = pSubs->eState;
pSubs->eState = eState; // RVSIP_SUBS_STATE_SUBS_SENT
pSubs->eLastState = eState; // RVSIP_SUBS_STATE_SUBS_SENT
//调用上层回调,通知用户订阅状态改变
SubsCallbackChangeSubsStateEv(pSubs,eState, eReason);
二、 接收Refer请求
//事务管理对象处理接收到的消息
SipTransactionMgrMessageReceivedEv
//处理请求消息
RequestMessageReceived
HandleIncomingRequestMsg
//从消息中获取事务关键字(from、to、call-id、cseq)
SipTransactionMgrGetKeyFromMessage((RvSipTranscMgrHandle)pTranscMgr,
hReceivedMsg, &key);
//根据关键字创建事务查找所用的HASH KEY
CreateTranscMgrHashKey(……)
//在事务管理对象中查找是否有对应的事务
SipTransactionMgrFindTransactionByHashKey(pTranscMgr, &hashKey,
hReceivedMsg,&pTransc);
//当前事务管理对象中没有匹配的事务
if(pTransc == NULL)
//检查此消息是否必须基于新的事务对象,当前处理的refer是需要的,
// bOpenTransaction为true
bOpenTransaction = IsNewTranscRequired(……)
if(bOpenTransaction == RV_FALSE)
XXX
//进行第二次尝试查找事务
S ipTransactionMgrFindTransactionByHashKey(pTranscMgr, &hashKey,
hReceivedMsg,&pTransc);
if(pTransc == NULL)
//进行冲突的检测,主要考虑有的中间代理进行了forking操作,导致最
//后终端已经在处理使用的事务了,但又出现相同的事务
if(pTranscMgr->bDisableMerging == RV_FALSE)
XXX
//创建新的事务对象
CreateNewServerTransaction(……)
//完成事务相关初始化
TransactionPostInitialization
FinalizeServerTranscCreation
TransactionSaveReceivedFromAddr
SipTransmitterSetLocalAddressHandle
//更新事务所属者
UpdateServerTransactionOwner(pTranscMgr, pTransc, hReceivedMsg, &key,
RV_FALSE, NULL);
//判断是否通知对话框对象,当前的Refer是基于对话内的,所以该
//函数流程不会更改bNotifyCallLeg值,而bNotifyCallLeg值默认为True
IsCallLegNotificationRequired(pTransc,&bNotifyCallLeg);
if(RV_TRUE == bNotifyCallLeg)
//调用对话框事务创建回调,该回调函数为
// CallLegMgrTranscCreatedEvHandler
TransactionCallbackCallTranscCreatedEv(……)
CallLegMgrTranscCreatedEvHandler
//当前refer为对话内,所以bInitialRequest为false
bInitialRequest = IsInitialRequest(pMgr, hTransc, pKey,
eMethod);
// bOnlyEstablishedCall为true
bOnlyEstablishedCall = (bInitialRequest == RV_TRUE) ?
RV_FALSE: RV_TRUE;
//构建hash key
CALL_TRANSC_KEY_TO_HASH_ELEM(pMgr,pKey,
RVSIP_CALL_LEG_DIRECTION_INCOMING,
bOnlyEstablishedCall,&hashElem);
//查找对应的对话框对象
CallLegMgrHashFindByElem(…)
//处理新接收的事务
CallLegHandleNewTransaction(…)
//当前方法为refer
if(eMethod != SIP_TRANSACTION_METHOD_INVITE)
//如果用户设置了对话框的
// pfnTranscCreatedEvHandler回调,则调用此回调
//通知有新的事务创建,根据回调返回的
// bAppHandleTransc结果,来决定该事务后续是否
//由用户来处理pTransc->bAppInitiate= true or false
NotifyAppOnGeneralTransactionIfNeeded
//当前为refer请求,这里假设上层用户在上面的新 //事务创建回调中确定不处理此事务,交给协议栈处 //理
if(eMethod == SIP_TRANSACTION_METHOD_REFER
&& bAppHandleTransc == RV_FALSE)
//订阅管理对象进行事务处理
SipSubsMgrSubsTranscCreated
//进行是否存在已经含有订阅对象的判断,并
//设置bFoundExistSubs标记,当前接收到的
//是一个新的refer请求,之前并没有创建过
//订阅对象,所以bFoundExistSubs=false
//之前没有订阅对象,则进行订阅对象的创建
if(RV_FALSE == bFoundExistSubs)
//创建新的订阅对象,目前订阅对象的创
//建由subscriber、notifier、refer三种事
//务触发,当前由notifier和refer触发的
//订阅对象创建的订阅类型都为
// RVSIP_SUBS_TYPE_NOTIFIER,其中第5
//参数bOutOfBand的值为RV_FALSE表示
//该订阅对象并非隐式创建,但对于使用
//subscriber、notifier触发的订阅创建应 //该都是隐式创建,所以这里即使
//订阅类型都为
//RVSIP_SUBS_TYPE_NOTIFIER,从
//bOutOfBand值中可以区分出来,这个
//订阅对象是什么触发的。
//pSubs->bOutOfBand=FALSE;
//pSubs->eSubsType=
// RVSIP_SUBS_TYPE_NOTIFIER
SubsMgrSubscriptionObjCreate(pMgr,
hCallLeg, NULL,
RVSIP_SUBS_TYPE_NOTIFIER, RV_FALSE,
&hSubs)
//订阅对象中Refer信息初始化,并且从
//消息中提取Refer-To、Referred-By
SubsReferIncomingReferInitialize
//调用上层设置的订阅管理对象
// pfnSubsCreatedEvHandler回调,通知上
//层创建了订阅对象
SubsCallbackSubsCreatedEv(pMgr, pSubs);
//将订阅对象设置到事务对象中
// pTransc->pSubsInfo
SipTransactionSetSubsInfo(hTransc,
(void*)hSubs);
//将事务加入到订阅对象的事务列表中
SubsAddTranscToList(pSubs, hTransc)
//更新如下返回参数:
//pKey->hToHeader
//pKey->hFromHeader
//pKey->strCallId
//ppOwner
// tripleLock
//当前获取了pOwner为对话框对象,同时也获取对话框中的锁
if(pOwner != NULL && tripleLock != NULL)
//更新事务对象的所属者
TransactionAttachOwner(hTransc, pOwner, pKey, tripleLock,
SIP_TRANSACTION_OWNER_CALL, RV_FALSE);
pTransc->pOwner = pOwner; //对话框对象
// SIP_TRANSACTION_OWNER_CALL
pTransc->eOwnerType = eOwnerType
//更新事务对象的事件回调处理为对话框对象设置的值
pTransc->pEvHandlers =
&((pTransc->pMgr)->pCallLegEvHandlers)
//从对话框中获取关键参数设置到事务对象中
TransactionAttachKey(pTransc,pKey)
//处理接收的消息
TransactionMsgReceived(pTransc, hReceivedMsg)
if (RVSIP_MSG_REQUEST == bMsgType)
HandleRequestMsg(pTransc, hMsg)
switch (pTransc->eState)
case (RVSIP_TRANSC_STATE_IDLE):
HandleRequestInInitialState(pTransc, hMsg)
switch (eMethod)
case (RVSIP_METHOD_REFER):
HandleGeneralInInitialState
//调用该事务所属对象的回调通知消息接收,
//当前事务所属对象为对话框对象,该回调函//数为CallLegMsgEvMsgRcvdHandler
//在下面单独分析该回调
TransactionMsgReceivedNotifyOthers
//更新事务状态为
//RVSIP_TRANSC_STATE_SERVER_GEN_REQUEST_RCVD
//并调用该事务所属对象的回调通知事务状
//态改变,该回调函数为
// CallLegTranscEvStateChangedHandler,在下
//面单独分析该回调
TransactionStateSrvGeneralReqRecvd(
RVSIP_TRANSC_REASON_REQUEST_RECEIVED,
pTransc);
------------------------------------------------------------------------------------------------------------------------------
CallLegMsgEvMsgRcvdHandler
//该事务含有订阅信息
if(SipTransactionGetSubsInfo(hTransc) != NULL)
//订阅对象处理消息接收
SipSubsMsgRcvdEvHandling(……)
//调用用户设置的订阅对象的消息接收回调,通知消息接收
SubsCallbackMsgRcvdEv
……
//之前该Refer事务上层已经标记由协议栈处理
if(bAppTransc == RV_FALSE &&eMethod == SIP_TRANSACTION_METHOD_REFER)
//从接收消息中提取所需数据
LoadFromSubsRcvdMsg(pCallLeg,hTransc,hMsg,eMsgType,eMethod)
switch (eMethod)
case SIP_TRANSACTION_METHOD_REFER:
CallLegSubsLoadFromRequestRcvdMsg(pCallLeg,hMsg);
//从Refer的contact头域中提取contact地址对象设置到对话框对象
//中pCallLeg->hRemoteContact
CallLegMsgLoaderLoadContactToRemoteContact(pCallLeg, hMsg)
------------------------------------------------------------------------------------------------------------------------------
CallLegTranscEvStateChangedHandler
//合法的请求校验,如果出现异常,则在这里中止之前的订阅对象,及Refer的事务对
//象
rv = RejectInvalidRequests(pCallLeg,hTransc,eTranscState,&b_wasRejected)
if(rv != RV_OK || b_wasRejected == RV_TRUE)
return;
//设置Tos值
switch(eTranscState)
case RVSIP_TRANSC_STATE_SERVER_GEN_REQUEST_RCVD:
SipTransactionSetTosValue (hTransc, pCallLeg->tosValue)
//订阅对象处理事务改变
SipSubsHandleTranscChangeState(hTransc, pCallLeg, eTranscState, eStateReason, eMethod,
pSubsInfo, &b_wasHandledBySubs);
switch(eTranscState)
case RVSIP_TRANSC_STATE_SERVER_GEN_REQUEST_RCVD:
if(eMethod == SIP_TRANSACTION_METHOD_REFER)
//订阅请求处理
SubsHandleSubscribeRequest(pSubs, hTransc, eMethod, hMsg)
//进行Refer请求的校验,如果检测到异常,则终止订阅
if(SIP_TRANSACTION_METHOD_REFER == eMethod)
SubsReferCheckReferRequestValidity(pSubs,hMsg,&responseCode);
if(responseCode > 0)
RvSipTransactionRespond(hTransc,responseCode,NULL)
SubsUpdateStateAfterReject(pSubs,
RVSIP_SUBS_REASON_ILLEGAL_REFER_MSG)
//处理订阅请求
HandleSubsRequest(pSubs, hTransc, hMsg);
//从Refer请求中提取expires值,如果头部没有,则使用默认值
rv = GetExpiresValFromMsg(hMsg, RV_FALSE, &expires);
if(rv != RV_OK)
expires = RVSIP_SUBS_EXPIRES_VAL_LIMIT;
//处理初始的订阅请求
if((expires >= 0) && (pSubs->eState == RVSIP_SUBS_STATE_IDLE))
HandleInitialSubsRequest(pSubs, hTransc, hMsg, expires)
//将该事务关联到订阅对象中
pSubs->hActiveTransc = hTransc;
//对referto头对象解析
SubsReferAnalyseSubsReferToHeader(pSubs);
//将referToUrl句柄转换为hHeadersList
RvSipAddrUrlGetHeaders(hReferToUrl, pBuffer,
buffLen, &buffLen)
RvSipAddrUrlGetHeadersList(hReferToUrl, hHeadersList, pBuffer)
//如果含有replaces,则将replaces头对象从
// hHeadersList列表中删除,同时将replaces头
//对象存储到
//pSubs->pReferInfo->hReferTo->hReplacesHeader
//中
SubsReferUpdateReplacesHeader(pSubs,
hReferToUrl, hHeadersList)
//将referTo头列表存储到订阅对象的pReferInfo中
pSubs->pReferInfo->hReferToHeadersList =
hHeadersList;
//确定接收原因,本地支持replace并且远端refer-to中
//含有replace,则返回原因值为
// RVSIP_SUBS_REASON_REFER_RCVD_WITH_REPLACES,
//否则返回原因值为RVSIP_SUBS_REASON_REFER_RCVD
eReason =
SubsReferDecideOnReferRcvdReason(pSubs,hMsg);
//根据接收到的Refer消息中是否协带
//Require: replaces或Supported: replaces,来设置
//对话框对象的statusReplaces值
SipCallLegUpdateReplacesStatus(pSubs->hCallLeg,
hMsg)
//从对话框管理对象中获取本地是否支持replace
//如果支持,则满足该条件处理
if(SipCallLegMgrGetReplacesStatus(
pSubs->pMgr->hCallLegMgr) !=
RVSIP_CALL_LEG_REPLACES_UNDEFINED)
//获取replaces头句柄
hReplacesHeader =
SipReferToHeaderGetReplacesHeader(
pSubs->pReferInfo->hReferTo);
if(hReplacesHeader != NULL)
returnRVSIP_SUBS_REASON_
REFER_RCVD_WITH_REPLACES
return RVSIP_SUBS_REASON_REFER_RCVD
//订阅状态更新
SubsChangeState(pSubs, RVSIP_SUBS_STATE_SUBS_RCVD,
eReason);
pSubs->eState = eState;
pSubs->eLastState = eState;
//调用用户设置的回调,通知用户收到订阅的请求
//以及订阅请求的原因。用户的回调函数为
// pfnStateChangedEvHandler
SubsCallbackChangeSubsStateEv(pSubs,eState,
eReason)
//Refer请求事务的处理已经在上面完成交给订阅对象来处理,这里b_wasHandledBySubs
//为true,不走此流程。
if(b_wasHandledBySubs == RV_FALSE)
XXX
三、 订阅StateChanged回调
pfnStateChangedEvHandler
//假设当前用户仅处理普通Refer请求触发的订阅
if(RVSIP_SUBS_STATE_SUBS_RCVD == eState && RVSIP_SUBS_REASON_REFER_RCVD ==
eReason)
eObjType = RVSIP_COMMON_STACK_OBJECT_TYPE_CALL_LEG
//对Refer请求进行接受处理
RvSipSubsReferAccept(hSubs, NULL, eObjType, &eObjType, (void**)&hCallLeg)
//给Refer请求回应202应答
SubsAccept(pSubs,202, UNDEFINED, RV_TRUE);
pSubs->expirationVal = UNDEFINED;
pSubs->requestedExpirationVal = UNDEFINED;
//发送事务应答,在后续流程中,也触发了事务状态转换的回调处理
// CallLegTranscEvStateChangedHandler,但分析该回调仅针对Refer的
//错误应答进行处理,当前回应202不会做其它处理。
RvSipTransactionRespond(pSubs->hActiveTransc,responseCode,NULL)
//订阅对象当在关联Refer事务
pSubs->hActiveTransc = NULL;
//订阅对象状态变迁为RVSIP_SUBS_STATE_ACTIVE,通知用户层回调
SubsChangeState(pSubs,RVSIP_SUBS_STATE_ACTIVE,
RVSIP_SUBS_REASON_UNDEFINED);
//当前一个与该订阅关联的对象,当前新对象为对话框对象
SubsReferAttachNewReferResultObject(……)
switch(*peCreatedObjType)
case RVSIP_COMMON_STACK_OBJECT_TYPE_CALL_LEG:
SubsReferCreateNewCallLegResultObj(……)
//创建对话框对象
SipCallLegMgrCreateCallLeg(……)
//使用订阅参数初始化对话框对象,
// hRemoteContact 取自Refer-to
// hToHeader 取自Refer-to
// hFromHeader 取自订阅关联的对话框中的From头
// hLocalContact 取自订阅关联的对话框中
//Call-id 是新生成的
ReferSetParamsInNewObjDialog(pSubs, hNewCallLeg)
//将Refer触发生成的对话框对象与订阅关联,该对话框后续处
//理状态都需要通过订阅对象发送给Refer端
SubsReferAttachResultCallLeg(pSubs, hNewCallLeg)
//将refer-by头对象复制到对话框对象中
SipCallLegSetReferredBy(hNewCallLeg,
pSubs->pReferInfo->hReferredBy)
//设置关联
SubsReferAttachResultObjToReferSubsGenerator (pSubs,
RVSIP_COMMON_STACK_OBJECT_TYPE_CALL_LEG,
tempNewSubs);
//将生成该对话框对象的订阅句柄设置到对话框对象
//中
SipCallLegAttachReferResultCallLegToReferSubsGenerator
pCallLeg->hReferSubsGenerator=
hReferSubsGenerator;
pCallLeg->tripleLock= pReferSubsTriplelock
//将生成的对话框对象设置到订阅对象的refer信息中
pSubs->pReferInfo->pReferResultObj = pObj;
pSubs->pReferInfo->eReferResultObjType = eObjType;
//如果本地支持replace,同时远端的Refer中协带了replace则
//设置到对话框对象中
SubsReferSetReplaces(pSubs,hNewCallLeg)
eReason = RVSIP_SUBS_REFER_NOTIFY_READY_REASON_INITIAL_NOTIFY;
responseCode = 100;
//调用用户设置的回调,通知用户新的订阅已经成功,需要发送初始的
//notify,该回调函数为pfnReferNotifyReadyEvHandler
SubsCallbackReferNotifyReadyEv(pSubs, eReason, responseCode, NULL)
四、 NotifyReady的回调
pfnReferNotifyReadyEvHandler
switch (eReason)
case RVSIP_SUBS_REFER_NOTIFY_READY_REASON_INITIAL_NOTIFY:
eSubsState = RVSIP_SUBSCRIPTION_SUBSTATE_ACTIVE;
notifyResponseCode = responseCode;
expires = 50;
//创建notify事务对象
RvSipSubsCreateNotify(hSubs, NULL, &hNotify)
SubsNotifyCreate(pSubs, hAppNotify, phNotify);
//在订阅对象的hNotifyList列表中分配一个Notify对象资源,并初始化nofify
//对象,同时更新订阅对象中notify对象数目pSubs->numOfNotifyObjs
SubsNotifyCreateObjInSubs(pSubs, hAppNotify, phNotify);
//设置notify对象参数
RvSipNotifySetSubscriptionStateParams(hNotify,eSubsState, eNotifyReason, expires);
SubsNotifySetSubscriptionStateParams(pNotify, eSubsState, eReason, expiresParamVal)
pNotify->eSubstate = eSubsState; // RVSIP_SUBSCRIPTION_SUBSTATE_ACTIVE
// RVSIP_SUBS_REFER_NOTIFY_READY_REASON_INITIAL_NOTIFY
pNotify->eReason = eReason;
pNotify->expiresParam = expiresParamVal; //50
//设置notify对象的body
RvSipNotifySetReferNotifyBody(hNotify, notifyResponseCode);
//订阅最后应答码到订阅对象的refer信息中
pNotify->pSubs->pReferInfo->referFinalStatus = (RvUint16)statusCode;
//设置notify对象消息body
SubsReferSetNotifyBody(pNotify, statusCode);
//发送Notify请求
RvSipNotifySend(hNotify);
SubsNotifySend(pNotify->pSubs, pNotify)
//创建事务
SubsNotifyCreateTransc(pNotify)
//创建事务对象,对象句柄保留到notify对象中pNotify->hTransc
SipCallLegCreateTransaction(…)
//将notify对象关联的事务中pTransc->pSubsInfo
SipTransactionSetSubsInfo(pNotify->hTransc, (void*)pNotify)
//在Notify消息对象中添加eSubstate、eReason、expiresVal等头对象
NotifyPrepareMsgBeforeSending(pNotify)
//更新notify对象参数,主要针对收到的notify消息,所以当前发送
//notify消息没有特别的处理
SetNotificationParamsFromMsg(…)
//将发出消息对象设置到事务对象中
SipTransactionSetOutboundMsg(pNotify->hTransc, pNotify->hOutboundMsg);
pNotify->hOutboundMsg = NULL;
//发送Notify请求,当前流程也触发了对话框的事务状态变迁回调,但在该
//回调中,没有针对notify事务请求的处理
SipCallLegSendRequest(pSubs->hCallLeg, pNotify->hTransc,
SIP_TRANSACTION_METHOD_NOTIFY, NULL)
//将notify事务的cseq保存到订阅对象的pSubs->expectedCSeq中
RvSipTransactionGetCSeqStep(pNotify->hTransc,&cseqTransc);
SipCommonCSeqSetStep(cseqTransc,&pSubs->expectedCSeq);
//更新notify状态
InformNotifyStatus(pNotify,RVSIP_SUBS_NOTIFY_STATUS_REQUEST_SENT,
RVSIP_SUBS_NOTIFY_REASON_UNDEFINED,NULL);
pNotify->eStatus // RVSIP_SUBS_NOTIFY_STATUS_REQUEST_SENT
//调用用户层的pfnNotifyEvHandler回调,通知用户notify已经发送
SubsCallbackChangeNotifyStateEv(……)
五、 接收Refer应答
SipTransactionMgrMessageReceivedEv
ResponseMessageReceived
HandleIncomingResponseMsg
//从消息中提取关键字段,查找是否存在对应的事务对象
SipTransactionMgrGetKeyFromMessage
SipTransactionMgrFindTransaction
//接收消息处理
TransactionMsgReceived(pTransc, hReceivedMsg)
HandleFinalResponse(pTransc, hMsg)
switch (pTransc->eState)
case (RVSIP_TRANSC_STATE_CLIENT_GEN_REQUEST_SENT):
//更新事务应答码pTransc->responseCode
TransactionSetResponseCode(pTransc, responseCode);
//处理完成应答
HandleGeneralFinalResponse
//调用该事务所属对象的回调通知消息接收,当前事务所属
//对象为对话框对象,该回调函数为
//CallLegMsgEvMsgRcvdHandler,在下面单独分析该回调
TransactionMsgReceivedNotifyOthers(pTransc,hMsg)
switch (pTransc->eMethod)
case SIP_TRANSACTION_METHOD_REFER:
//更新事务的To头域对象和From头域对象
if ((200 <= responseCode) && (300 > responseCode))
TransactionUpdatePartyHeaders
//事务状态更新,调用对话框对象的事务状态更新回调,该
//回调函数为CallLegTranscEvStateChangedHandler,在下面
//单独分析该回调
//eReason =
// RVSIP_TRANSC_REASON_RESPONSE_SUCCESSFUL_RECVD
TransactionStateUacGeneralFinalResponseRcvd(…)
TransactionChangeState(pTransc,
RVSIP_TRANSC_STATE_CLIENT_GEN_FINAL_RESPONSE_RCVD,
eReason);
---------------------------------------------------------------------------------------------------------------------------------
CallLegMsgEvMsgRcvdHandler
//处理订阅信息
if(SipTransactionGetSubsInfo(hTransc) != NULL)
SipSubsMsgRcvdEvHandling(……)
//调用用户设置的订阅对象的消息接收回调,通知消息接收
SubsCallbackMsgRcvdEv(pSubs, hNotify, hAppNotify, hMsg);
---------------------------------------------------------------------------------------------------------------------------------
CallLegTranscEvStateChangedHandler
//该事务含有订阅信息
pSubsInfo = SipTransactionGetSubsInfo(hTransc);
if(pSubsInfo != NULL)
//由订阅对象处理事务状态改变
SipSubsHandleTranscChangeState
switch(eTranscState)
case RVSIP_TRANSC_STATE_CLIENT_GEN_FINAL_RESPONSE_RCVD:
if(eMethod == SIP_TRANSACTION_METHOD_REFER )
//处理订阅应答
SubsHandleSubscribeResponse(pSubs, hMsg, statusCode, RV_TRUE);
switch (pSubs->eState)
case RVSIP_SUBS_STATE_SUBS_SENT:
SubsHandleResponseOnInitialSubscribe
if (responseCode >= 200 && responseCode < 300)
//这里Refer的应答后,启动无Notify的定时器
//在该时间范围内,如果没有收到Notify通知,则
//触发该定时器的回调函数
// SubsNoNotifyTimerHandleTimeout
SubsSetNoNotifyTimer(pSubs)
//订阅状态更新
// eNewState = RVSIP_SUBS_STATE_2XX_RCVD;
// eReason = RVSIP_SUBS_REASON_UNDEFINED
SubsResponseRcvdStateChange(pSubs, eNewState,
eReason);
//调用用户层回调,通知订阅状态更新
SubsChangeState(pSubs, eNewState, eReason);
pSubs->hActiveTransc = NULL
六、 接收Notify请求
SipTransactionMgrMessageReceivedEv
//处理请求消息
RequestMessageReceived
HandleIncomingRequestMsg
//从消息中获取事务关键字(from、to、call-id、cseq)
SipTransactionMgrGetKeyFromMessage((RvSipTranscMgrHandle)pTranscMgr,
hReceivedMsg, &key);
//根据关键字创建事务查找所用的HASH KEY
CreateTranscMgrHashKey(……)
//在事务管理对象中查找是否有对应的事务
SipTransactionMgrFindTransactionByHashKey(pTranscMgr, &hashKey,
hReceivedMsg,&pTransc);
//当前事务管理对象中没有匹配的事务
if(pTransc == NULL)
//检查此消息是否必须基于新的事务对象,当前处理的notify是需要的,
// bOpenTransaction为true
bOpenTransaction = IsNewTranscRequired(……)
if(bOpenTransaction == RV_FALSE)
XXX
//进行第二次尝试查找事务
S ipTransactionMgrFindTransactionByHashKey(pTranscMgr, &hashKey,
hReceivedMsg,&pTransc);
if(pTransc == NULL)
//进行冲突的检测,主要考虑有的中间代理进行了forking操作,导致最
//后终端已经在处理使用的事务了,但又出现相同的事务
if(pTranscMgr->bDisableMerging == RV_FALSE)
XXX
//创建新的事务对象
CreateNewServerTransaction(……)
//完成事务相关初始化
TransactionPostInitialization
FinalizeServerTranscCreation
TransactionSaveReceivedFromAddr
SipTransmitterSetLocalAddressHandle
//更新事务所属者
UpdateServerTransactionOwner(pTranscMgr, pTransc, hReceivedMsg, &key,
RV_FALSE, NULL);
//判断是否通知对话框对象,当前的notify是基于对话内的,所以该
//函数流程不会更改bNotifyCallLeg值,而bNotifyCallLeg值默认为True
IsCallLegNotificationRequired(pTransc,&bNotifyCallLeg);
if(RV_TRUE == bNotifyCallLeg)
//调用对话框事务创建回调,该回调函数为
// CallLegMgrTranscCreatedEvHandler
TransactionCallbackCallTranscCreatedEv(……)
CallLegMgrTranscCreatedEvHandler
//当前notify为对话内,所以bInitialRequest为false
bInitialRequest = IsInitialRequest(pMgr, hTransc, pKey,
eMethod);
// bOnlyEstablishedCall为true
bOnlyEstablishedCall = (bInitialRequest == RV_TRUE) ?
RV_FALSE: RV_TRUE;
//如果处理接收的notify请求,则考虑可能notify比refer
//的应答提前来的,将bOnlyEstablishedCall置为false
if(eMethod == SIP_TRANSACTION_METHOD_NOTIFY)
bOnlyEstablishedCall = RV_FALSE;
//构建hash key
CALL_TRANSC_KEY_TO_HASH_ELEM(pMgr,pKey,
RVSIP_CALL_LEG_DIRECTION_INCOMING,
bOnlyEstablishedCall,&hashElem);
//查找对应的对话框对象
CallLegMgrHashFindByElem(…)
//处理新接收的事务
CallLegHandleNewTransaction(…)
//当前方法为notify
if(eMethod == SIP_TRANSACTION_METHOD_NOTIFY)
//订阅管理对象处理notify事务
SipSubsMgrNotifyTranscCreated
//查找该对话框关联的订阅对象
SipCallLegSubsFindSubscription(hCallLeg,
hEvent, RVSIP_SUBS_TYPE_SUBSCRIBER,
&hSubs)
//创建Notify对象,并加入到订阅对象的列表
//中pSubs->hNotifyList
SubsNotifyCreateObjInSubs(pSubs, NULL,
&hNotify)
//使用用户回调,通知创建了Notify事务
SubsCallbackNotifyTranscCreatedEv(pMgr,
pSubs, pNotify);
//将Notify对句柄关联的事务对象中
SipTransactionSetSubsInfo(hTransc,
(void*)hNotify)
pTransc->pSubsInfo = pSubsInfo;
//将当前事务关联到notify对象中
pNotify->hTransc = hTransc;
//更新如下返回参数:
//pKey->hToHeader
//pKey->hFromHeader
//pKey->strCallId
//ppOwner
// tripleLock
//当前获取了pOwner为对话框对象,同时也获取对话框中的锁
if(pOwner != NULL && tripleLock != NULL)
//更新事务对象的所属者
TransactionAttachOwner(hTransc, pOwner, pKey, tripleLock,
SIP_TRANSACTION_OWNER_CALL, RV_FALSE);
pTransc->pOwner = pOwner; //对话框对象
// SIP_TRANSACTION_OWNER_CALL
pTransc->eOwnerType = eOwnerType
//更新事务对象的事件回调处理为对话框对象设置的值
pTransc->pEvHandlers =
&((pTransc->pMgr)->pCallLegEvHandlers)
//从对话框中获取关键参数设置到事务对象中
TransactionAttachKey(pTransc,pKey)
//处理接收的消息
TransactionMsgReceived(pTransc, hReceivedMsg);
HandleRequestMsg(pTransc, hMsg)
switch (pTransc->eState)
case (RVSIP_TRANSC_STATE_IDLE):
HandleRequestInInitialState(pTransc, hMsg)
HandleGeneralInInitialState(pTransc, hMsg)
//调用该事务所属对象的回调通知消息接收,当前事务所属
//对象为对话框对象,该回调函数为
//CallLegMsgEvMsgRcvdHandler,在下面单独分析该回调
TransactionMsgReceivedNotifyOthers(pTransc,hMsg)
//更新事务状态为
//RVSIP_TRANSC_STATE_SERVER_GEN_REQUEST_RCVD
//并调用该事务所属对象的回调通知事务状态改变,该回调
//函数为CallLegTranscEvStateChangedHandler,在下面单独
//分析该回调
TransactionStateSrvGeneralReqRecvd(
RVSIP_TRANSC_REASON_REQUEST_RECEIVED, pTransc);
---------------------------------------------------------------------------------------------------------------------------------
CallLegMsgEvMsgRcvdHandler
//该事务含有订阅信息
if(SipTransactionGetSubsInfo(hTransc) != NULL)
//订阅管理模块进行消息接收处理
SipSubsMsgRcvdEvHandling
//调用用户回调,通知收到消息
SubsCallbackMsgRcvdEv
//如果上层用户不处理该Notify请求事务,则由协议栈处理
if(bAppTransc == RV_FALSE && eMethod == SIP_TRANSACTION_METHOD_NOTIFY)
//从消息中获取contact头域,更新到对话框对象中pCallLeg->hRemoteContact
LoadFromSubsRcvdMsg(pCallLeg,hTransc,hMsg,eMsgType,eMethod);
---------------------------------------------------------------------------------------------------------------------------------
CallLegTranscEvStateChangedHandler
//合法的请求校验,如果出现异常,则在这里中止之前的订阅对象,及Notify的事务对
//象
rv = RejectInvalidRequests(pCallLeg,hTransc,eTranscState,&b_wasRejected)
if(rv != RV_OK || b_wasRejected == RV_TRUE)
return;
//设置Tos值
switch(eTranscState)
case RVSIP_TRANSC_STATE_SERVER_GEN_REQUEST_RCVD:
SipTransactionSetTosValue (hTransc, pCallLeg->tosValue)
//订阅对象处理事务改变
SipSubsHandleTranscChangeState(hTransc, pCallLeg, eTranscState, eStateReason, eMethod,
pSubsInfo, &b_wasHandledBySubs);
switch(eTranscState)
case RVSIP_TRANSC_STATE_SERVER_GEN_REQUEST_RCVD:
if(eMethod == SIP_TRANSACTION_METHOD_NOTIFY)
//Notify请求处理
SubsNotifyHandleRequest(pNotify, hTransc, hMsg);
//更新notify参数,从消息中提取subscription-state、eReason、
// expiresParam
SetNotificationParamsFromMsg(pNotify, hMsg, &eReason)
pNotify->hTransc = hTransc;
//从notify消息中提取body中的应答码,并存储到订阅对象的refer
//信息中pSubs->pReferInfo->referFinalStatus
SubsReferLoadFromNotifyRequestRcvdMsg(pNotify, hMsg)
//调用用户回调,通知已经收到Notify请求,该回调函数为
// pfnNotifyEvHandler
InformNotifyStatus(pNotify,
RVSIP_SUBS_NOTIFY_STATUS_REQUEST_RCVD, eReason, hMsg);
//Notify请求事务的处理已经在上面完成交给订阅对象来处理,这里
//b_wasHandledBySubs为true,不走此流程。
if(b_wasHandledBySubs == RV_FALSE)
XXX
七、 pfnNotifyEvHandler回调
pfnNotifyEvHandler
switch (eNotifyStatus)
case RVSIP_SUBS_NOTIFY_STATUS_REQUEST_RCVD:
//对Notify进行应答
RvSipNotifyAccept(hNotification)
SubsNotifyRespond(pNotify->pSubs, pNotify, 200)
//发送事务应答
RvSipTransactionRespond(pNotify->hTransc,statusCode,NULL);
//调用用户回调,通知已经发送Notify对应的应答
InformNotifyStatus(pNotify,
RVSIP_SUBS_NOTIFY_STATUS_FINAL_RESPONSE_SENT,
RVSIP_SUBS_NOTIFY_REASON_UNDEFINED,NULL);
if(statusCode == 200)
//更新订阅对象
UpdateSubsAfter2xxOnNotifySent(pSubs, pNotify, &bWasSubsDeleted);
//收到notify后,释放之前已经启动的无notify定时器
if(pSubs->eState != RVSIP_SUBS_STATE_UNSUBSCRIBE_2XX_RCVD)
SubsNoNotifyTimerRelease(pSubs)
//如果远端的notify含有超时时间,则启动订阅告警定时器,该
//定时器超时后,会发起订阅刷新(如果设置为自动模式)
if(pNotify->expiresParam > 0 && pSubs->bOutOfBand == RV_FALSE) SubsCalculateAndSetAlertTimer(pSubs,
pNotify->expiresParam);
//Notify的原因码转换,Notify请求中不含有原因值时,转换为
// RVSIP_SUBS_REASON_NOTIFY_2XX_SENT
NotifyReason2MsgReason(pNotify->eReason);
switch(pNotify->eSubstate)
case RVSIP_SUBSCRIPTION_SUBSTATE_ACTIVE:
//订阅状态机,当前更新如下:
// eNewState= RVSIP_SUBS_STATE_ACTIVE
// bFinished = FALSE
Handle2xxOnNotifyActiveSent (pSubs, &eNewState,
&bFinished)
//调用用户层回调,通知上层状阅状态更新
SubsChangeState(pSubs, eNewState, eReason);
八、 接收Notify应答
SipTransactionMgrMessageReceivedEv
ResponseMessageReceived
HandleIncomingResponseMsg
//从消息中提取关键字段,查找是否存在对应的事务对象
SipTransactionMgrGetKeyFromMessage
SipTransactionMgrFindTransaction
//接收消息处理
TransactionMsgReceived(pTransc, hReceivedMsg)
HandleFinalResponse(pTransc, hMsg)
switch (pTransc->eState)
case (RVSIP_TRANSC_STATE_CLIENT_GEN_REQUEST_SENT):
//更新事务应答码pTransc->responseCode
TransactionSetResponseCode(pTransc, responseCode);
//处理完成应答
HandleGeneralFinalResponse
//调用该事务所属对象的回调通知消息接收,当前事务所属
//对象为对话框对象,该回调函数为
//CallLegMsgEvMsgRcvdHandler,在下面单独分析该回调
TransactionMsgReceivedNotifyOthers(pTransc,hMsg)
//事务状态更新,调用对话框对象的事务状态更新回调,该
//回调函数为CallLegTranscEvStateChangedHandler,在下面
//单独分析该回调
//eReason =
// RVSIP_TRANSC_REASON_RESPONSE_SUCCESSFUL_RECVD
TransactionStateUacGeneralFinalResponseRcvd(…)
TransactionChangeState(pTransc,
RVSIP_TRANSC_STATE_CLIENT_GEN_FINAL_RESPONSE_RCVD,
eReason);
-------------------------------------------------------------------------------------------------------------------------------
CallLegMsgEvMsgRcvdHandler
//该事务含有订阅信息
if(SipTransactionGetSubsInfo(hTransc) != NULL)
//订阅对象处理消息接收
SipSubsMsgRcvdEvHandling(……)
//调用用户设置的订阅对象的消息接收回调,通知消息接收
SubsCallbackMsgRcvdEv
……
//之前该Notify事务上层已经标记由协议栈处理
if(bAppTransc == RV_FALSE &&eMethod == SIP_TRANSACTION_METHOD_NOTIFY)
//从接收消息中提取所需数据
LoadFromSubsRcvdMsg(pCallLeg,hTransc,hMsg,eMsgType,eMethod)
switch (eMethod)
case SIP_TRANSACTION_METHOD_NOTIFY:
CallLegSubsLoadFromRequestRcvdMsg(pCallLeg,hMsg);
//从Notify的contact头域中提取contact地址对象设置到对话框对象
//中pCallLeg->hRemoteContact
CallLegSubsLoadFromNotifyResponseRcvdMsg (pCallLeg, hMsg)
--------------------------------------------------------------------------------------------------------------------------------
CallLegTranscEvStateChangedHandler
//该事务含有订阅信息
pSubsInfo = SipTransactionGetSubsInfo(hTransc);
if(pSubsInfo != NULL)
//由订阅对象处理事务状态改变
SipSubsHandleTranscChangeState
switch(eTranscState)
case RVSIP_TRANSC_STATE_CLIENT_GEN_FINAL_RESPONSE_RCVD:
if(eMethod == SIP_TRANSACTION_METHOD_NOTIFY)
//处理notify应答
SubsNotifyHandleResponse(pNotify, hMsg, hTransc, statusCode);
//更新状态变量
if(responseCode >= 200 && responseCode < 300)
status = RVSIP_SUBS_NOTIFY_STATUS_2XX_RCVD;
//调用上层回调,通知Notify成功应答已经接收
InformNotifyStatus(pNotify, status,
RVSIP_SUBS_NOTIFY_REASON_UNDEFINED, hMsg);
//更新订阅对象
UpdateSubsAfter2xxOnNotifyRcvd(pNotify->pSubs, pNotify,
hNotifyTransc, &bSubsDeleted)
//notify中含有生存期值
if(pNotify->expiresParam > 0)
//如果告警定时器已经启动,则获取剩余时间
if (SipCommonCoreRvTimerStarted
(&pNotify->pSubs->alertTimer) == RV_TRUE)
RvTimerGetRemainingTime(
&pNotify->pSubs->alertTimer.hTimer, &delay);
//notify应答中的生存期值比剩余时间短,则进行
//告警定时器更新
if (pNotify->expiresParam <
RvInt64ToRvInt32(RvInt64Div(delay,
RV_TIME64_NSECPERSEC)) || delay == 0)
SubsObjectSetAlertTimer(pSubs,
(pNotify->expiresParam)*1000);
if(pNotify->eSubstate ==
RVSIP_SUBSCRIPTION_SUBSTATE_ACTIVE)
//当前pSubs订阅对象状态仍为ACTIVE,状态没有改变,
//直接返回
//notify请求事务已经收到应答,将notify对象及事务销毁
SubsNotifyTerminate(pNotify,
RVSIP_SUBS_NOTIFY_REASON_UNDEFINED);
Rv Refer订阅相关处理
最新推荐文章于 2021-03-05 09:17:59 发布