SIP的路由机制

介绍一下SIP中的路由机制。总的来说,SIP中存在两种路由场景:1、请求消息的路由;2、响应消息的路由 ,响应消息的路由非常简单,就是完全依靠Via来完成的,具体请见我关于RFC3261中会话流程的分析。

下面我们只谈SIP请求消息的路由。 首先,我们要搞清楚什么是严格路由和松散路由。 

严格路由(Strict Routing):可以理解为比较“死板”的理由机制,这种路由机制在SIP协议的前身RFC 2534中定义,其机制非常简单。要求接收到的消息的request-URI必须是自己的URI,然后它会把第一个Route头域“弹”出来,并把其中的URI作为新的request-RUI,然后把该消息路由给该URI。 

松散路由(Louse Routing,lr):该路由机制较为灵活,也是SIP路由机制的灵魂所在,在SIP的RFC 3261中定义。

松散路由的Proxy的路由决策过程: 

1、Proxy首先会检查消息的request-URI是不是自己属于自己所负责的域。如果是,它就会通过定位服务将该地址“翻译”成具体的联系地址并以此替换掉原来的request-URI;否则,它不会动request-URI。

 2、Proxy检查第一个Route头域中的URI是不是自己的,如果是,则移除。 

3、如果还有Route头域,则Proxy会把消息路由给该头域中的URI,否则就路由给request-URI。

对于以上的3条规则,我们可以简单总结为一句话:Route的优先级高于request-URI的。

了解了两种路由机制,我们再来了解一下Route和Record-Route。如果说Via是为了给一个请求消息的响应消息留后路,那么Record-Route就是为了给该请求消息之后的请求消息留后路。

首先,我们来介绍下via头域的用法。一个SIP消息每经过一个Proxy(包括主叫),都会被加上一个Via头域,当消息到达被叫后,Via头域就会记录请求消息经过的完整路径。被叫将Via头域原样copy到响应消息中(包括各Via的参数,以及各Via的顺序),然后下发给第一个Via中的URI,每个Proxy转发响应消息前都会把第一个Via(也就是它自己添加的Via)删除,然后将消息转发给新的第一个Via中的URI,直到消息到达主叫。

 在一个请求消息的传输过程中,Proxy也可能(纯粹自愿,如果它希望还能接收到本次会话的后续请求消息的话)会添加一个Record-Route头域,这样当消息到达被叫后里面就有会有0个或若干个Record-Route头域。被叫会将这些Record-Route头域并入路由集,并入自己的路由集,随后被叫在发送请求消息时就会使用该路由集构造一系列Route头域,以便对消息进行路由。 然后,将Record-Route头域全部原样copy到响应消息中返回给主叫。主叫收到响应消息后也会将这些Record-Route头域并入路由集,只是它会将其反序。该会话中的后续请求消息的Route头域将会通过路由集构造。

注意:Record-Route头域不是用来路由,而只是起到传递信息的作用。Record-Route头域不是路由集唯一来源,路由集还可以通过手工配置等方式得到。  

以上的描述还是比较抽象,下面就以两个实例来解释一下。

例子是一个基本的SIP四边传送,U1->P1->P2->U2,使用proxy来传送。下边是过程。

U1 发送:

INVITE sip:callee@domain.com SIP/2.0

Contact: sip:caller@u1.example.com

发给P1,P1是一个外发的proxy。P1并不管辖domain.com,所以它查找DNS并且发请求到那里。它也增加一个Record-Route头域值:

INVITE sip:callee@domain.com SIP/2.0

Contact: sip:caller@u1.example.com

Record-Route: <sip:p1.example.com; lr>


P2收到这个请求。这是domain.com所以它查找位置服务器并且重写Request-URI。它也增加一个Record-Route头域值。请求中没有Route头域,所以它解析一个新的Request-URI来决定把请求发送到哪里。

INVITE sip:callee@u2.domain.com SIP/2.0

Contact: sip:caller@u1.example.com

Record-Route: <sip:p2.domain.com; lr>

Record-Route: <sip:p1.example.com; lr>

 

在u2.domain.com的被叫方接收到这个请求并且返回一个200OK应答:

SIP/2.0 200 OK

Contact: sip: callee@u2.domain.com

Record-Route: <sip:p2.domain.com;lr>

Record-Route: <sip:p1.example.com;lr>

 

u2的被叫方并且设置对话的状态的remote target URI为:

sip: caller@u1.example.com并且它的路由集合是:

(<sip:p2.domain.com;lr>,<sip:p1.example.com;lr>)

 

这个转发通过P2到P1到U1。现在U1设置它自己的对话状态的remote target URI为:sip:calle@u2.domain.com并且它的路由集合是:

(<sip:p1.example.com;lr>,<sip:p2.domain.com;lr>)

 

由于所有的路由集合元素都包含了lr参数,那么U1构造最后的BYE请求:

BYE sip:callee@u2.domain.com SIP/2.0

Route:<sip:p1.example.com;lr>,<sip:p2.domain.com;lr>

 

就像其他所有的节点(包括proxy)会做的那样,它会使用DNS来解析最上的Route头域的URI值,这样来决定往哪里发送这个请求。这就发到了P1。P1发现Request-URI中标记的URI不是它负责的域,于是它就不改变这个Request-URI。然后看到它是Route头域的第一个值,于是就从Route头域中移去,并且转发这个请求到P2:

BYE sip:callee@u2.domain.com SIP/2.0

Route: <sip:p2.domain.com;lr>

P2也发现它自己并非负责这个Request-URI的域(P2负责的是domain.com并非u2.domain.com),于是P2并不改变它。它看到自己在Route的第一个值,于是移去这个,并且向u2.domain.com转发(根据在Request-URI上查找DNS):

BYE sip:callee@u2.domain.com SIP/2.0

 

穿越一个严格路由proxy

在这个例子中,对话建立通过4个proxy,每一个增加Record-Route头域值。第三个proxy是由严格路由实现的(RFC 2543)。

U1->P1->P2->P3->P4->U2

 

INVITE请求到达U2包括了:

INVITE sip:callee@u2.domain.com SIP/2.0

Contact: sip:caller@u1.example.com

Record-Route: <sip:p4.domain.com;lr>

Record-Route: <sip:p3.middle.com>

Record-Route: <sip:p2.example.com;lr>

Record-Route: <sip:p1.example.com;lr>

 

并且U2返回了一个200 OK。接着,U2根据第一个Route头域值发送下边的BYE请求到P4:

BYE sip:caller@u1.example.com SIP/2.0

Route: <sip:p4.domain.com;lr>

Route: <sip:p3.middle.com>

Route: <sip:p2.example.com;lr>

Route: <sip:p1.example.com;lr>

 

P4并不管辖Request-URI指出的域,于是就不更改这个Reqeust-URI。它发现自己在第一个Route头域中,于是把自己从Route头域移除。然后准备发送请求到现在的第一个Route头域值:sip:p3.middle.com,但是它发现这个URI并没有包含lr参数,于是在发送前,它把这个请求更改成为:

BYE sip:p3.middle.com SIP/2.0

Route: <sip:p2.example.com;lr>

Route: <sip:p1.example.com;lr>

Route: <sip:caller@u1.example.com>

P3是一个严格路由,于是它转发到P2:

BYE sip:p2.example.com;lr SIP/2.0

Route: <sip:p1.example.com;lr>

Route: <sip:caller@u1.example.com>

P2看到Request-URI是它放在Record-Route头域中的值,于是在进一步处理前,它把这个请求改写为:

BYE sip:caller@u1.example.com SIP/2.0

Route: <sip:p1.example.com; lr>

P2自己并不管辖u1.example.com,于是它根据Route头域的值,转发这个请求到P1。

 

P1发现自己在Route头域的最上,于是把自己移除,得到:

BYE sip:caller@u1.example.com SIP/2.0

由于P1并不管辖u1.example.com并且没有其他的Route头域,P1会基于Request-URI转发这个请求到u1.example.com。

 

重写Record-Route头域值。

在这里例子中,U1和U2是在不同的私有域空间中,并且他们通过proxy P1开始一个对话,这个P1作为不同私有namespace的一个网关存在。

U1->P1->U2

U1发送:

INVITE sip:callee@gateway.leftprivatespace.com SIP/2.0

Contact: <sip:caller@u1.leftprivatespace.com>

 

P1使用自己的定位服务并且发送下边的信息到U2:

INVITE sip:callee@rightprivatespace.com SIP/2.0

Contact: <sip:caller@u1.leftprivatespace.com>

Record-Route:<sip:gateway.rightprivatespace.com;lr>

 

U2发送200 OK应答回给P1:

SIP/2.0 200 OK

Contact: <sip:callee@u2.rightprivatespace.com>

Record-Route: <sip:gateway.rightprivatespace.com;lr>

 

P1重写它的Record-Route头域参数,提供成为U1能够使用的参数,并且发送给P1:

SIP/2.0 200 OK

Contact: <sip:callee@u2.rightprivatespace.com>

Record-Route:<sip:gateway.leftprivatespace.com;lr>

 

稍后,U1发送接下来的BYE到P1:

BYE sip:callee@u2.rightprivatespace.com SIP/2.0

Route: <sip:gateway.leftprivatespace.com;lr>

 

P1转发到U2:

BYEsip:callee@u2.rightpriatespace.com SIP/2.0

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值