锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

使用OpenSER构建VoIP通话 (转载)

时间:2023-05-08 11:37:00 uas电子式压力变送器

使用OpenSER构建VoIP通话
使用OpenSER构建电话通信系统-第一章(1)



前言:openser已经成为opensips项目,但这本书的大部分内容都适合学习相关知识。所以还是原封不动的翻译。
使用OpenSER构建电话通信系统
Building Telephony Systems with OpenSER
第一章:SIP介绍(Introduction to SIP)
会议的初始协议是互联网工程任务组(IETF)协议标准在多个方面制定RFC(Request for Comments)文件中有描述。RFC3261是最近的一个RFC,一般称它为SIP版本2。SIP是一个应用层的协议,用来建立,修改,终止会话(sessions)或多媒体通话(multimedia calls)。这些会话可以开会(conferences),e-learning,网络电话和一些类似的应用。它是同HTTP本协议类似于文本协议,设计用于启动、维护和关闭用户之间的互动对话。目前SIP已经是VoIP该领域被广泛使用的协议之一是市场上几乎每个协议IP所有会支持它。
本章结束时,您将能够:
l 描述SIP是什么
l 描述SIP是干什么的
l 描述SIP的框架
l 解释SIP主要部件的意义
l 理解和比较重要SIP消息
l 描述INVITE和REGISTER请求处理消息头部的过程
在建立和关闭多媒体通话的过程中,SIP协议支持五个要素。
l 用户定位(User location)
l 协商用户参数(User parameters negotiation)
l 用户可用性(User availability)
l 通话建立(Call establishment)
l 通话管理(Call management)
SIP该协议被设计成多媒体框架的一部分,包括RVSP,RTP,RTSP还有SDP等待其他协议。SIP但不依赖其他协议。
SIP基础(SIP Basics)
SIP以工作的方式和HTTP协议相似。SIP的地址像是e-mail的地址。SIP代理中使用的一个有趣的特点是别名(alias)也就是说,你可以有多个SIP地址,譬如:
johndoe@sipA.com
554845678901@sipA.com
45678901@sipA.com
在SIP在系统结构中,有多个用户代理和服务器提供不同的服务。SIP使用点对点(peer-to-peer)的分布模型来和服务器进行消息的交互。服务器只进行消息(signaling)用户代理的客户端和服务端可以处理新闻或媒体。下图描述了这样一个系统:

在SIP在模型中,用户代理通常是一个SIP话机与它的SIP从上图可以看出,可以看出,外呼代理(outgoing proxy)将使用INVITE消息发出通话请求。
呼叫代理将观察呼叫是否定向于外部域名。然后它会向前移动DNS服务器要求将目标域名分析为相应的IP地址DomainB对应的SIP代理。
呼入代理(incoming proxy)地址列表(location table)中查询agentB的IP地址。如果地址列表与之前注册过程中的地址相同IP地址对应,然后呼入代理可以定位地址。现在您可以使用此地址将通话请求发送到agentB了。
agentB收到这个SIP消息后(INVITE),拥有可以和agentA建立RTP会话所需的信息(通常是音频会话)。BYE消息可以终止会话。
SIP代理在VoIP提供者的作用/上下文(SIP Proxy in the Context of a VoIP Provider)
通常VoIP服务提供商不会像上图那样纯粹SIP四边形结构不允许你向外部域名发送电话请求,因为如果是这样,会影响他们的收入(revenue stream)。取而代之的是三角形SIP网络结构(如下图所示)

SIP工作原理(SIP Operation Theory)
你可以在上图中看到SIP系统结构的主要组成部分。SIP消息将通过SIP代理服务器。另一方面,由RTP协议承载的媒体流直接从一端流向另一端。我们将在下列表中简要解释一些组件。

l 用户代理客户端(UAC user agent client)——发起SIP客户端或消息终端
l 用户代理服务端(UAS user agent server)——从用户代理客户端接收到的对接SIP相应的服务端消息。
l 用户代理(UA user agent)——SIP终端(IP电话,电话适配器(ATA),软电话(softphone))
l 代理服务器(Proxy Server)——从用户代理接收请求,如果指定的请求终端不在其域,请求将发送到其他域SIP代理。
l 重定向服务器(Redirect Server)——接收请求,但不直接发送给被称用户,而是将目的地址信息发送给被称用户。
l 定位服务器(Location Server)——为代理服务器和重定向服务器提供联系地址。
通常,代理服务器、重定向服务器和定位服务器存在于同一台计算机和软件中。
SIP注册过程(SIP Registration Process)

SIP该协议使用了一个叫做注册服务器的部件。它不仅可以接收REGISTER信息请求还可以将收到的信息包中的信息保存应域名的定位服务器上。SIP协议有发现能力;换句话说,如果一个用户想开始与另一个用户交谈,那么SIP协议必须找到用户可以到达的主机。由于定位服务器可以收到请求信息并找到发送到哪里,因此该发现过程由定位服务器完成。这是基于管理每个域的定位服务器护定位数据库的事实。注册服务器不仅可以接收客户端IP还可以接收其他类型的消息。例如,您可以在服务器上收到它CPL(CallProcessing Language)脚本。
在一台话机能够接收一通通话之前,它需要在定位数据库中有注册信息。在这个数据库中我们要拥有所有电话的各自的相关的IP地址。在我们的例子中,你将看到SIP用户8590@voffice.com.br注册到200.180.1.1上面的过程。
RFC3665定义实现了一个最小的功能集合,这是使得SIP进行IP网络交互时的最好实践。下面的图就是根据RFC3665中的描述所画出的注册事务处理流程。

 
按照rfc3665中所说,与注册一个用户代理的过程相关的有五个基本的流程,如下所述:
1.    一个新的成功的注册(A successful new registration)——用户代理在发送Register请求后,将收到认证过程的挑战。我们将在阐述验证过程的章节中看到这个过程的细节。
2.    联系列表的更新(An update of the contact list)——由于不再是新的注册,消息中已经包含了摘要(digest),那么不会返回401消息。为了改变联系列表,用户代理仅仅需要发送一条在CONTACT头中带有新的联系信息的注册信息即可。
3.    请求获得当前的联系列表——在这种情况下,用户代理将把发送消息中的CONTACT头置空,表明用户希望向服务器询问当前的联系列表。在回复的200OK消息中,SIP服务器将把当前的联系列表放在其CONTACT的头中。
4.    取消注册(Cancellation of a registration)——用户代理在发送的消息中将EXPIRES头置成0,并且将CONTACT头设置为“*”表示将此过程应用到所有存在的联系信息。
5.    不成功的注册(Unsuccessful Registration)——用户代理客户端(UAC)发送一条Register请求消息,收到一条“401 Unauthorized”消息,事实上,这个过程同成功注册过程相同。但是接下来,它进行哈希运算尝试进行认证。而服务器检测到的是一个无效的密码,继续发送“401 Unauthorized”消息。这个过程一直重复直到重复次数超过在UAC设置的最大值。
 
作为SIP代理运转的服务器(Server Operating as a SIP Proxy)
在SIP代理模式下,所有的IP消息都要经过SIP代理。这种行为在向诸如计费(billing)的过程中帮助很大,而且迄今为止,这也是一种最普遍的选择。但是它的缺点就是在会话建立过程中的所有的SIP交互中,服务器造成的额外开销也是客观的。要记住的是,即使服务器作为SIP代理在工作时,RTP包也总是直接从一端传送到另一端,而不会经过服务器。

 
作为SIP重定向运转的服务器(Server Operating as a SIP Redirect)
SIP代理可以运行在SIP重定向模式。在这种模式下,SIP服务器的处理量是相当巨大的,因为它不需要保持事务处理的状态。在对INVITE消息进行初始化后,仅仅向UAC回复一条“302 Moved Temporarily”消息就可以离开SIP对话(dialog)了。在这种模式下的SIP代理,即使只是利用非常少的资源也可以每小时传送上百万的通话。当你需要的规模很大并且不需要对通话计费的情况下,这种模式通常会被使用。
 
 
基本消息(Basic Messages)
在SIP环境中会被发送的基本的消息有:

大多数时间内,你会使用到REGISTER,INVITE,BYE还有CANCEL。而另外一些消息会被用在其他的特性当中。举例来说,INFO被用在DTMF relay和通话中消息信息(mid-call signaling information)。PUBLISH,NOTIFY和SUBSCRIBE则用来支持列席系统(presence systems)。REFER用来进行通话转接(call transfer)而MESSAGE则应用于一些聊天应用程序中。更新的消息也会随着协议标准化进程而随之出现。
像HTTP协议一样,这些消息的响应也会以文本形式出现。其中一些最终的响应消息被列在下图当中:

SIP对话流程(SIP Dialog Flow)
这一节将通过一个简单的例子来介绍一些基本的SIP操作。先让我们来诊视下图展示的两个用户代理之间的消息顺序。你可以看到伴随这RFC3665描述的会话建立过程还有几个其它的流程。

我们在这些消息上标上了序号。在这个例子中用户A使用IP电话向网络上的另外一台IP电话发出通话请求。为了完成通话,使用了两个SIP代理。
用户A使用称为SIP URI的SIP标识向用户发出通话。URI就像是一个电子邮件地址,比如sip:userA@sip.com。一种可靠安全的SIP URI也可以被使用,譬如sips:userA@sip.com。使用SIPS建立的通话将会在主叫和被叫之间使用安全可靠的传输机制(TLS-Transport Layer Security)
事务(transaction)的建立始于用户A向用户B发送INVITE请求消息。INVITE请求中包含一些特定头域。这些头域被称之为属性,为消息提供了额外的一些信息。包括唯一的标识,目的地,还有关于会话(session)的信息。

 
第一行是消息的方法名(the method name)。接下来是列出的头域。这个例子包含了所需要的头的最小集合。我们将在下面简要的描述这些头域。
l        VIA:它包含了用户A等待发出请求对应响应的所在地址。还包含了一个叫做“branch”的参数,这个参数用来唯一的标识这个事务(transaction)。VIA头将最近从“SIP跳”(SIP hop)定义为IP,传输,和指定事务参数(The VIA header defines the last SIP hop as IP,transport,and transaction-specific parameters)。VIA专门用来路由响应消息。请求经过的每一个代理都会增加一个VIA头。而对于响应消息而言,相对于再次向定位服务器或是DNS服务器进行定位请求,使用VIA头进行路由将更加容易。
l        TO :它包含了名字(显示名(display name))和最初选择的目的地的SIP URI(这里是sip:userB@sip.com)。TO头域不被用来路由消息包。
l        FROM:它包含了名字和表明主叫ID(caller ID)的SIP URI(这里是sip: userA@sip.com)。这个头域有一个tag参数,而这个参数包含了被IP电话添加进URI的一个随机字符串。是被用来进行辨识唯一性的。tag参数被用在TO和FROM头域中。作为一种普遍的机制用来标识对话(dialog),对话是CALL-ID和两个tag的结合,而这两个tag分别来自参与对话的双方。Tags在并行派生(parallel forking)中作用显著。
l        CALL -ID:它包含了一个作为这通通话全局性的唯一的标识,而这个唯一标识是有一个随机字符串,来自IP电话的主机名或是IP地址结合而成的。TO,FROM的tag和CALL-ID的结合完整的定义了一个端到端的SIP关系,这种关系就是我们所知道的SIP对话(SIP dialog)
l        CSEQ:CSEQ或者称之为命令序列(command sequence)包含了一个整数和一个方法名。CSEQ数对于每一个在SIP对话中的新请求都会递增,是一个传统的序列数。
l        CONTACT:它包含一个代表直接路由可以联系到用户A的SIP URI,通常是有一个用户名和FQDN(fully qualified domain name)。有时候域名没有被注册,所以,IP地址也是允许使用的。VIA头告诉其他的组件向什么地方发送响应消息,而CONTACT则告诉其他组件向什么地方发送将来的请求消息。
l        MAX-FORWARDS:它被用来限制请求在到达最终目的地的路径中被允许的最大跳数(hops)。由一个整数构成,而这个整数在每一跳中将会递减。
l        CONTENT-TYPE:它包含了对内容消息的描述。
l        CONTENT-LENGTH:它用来告知内容消息的字节数。
会话的一些细节,像媒体类型和编码方式并不是使用SIP进行描述的。而是使用叫做会话描述协议(SDP RFC2327)来进行描述。SDP消息由SIP消息承载,就像是一封电子邮件的附件一样。
 
过程如下:
 
话机开始并不知道用户B和负责域B的服务器的位置。因此,它向负责sipA域的服务器发送INVITE消息请求。发送地址在用户A的话机中进行设置或通过DHCP发现。服务器sipA.com也就是我们知道的域sipA.com的SIP代理服务器。
 
1. 在这个例子中,代理服务器收到INVITE请求消息并发送“100 trying”响应消息给用户A,表明代理服务器已经收到了INVITE消息并正在转发这个请求。SIP的响应消息使用一个三个数字组成的数字码和一条描述语句说明响应的类型。并拥有和INVITE请求一样的TO,FROM,CALL-ID和CSEQ等头域,以及VIA和其“branch”参数。这就使得用户A的话机同发出的INVITE请求联系在一起。
 
2. 代理A定位代理B的方法是向DNS服务器(SRV 记录)进行查询以找到负责sipB的SIP域的服务器地址并将INVITE请求转发给它。在向代理B(译者注:这里作者写的是proxyA,但是应该是B)发送INVITE消息前,代理A将其自己的地址通过VIA头添加进INVITE,这就使得用户A的话机同INVITE请求的响应消息联系在了一起。
 
3. 代理B收到INVITE请求,返回“100 Trying”消息响应,表明其正在处理这个请求。
 
4. 代理B查询自己的位置数据库以找到用户B的地址,然后将自己的地址也通过VIA头域添加进INVITE消息发送给用户B的IP地址。
 
5. 用户B的话机收到INVITE消息后开始振铃。话机为了要表明这种情况(振铃),发送回“180 Ringing”响应消息。
 
6. 这个消息以相反的方向路由通过那两个代理服务器。每一个代理利用VIA头域来决定向哪里发送响应消息并从顶部将其自己的VIA头去除。结果就是,180 Ringing消息不需要任何的DNS查询,不需要定位服务的响应,也不需要任何的状态处理就能够返回到用户那里。这样的话,每一个代理服务器都能够看到由INVITE开始的所有消息。
 
7. 当用户A的话机收到“180 Ringing” 响应消息后开始“回铃”,表明另一端的用户正在振铃。一些话机是通过显示一些信息进行表示的。
 
8. 在这个例子中,用户B对对方发起的通话进行了响应。当用户B响应时,话机发送”200 Ok“响应消息以表明通话被接起。“200 Ok”的消息体中包含了会话的描述信息,这些信息包括指定了编码方式,端口号,以及从属于会话的所有事情。作这项工作的就是SDP协议。结果就是,在从A到B(INVITE)和从B到A(200 OK)的两个阶段,双方交换了一些信息,以一种简单的“请求/响应”的模式协商了在这通通话中所需的资源和所需要的能力要求。如果用户B不想得到这通通话或是此刻处于忙线中,200 Ok将不会发出,取代它的是描述这种状况(这里是486 Busy Here)的消息。

第一行是响应码和描述信息(OK)。接下来是头域行。VIA,TO,FROM,CALL-ID和CSEQ是从INVITE请求中拷贝的。有三个VIA头,一个是用户A添加的,另一个是代理A添加的,最后一个则是代理B添加的。用户B的SIP话机在对话的双方加入了一个TAG参数,这个参数在这通通话的以后的请求和响应消息中都将出现。
CONTACT头域中包含了URI信息,这个URI信息是用户B能够直接被联系到他们自己的IP话机的地址。
CONTENT-TYPE和CONTENT-LENGTH头域先给出了关于SDP头的一些信息。而SDP头则包含了用来建立RTP会话的媒体相关的参数。
1. 在这个例子中,“200 Ok”消息通过两个代理服务器被送回给用户A,之后用华A的话机停止“回铃”表明通话被接起。
 
2. 最后用户A向用户B的话机发送ACK消息确认收到了“200 Ok”消息。在这里,ACK避开了两个代理服务器直接发送给用户B。ACK是SIP中唯一不需要进行响应的消息请求。两端在INVITE的过程中从CONTACT消息中了解双方的地址信息。也结束了INVITE/200 OK/ACK的过程,这个过程也就是我们所熟知的SIP三次握手。
 
3. 这个时候两个用户之间开始进行会话,他们以用SDP协议协商好的方式来发送媒体包。通常这些包是端对端进行传送的。在会话中,通话方可以通过发送一个新的INVITE请求来改变会话的一些特性。这叫做re-invite。如果re-invite不被接受,那么“488 Not Acceptable Here”响应就会被发出,但是会话不会因此而失败。
 
4. 要结束会话的时候,用户B产生BYE消息来中断通话。这个消息绕过两个代理服务器直接路由回用户A的软电话上。
 
5. 用户A发出“200 OK”响应消息以确认收到了BYE消息请求,从而结束会话。这里,不会发出ACK。ACK只在INVITE请求过程中出现。
 
有些情况下,在整个会话过程中,对于代理服务器来说,能够待在消息传输的中间位置来观察两端的所有消息交互是很重要的。如果代理服务器想在INVITE请求初始化完成后还待在此路径中,可以在请求消息中添加RECORD-ROUTE头。用户B的话机得到了这个消息,之后在其消息中也会带有这个头,并且会将消息发送回代理。记录路由(Record Routing)在大多数的方案中都会被使用。
 
REGISTER请求是代理B用来定位用户B的方法。当话机初始化的时候或是在通常的时间间隔中,软电话B向在域sipB中的一个服务器(SIP REGISTRAR)发送REGISTER请求。注册服务器(REGISTER)将URI与一个IP地址联系在一起,这种绑定被存储在定位服务器上面的数据库里。通常,注册服务器,定位服务器,和代理服务器在同一台物理机器上,并使用相同的软件。OpenSER就能够扮演这三种角色。一个URI只能够在一个特定的时间内由一个单独的机器注册。
 
SIP事务和对话(SIP Transactions and Dialogs)
理解“事务”(transaction)和“对话”(dialog)的区别是非常重要的。事务发生在一个用户代理客户端和另一个用户代理服务端之间,包含从第一请求到最后一个响应的所有消息。中间的阶段性的响应消息可以是以1开头的三位数字码(比如180 Ringing),最终的响应消息则是以2开头的三位数字码(比如 200 OK)。事务包括的范围由SIP消息中VIA头形成“堆栈”来决定。因此,用户代理在初始化invite后才不需要依靠DNS或位置表进行消息路由。
对话(Dialog)通常是从INVITE事务开始,由BYE事务结束。一个对话由CALL-ID头唯一标识。TO tag,FROM tag和CALL-ID的结合来完整的定义。
按照rfc3665的描述,有11个基本的会话建立流程。其列出的并不一定是完整的,但是覆盖了最好的例子。前两个流程在这一章节中进行了阐述——“成功建立会话Successful Session Establishment”和“通过两个代理建立会话Session Establishment Through Two Proxies”。其中的一些流程的描述你将在其他阐述呼叫前传(call forwarding)(譬如:“不接听导致没能成功建立Unsuccessful with no Answer”和“忙音导致建立失败Unsuccessful Busy”)的章节中看到。
 
RTP协议(The RTP Protocol)
译者注:应为Real Time Transport Protocol
实时传输协议是负责诸如音频和视频等数据的实时传输的。它标准化于RFC3550。使用UDP协议进行传输承载。为了能够被实时传输,音频或视频必须经过一定的编码打包。最基本的,该协议允许使用如下的一些特性对进出的数据包的媒体传输的时间和内容要求进行指定:
l        序号
l        时间戳
l        无重传机制的包的前转
l        源识别
l        内容识别
l        同步
与RTP相伴的协议叫做RTCP(Real Time Control Protocol),被用作对RTP包进行监控。它可以度量延迟和抖动。
 
编码(Codecs)
RTP协议描述的内容通常会由一种编码方式进行编码。每一种编码方式都有一种指定的用途。一些有压缩算法而另外一些则不需要。比较普遍的是使用不需要压缩的G.711编码方式。一个信道64Kbps的带宽要求需要一个高速的网络,通常在局域网(LANs)中比较常见。但是在广域网(WAN)中对于一个单独的声音信道来说,64Kbps的带宽购买起来比较昂贵。这时候诸如G.729和GSM等可以将声音包压缩至8Kbps的编码方法则可以节省很多的带宽。由Global IP sound公司发明的iLBC编码方式则可以掩盖网络中由丢包造成的影响。在丢包率带到7%的情况下,使用iLBC仍然能够维持一个比较好的声音质量。所以对于你的VoIP提供商支持的编码方式你必须进行明智的选择。
DTMF-Relay
在一些情况下,RTP协议被用来承载诸如DTMF的信号信息。RFC2833中描述了一种方法,这种方法就是将DTMF作为RTP协议中的命名事件(named events)进行传输。在用户代理客户端和用户代理服务端之间使用同一种方法进行DTMF传输是非常重要的。
实时控制协议(Real Time Control Protocol-RTCP)
RTCP可以对接受的质量进行反馈。它为RTP媒体流提供带外控制信息。诸如抖动(Jitter),往返时延(RTT-Round Trip Time),传输延迟(latency)和丢包等的数据可以使用RTCP进行搜集。RTCP通常用来对声音质量进行报告。
会话描述协议(Session Description Protocol-SDP)
SDP协议在RFC4566中被进行了详细的描述。它是在用户代理之间进行会话参数协商之用的。媒体的细节,传输的地址还有其他与媒体相关的一些信息都使用SDP协议在用户代理之间进行交互。通常,INVTIE消息中包含了SDP“供给消息”,而200 Ok则包含了“回答消息”。这些消息会在下面的图中进行展示。在下图中,你可以观察到GSM编码方式被“供给”,但是另外一台话机却并不支持该编码,那么然后它将使用它本身支持的编码方式进行“回答”,在这个例子中它支持的是G.711 ulaw(PCMU)和G.729编码方式。 会话的“rtpmap:101”就是在RFC2833中描述的DTMF-relay信息。
INVITE (SDP Offer)

200 OK(SDP Answer)

 
SIP协议与OSI七层模型(The SIP Protocol and the OSI Model)
理解声音相关协议的每一个协议对于OSI模型是属于哪一层也是相当重要的。

VoIP服务提供商的整体框图(The VoIP Provider “Big Picture”)
在我们开始深入的挖掘SIP代理之前,了解VoIP提供商的解决方案中的所有部件是非常重要的。服务提供者通常由多个服务器(servers)和多个服务(services)组成。这里说的服务可以根据规模的大小来决定是被安装在一台单独的服务器上还是安装在多台机器上面。
本书将在前几个章节中按照这张图从左到右来描述每一个部件。所有的章节中都将使用这张图来帮助你来了解你所处的位置何在。
SIP 代理(SIP Proxy)
SIP代理是我们解决方案中的核心部件。用来负责用户的注册和维护位置数据库(映射IP和SIP地址)。所有的SIP路由和消息都会被SIP代理处理,它也负责一些用户端级别的服务譬如呼叫前转,白/黑名单,快速拨号等。这个部件从不处理媒体(RTP包),所有与媒体相关的包都从用户代理客户端,服务器和PSDN网关直接路由。
用户,管理和供给入口(User,Administration,and Provisioning Portal)
用户管理和供给入口是一个重要的部件。在入口当中,用户订阅服务并且应该能够购买信用量,修改密码和验证他/她的账号。另一方面,管理者应该能够删除用户,改变用户信用级别,承认,删除权限。对于管理员来说,“供给(Provisioning)”过程使得用户代理如IP电话,模拟话机适配器还有软电话的自动安装过程更加容易。
PSDN 网关(PSDN网关)
为了能和公共的交换电话网络交互,PSTN网关是需要的。通常,这个网关是使用E1或T1中继线的PSTN的接口。在这个领域中使用最广泛的是来自Cisco,AudoCodes和Quintum公司的网关。Asterisk也占据了一定的市场份额,因为它的每个端口的价格要比竞争对手们便宜75%。如何评估一个网关的好坏,要检查它对SIP协议扩展的支持程度,譬如对RFC3515(REFER),RFC3891(Replaces)还有RFC3892(Referred by)。这些协议使得我们能够在SIP代理背后进行呼叫转移;如果网关中不支持他们,进行呼叫转移是不太可能的事。
媒体服务器(Media Server)
因为SIP代理从不处理媒体,所以如IVRs,语音邮箱,电话会议等和媒体相关的服务要能够在媒体服务中得到实现。由iptel开发的SEMS SIP Express媒体服务器具有一些很好的特性,如conference,voicemail和announcements等。我们要再一次提到Asterisk,因为它也能够用来提供这些服务。
穿透NAT的媒体代理或RTP代理(Media Proxy or RTP Proxy for Nat Traversal)
任何SIP服务提供者必须要为他的客户提供NAT穿透的解决方案。媒体代理就是一座帮助处在对称式防火墙(symmetric firewall)之后的用户能够访问SIP服务提供者进行RTP连接的桥梁。如果没有了这些代理,服务提供者可能会流失35%的用户。你可以使用这些部件来实现一个通用的NAT穿透技术。媒体代理还可以帮助你进行记帐纠错,比如,因为某种原因,没有收到BYE消息而导致了SIP对话没有结束,结果记帐发生了错误等情况。
RADIUS记账(RADIUS Accounting)
拥有一台安装了RADIUS的服务器是对通话进行记账的基本条件。SIP服务提供者对账单记录是最关心的。OpenSER可以被配置将一些记账信息发送到一台RADIUS服务器(比如Radiator或FreeRADIUS)上。SIP通话账单也可以被记录到数据库中。但是,这样将产生两条记录,而这两条记录需要手工进行核对。
用CDRTool计费(CDRTool Rating)
RADIUS服务器可以记录关于通话时长的一些信息,但是却不能记录每通通话的资费信息。将资费信息应用到通话上是需要技巧的。这里我们使用AG项目组(cdrtool.agprojects.com)开发的被称为CDRTool的GPL工具。它负责将资费应用到通话上面。
监控工具(Monitoring Tools)
最后我们需要一些监控,故障检修和测试的工具来帮助我们定位并解决在SIP服务器上发生的一些问题。首当其冲的当然是协议分析工具,在余下的章节中我们将能够看到如何使用ngrep,ethereal和tethereal。OpenSER有一个被称为SIP trace的模块,我们也将使用到。
哪儿能够找到更多信息
SIP协议最好的参考资料就是RFC3261。阅读RFC确实有点沉闷(不过如果你有点失眠这确实是一种好办法)。你可以在 http://www.ietf.org/rfc/rfc3261.txt上找到它。也可以在哥伦比亚大学的网站上找到好的SIP教程如: http://www.cs.columbia.edu/~coms6181/slides/11/sip_long.pdf。也可以在 http://www.cs.columbia.edu/sip/上找到许多关于SIP的信息。
一个非常好的教程在iptel的网站上: http://www.iptel.org/files/sip_tutorial.pdf。
下面是一个叫做SIP应用者(SIP implementors)的邮件列表,你可以在上面就SIP的知识进行提问: https://lists.cs.columbia.edu/mailman/listinfo/sip-implementors。
概要(Summary)
这一章你已经学到了什么是SIP协议以及SIP协议的功能。也知道了诸如SIP代理,SIP注册服务器,用户代理客户端,用户代理服务端,PSTN网关等SIP协议中的部件。还看到了SIP的体系结构,主要的消息和处理过程。以及去什么地方可以找到更多相关的信息。
 
 
第二章:SIP快速路由器(The SIP Express Router)
上一章节中我们讨论了VoIP提供商的“整体框图”(the big picture)。通常,一个VoIP提供商由几个部件构成。这些部件根据规模的大小或驻留在同一台机器上或分布于多个机器上面。其中的一个部件就是SIP代理,在我们的例子中代理服务器运行的是OpenSER软件。就像它的名字一样,描述SER的最好的东西就是SIP路由器(a SIP Router)。它能够对SIP的头域进行操作并能够以极高的速度对SIP包进行路由。第三方的模块给了SER极高的灵活性来完成一些原本没有的功能,诸如NAT穿透,IMS,负载均衡等其他功能。在这一章,我们将向你展示SIP快速路由器的能力和框架。
在本章的末尾,你将能够:
l        解释SIP快速路由器(SER)到底是什么
l        在两个开源项目SER和OpenSER中作出选择
l        描述对它们的使用方案
l        辨别出openser.cfg文件中的不同的区段
l        描述SIP消息的处理过程
l        辨别松散路由和严格路由
l        辨别SIP和SDP
我们在哪儿?(Where Are We?)
VoIP提供商的解决有很多部件。为了能够对各个部件的联系保持一个整体的把握,我们将在每一个章节中展示下面这张图片。在这一章中,我们的主要的讨论围绕SIP代理部件来进行。

 
SIP快速路由器是什么?(What is the SIP Express Router?)
SIP快速路由器是一套兼容IETF RFC3261 sip协议的开源的SIP代理服务器。它的目的是兼容并包尽可能多的应用。

只需要起一个单独的服务,SER就可以以它“短小精悍”的特点最快速的对请求进行前转,并能够处理成千上万的用户。它被大量的VoIP的提供商所使用,也被使用在处理能力相对较弱的嵌入式IP PBX上面。它和其他一些设备的互操作性也使得它成为实际的标准。
用哪个软件,SER还是OpenSER?(What software to use,SER or OpenSER?)
SER最开始是由德国柏林的FhG Fokus研究院所开发,发布的时候是遵从GPL许可的。它的核心开发人员是Andrei Pelinescu-Onciul,Bogdan-Andrei Iancu,Daniel Constantin Mierla,Jan Janak,
还有Jiri Kuthan。之后,其他的一些人也为此作出了贡献,他们是Juha Heinamen(RADIUS, ENUM, DOMAIN, URI), Greg Fausak (POSTGRES), Maxim Sobolev
(NATHELPER), Adrian Georgescu (MEDIAPROXY), Elena Ramona Modroiu
(XLOG, DIAMETER, AVPOPS, SPEEDDIAL), Miklos Tirpak (Permissions),
等其他人。
OpenSER是SER项目的衍生品。2004年FhG Fokus进行了SER项目的副产品
的开发创立了iptel.org。2005IPtel的商业变种被卖给了TEKELEC。核心开发团队一分为二。他们中的三位成员去了iptel.org(Andrei Pelinescu-Onciul, Jan Janak, and Jiri Kuthan),另外两名成员则离开FhG,创建了一家叫做Voice-System的公司,他们也是2005年开始的OpenSER项目的主要维护人员。
 
这本书始于2005后半年,基于SER项目。那个时候,我对使用SER进行NAT穿透的解决方案很感兴趣。Asterisk的可伸缩性对于(host??)SIP提供商不是足够的好,所以我转而投向SER的研究中。它的文档真的很难懂,于是乎我开始撰写自己的文档来对SIP提供商的管理者们进行培训。
在电子书完成后,我发现SER项目已经停止维护了。大部分的代码还停留在2003年。经过一点研究我找到了OpenSER项目。它似乎更有活力,它有更加新的模块,更频繁发行的版本。我于是在非常短的时间内将所有的东西转向了OpenSER。
我不想陷入SER VS OpenSER的争论中。这样的争论是毫无意义的。现在的事实就是,这本书是为OpenSER而写的。
OpenSER为第三方应用程序提供了一个灵活的可插入模型。应用程序可以被很容易的创建并插入服务器中。这种可插入模型给予了一些新的模块的开发,譬如                 RADIUS, DIAMETER, ENUM,
PRESENCE 还有SMS。更新的模块每个月都会被添加进来。你可以在 http://www.openser.org/docs/modules/1.2.x上查看OpenSER 1.2.x支持的模块。
它的高效和健壮使得OpenSER能够被用来为数百万的用户提供服务。在最近的2007 3月14号的性能报告中,OpenSER 1.2.x能够处理相当于400万用户的注册请求。TM(事务模块)能够每小时处理2800万通通话。完整的报告可以在 http://www.openser.org/docs/openser-performance-tests/上面找到。
OpenSER不仅仅被服务提供商所使用。它还可以构造SIP应用。目前有一些SIP防火墙(SIP firewall),会话边缘处理器(Session Border Controller),和负载均衡的代码都是从OpenSER项目中借鉴的。LINKSYS选择OpenSER作为它的一款PBX的平台,可能就是因为它的资源耗用少但性能高的特性吧。
OpenSER灵活,移植性好并且可以扩展。用ANSI C开发的它能够被轻易的移植到任何平台上。使用C语言能够很容易的创建出新的模块用于扩展。近来,编程中的一些新的层次被添加了进来。使用呼叫处理语言(Call Processing Language)简化路由脚本,使用Perl实时的对请求进行处理都成为可能。WeSIP是一种应用程序的编程接口,它允许你使用Java和Servlets创建SIP应用服务对OpenSER服务器进行扩展。可以在 www.wesip.com上查看WeSIP。
使用方案(Usage Scenarios)
OpenSER主要用来作为SIP代理和注册服务器。但是,它也可以被用于其他的一些应用当中,比如代理分发器(Proxy dispatches),Jabber网关(Jabber Gateway),与媒体网关和RTP代理合作来进行NAT穿透等。支持IPv4和IPv6并且能够支持多域。OpenSER可以被应用在Linux,Solaris,还有FreeBSD等平台。
OpenSER本身的创建是为了当作SIP代理服务器使用的。然而,利用它的新的模块,如今,OpenSER能够被用在如下的一些方案中:
Modules
 Functionality
  
DISPATCHER,PATH
 Load balancing
  
MEDIAPROXY,RTPPROXY,NATHELPER
 Nat Traversal
  
PRESENCE
 Presence Server
  
IMC XMPP
 Instant Messaging
  
 
让我们看看OpenSER的大多的使用场景吧。在所有这些场景中,OpenSER就像胶水一样,将所有的SIP部件粘在一起。
l        VoIP服务提供商
l        即时消息服务提供商
l        SIP负载均衡
l        嵌入式IP PBX
l        NAT穿透
l        SIP.EDU
OpenSER 框架(OpenSER Architecture)

 
核心和模块(Core and Modules)
OpenSER建造在一套核心之上,这套核心负责基本的功能实现以及对SIP消息进行处理。模块则负责OpenSER的大半的功能实现。模块和在脚本中使用的命令和参数一起将他们的功能性曝露在OpenSER当中。在一个叫做openser.cfg的文件中我们对OpenSER进行配置。这个配置文件控制着哪个模块被加载以及他们对应的参数。所有的SIP流程也都在此文件中定义的一些流程块中被控制。Openser.cfg是OpenSER的主要的配置文件。
Openser.cfg文件中的各个区段(Sections of the File openser.cfg)
Openser.cfg文件有七个区段:
l        全局定义(Global definitions):文件的这一部分包含了OpenSER的几个工作参数,包括SIP服务的监听ip端口对和debug等级。
l        模块(Modules):包含了外部库的列表,这些外部库是核心所没有的但却是能够展现其功能的。模块的加载使用loadmodule。
l        模块配置(Modules configuratio):模块有一些参数是需要被合适的设置的。这些参数可以使用modparam(modulename, parametername,parametervale)进行配置。
l        主路由块(Main routing block):主路由块是进行SIP消息处理的开始之处。它控制着所有收到的消息的处理。
l        次要路由块(Secondary routing blocks):管理员可以使用route()命令来定义新的路由块。这些路由块就像是OpenSER脚本中的子程序一样。
l        处理响应路由块(Reply routing blocks):响应路由块白被用来处理响应消息,通常是200 ok。
l        处理出错路由块(Failure routing blocks):处理出错路由块用来处理一些出错情况如线路繁忙(busy)或是超时(timeout)。
注:这个文件的细节将在4,5,6,7,8,9章节中详细进行描述。
会话,对话和事务(Sessions,Dialogs,and Transactions)
理解一些在OpenSER处理过程中使用的SIP概念是很重要的:
l        SIP事务(SIP transaction):包括一条sip消息或任何重发的和对他们的直接响应消息(如,REGISTER和200 OK)
l        SIP对话(SIP dialog):两个SIP实体之间存在一段时间的关系。如,两个UAC之间由INVITE消息到BYE消息这段时间建立的对话)
l        SIP会话(SIP session):在两个SIP实体之间的一通媒体流(音频/视频/文本)
openser.cfg消息处理
openser.cfg是为了处理收到的sip消息而执行的一段脚本。例如:如果用户A想要和用户B进行通话,它就要向B发送INVITE消息。这个消息在主路由块中被处理。这个处理过程一直要延续到它找到t_relay()(前转)或是s1_send_reply(发送出错信息)或是最终在块的末尾使用exit()命令丢弃该消息。billing
 
SIP代理——期望的行为(SIP Proxy—Expected Behavior)
按照RFC3261中描述的SIP代理的基本的处理过程是非常重要的。如果不能很好的理解,将很难去配置代理服务器。
每一个代理在将请求消息发送到下一个部件时会进行路由抉择,并对请求消息作些修改。响应消息将沿着请求消息走的路线原路路由回同样的一组代理。
代理服务器既可以运作在有状态模式下也可以以无状态的模式运行。当SIP代理服务器只是被当作一个简单的SIP包前转器(forwarder)工作时,它只是按照请求消息的要求将消息包前转到一个单独的部件上。无状态模式工作的代理会丢弃它所前转的消息的任何信息。而这个特性限制则限制了对错误的处理和对费用的记录。
如果OpenSER知道200 Ok是和一个特定的INVITE相对应,那么我们就说它此时工作在有状态模式下。这意味和你现在可以在onreply_route()块中来对响应消息进行管理。而无状态下的消息处理过程不会有上下文的处理方式。无状态处理过程通常被用在类似负载均衡的应用中;在脚本中使用forward()命令来处理。
当你需要更加复杂的资源如计费,呼叫前转,voicemail等时,有状态处理方式是你所需要的。每个事务都将在内存中被维护,并且出错信息,响应信息和重传信息都将和这些事务有所联系。有状态事务由TM(transaction module)处理,通常使用t_relay()命令。
一个经常会被误解的概念是:所谓处理过程的有状态指的是事务而不是对话。因此,一条INVITE请求消息的有状态处理过程的结束是到收到200 OK响应为止,而不是收到BYE。
状态操作(Stateful Operation)

这只是对有状态操作的简单描述。你会在RFC3261中找到更加完整和详尽的描述。openser.cfg和上图有些相似的地方。有些过程是手工完成的,如检查Max-forwards头域,而其他一些过程则在一条命令中即可完成。更好的说明就是,当你调用t_relay()时,所有的就像描述中的前转请求处理过程都将自动完成。
当处在有状态模式下是,代理只是一个简单的SIP事务处理器而且下面的这些处理步骤都是需要的:
l        验证请求
l        预处理路由信息
l        决定请求的目的地
l        前转请求到达目标
l        处理所有响应消息
有状态代理为每一个得到的请求创建一个新的服务器事务(server transaction)。该请求的任何重传都会被该服务器事务所处理。
举个例子:对于每一个经过我们SIP代理服务器的请求,我们都会:
第一步:请求验证
l        检查消息大小,避免缓存溢出
l        检查Max-forwards头域以检测出是否发生回环(loops)
第二步:路由信息的预处理
l        如果有record-route头,处理之
第三步:决定请求的目的地
l        目的地在定位数据库中么?(对于注册用户来说)
l        可以路由到目的地么?(网关目的地)
l        能够到达外部的域么?(外部地址)
第四步:请求前转
l        调用t_relay()函数,OpenSER将在有状态的模式下处理所有的工作任务。
第五步:响应消息的处理过程
l        通常这个过程会被OpenSER自动完成。有时候你可以使用onreply_route[]区段对一些响应作出处理。譬如:在“忙则呼叫前转”(call forward on busy)的情形中,我们可以使用486响应消息将通话转向voicemail服务器。
严格路由和松散路由之间的区别(Differences between Strict Routing and
 Loose Routing
在路由SIP消息的过程中,有松散和严格两种不同的方法。松散路由是SIP版本2中的新方法。当使用松散路由时,R-URI从来都不会被改变,这种方法和之前的旧方法保持向后兼容。(严格路由RFC2543)
严格路由的问题是开始对话前的初始化请求消息时指定所有的代理集合的过程。这种处理过程抛弃了包含在得到的R-URI中的信息。带有带外代理(outbound-proxy)的UA的行为是不确定的。如果其中的一个部件发生错误那么整个系统都将会出错。

 
解决办法就是松散路由。这种方法将目标从路由信息中分离。允许每一个目的地来路由消息包,并且有机制能够保证和严格路由向后兼容。参数;lr的使用就是对松散路由的支持象征。

当SIP服务器收到一个消息,它可以决定它自己是否处在中间位置。也就是说,如果SIP服务器不愿意待在中间位置,那么它就将信息传递给用户代理的UA让他们能够能够连接起来。然后消息就将在两个用户代理间进行处理。
而如果它想要待在中间,那么就应该使用函数record_route()插入ROUTE头。
理解SIP和RTP(Understanding SIP and RTP)
在理解接下来的子区段之前,你应该要懂得一些关于SIP和RTP的知识。首先,SIP是一个使用INVITE,BYE,和CANCEL方法来控制通话的信号协议。在INVITE请求消息中的关于会话(音频/视频/文本)消息包含在SIP协议中,使用的是叫做SDP(Session Description Protocol)的协议来包含的这些信息。包含在SDP中的信息描述了两个用户代理间的一个或是更多的媒体流的配置情况。
代理服务器从不参与到媒体流中,因此他对于媒体是什么都不用了解的。换句话说,无论UA和网关指定的媒体是什么格式,它都支持。但是有时候,B2BUA(back to back user agent)如媒体代理,可以安装在同一个服务器上来处理RTP音频(也就是NAT穿透机制)。SDP协议是供给/应答模型(Offer/Answer model)。SDP供给信息嵌入在INVITE请求消息中而应答信息在在200 OK的响应消息中。
举例:摘自Ethereal:

 
上图中的包是一个INVITE请求消息。该请求消息中嵌入了描述会话信息的SDP包。我们可以看到这是eyeBeam软电话产生的INVITE消息。它提供使用G.729编码格式,并使用UDP的8558端口(为了安全起见,我隐藏了IP地址)。属性rtpmap:101 telephone-event/8000描述了使用的DTMF前转方法(RFC2833)。另一个设备,在这个例子中是一个网关,在200 Ok的回复中对“供给”进行了应答。

 
概要(Summary)
这一章中,我们学到了什么是OpenSER以及它的主要特性。现在,你可以识别出openser.cfg配置文件和它的一些配置块,如全局定义(global definitions),加载模块(load modules),模块的参数,主路由块,路由块,响应路由块和出错处理路由块。每一个代理接收的请求都按照openser.cfg脚本中的配置来进行处理。脚本的内容的组织几乎和SIP有状态代理处理过程相一致。通常OpenSER作为松散路由器来运行(SIP版本2)。最后我们介绍了SIP和SDP的概念。
 

 
使用OpenSER构建电话通信系统——第三章(1)
 
 
 
 

 
注:以下文章如需转载,请注明所属作者,转载地址,谢谢!
这一章前半部分的内容是介绍系统安装和openser安装的,图片较多,而本blog文章中嵌入图片太过费时,所以直接将pdf文档链接公布如下,请直接下载。
 
使用OpenSER构建电话通信系统——第三章(1)
 
OpenSER v1.2 目录结构
在安装完成后,OpenSER将创建文件安放架构。了解这个架构对于定位系统存储在哪一个主文件夹中是很重要的。你需要这些消息来更新或删除软件。
配置文件(etc/openser)
openser-1:/etc/openser# ls -l
   total 12
   -rw-r--r-- 1 root root 1804 2007-09-10 14:02 dictionary.radius
   -rw-r--r-- 1 root root 4077 2007-09-10 14:05 openser.cfg
   -rw-r--r-- 1 root root 1203 2007-09-10 14:02 openserctlrccd
 
模块(/lib/openser/modules)
openser-1:/lib/openser/modules# ls
   acc.so            domain.so       msilo.so        sms.so
   alias_db.so       enum.so         mysql.so        speeddial.so
   auth_db.so        exec.so         nathelper.so    sst.so
   auth_diameter.so  flatstore.so    options.so      statistics.so
   auth_radius.so    gflags.so       path.so         textops.so
   auth.so           group_radius.so pdt.so          tm.so
   avpops.so         group.so        permissions.so uac_redirect.so
   avp_radius.so     imc.so          pike.so         uac.so
   dbtext.so         lcr.so          registrar.so    uri_db.so
   dialog.so         mangler.so      rr.so           uri.so
   dispatcher.so     maxfwd.so       seas.so         usrloc.so
   diversion.so      mediaproxy.so   siptrace.so     xlog.so
二进制文件(/sbin)
openser-1:/sbin# ls -l op*
    -rwxr-xr-x 1 root root 2172235 2007-09-10 14:02 openser
    -rwxr-xr-x 1 root root   41862 2007-09-10 14:02 openserctl
    -rwxr-xr-x 1 root root   38107 2007-09-10 14:02 openser_mysql.sh
    -rwxr-xr-x 1 root root   13562 2007-09-10 14:02 openserunixcd /sbin
 日志文件(Log Files)
初始化日志可以在syslog文件中查看到(/var/log/syslog):
Sep 10 14:25:56 openser-1 openser: init_tcp: using epoll_lt as the io watch
 method (auto detected)
 Sep 10 14:25:56 openser-1 /sbin/openser[7791]: INFO: statistics manager
 successfully initialized
 Sep 10 14:25:56 openser-1 /sbin/openser[7791]: StateLess module - initializing
 Sep 10 14:25:56 openser-1 /sbin/openser[7791]: TM - initializing...
 Sep 10 14:25:56 openser-1 /sbin/openser[7791]: Maxfwd module- initializing
 Sep 10 14:25:56 openser-1 /sbin/openser[7791]: INFO:ul_init_locks: locks array
 size 512
 Sep 10 14:25:56 openser-1 /sbin/openser[7791]: TextOPS - initializing
 Sep 10 14:25:56 openser-1 /sbin/openser[7791]: INFO: udp_init: SO_RCVBUF is
 initially 109568
 Sep 10 14:25:56 openser-1 /sbin/openser[7791]: INFO: udp_init: SO_RCVBUF is
 finally 262142
 Sep 10 14:25:56 openser-1 /sbin/openser[7791]: INFO: udp_init: SO_RCVBUF is
 initially 109568
 Sep 10 14:25:56 openser-1 /sbin/openser[7791]: INFO: udp_init: SO_RCVBUF is
 finally 262142
 Sep 10 14:25:56 openser-1 /sbin/openser[7792]: INFO: mi_fifo:mi_child_
 init(1): extra fifo listener processes created
 
启动选项(Startup Options)
OpenSER可以使用初始化脚本或使用openserctl工具进行启动。如果你使用的是初始化脚本启动的openser,那么你也只能使用初始化脚本来终止其运行。同样的道理适用于使用openserctl工具。
使用初始化脚本启动,终止和重启OpenSER。
/etc/init/d/openser start|stop|restart
使用openserctl工具脚本启动,终止和重启OpenSER。
/etc/init/d/openserctl start|stop|restart
OpenSER的执行有几个启动选项。展现于下面的这些选项允许你改变守护进程(DAEMON)的配置。最有用的几个如下:
l        “-c”用来查看配置文件
l        “-D -E dddddd”用来查看模块加载(不要用于[production??],它只是绑定第一个接口)
还有许多其他的选项允许你调整你的配置。对于每一个选项,在你填入的配置文件中都能找到对应的核心参数。
Usage: openser -l address [-p port] [-l address [-p port]...] [options]
 
Options:
     -f file      Configuration file (default //etc/openser/openser.cfg)
     -c           Check configuration f

相关文章