Rv Refer订阅相关处理

一、	发送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);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值