我们在IP语音通信领域中一直在讨论SIP服务器和应用等相关的话题。关于SIP协议中,让读者比较关心的或者我们经常使用的就是SIP应用服务器,包括企业IPPBX,SBC,注册服务器等核心的构件。这些典型的应用大部分都是B2BUA的形式出现的,大部分技术人员可能仅知道它们是一个背靠背服务,可以通过此服务做一些SIP消息的管理。可能很多人不了解B2BUA可以做哪些方面的管理,B2BUA的类型,以及所遵守的规范,还有和SIP代理服务器之间的区别等概念,也缺乏深入了解。
今天,笔者将对以上这些问题做比较详细地分析解释。我们本次讨论将覆盖,B2BUA和SIP Proxy的区别,B2BUA的概念,RFC7092规范,使用B2BUA的原因,3PCC场景,SIP代理和B2BUA如何重构SIP消息,SBC和SIP Proxy对比。
目录
为什么使用B2BUA
首先,我们介绍一下使用B2BUA的背景和SIP Proxy的基本概念。根据RFC3261规范的定义,SIP Proxy是:
SIP proxies are elements that route SIP requests to user agent servers and SIP responses to user agent clients.
#section-16
根据RFC3261的定义,SIP Proxy主要作用是对SIP请求的路由。“路由”这个词具有多层含义,它负责执行路由,认证,签权,地址解析,回环检测和均衡负载的功能。根据这些功能,市场上衍生出了很多这些业务的SIP服务器业务,包括:注册服务器,签权服务器,DNS服务器和均衡负载的服务器等多种服务器类型。大家熟悉的开源SIP服务器Kamalio,OpenSIPS就是比较常用的SIP Proxy。笔者在以前的讨论中有对这些服务器的介绍,这里不再讨论。
SIP Proxy有分为两种模式,一种是状态代理模式,另外一种是无状态代理模式。关于这两种模式的使用场景和各自的工作方式,我们在以前的文章中有非常完整的介绍,读者可以查阅历史完整来了解它们的功能概念。SIP代理的概念说起来比较抽象,如果没有很多SIP使用经验的话,一些读者可能会产生误解。
简单来说,SIP 代理可以看作是我们生活中某些业务场景的代理一样。例如,如果客户A正在打高尔夫球,不能出席某个会议,他委托公司其他人或者第三方实体帮助他代理出席某一个会议,代理人在现场根据现场的内容,转发或者通知客户A。这里,中间代理人实体实际上就是一个会议的中转人,不承担也不执行某些主要的业务。
通过以上的介绍读者应该可以明白,事实上,代理的功能极其有限,IP语音业务的很多功能,它不能实现。另外,SIP代理自己本身不能发起INVITE请求,这样就不能满足IP语音通信的基本呼叫功能。例如,以下的预付费的功能。
如果在简单的场景中,双方进行呼叫,通过Proxy的计费系统可以满足计费的要求。如果话费不足时,SIP Proxy应该自己生成BYE请求,同时对双方终端发送其生成的请求。事实上,Proxy自己本身不能生成BYE请求,后续的请求应该由终端生成,而不是Proxy自己。因此,SIP Proxy很难满足某些复杂的业务功能。
另外,在以前的文章中,我们已经讨论过,双方终端通过多个Proxy代理以后,根据Route Set返回处理流程。但是,在一些情况下,如果终端忽略了Route Set以后,直接通过呼叫方和被呼叫方,双方可能进行非法呼叫,它们跳过了代理服务器,导致业务控制层很难对其进行管理。
对此,一些聪明的开发人员提出了一个非常有创造力的设计思路,他们建议采用一个新的技术架构-(背靠背)B2BUA的机制,通过背靠背的方式来实现业务能力的管理和会话的管理,主要引进了我们通常所说的B2BUA的概念。
根据RFC3261对B2BUA定义,B2BUA-6定义是:
A back-to-back user agent (B2BUA) is a logical entity that receives a request and processes it as a user agent server (UAS). In order to determine how the request should be answered, it acts as a user agent client (UAC) and generates requests. it maintains dialog state and must participate.
通过以上定义,我们可以看出,B2BUA是一个逻辑实体,它由一个UAS和一个UAC两个部分构成,分别负责接收请求,处理请求和生成请求。B2BUA和SIP代理不同,它必须保持在dialog中所有创建的请求。只有这样,B2BUA才能完全控制所有需要管理的会话。
通常来说,SIP 服务器端是不会信任任何终端的,因此,UAC发起呼叫后,首先需要面对UAS来进行验证,然后才能进行下一步的处理。一个B2BUA支持的基本功能包括:
呼叫管理,自动呼叫挂断,呼叫转移等。网络连接包括协议调整隐藏内网地址,终端地址监控整个呼叫状态B2BUA的基本功能和典型的使用场景: 电话会议,网关,SBC,IPPBX,电话转接等场景,这些都是通过3PCC来实现。
RFC7092对B2BUA的类别
根据RFC7092规范的定义,B2BUA可分为多个类别,主要包括两个主类别和多个次类别:
Signaling Plane B2BUA Roles, 其子类别分别包括:Proxy-B2BUA, Signaling-only和 SDP-Modifying Signaling-only。这个类别中,B2BUA侧重于信令的处理,SDP的管理,它们本身不介于媒体路径上,所以,它们不能管理RTP头和payload。Signaling/Media Plane B2BUA Roles,其子类别分别包括:Media Relay,Media Aware和Media Termination。扮演信令媒体的B2BUA,它们不仅那个管理SIP头,而且可以对RTP 头进行管理或者修改。通过此B2BUA处理后的信令和媒体能够保证双方的一致性。大家比较熟悉的SBC可以实现以上这些功能。通过以上的分类描述,我们可以通过以上抽象的概念映射到我们具体的应用环境中。B2BUA可以实现以下几个方面的应用场景:
基于SIP的IPPBX和软交换,市场上很多企业融合通信的IPPBX就是一个非常典型的B2BUA场景。比较熟悉的开源的Asterisk或FreeSWITCH,以及基于Asterisk引擎的开源IPPBX界面管理系统FreePBX基于应用服务器支持,包括3GPP环境下的分机随行,ACD等服务SBC边界控制器,笔者已经多次介绍编码转换服务,支持不同编码转换,实现双方编码的一致性支持会议服务器,通过B2BUA实现会议,以及会议控制功能,混音等P-CSCF和IBCF Functions,支持IMS网络中的网关访问和切换功能S-CSCF Function,支持IMS环境中的Proxy-B2BUA在RFC7092规范中定义了具体的角色,但是规范并没有详细说明应用场景的具体的使用方式,读者可以参考具体的场景示例自己去做进一步的研究。在接下来的章节,我们重点介绍B2BUA的具体的工作流程和一些媒体管理的细节。
B2BUA具体呼叫工作流程
通过上面章节的介绍,可能读者已基本掌握了B2BUA的基本概念。现在我们重点介绍一下B2BUA是如何工作的。首先,这里说明,根据以上对B2BUA的定义,为了管理双方的终端和对会话进行管理,B2BUA需要分别创建两个不同的会话,B2BUA根据终端的不同,B2BUA可以扮演UAS/UAC的功能,只有这样,B2BUA才能完全控制双方的呼叫流程,保证双方在同一信令路径上。
以上示例是一个简单的双方终端呼叫的流程,B2BUA介于两个终端之间。此呼叫流程经过了大概四个步骤。
UAC对B2BUA发起一个INVITE请求,在B2BUA端,B2BUA是一个UAS来接收这个请求,创建了第一个会话来管理这个请求。双方保存了彼此的Route Set 记录消息。为了对另外一个终端发起INVITE请求,B2BUA同时也扮演了一个UAC的角色,它创建了第二个会话,并且再次对下游终端发起INVITE请求。这里,UAC需要从UAS端拷贝SDP消息和其他必要消息内容。然后,UAC对下游终端发起INVITE请求。终端接收了INVITE请求,并且保存了Route Set数据记录。为了响应INVITE请求,这里,下游终端就会变成一个UAS回复B2BUA 200 OK。B2BUA再次拷贝200 OK的消息,然后通过UAS再次返回到UAC终端。UAC终端收到200 OK以后,保存为Route Set数据内容。在最后的握手确认时,终端必须根据Route Set 返回到B2BUA,因为其中的Contact不是另外终端的Contact地址,而是B2BUA的Contact。接下来,UAC终端继续对B2BUA的UAS发送ACK消息。这里的UAC 终端必须通过B2BUA返回到另外一端,而不是直接进行ACK的交互,这样,B2BUA就会保证对终端双方的会话管理,同时可以支持其他业务功能的实现,例如,计费功能。
这里,读者一定要注意,B2BUA负责桥接两个呼叫的会话,拷贝必要的消息内容。关于拷贝什么消息,不能拷贝什么消息,我们在接下来的章节介绍。另外,B2BUA保持会话内容,两个会话负责不同的终端。双方终端不知道对端的Contact地址。终端的Contact地址仅是B2BUA的地址。在这一点上,B2BUA和SIP Proxy有着非常明显的区别。因此,双方终端只能通过B2BUA才能进行信令路径的完整性处理。
另外,一个比较特殊的场景是呼叫的预付费功能,这也是transparent B2BUA的一个基本功能。比较简单计费的原理如下:
If there is more time left, the B2BUA starts the timer again with the same operations as described above. If there is no more time left, the call legs willbe disconnected by sending BYE messages to all call legs . If either side disconnects the call, the B2BUA stops accounting.
事实上,关于预付费的复杂的处理流程,可能需要借助于媒体服务器的支持,通过mid-call announcements的方式,对预付费的电话服务进行语音播放,然后再执行挂机处理。具体的处理方式,读者查阅RFC3725-3。另外,关于透明B2BUA的介绍,读者可以查阅
Send a BYE request towards one, or even both parties, for example in prepaid applications.
#section-3
根据计费原理的工作方式,如果计费模块检测到双方呼叫费用出现超额的时候,这时,B2BUA会切换成UAC/UAC的状态,同时对终端发送BYE消息。
这里,透明B2BUA的工作方式类似于一个SIP Proxy,而且仍然利用了B2BUA的其他优点。和透明(transparent)B2BUA相对的是拓展(extended proxy)B2BUA,它可以支持其他的功能设置。两者之间没有特别明显的区别,具体的内容,读者可查阅:
Requirements for a Session Initiation Protocol (SIP) Transparent Back- To-Back User-Agent (B2BUA) draft-marjou-sipping-b2bua-00B2BUA功能实现3PCC讨论
B2BUA可以支持很多应用功能,比较常见的是3PCC,第三方呼叫控制。第三方呼叫控制实现了很多用户场景,包括点击呼叫,电话转接等功能。这些具体的实现流程,笔者在以前的文章中有非常详细的介绍和消息流程图,包括18个呼叫流程,读者可以查阅。
在3PCC的呼叫中,我们需要明确两个主要的定义:3PCC和控制器。根据RFC3725的定义,这两个定义是:
3pcc: Third Party Call Control, which refers to the general ability to manipulate calls between other parties.
Controller: A controller is a SIP User Agent that wishes to create a session between two other user agents.
在第三方呼叫的规范中定义了四种第三方呼叫的呼叫模式,其中的控制器就扮演着B2BUA的角色。比较典型的场景就是页面点击呼叫或者转接的处理。
在典型的转接环境中,两个终端可能已经接通了呼叫,因为其他的原因,终端可能需要转接此呼叫到第三方。这时,B2BUA或者控制器就会对另外一端挂机,继续保持着和呼叫方会话。呼叫方收到消息后,再次对第三方发送无SDP的INVITE(不是Option,是一个INVITE Request without SDP),双方接通后实现RTP创建。然后,B2BUA对另外一端彻底拆线。在整个流程控制中,B2BUA始终扮演和一个控制器的作用,会话互相不影响。关于3PCC的四种操作流程,读者可以查阅RFC3725进行进一步学习,规范分别对四种流程中INVITE和SDP处理要求有非常详细的描述,这里不再讨论。
SIP Proxy和B2BUA消息重构
在前面的讨论中,B2BUA是介于两个会话直接的一个逻辑实体,为了能够管理修改和保持双方的会话状态,B2BUA必须可以修改保存双方会话的消息数据,这样才能真正实现信令路径和媒体路径的完整性。因此,在B2BUA作为UAS/UAC角色切换时,UAS需要拷贝一些SIP消息到UAC,或者相反方向的SIP拷贝重构,否则没有办法获悉从上游过来的消息。但是,因为SIP协议中有很多规范是需要双方必须遵守的,因此,在拷贝双方的SIP消息时,需要考虑哪些SIP消息头是必须拷贝的,哪些SIP头是完全可能拷贝的,哪些SIP头是可以拷贝的。下面,我们通过一个示例就以上几个问题进行分析,检查双方数据映射处理时重构结果。
我们的示例是一个简单SIP终端通过B2BUA呼叫(INVITE)远端SIP电话。这里,我们再次强调,双方呼叫的会话没有直接的关系,这些SIP头的重构完全依赖于B2BUA本身。现在,我们逐一介绍这些SIP头的处理。
首先,在INVITE中的Request-URL可以拷贝也可以通过B2BUA自己重新定义。典型的应用方式是B2BUA直接拷贝这个地址。所以,这个地址是可以直接拷贝的地址。Call-ID,根据RFC3261的定义,它是一个全局变量,并且具有唯一性,因此,两个会话都分别有各自不同的Call_ID,因此它是不能拷贝的。服务器端需要自己生成自己的ID。Content-Length和Content-Type的处理,双方的呼叫中,包含了SDP消息和其他下游媒体说需要的参数来和终端协商,B2BUA可以利用它们的Content-Length和Content-Type作为另外一个UA的SDP消息数据。因此,这些数据是可以拷贝的。当然,如果B2BUA进行了特别的编码处理则是另外一个话题。To和From 地址的处理,理论上说,B2BUA可以自由选择自己本身所需要的地址。但是,如果没有其他特别的要求,一般来说,B2BUA直接拷贝了另外一个UA的To地址。From 地址也是一样的道理,B2BUA可以直接拷贝上游From地址,然后传递给下游终端,这样SIP终端就会获悉是哪个SIP终端的呼叫。当然,为了更好管理终端之间的呼叫,B2BUA也可以修改为自己B2BUA的地址,下游SIP终端可以获悉是来自于B2BUA地址的3PCC呼叫。Contact地址的处理,大家知道,如果呼叫到远端SIP终端时,SIP终端就会保存Route Set的地址,这个地址用来支持后续的请求处理,这个Contact地址不应该是SIP终端地址,如果是SIP终端地址的话,两个分机就可以实现直接呼叫。但是,在B2BUA的模式下,这个Contact地址不能直接拷贝到下游的Contact地址,只能使用本地B2BUA地址,这样,下游的SIP终端收到的Contact地址就是B2BUA的地址。在呼叫创建时,下游终端就会通过B2BUA地址呼出。这样,B2BUA始终在呼叫双方的媒体路径和信令路径,保证B2BUA可以控制和管理呼叫流程。因此,这个Contact地址是不能直接拷贝的。关于CSeq的处理,根据RFC3261的定义,CSeq method类型必须反映request method的类型。为了保证请求类型的正确,因此,在B2BUA中CSeq的值可以直接拷贝,也可以重新初始化一个新的计算器值。Max-Forward的处理,因为SIP终端设备可以选择任何计算器的值,B2BUA可以自己决定重新设置为默认的计算器70。另外,因为在SIP路径经过了一个Hop,所以B2BUA也可以根据上游设备提供的计算器值,自动递减一次。因此,Max-Forward计算器值也可以直接拷贝或者直接使用上有的值。Via 头的处理。我们在以前的文章中专门讨论了Via的用法,这个地址通知下游设备回复响应的地址。上游的Via可能经过了多个Hop或者Proxy,对下游SIP终端发送Via时,这里的B2BUA不关心上游Via的结果,B2BUA仅关心下游SIP终端返回的响应地址,通知下游SIP终端返回到B2BUA的地址,而不是其他的地址。这个Via地址必须是B2BUA的地址,所以,B2BUA不能直接拷贝上游Via的地址。根据以上分析,我们可以看到,在B2BUA的模式下,大部分的SIP头是可以拷贝重构的,Call-ID, Contact 地址和Via是完全不能拷贝的。基本上没有B2BUA必须拷贝的SIP头。因此,B2BUA是非常灵活,而且具有多种权限来管理SIP话话和应用服务。
特别注意,可能有时出现一些比较特殊的应用场景,例如mid-call的应用场景(中间播放语音提示或者或其他业务流程),如果SIP终端通过Proxy呼叫一个功能服务器,Proxy希望功能服务器端能够快速响应,收到系统的请求返回到Proxy。但是,因为是B2BUA,功能服务器可能重新生成一个Call-ID, 这样会导致远端的SIP终端产生误解。如何解决这个问题,B2BUA只能拷贝原来的Call-ID确保这是一个同样的处理流程。具体此细节处理在RFC7329-4.5.2有定义。
根据以上讨论,我们可以总结一些它们之间的区别。一般情况下,经过Proxy处理的SIP消息具有几个方面的特点:大部分的头是相同的,Proxy没有处理这些SIP头,Max-Forwards是递减的,而且Via头增加了一个Proxy自己的地址。但是,经过了B2BUA的SIP消息是经过重构的,因此很多SIP头可能是不一样的。SIP消息经过了B2BUA的重构以后,SIP消息具有明显的不同:Contact地址变成了B2BUA的服务器的地址,Via消息是一个单列的地址,这个地址是B2BUA的需要的返回的地址,这里可能是B2BUA的地址。这里的Call-ID可能有例外(前面已经讨论),可以是同样的Call-ID。另外,CSeq具有灵活性,可以处理也可以恢复到默认状态。
其他相关问题讨论
除了我们上面讨论的B2BUA的SIP消息重构以外,笔者在这里和大家讨论几个和本文章相关的讨论。在很多文章中,包括我们今天的讨论中,我们一直使用透明B2BUA(transparent B2BUA)的说法。事实上,根据IETF组织的草案,透明B2BUA的工作方式类似于一个特别的Proxy,但是更多利用了UA的功能。透明B2BUA的功能其实和我们前面介绍的B2BUA功能相似,因此,这里不再累述。因为透明B2BUA的概念比较宽泛,很多人对这个概念有很多争论,而且在SIP处理方面具有非常强的灵活性,在一般的讨论中,笔者建议根据具体的操作场景来解释,或者通过一定的场景来理解。
当然,transparency(透明)proxy或者B2BUA是一个无休止的讨论,到底有多透明,事实上,完全取决于SIP 处理的流程和业务场景。Proxy比较透明,因为它仅实现了RFC3261的简单功能,没有涉及太多的SIP消息重构和3PCC的处理。为了满足3PCC或其他业务能力,透明B2BUA是一个非常明确的需求,但是在B2BUA的使用场景中,很多SIP 头是需要经过UA处理的,例如,我们现在使用的SBC。SBC作为一个B2BUA需要对SIP 头进行处理才能实现拓扑隐藏,协议正规化,编码转换和协议转换等功能。因此,一些比较专业的SBC采取了一定的控制机制来实现透明处理(Relay和Transparency)。
我们在前面的章节中已经多次提及B2BUA和SIP Proxy之间的区别和SIP头的变化。下面,我们提供几个示例结合以前B2BUA和Proxy的区别,再次对SBC功能和SIP Proxy进行一个对比说明以帮助读者进一步了解SBC和Proxy主要区别。读者一定要注意标注的关键词部分。
我们可以通过两个示例来对比SBC和SIPProxy的消息经过变化。
经过了SBC后,Via 头变成了SBC的地址,Call-ID发生了变化,Max-Forwards递减,Contact头修改为SBC地址,最后c=和m=发送了变化,支持RTP和RTCP的创建。如果经过了Proxy以后,SIP Via 头中插入了新的Via地址,就是Proxy地址,另外,Max-Forwards发生递减。其他头没有任何修改和变化。
通过以上示例,我们基本上可以理解B2BUA或者SBC和SIPProxy的区别。很多情况下,我们需要检查系统的日志来排查问题。那么,现在问题来了。如何判断这些SIP消息是经过Proxy的SIP消息还是B2BUA的SIP消息?这里,我们做一个简单的介绍以帮助读者能够非常快速判断系统的SIP消息日志。经过SIP Proxy的系统日志是这样的:
经过B2BUA 的SIP重构以后的消息变化是这样的:
根据我们介绍的SIP消息经过Proxy和B2BUA的不同也可以看出两者之间的不同,它们两者都基本上完全遵守SIP的规范和各自的定义。
总结
本文章介绍了B2BUA的基本概念,SIP Proxy和B2BUA的区别,然后笔者介绍了B2BUA在3PCC中的应用场景分析。另外,笔者花费时间对B2BUA消息重构做了非常详细地说明解析,同时对某些SIP头的处理针对性地做了强调,帮助读者能够有重点地了解某些规范支持。最后,笔者对透明B2BUA处理,B2BUA的透明处理机制和SIP Proxy的区别做了讨论。
再次说明,如果读者缺少SIP其他方面基础的介绍,需要查阅笔者的历史文档补充这些知识,这样可以更好理解本章所学习的内容。