Resiprocate协议栈分析.docx

上传人:牧羊曲112 文档编号:3062382 上传时间:2023-03-10 格式:DOCX 页数:46 大小:57.08KB
返回 下载 相关 举报
Resiprocate协议栈分析.docx_第1页
第1页 / 共46页
Resiprocate协议栈分析.docx_第2页
第2页 / 共46页
Resiprocate协议栈分析.docx_第3页
第3页 / 共46页
Resiprocate协议栈分析.docx_第4页
第4页 / 共46页
Resiprocate协议栈分析.docx_第5页
第5页 / 共46页
亲,该文档总共46页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《Resiprocate协议栈分析.docx》由会员分享,可在线阅读,更多相关《Resiprocate协议栈分析.docx(46页珍藏版)》请在三一办公上搜索。

1、Resiprocate协议栈分析协议栈的层次 SIP为应用层(Application-Layer)的协议,所以不需要改变操作系统便可以支持。SIP 已经获得3GPP (Third GenerationPartnership Project)、3GPP2 (Third Generation Partnership ProjectNumber 2)等机构认证,成为未来第三代行动通讯 (3G) 的标准。 下面是SIP的分层图示,IETF坚持分层,不同模块功能相对独立,各层之间松散耦合。 事务用户层(Transaction User) 事务层(Transaction ) 传输层(Transport)

2、语法与编码层(Syntax and Encoding) 关于Resiprocate设计 首先祭出这面大旗,”类是对概念的描述,面向接口编程;封装变化的概念。”-这不是我讲的,是大师们的口水。 Resiprocate中大部分类就是对RFC3261各种SIP元素、组件的封装,并且也体现了RFC协议设计的层次。 在面向对象的设计中我们首先就要厘清问题域的所在;SIP Stack的设计就是要充分考虑完整展现RFC定义的各种元素和概念以及让这些独立而又关联的元素互动起来成为一个活的系统。 可以这样来考虑,比如我们知道RFC定义了一个SIP MESSAGE的概念;下面是从 RFC文档拷贝的内容: SIP

3、消息 = 起始行 *消息头部 CRLF(空行) 消息体 因此SIP Message这个概念元素还包括了更多的元素和概念;SIP Message中我们能抽 象出更通用的概念我们暂且叫它Message; 起始行的概念E文RequestLine以及Status Line又包括了很多消息头,SIPURL也包括消息头,等等,还有什么参数什么的元素呢;当我们在考虑和提炼这些概念和元素的时候,我们思考怎么抽象他们呢,它们又有什么基本的元素及其共性呢?他们之间的关系如何组织呢?Resiprocate的源码告诉了我们如何去设计和封装这些概念的上佳实现。在Resiprocate中一些RFC3261中定义元素的对应

4、: 建议:利用CRC卡片的方式去记录理解Resiprocate中的大量的类及其关系。CRC:类、职责、协作。 部分设计的理解 OBSERVER/VISITOR/COMMAND/ITERATOR模式,工厂模式(大量容器的使用也是一种变体如:DialogSet),代理类句柄类, 大量的界面类(如AppXXX系列)是遵循大师BS“界面和实现分离”的原则吧;而句柄方式对对象的间接管理是老外的惯用伎俩啦,关于句柄设计从大师BS的著作到的Handle_Body论和的大段描述再到都有发挥和外延,感兴趣可以观之。 插播: 源码中的大量Clone函数是模仿大师BS的虚拟构造函数一说,是原型模式的体现;源码中对同

5、步的封装值得借鉴,其中有“资源开始即初始化”理论的体现;在DUM部分回调机制所遵循的著名“好莱坞原则”;句柄和代理的一个特点就是重载了operator-、operator*等;源码中也非常注重效率如Sip Core部分中大量Hash表的建立。 T* operator- return get; const T* operator- const return get; T&operator- return *get; const T&operator* const return *get; Handled:Handled(HandleManager& ham) : mHam(ham), mId(H

6、andled:npos) mId = mHam.create(this); Handled:Id HandleManager:create(Handled* handled) mHandleMap+mLastId = handled;/typedef HashMap HandleMap; /HandleMap mHandleMap; return mLastId; 1. SIP Stack分析 11 Resiprocate SIP Stack系统架构图示 12 FIFO流的走向图 13 Sending datagram 1. 4 Process Incoming UDP 2. Applicat

7、ion/DUM 设计浅析 抽象接口:CLASSHANDLED ,CLASS InviteSessionHandler(诸如此类) 对象之源:CLASSHANDLED 交互控制: CLASS Handle,CLASS HandleManager 概念封装成类典型:CLASS Dialog, CLASS DialogId, CLASSDialogSet, CLASSDialogSetId, CLASSInviteSession. Utility工具类:CLASSBaseCreator , CLASSDestroyUsage,CLASSProfile 流动之源:DialogUsageManager:

8、process,Dialog:dispatch(const SipMessage& msg) 状态机的位置:DialogUsageManager:incomingProcess,DialogSet:dispatch,Dialog:dispatch 在整个Resiprocate大家族中事务层概念1的体现是TransactionUser类,而其真正的实现和管理类就是DialogUsageManager;从其: class DialogUsageManager : public HandleManager, public TransactionUser 能看出来;HandleManager点出了Di

9、alogUsageManager的管理功能的本质,并且管理各种对象。 在整个Resiprocate系统中不管是我们发出或者收到的SIP Message都是放进了先进先出的队列然后不断轮询处理,这有点象Windows的消息系统,对应收发的消息DUM提供事件通知的机制。DUM利用事件回调模型,事件响应可以选择继承系列XXXHandler抽象接口,并向TU注册,以实现VISITOR模式;我在另外的文档里也提到这是Reactor模式,应用程序开发者只负责实现具体事件处理程序,并在反应器上注册它们 -“好莱坞原则”。 1也许是事务用户层 DialogUsageManager是sip事务层管理类,是一个大

10、总管的角色;看其Makexxx系列的函数能明白它能发起一系列登陆、会话邀请的动作及其回复。 Dum定义了很多句柄管理类,通过它我们能得到真实的对象,从而完成操作,这在事件响应中非常有用。 在Dum的类中基本上这样一条线(以INVITE为例): DialogUsageManager产生DialogSet,Dialog Set产生Dialog,Dialog产生InviteSession; InviteSession又分ClientInviteSession和ServerInviteSession。 而上面的各个对象的PROCESS或者DISPATCH函数产生的各种状态的变化并触发相应事件。 在DU

11、M的IM/PRESENSE部分广泛使用SUBSCRIBE/NOTIFY的模式,目前协议的定义似乎参照成熟的设计模式。 个人一直比较喜欢这段论述: session有两种含义,一种是传统意义上的RTP会话,一种是信令意义上的会话。SIP中的会话指后一种,在层次上它在dialog之上,也就是dialog可以看成session的组成单元。二者的分别主要基于目前出现的subscription应用,对于session和subscription可以共享一个dialog,dialog由基本的会话标识组成,如 Call-ID,From-Tag,To-Tag,以及一些目的target等共性单元组成。而sessio

12、n除了具备这些单元外,包含INVITE建立起的会话其他内容,例如INVITE引起的状态机处理内容、PRACK处理记录等内容。有一个最为重要的区别是:Session是完成了SDP的Offer-Answer过程,也就是此时双方可以进行双向的RTP传输了。而Dialog只是双方建立了联系,这个联系是通过Dialog Context来记录的。在Dialog状态下双方不一定可以作双向的RTP传输。所以必定是Dialog在前,而Session在后,但两者可以同时一起建立。 Session是基于SDP Message的交互,没有SDP的交互,就没有Session。而Dialog是基于请求消息中的Header

13、 Field进行交互。因此两者在层次上也是不一样的。 下图是DUM中各种对象实例间的关系表示: DUM中几个重要的类图: 3. RESIPROCATE SIP Core重要模块的简单介绍 SipStack模块 SipStack是Sip Stack Core的面向外界的接口;可以说它是Sip Stack Core的外覆类(wrapper)或者是界面类(以大师BS的观点来看),它是和外界交互的窗口和协议,具体的实现又分散到更具体的实现类和层次。 在整个的协议栈架构中SipStack处于承上启下的位置,它既面向DUM层(表现为向DialogUsageManager服务)又可以直接为外界所用;列举其主

14、要面向外界的接口函数: /* Adds a TU to the TU selection chain. Tus do not call receive or receiveAny, the SipStack will call postToTu on the appropriate Tu. Messages not associated with a registered TU go into SipStack:mTuFifo. */ void registerTransactionUser(TransactionUser&); 注释基本上已经讲的很清楚,我就补充其交互的细节吧。这个函数基本上

15、能让我们看到TU和SipStack交互间其visitor/observer模式的影子。 void SipStack:registerTransactionUser(TransactionUser& tu) mTuSelector.registerTransactionUser(tu); 回溯SipStack的成员变量: / Responsible for routing messages to the correct TU based on installed rules TuSelector mTuSelector; 把SipStack中的Transaction User角色独立出来交与一个

16、独立的类管理是个不错的选择。 消息的流向分向两端,一路向下直达Transport层而去,一路向上提交Transaction User直至UI。 因此接口类Message中存在这个函数就不足为奇啦: class Message 。 void setTransactionUser(TransactionUser* t) tu = t; TransactionUser* getTransactionUser return tu; TransactionUser* tu; ; 正是setTransactionUser给予消息Transaction User归属。 而在TransactionState中

17、我们将会看到SipMessage是如何兵分两路的: staticvoid sendToTU(TransactionUser* tu, TransactionController& controller, TransactionMessage* msg); void sendToWire(TransactionMessage* msg, bool retransmit=false); 现在我们先重点关注一下sendToTU: void TransactionState:sendToTU(TransactionUser* tu, TransactionController& controller,

18、 TransactionMessage* msg) msg-setTransactionUser(tu); controller.mTuSelector.add(msg, TimeLimitFifo:InternalElement); 上面探索了一下SipStack和TU层的交互都要跑远啦,让我们再回到SipStack看看这个界面类其他的迎来送往的窗口吧。 一、发送消息的两个重载函数: /* Interface for the TU to send a message. Makes a copy of the SipMessage. Caller is responsible for dele

19、ting the memory and may do so as soon as it returns. Loose Routing processing as per RFC3261 must be done before calling send by the TU. See Helper:processStrictRoute param msg SipMessage to send. param tu TransactionUser to send from. */ void send(const SipMessage& msg, TransactionUser* tu=0); void

20、 send(std:auto_ptr msg, TransactionUser* tu = 0); 再看了一下这两个函数体的实现比较简单,还是端上来吧: void SipStack:send(const SipMessage& msg, TransactionUser* tu) SipMessage* toSend = newSipMessage(msg); if (tu) toSend-setTransactionUser(tu); toSend-setFromTU; mTransactionController.send(toSend); checkAsyncProcessHandler;

21、 mTransactionController.send(toSend)这一段才是我们值得关注的地方,很显然这是消息的去向,现在我们不用管它去向哪儿,我们知道它被转交给mTransactionController去具体完成任务,就象在一条生产线上我们把消息交给了下游或者另一个直管部门去处理。SipMessage是我们投递出的邮件,从投向邮筒的那一瞬间,开始了它向各个驿站的传递;出于职责链上的各个类和对象是任务传递驿站的抽象和实现,是代码所表现出的和谐世界,当然如果是垃圾代码的话,那就是一个混乱的世界和杂物堆放的仓库。 checkAsyncProcessHandler这是协议栈提供的异步消息处理

22、的一种推荐方式,协议栈源码中只是实现了个大概,具体的异步处理细节需要根据具体情况而完成其实现类,此处再次体现了“封装变化的概念”的要诀。 因为异步处理句柄是指向抽象基类的指针: AsyncProcessHandler* mAsyncProcessHandler; 二、SendTo有好几个重载函数,看看注释再和Send比较一下就可耶。 /* this is only if you want to send to a destination not in the route. You probably dont want to use it. */ void sendTo(std:auto_ptr

23、 msg, const Uri& uri, TransactionUser* tu=0); void sendTo(std:auto_ptr msg, const Tuple& tuple, TransactionUser* tu=0); void sendTo(const SipMessage& msg, const Uri& uri, TransactionUser* tu=0); void sendTo(const SipMessage& msg, const Tuple& tuple, TransactionUser* tu=0); 三、就如在Win32编程中有SendMessage和

24、PostMessage一样,SipStack消息分发中也有一个Post。 /* Makes the message available to the TU at some later time - specified in seconds. Note: TranasactionUser subclasses can just post to themselves. param message ApplicationMessage to post param secondsLater Number of seconds before message is to be posted. param

25、tu TransactionUser to post to. */ void post(const std:auto_ptr message, unsignedint secondsLater, TransactionUser* tu=0); void postMS(const std:auto_ptr message, unsignedint ms, TransactionUser* tu=0); void post(const ApplicationMessage& message); void post(const ApplicationMessage& message, unsigne

26、dint secondsLater, TransactionUser* tu=0); /* Makes the message available to the TU at some later time - specified in milli-seconds. Makes a copy of the ApplicationMessage. Caller is responsible for deleting the memory and may do so as soon as it returns. Note: TransactionUser subclasses can just po

27、st to themselves. param message ApplicationMessage to post param ms Number of milli-seconds before message is to be posted. param tu TransactionUser to post to. */ void postMS(const ApplicationMessage& message, unsignedint ms, TransactionUser* tu=0); ApplicationMesage基本上是个结点类,因此可以自定义自己的消息类,然后自己管理;因为

28、我们可以看到Post出去的消息更多的是交给TU去处理,TU层就在应用层隔壁。 四、下面的函数,非常容易看明白。 /* Retrieve a SipMessage off the old TuFifo. Caller now owns the memory. Returns 0 if nothing there. Since the addition of TransactionUsers, this method is deprecated. This only looks into the old TuFifo that is not associated with any Transact

29、ionUser. Note: Applications posting non-sip messages must use receive any. If non SipMessages are on the Fifo, then they are just deleted. deprecated returns pointer to received SipMessage, 0 if nothing there. */ SipMessage* receive; /* Retrieve a Message off the old TuFifo. Caller now owns the memo

30、ry. Returns 0 if nothing there. Since the addition of TransactionUsers, this method is deprecated. This only looks into the old TuFifo that is not associated with any TransactionUser. Note: Applications posting non-sip messages must use receive any. If non SipMessages are on the Fifo, then they are

31、just deleted. deprecated returns pointer to received Message, 0 if nothing there. May return TransactionTerminated*, TimerMessage*, SipMessage* or derived ApplicationMessage* */ Message* receiveAny; /* Return true if the stack has new messages for the TU. Since the addition of TransactionUsers, this

32、 method is deprecated. This only looks into the old TuFifo that is not associated with any TransactionUser. deprecated */ bool hasMessage const; 五、几个成员变量的说明 / if this object exists, it manages advanced security featues Security* mSecurity; 这是如果需要安全处理而用到的类。 DnsStub* mDnsStub; 这是如果自己定义DNS处理的话所需要的DNS处理

33、的存根和截取器。 / if this object exists, it gets notified when ApplicationMessages get posted AsyncProcessHandler* mAsyncProcessHandler; 异步处理的基类指针对象,可以自定义异步处理的方式。 /* fifo used to communicate between the TU (Transaction User) and stack Note: since the introduction of multiple TUs this Fifo should no longer

34、be used by most applications - each TU now owns its own Fifo. */ TimeLimitFifo mTUFifo; 这个就不用说啦,看注释吧。 / Protection for AppTimerQueue mutable Mutex mAppTimerMutex; 整个协议栈的同步都是集中利用了源码中实现的同步对象,非常不错,实现同步类的理论基础应该是基于大师BS的理论“资源开始即初始化”。 / All aspects of the Transaction State Machine / DNS resolver Transactio

35、nController mTransactionController; /* store all domains that this stack is responsible for. Controlled by addAlias and addTransport interfaces and checks can be made with isMyDomain */ std:set mDomains; / Responsible for routing messages to the correct TU based on installed rules TuSelector mTuSele

36、ctor; TransactionController模块 在SipStack中看到这样的描述: / All aspects of the Transaction State Machine / DNS resolver TransactionController mTransactionController; 注意all aspects在我的理解中这又是一个界面类,SipStack是Sip Core整个庭院的外围的门面的话这又是进入庭院后第二道城墙;就如庭院高深的故宫和亭廊回环的苏州园林它们的实现中更有层次的递张以及庭院间的交互回环。 BS教导我们不要写“臃肿的界面”,SipStack这个大

37、界面里面又套这个实现层次的界面是不是一种好的实践呢?我的理解是,应该是这样的。努力达到界面和实现分离。 现在就看看这个Transaction State Machine / DNS resolver界面类吧,在我的实现中,其实把DNS Resolver部分清理掉啦,导致只是个Transaction State Machine的界面类吧。 如果仔细看看TransactionControl的函数也就是它的接口函数的话和SipStack就差不离,翻版而也,就是一道门进去还是一道门,就连造型都差不多,外面是拱洞型的里面还是;故宫和苏州园林的设计把古建筑的设计模式推向了极致。 还是列一下吧: void

38、process(FdSet& fdset); unsignedint getTimeTillNextProcessMS; void buildFdSet(FdSet& fdset); / graceful shutdown (eventually) void shutdown; TransportSelector&transportSelector return mTransportSelector; const TransportSelector& transportSelector const return mTransportSelector; bool isTUOverloaded c

39、onst; void send(SipMessage* msg); 再看一下几个重要的成员变量: / fifo used to communicate to the transaction state machine within the / stack. Not for external use by the application. May contain, sip / messages (requests and responses), timers (used by state machines), / asynchronous dns responses, transport err

40、ors from the underlying / transports, etc. Fifo mStateMacFifo; / from the sipstack (for convenience) TuSelector& mTuSelector; / Used to decide which transport to send a sip message on. TransportSelector mTransportSelector; / stores all of the transactions that are currently active in this stack Tran

41、sactionMap mClientTransactionMap; TransactionMap mServerTransactionMap; 重点和关键成员变量: Fifo mStateMacFifo; 看看这个成员变量的价值: void TransactionController:send(SipMessage* msg) mStateMacFifo.add(msg); 消息的流动不可能到此为止,它要上传下递,如何实现的呢? 看看构造函数吧: TransactionController:TransactionController(SipStack& stack) : mStack(stac

42、k), mRegisteredForTransactionTermination(false), mDiscardStrayResponses(true), mStateMacFifo, mTuSelector(stack.mTuSelector), mTransportSelector(mStateMacFifo, stack.getSecurity, stack.getDnsStub), mTimers(mStateMacFifo), mShuttingDown(false), mStatsManager(stack.mStatsManager) 既然都点出来了,就继续往下看看,看看流向T

43、ransportSelector会怎样呢: TransportSelector:TransportSelector(Fifo& fifo, Security* security, DnsStub& dnsStub) : mDns(dnsStub), mStateMacFifo(fifo), mSecurity(security), mSocket( INVALID_SOCKET ), mSocket6( INVALID_SOCKET ) memset(&mUnspecified.v4Address, 0, sizeof(sockaddr_in); mUnspecified.v4Address.

44、sin_family = AF_UNSPEC; 再让我们看另外一支,只是一直在Process中处理的: void TransactionController:process(FdSet& fdset) if (mShuttingDown & !mStateMacFifo.messageAvailable & !mStack.mTUFifo.messageAvailable & mTransportSelector.isFinished) 。 else 。 while (mStateMacFifo.messageAvailable) TransactionState:process(*this); TransactionState的这个静态函数Process的参数居然是*this,也就是是说TransactionS

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号