分享

Freeswitch之SIP模块

 草莓加冰 2017-05-22
1、基本概念
(1)Sofia-SIP:Freeswitch的SIP功能是在mod_sofia模块中实现的,使用成熟的开源
SIP协议栈Sofia-SIP。
(2)Endpoint:实现一些互联协议接口的模块。Freeswitch支持很多类型的Endpoint,如SIP,H232等。这些不同的Endpoint主要是使用不同的控制协议跟其他的Endpoint通话。所以它一般是跟通话相关的。
(3)mod_sofia:实现了SIP中的注册服务器、重定向服务器、媒体服务器、SBC等各种功能,但它不能实现SIP代理服务器的功能。
(4)SIP Profile:在mod_sofia中,有一个概念是SIP Profile,它相当于一个SIPUA,通过各种不同的配置参数可以配置一个UA行为。一个系统中可以有多个SIP Profile,每个SIP Profile都可以舰艇不同的IP地址和端口对。
(5)Gateway:一个SIP Profile中有多个Gateway,它主要用于定义一个远端的SIP服务器,使Freeswitch可以与其他服务器通信。
(6)本地SIP用户:Freeswitch可以作为注册服务器,其他的SIP客户端就可以向它注册。Freeswitch将通过用户目录(Directory)中的配置信息对注册用户进行鉴权。这些SIP客户端所代表的用户称为本地SIP用户。
(7)来话和去话:相对Freeswitch而言的。
(8)中继来话或中继去话:如果来、去话不是本地的,双方通话需要以中继方式进行。
2、Sofia配置文件
Sofia的配置文件是conf/autoload_configs/sofia.conf.xml,不过它的大部分的配置参数实际上是直接在预处理指令装入conf/sip_profiles/目录中的XML文件中的配置:

<X-PRE-PROCESS cmd="include" data="../sip_profiles/*.xml"/>
Sofia的配置文件的总体结构应该是这样的:
<configuration name="sofia.conf" description="sofia Endpoint">
<global_settings>
<!-- 全局参数设置 -- >
</global_settings>
<profiles>
<profile name="profile1">
</profile>
<profile name="profile2">
</profile>
</profiles> 
 </configuration>
其中,global_settings中存放了一些全局配置参数。下面的profiles标签中又包含了多个profile标签。每个profile标签的详细信息都是在conf/sip_profiles/下的配置文件中配置的。
Sofia支持多个Profile,而每个Profile相当于一个UA,在启动后它会监听一个“IP地址:端口”对。Freeswitch默认的配置带了三个Profile(也就是三个UA),我们仅讨论internal和external两个。internal和external最大的区别是一个运行在5060端口上,一个在5080端口上。
3、Profile配置文件
由于Sofia Profile的参数比较多,因此默认把不同的Profile的配置存放在单独的文件夹中。
internal.xml为例,首先一个Profile的定义是从下面一行开始的:
<profile name="internal">
该行定义了一个Profile,它的名字叫internal,这个名字本分没有特殊意义,可以改成你喜欢的名字,但是必须记住它,因为很多地方都要使用这个名字,也可以为Profile起个别名:
<aliases> <alias name="default"/> </aliases>
有了这个别名,可以在呼叫字符串中使用这个别名。
在一个Profile中,可以配置多个网关,网关是在<gateways></gateways>标签中定义的。既然Profile是一个UA,它就应该可以注册到别的SIP服务器上去,它要注册的远端SIP服务器对于该Profile来说,就称为网关,我们一般不在internal上使用Gateway,大多数在external上使用。
接下来就定义Profile所属的域(Domain)。Domain可以使一个IP地址或一个DNS域名。需要注意,如果使用域名,大多数SIP UA都需要有一个真正的DNS服务器。Domain的配置代码如下:
<domains> <!--<domain name="all" alias="true" parse="true"/>--> <domain name="all" alias="true" parse="false"/> </domains>
在默认的配置文件中,vars.xml中定义了一个名为domain的全局变量,它的默认值来自于local_ip_v4这个全局变量,也就是一个IP地址。当然domain就是一个字符串,它可以是IP地址,也可以是其他值。
上面第三行的含义是:在该Profile中定义一个Domain,name=“all”表示检查所有的用户目录中定义的Domain(默认是在conf/directory目录下定义的Domain,如果name等于一个特定的Domain,则仅检查制定的Domain),然后执行下列动作:
如果alias=“true”,则会为所有的Domain取一个别名,放到与Profile同等重要的位置。
如果parse=“true”(默认的位false),则Freeswitch会解析Profile中的所有网关。
注意:alias和parse属性都具有排他性,即再有多个Profile的情况下,它们的值只能有一个为true,否则会产生冲突。
4、 profile的几个重要参数
inbound-bypass-media用于设置入局呼叫是否启用“媒体绕过”模式,它的取值有“true”和“false”两种,如:
<param name="inbound-bypass-media" value="true"/>
那么什么是Bypass Media呢?
Bob和Alice通过Freeswitch使用SIP接通了电话,他们谈话的语音数据要通过RTP包传送。RTP可以像SIP一样经过Freeswitch转发。但是,RTP与SIP相比占用很大的带宽,若果Freeswitch不需要“偷听”他们的谈话,为了节省带宽,可以让RTP直接在两点之间点对点传送,这种情况对Freeswitch来讲就是没有媒体的,在Freeswitch中就称为Bypass Media(媒体绕过)。
如果将inbound-bypass-media的值设为“true”,那么对于任何来话(Alice打给Bob,电话要先进入Freeswitch,对Freeswitch来说该电话就称为来话)都会自动采用Bypass Media模式。
Bypass Media的相关参数如下:
media-option:媒体选项,它有两个可能的取值—resume-media-hold和bypass-media-after-att-xfer。前者的意思是,如果Freeswitch是没有媒体的,那么如果设置了该参数,当你在话机上按下Hold键时,Freeswitch会回到有媒体的状态;后者是跟Attended Transfer有关的,Attended Transfer即出席转移,又称协商转移,它需要媒体配合才能完成工作。但如果在执行转接之前没有媒体,则该参数能让转接执行时通过re-INVITE请求要回媒体,等到转接结束后再回到
Bypass Media的状态。
context: 设置来话将进入Dialplan中的哪个Context进行路由。
<param name="context" value="public"/>
dialplan:设置默认的dialplan类型,即在该Profile上有电话呼入后到哪个Dialplan中进行路由。
<param name="dialplan" value="XML"/>
inbound-codec-prefs:设置支持的来话媒体编码,用于编码协商。默认值引用了vars.xml中的一个global_codec_prefs变量,该变量的默认值是“G722,PCMU,PCMA,GSM”。
<param name="inbound-codec-prefs" value="$${global_codec_prefs}"/>
outbound-codec-prefs:设置去话语音编码。
<param name="outbound-codec-prefs" value="$${global_codec_prefs}"/>
rtp-ip:设置RTP的IP地址。
<param name="rtp-ip" value="$${local_ip_v4}"/>
sip-ip:设置SIP的IP地址。
<param name="sip-ip" value="$${local_ip_v4}"/>
sip-port:该Profile启动后监听的SIP端口号。默认的配置中引用了var.xml中定义的一个变量internal_sip_port,默认是5060.
<param name="sip-port" value="$${internal_sip_port}"/>
auth-calls:设置是否对来电进行鉴权。默认是需要鉴权,即所有从该Profile进来的INVITE请求都需要经过Digest验证。
<param name="auth-calls" value="$${internal_auth_calls}"/>
ext-rtp-ip和ext-sip-ip:用于设置NAT环境中公网的RTP IP和SIP IP。该设置会影响SDP中的IP地址。
<param name="ext-rtp-ip" value="auto-nat"/>
     <param name="ext-sip-ip" value="auto-nat"/>
其中value的取值有以下几种可能:
1.一个IP地址;
2.一个STUN服务器,它会使用STUN协议获得公网IP;
3.一个DNS名称;
4.auto,它会自动检测IP地址
5.auto-nat,如果路由器支持NAT-PMP或uPnP,则可以使用这些协议获取公网IP。
5、external.xml
external.xml是另一个UA配置文件,它定义了另一个名为“external”的UA,默认使用5080端口。从external.xml中可以看到,其中的大部分参数斗鱼internal.xml中相同。最大不同的就是auth-calls参数。在internal.xml中,auth-calls默认值是true;而在external.xml中,默认值是false。我们一般把本地用户都注册到5060上,所以它们打电话都要经过鉴权,保证只有授权用户才能注册和拨打电话。而5080不同,任何人均可以向该端口发送SIP INVITE请求。
本地用户1000注册到5060端口上,每次它向外打电话时,它向Freeswitch的5060端口发送INVITE请求,Freeswitch对其鉴权,验证通过后,才允许通话继续进行。如果呼叫本地用户,则Freeswitch继续向用户1001发送INVITE请求,如果呼叫外部电话,则通过端口5080向外部网关发送INVITE请求。
       在上面的例子中,Freeswitch也可以通过5060端口向外部网关发送INVITE请求,效果是一样的。也就是对于去话而言,两者没有区别。但对于来话就不同了。Freeswitch能接收来话,一般有两种方式:
       1.Freeswitch作为一个UAC从本地的5080端口通过SIP注册到外部网关上,这样外部网关就可以通过SIP消息中的Contact字段知道该UAC所在的IP地址和监听的端口(这里是5080)。当有电话进来时,外部网关就向Freeswitch所在的IP地址和监听的窗口发送INVITE请求。
       2.某些网关是把来话和去话分开的,一般不需要或者根本不允许注册。在这种情况下它们一般是在申请的时候事先配置好的。如果有来话,外部网关就按照事先配置好的地址发送INVITE请求。

6、Gateway
       Freeswitch需要通过外部网关向外打电话,而这个网管就是Gateway。在external.xml中,我们可以看到它使用预处理指令将external目录下的所有的XML配置文件都装入了该Profile的gateways标签中:
<gateways> <X-PRE-PROCESS cmd="include" data="external/*.xml"/>
</gateways>
这样做的好处是,我们可以把每个网关配置写到不同的文件中。默认的配置中包含了一个example.xml,里面有很多配置选项。
添加一个新的网关只需要在external目录中新建一个XML文件,名字可以随便起,但需要以.xml结尾,如“gw1.xml”。其内容如下:
<gateway name="gw1">
<param name="realm" value="SIP服务器地址"/>
<param name="username" value="SIP用户名"/>
<param name="password" value="密码"/>
</gateway>
其中,每个网关都有一个名字,有第一行的name属性指定。该名字可以与XML文件的名字相同,也可以不同。在Freeswitch内部,将以该名字唯一确定该网关。在整个Freeswitch中,网关名字必须唯一,否则除第一个外,其他的都将被忽略。
realm指定SIP网关服务器的地址,可以使一个合法的域名或IP地址,在地址后面可以添加端口号,如“192.168.200.158:5080”。该参数是可选的,如果没有,则默认跟网关的名字(name)相同。username和password这两个参数是必须的,但他们的值将被忽略。
我们看一下example.xml都有哪些默认参数。
<include>
- <!--<gateway name="asterlink.com">-->
- <!--<param name="username" value="cluecon"/>-->
  <!--<param name="password" value="2007"/>-->
- <!--<param name="realm" value="asterlink.com"/>-->
-  其中,<include>以及后面的</include>标签指明该文件被其他文件包含,它将在预处理阶段被去掉。
下面的代码用于设置SIP消息中From字段的值,如果省略,则默认与username相同。
- <!--<param name="from-user" value="cluecon"/>-->
下面的代码用于设置From字段中的domain值,默认与realm相同。
- <!--<param name="from-domain" value="asterlink.com"/>-->
-  下面的代码用于设置来话中的分机号,默认与username相同。
 <!--<param name="extension" value="cluecon"/>-->
如果需要代理服务器,则设置该proxy的值,默认与realm相同。
- <!--<param name="proxy" value="asterlink.com"/>-->
-  如果需要注册到代理服务器,则设置该register-proxy的值,默认与realm相同。
- <!--<param name="register-proxy" value="mysbc.com"/>-->
-  下面的代码用于设置注册时SIP消息中Expires字段的值。
- <!--<param name="expire-seconds" value="60"/>-->
如果网关不需要注册,则为false,默认为true。
- <!--<param name="register" value="false"/>-->
-  下面的代码用于设置SIP消息使用UDP还是TCP承载。
- <!--<param name="register-transport" value="udp"/>-->
下面的代码用于设置如果注册失败或者超时,则多少秒后再重新注册。
- <!--<param name="retry-seconds" value="30"/>-->
将主叫号码放到SIP的From字段中。默认会放到Remote-Party-ID字段中。
- <!--<param name="caller-id-in-from" value="false"/>-->
-  下面的代码用于设置在SIP协议中Contact字段中额外的参数。
- <!--<param name="contact-params" value=""/>-->
每隔一段时间发送一个SIP OPTIONS消息,如果失败,则会从该网关注销,并将其设置为down状态。通过周期性的发送无关紧要的SIP消息,有助于快速发现对方的状态变化,同时也在NAT环境中有助于保持路由器上的NAT映射关系,保持连接畅通。
  <!--<param name="ping" value="25"/>-->
最后是网关及include的关闭标签,保持XML的完整性。
- <!--</gateway>-->
  </include>
7、常用命令
mod_sofia提供了一个API命令--sofia,它有很多参数,可以提供很多功能。
1.列出某个Profile的状态
>sofia status profile internal
2.列出某个Profile上所有已注册的用户
>sofia status profile internal reg
3.过滤某些符合条件的用户
>sofia status profile internal reg 1000
4.列出某个特定用户
>sofia status profile internal user 1000
5.列出网关状态
>sofia status gateway gw1
7.1 Profile相关命令
常用的启动、停止、重启某个Profile的命令分别如下:
>sofia profile internal start
>sofia profile internal stop
>sofia profile internal restart
使用下列命令让Freeswitch重读sofia的而配置:
>sofia profile internal rescan
添加了一个新的gateway以后,也可以使用上述rescan指令读取。
如果是修改了一个网关,则可以先将该网关删除,再rescan,如:
>sofia profile external killgw gw1
>sofia profile external rescan
下列命令可以指定某个网关立即向外注册或注销:
>sofia profile external register gw1
>sofia profile external unregister gw2
开启该Profile的SIP跟踪功能抓SIP包:
>sofia profile internal siptrace on
下列命令可以将已经注册的用户清理掉:
>sofia profile internal flush_inbound_reg 1000@192.168.200.158
flush_inbound_reg时,Freeswitch只是简单的清理本地数据库中用户的注册信息,它无法防止客户端重新注册。
7.2 global相关
在使用sofia命令的siptrace子命令进行抓包时,用户经常搞不清楚该对哪个Profile进行抓包。因此,Freeswitch为这部分用户加入了这个特性——通过使用global参数,使siptrace子命令对所有Profile都有效,如下两条命令可以分别打开和关闭全局的SIP消息跟踪:
>sofia global siptrace on
>sofia global siptrace off
以下两条命令可以分别打开和关闭全局的SIP捕获:
>sofia global captuer on
>sofia global captuer off
7.3 debug相关
有时候,可能是协议栈更底层的原因引起的问题,由于收到或发送非法消息会导致协议栈出错,这可能会使消息丢弃,当然也可能是协议栈层的Bug,在这种情况下即使开启了详细的Freeswitch日志以及SIP跟踪(siptrace)也查不到问题的原因。这时候可以使用如下命令打开更低级别的调试器
>sofia loglevel all 9
loglevel的其他参数可以在sofia的命令帮助中找到。 下面的命令可以分别将sofia的日志映射到debug和notice级别:
>sofia tracelevel debug
>sofia tracelevel notice
最后,可以使用如下命令关闭这些调试:
>sofia loglevel all 0
8、NAT穿越
适当的解决在NAT网络环境下的内、外网通信问题,就称为NAT穿越。NAT的全称是Network Address Translation(网络地址转换),它最初是为了克服IPv4网络地址不足出现的一项技术。
NAT有三种类型:静态NAT(Static NAT)、动态地址NAT(Pooled NAT)和网络地址端口转换(Network Address Port Translation,NAPT)。其中静态NAT设置起来最简单;内部网络中的每个主机都被永久映射成外部网络中的某个合法地址,而动态地址NAT则是在外部网络中定义一系列合法地址,采用动态分配的方法映射到内部网络;NAPT则是把内部地址映射到外部网络的一个IP地址的不同端口上。
一般来说,NAPT有四种类型,但它实际上又分为两大类:锥形NAT和对称NAT。其中锥形NAT又分为三类,因为一共是四类。
(1)Full Cone NAT:全锥形NATP
内网主机建立一个UDP socket(LocalIP:LocalPort如192.168.200.158:5060),第一次使用这个socket给外部主机发送数据时,NAT设备会给其分配一个公网IP、端口对(PublicIP:PublicPort,如1.2.3.4:5060),并记住他们之间的映射关系。以后用这个socket向外面任何主机发送数据都将使用这对PublicIP:PublicPort。此外,任何主机只要知道这个PublicIP:PublicPort就可以给它发送数据,NAT设备会根据它已经记住的映射关系将收到的数据转发到相应的内部主机的LocalIP:LocalPort上。按洞的理论来说:内部主机向外打了一个洞,外网的任何主机都可以利用这个洞与它通信。
(2)Restricted Cone NAT:限制锥形NAT
按洞的理论来说:内部主机向某一外部主机打了一个洞,只有该外部主机可以利用这个洞与它通信。
(3)Port Restricted Cone NAT:端口限制锥形NAT
按洞的理论来说:内部主机向外部主机上某一程序(一个端口)打了一个洞,则只有该程序可以利用这个洞,其他的不行。
(4)Symmetric NAT:对称型NAT
按洞的理论来说:同一内部主机联系不同的外部主机时都需要打不同的洞。




    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多