Resiprocate协议栈分析Word文档格式.docx
《Resiprocate协议栈分析Word文档格式.docx》由会员分享,可在线阅读,更多相关《Resiprocate协议栈分析Word文档格式.docx(51页珍藏版)》请在冰点文库上搜索。
在Resiprocate中一些RFC3261中定义元素的对应:
建议:
利用CRC卡片的方式去记录理解Resiprocate中的大量的类及其关系。
CRC:
类、职责、协作。
部分设计的理解
OBSERVER/VISITOR/COMMAND/ITERATOR模式,工厂模式(大量容器的使用也是一种变体如:
DialogSet),代理类句柄类(界面实现分离,隐藏实现…),……
大量的界面类(如AppXXX系列)是遵循大师BS“界面和实现分离”的原则吧;
而句柄方式对对象的间接管理是老外的惯用伎俩啦,关于句柄设计从大师BS的著作到<
<
EffectiveC++>
>
的Handle_Body论和<
C++沉思录>
的大段描述再到<
C++ModelDesign>
都有发挥和外延,感兴趣可以观之。
插播:
源码中的大量Clone函数是模仿大师BS的虚拟构造函数一说,是原型模式的体现;
源码中对同步的封装值得借鉴,其中有“资源开始即初始化”理论的体现;
在DUM部分回调机制所遵循的著名“好莱坞原则”;
句柄和代理的一个特点就是重载了operator->
、operator*等;
源码中也非常注重效率如SipCore部分中大量Hash表的建立。
T*operator->
()
{
returnget();
}
constT*operator->
()const
T&
operator->
()
return*get();
constT&
operator*()const
Handled:
:
Handled(HandleManager&
ham):
mHam(ham),
mId(Handled:
npos)
{
mId=mHam.create(this);
}
Id
HandleManager:
create(Handled*handled)
mHandleMap[++mLastId]=handled;
//typedefHashMap<
Id,Handled*>
HandleMap;
//HandleMapmHandleMap;
returnmLastId;
1.SIPStack分析
1.1ResiprocateSIPStack系统架构图示
1.2FIFO流的走向图
1.3Sendingdatagram
1.4ProcessIncomingUDP
2.Application/DUM
设计浅析
抽象接口:
CLASSHANDLED,CLASSInviteSessionHandler(诸如此类)……
对象之源:
CLASSHANDLED(多态和控制的基础)……
交互控制:
CLASSHandle,CLASSHandleManager……
概念封装成类典型:
CLASSDialog,CLASSDialogId,CLASSDialogSet,CLASSDialogSetId,CLASSInviteSession…..
Utility工具类:
CLASSBaseCreator,CLASSDestroyUsage,CLASSProfile……
流动之源:
DialogUsageManager:
process(),Dialog:
dispatch(constSipMessage&
msg)……
状态机的位置:
incomingProcess,DialogSet:
dispatch,Dialog:
dispatch
在整个Resiprocate大家族中事务层概念的体现是TransactionUser类,而其真正的实现和管理类就是DialogUsageManager;
从其:
classDialogUsageManager:
publicHandleManager,publicTransactionUser
能看出来;
HandleManager点出了DialogUsageManager的管理功能的本质,并且管理各种对象(Handle是各类对象的句柄)。
在整个Resiprocate系统中不管是我们发出或者收到的SIPMessage都是放进了先进先出的队列然后不断轮询处理,这有点象Windows的消息系统,对应收发的消息DUM提供事件通知的机制。
DUM利用事件回调模型,事件响应可以选择继承系列XXXHandler抽象接口,并向TU注册,以实现VISITOR模式;
我在另外的文档里也提到这是Reactor(Dispatcher,Notifier)模式,应用程序开发者只负责实现具体事件处理程序,并在反应器上注册它们----“好莱坞原则”。
DialogUsageManager是sip事务层管理类,是一个大总管的角色;
看其Makexxx系列的函数能明白它能发起一系列登陆、会话邀请的动作及其回复。
Dum定义了很多句柄管理类,通过它我们能得到真实的对象,从而完成操作,这在事件响应中非常有用。
在Dum(DialogUsageManager)的类中基本上这样一条线(以INVITE为例):
DialogUsageManager产生DialogSet,DialogSet产生Dialog,Dialog产生InviteSession;
InviteSession又分ClientInviteSession和ServerInviteSession。
而上面的各个对象的PROCESS或者DISPATCH函数产生的各种状态的变化并触发相应事件。
在DUM的IM/PRESENSE部分广泛使用SUBSCRIBE/NOTIFY的模式,目前协议的定义似乎参照成熟的设计模式。
个人一直比较喜欢这段论述:
session有两种含义,一种是传统意义上的RTP会话,一种是信令意义上的会话。
SIP中的会话指后一种,在层次上它在dialog之上,也就是dialog可以看成session的组成单元。
二者的分别主要基于目前出现的subscription应用,对于session和subscription可以共享一个dialog,dialog由基本的会话标识组成,如Call-ID,From-Tag,To-Tag,以及一些目的target等共性单元组成。
而session除了具备这些单元外,包含INVITE建立起的会话其他内容,例如INVITE引起的状态机处理内容、PRACK处理记录等内容。
有一个最为重要的区别是:
Session是完成了SDP的Offer-Answer过程,也就是此时双方可以进行双向的RTP传输了。
而Dialog只是双方建立了联系,这个联系是通过DialogContext来记录的。
在Dialog状态下双方不一定可以作双向的RTP传输。
所以必定是Dialog在前,而Session在后,但两者可以同时一起建立。
Session是基于SDP Message的交互,没有SDP的交互,就没有Session。
而Dialog是基于请求消息中的HeaderField进行交互。
因此两者在层次上也是不一样的。
下图是DUM中各种对象实例间的关系表示:
DUM中几个重要的类图:
3.RESIPROCATESIPCore重要模块的简单介绍
SipStack模块
SipStack是SipStackCore的面向外界的接口;
可以说它是SipStackCore的外覆类(wrapper)或者是界面类(以大师BS的观点来看),它是和外界交互的窗口和协议,具体的实现又分散到更具体的实现类和层次。
在整个的协议栈架构中SipStack处于承上启下的位置,它既面向DUM层(表现为向DialogUsageManager服务)又可以直接为外界(如UI)所用;
列举其主要面向外界的接口函数:
/**
AddsaTUtotheTUselectionchain.Tu'
sdonotcallreceiveor
receiveAny,theSipStackwillcallpostToTuontheappropriate
Tu.MessagesnotassociatedwitharegisteredTUgointoSipStack:
mTuFifo.
*/
voidregisterTransactionUser(TransactionUser&
);
注释基本上已经讲的很清楚,我就补充其交互的细节吧。
这个函数基本上能让我们看到TU和SipStack交互间其visitor/observer模式的影子。
void
SipStack:
registerTransactionUser(TransactionUser&
tu)
mTuSelector.registerTransactionUser(tu);
回溯SipStack的成员变量:
///ResponsibleforroutingmessagestothecorrectTUbasedoninstalledrules
TuSelectormTuSelector;
把SipStack中的TransactionUser角色独立出来交与一个独立的类管理是个不错的选择。
消息的流向分向两端,一路向下直达Transport层而去,一路向上提交TransactionUser直至UI。
因此接口类Message中存在这个函数就不足为奇啦:
classMessage
。
。
voidsetTransactionUser(TransactionUser*t){tu=t;
TransactionUser*getTransactionUser(){returntu;
TransactionUser*tu;
};
正是setTransactionUser给予消息TransactionUser归属。
而在TransactionState中我们将会看到SipMessage是如何兵分两路的:
staticvoidsendToTU(TransactionUser*tu,TransactionController&
controller,TransactionMessage*msg);
voidsendToWire(TransactionMessage*msg,boolretransmit=false);
现在我们先重点关注一下sendToTU:
void
TransactionState:
sendToTU(TransactionUser*tu,TransactionController&
controller,TransactionMessage*msg)
msg->
setTransactionUser(tu);
controller.mTuSelector.add(msg,TimeLimitFifo<
Message>
InternalElement);
上面探索了一下SipStack和TU层的交互都要跑远啦,让我们再回到SipStack看看这个界面类其他的迎来送往的窗口吧。
一、发送消息的两个重载函数:
InterfacefortheTUtosendamessage.Makesacopyofthe
SipMessage.Callerisresponsiblefordeletingthememoryandmaydo
soassoonasitreturns.LooseRoutingprocessingasperRFC3261must
bedonebeforecallingsendbytheTU.SeeHelper:
processStrictRoute
@parammsgSipMessagetosend.
@paramtuTransactionUsertosendfrom.
voidsend(constSipMessage&
msg,TransactionUser*tu=0);
voidsend(std:
auto_ptr<
SipMessage>
msg,TransactionUser*tu=0);
再看了一下这两个函数体的实现比较简单,还是端上来吧:
send(constSipMessage&
msg,TransactionUser*tu)
SipMessage*toSend=newSipMessage(msg);
if(tu)
toSend->
}
setFromTU();
mTransactionController.send(toSend);
checkAsyncProcessHandler();
mTransactionController.send(toSend)这一段才是我们值得关注的地方,很显然这是消息的去向,现在我们不用管它去向哪儿,我们知道它被转交给mTransactionController去具体完成任务,就象在一条生产线上我们把消息交给了下游或者另一个直管部门去处理。
SipMessage是我们投递出的邮件,从投向邮筒的那一瞬间,开始了它向各个驿站的传递;
出于职责链上的各个类和对象是任务传递驿站的抽象和实现,是代码所表现出的和谐世界,当然如果是垃圾代码的话,那就是一个混乱的世界和杂物堆放的仓库。
checkAsyncProcessHandler()这是协议栈提供的异步消息处理的一种推荐方式,协议栈源码中只是实现了个大概,具体的异步处理细节需要根据具体情况而完成其实现类,此处再次体现了“封装变化的概念”的要诀。
因为异步处理句柄是指向抽象基类的指针:
AsyncProcessHandler*mAsyncProcessHandler;
二、SendTo有好几个重载函数,看看注释再和Send比较一下就可耶。
/**thisisonlyifyouwanttosendtoadestinationnotintheroute.You
probablydon'
twanttouseit.*/
voidsendTo(std:
msg,constUri&
uri,TransactionUser*tu=0);
msg,constTuple&
tuple,TransactionUser*tu=0);
voidsendTo(constSipMessage&
tuple,
TransactionUser*tu=0);
三、就如在Win32编程中有SendMessage和PostMessage一样,SipStack消息分发中也有一个Post。
/**
MakesthemessageavailabletotheTUatsomelatertime-specifiedin
seconds.
Note:
TranasactionUsersubclassescanjustposttothemselves.
@parammessageApplicationMessagetopost
@paramsecondsLaterNumberofsecondsbeforemessageistobeposted.
@paramtuTransactionUsertopostto.
voidpost(conststd:
ApplicationMessage>
message,
unsignedintsecondsLater,
voidpostMS(conststd:
unsignedintms,
voidpost(constApplicationMessage&
message);
message,unsignedintsecondsLater,
milli-seconds.MakesacopyoftheApplicationMessage.Calleris
responsiblefordeletingthememoryandmaydosoassoonasitreturns.
TransactionUsersubclassescanjustposttothemselves.
@parammsNumberofmilli-secondsbeforemessageistobeposted.
voidpostMS(constApplicationMessage&
message,unsignedintms,
ApplicationMesage基本上是个结点类,因此可以自定义自己的消息类,然后自己管理;
因为我们可以看到Post出去的消息更多的是交给TU去处理,TU层就在应用层隔壁。
四、下面的函数,非常容易看明白。
/**
RetrieveaSipMessageofftheoldTuFifo.Callernowownsthememory.Returns
0ifnothingthere.SincetheadditionofTransactionUsers,thismethod
isdeprecated.ThisonlylooksintotheoldTuFifothatisnotassociated
withanyTransactionUser.
Applicationspostingnon-sipmessagesmustusereceiveany.Ifnon
SipMessagesareontheFifo,thentheyarejustdeleted.
@deprecated
@returnspointertoreceivedSipMessage,0ifnothingthere.
SipMessage*receive();
RetrieveaMessageofftheoldTuFifo.Callernowownsthememory.Returns
@returnspointertoreceivedMessage,0ifnothingthere.Mayreturn
TransactionTerminated*,TimerMessage*,SipMessage*orderived
ApplicationMessage*
Message*receiveAny