知行合一
全部博文(31)
分类: 系统运维
2009-08-24 20:08:22
首先,让我们来实现呼叫盲转服务。在INVITE请求的处理过程中,我们将从数据库中的用户优先表中加载名称为callfwd的AVP。如果callfwd被设置给了指定的用户,那么我们在对该请求进行前转前将它“推进”(push)到R-URI中。
if(avp_db_load("$ruri/username","s:callfwd")){
#Check the existence of the
callfwd attribute on the
#usr_preferences table. If found,
assign the vaue to the AVP
# and push the value to the ruri
of the SIP header.
avp_pushto("$ruri","s:callfwd");
route(1);
exit;
};
为了能让这个特性得以工作,重要点在于在数据库中插入正确的入口点。AVPs使用的表叫做usr_preferences。
你可以在SerMyAdmin的帮助下来对用户的喜好进行修改;只需要浏览菜单中“user preferences”即可。在那个选单中你可以查看所有的用户喜好,编辑它们,还可以创建新的。
如果你工作在多域环境中,请将模块AVPOPS的多域参数功能打开,并用域名来填充数据库。
在上面的记录中,我们告诉系统将任何呼给1001的呼叫都呼给URI:sip:1004@yourdomain。
步骤1:让我们使用在第六章里第一次见到的SerMyAdmin接口来插入AVP对。
你的浏览器中访问SerWEB的管理接口为:
步骤2:使用一个具有“全局管理员”角色的用户登录接口。
步骤3:点击用户喜好(User preferences)标签。在这个菜单中,点击“New
Preference”按钮,为你想要前转通话的用户来创建AVP;在这个例子中,。它的属性比较取名为callfwd,值是你要前转通话的URI;。
步骤4:编辑openser.cfg以包含上面做的那些说明解释。文件应该以下面的代码结束。在openser.cfg文件中包含下面的代码行。或是简单地从。
在模块加载部分:
loadmodule
"avpops.so"
loadmodule
"xlog.so"
在模块参数部分:
modparam("avpops",
"avp_url", "mysql://openser:openserrw@localhost/openser")
modparam("avpops",
"avp_table", "usr_preferences")
在route[3]部分:
route[3] {
#
# -- INVITE
request handler --
#
if
(is_from_local()){
# From an internal
domain -> check the credentials and the FROM
if(!allow_trusted()){
if (!proxy_authorize("","subscriber")) {
proxy_challenge("","1");
exit;
} else if (!check_from()) {
sl_send_reply("403", "Forbidden, use From=ID");
exit;
};
} else {
log("Request bypassed the auth. using allow_trusted");
};
if(avp_db_load("$ru/username","$avp(s:callfwd)"))
{
avp_pushto("$ru", "$avp(s:callfwd)");
xlog("forwarded to: $avp(s:callfwd)");
route(1);
exit;
}
consume_credentials();
步骤5:注册分机1001和1004。使用1001打给1000,这时候这通通话就应该按照usr_preferences表中说明被前转到1004。
这是这一章的第二部分。现在我们将介绍两个新的重要概念。第一个是failure_route,第二个则是append_branch,其被用来派生通话(fork the call)。我们将处理下面的出错情况:
l
408 – Timeout
l
486 – Busy Here
l
487 – Request Cancelled
为了实现在忙线和无人接听的情况下的通话前转,我们将使用出错路由(failure route)的概念。
下面的逻辑中,在发送INVITE到标准处理过程前,我们将调用函数t_on_failure(“1”)。这允许我们在failure_route[1]中处理SIP出错消息(返回的消息高于299的,也叫做负应答negative replies)
当在这种情况下收到一通通话时,我们将其前转到一个语音邮箱系统。Asterisk能够充当一个相当好的语音邮箱系统。让我们来看看如何整合asterisk来记录语音邮箱消息。我们将在URI使用b(busy)前缀来告诉asterisk服务器播放busy消息,使用u(unanswered)来播放无应答消息。Asterisk将分别使用应用voicemail(b${EXTEN})和voicemail(u${EXTEN})来处理忙线和无人接听的语音邮箱请求。
下面是一个完整的脚本,修改部分使用高亮显示。
#
#
#
$Id: openser.cfg 1676 2007-02-21 13:16:34Z bogdan_iancu $
#
#
simple quick-start config script
#
Please refer to the Core CookBook at
#
for a explanation of possible statements, functions and parameters.
#
#
----------- global configuration parameters ------------------------
debug=3
# debug level (cmd line: -dddddddddd)
fork=yes
log_stderror=no
# (cmd line: -E)
children=4
port=5060
# ------------------ module loading ----------------------------------
#set
module path
mpath="//lib/openser/modules/"
#
Uncomment this if you want to use SQL database
#loadmodule
"mysql.so"
loadmodule
"mysql.so"
loadmodule
"sl.so"
loadmodule
"tm.so"
loadmodule
"rr.so"
loadmodule
"maxfwd.so"
loadmodule
"usrloc.so"
loadmodule
"registrar.so"
loadmodule
"textops.so"
loadmodule
"uri.so"
loadmodule
"uri_db.so"
loadmodule
"domain.so"
loadmodule
"permissions.so"
loadmodule
"group.so"
loadmodule
"mi_fifo.so"
loadmodule
"lcr.so"
loadmodule
"avpops.so"
loadmodule
"xlog.so"
#
Uncomment this if you want digest authentication
#
mysql.so must be loaded !
loadmodule
"auth.so"
loadmodule
"auth_db.so"
#
----------------- setting module-specific parameters ---------------
modparam("mi_fifo",
"fifo_name", "/tmp/openser_fifo")
modparam("usrloc",
"db_mode", 2)
modparam("auth_db",
"calculate_ha1", yes)
modparam("auth_db",
"password_column", "password")
modparam("rr",
"enable_full_lr", 1)
modparam("auth_db|permissions|uri_db|usrloc","db_url","mysql://openser:openserrw@localhost/openser")
modparam("permissions",
"db_mode", 1)
modparam("permissions",
"trusted_table", "trusted")
modparam("avpops",
"avp_url", "mysql://openser:openserrw@localhost/openser")
modparam("avpops", "avp_table",
"usr_preferences")
#
------------------------- request routing logic -------------------
#
main routing logic
route{
#
# --
1 -- Request Validation
#
if
(!mf_process_maxfwd_header("10")) {
sl_send_reply("483","Too
Many Hops");
exit;
};
if
(msg:len >= 2048 ) {
sl_send_reply("513",
"Message too big");
exit;
};
#
# --
2 -- Routing Preprocessing
#
##
Record-route all except Register
if
(!method=="REGISTER") record_route();
##Loose_route
packets
if
(has_totag()) {
#sequential
request withing a dialog should
#
take the path determined by record-routing
if
(loose_route()) {
#Check
authentication of re-invites
if(method=="INVITE"
&& (!allow_trusted())) {
if
(!proxy_authorize("","subscriber")) {
proxy_challenge("","1");
exit;
}
else if (!check_from()) {
sl_send_reply("403",
"Forbidden, use From=ID");
exit;
};
};
route(1);
}
else {
sl_send_reply("404","Not
here");
}
exit;
}
#CANCEL
processing
if
(is_method("CANCEL")) {
if
(t_check_trans()) t_relay();
exit;
};
t_check_trans();
#
# -- 3 -- Determine Request Target
#
if (method=="REGISTER") {
route(2);
} else {
route(3);
};
}
route[1] {
#
# -- 4 -- Forward request to target
#
## Forward statefully
t_on_failure("1");
if (!t_relay()) {
sl_reply_error();
};
exit;
}
route[2] {
## Register request handler
if (is_uri_host_local()) {
if (!www_authorize("",
"subscriber")) {
www_challenge("", "1");
exit;
};
if (!check_to()) {
sl_send_reply("401",
"Unauthorized");
exit;
};
save("location");
exit;
}
else if {
sl_send_reply("401",
"Unauthorized");
};
}
route[3]
{
##
Non-Register request handler
if
(is_from_local()){
#
From an internal domain -> check the credentials and FROM
if(!allow_trusted()){
if
(!proxy_authorize("","subscriber")) {
proxy_challenge("","1");
exit;
}
else if (!check_from()) {
sl_send_reply("403",
"Forbidden, use From=ID");
exit;
};
}
else {
log("Request
bypassed the auth.using allow_trusted");
};
if(avp_db_load("$ru/username","$avp(s:callfwd)"))
{
avp_pushto("$ru",
"$avp(s:callfwd)");
route(1);
exit;
}
consume_credentials();
#Verify
aliases, if found replace R-URI.
lookup("aliases");
if
(is_uri_host_local()) {
# --
Inbound to Inbound
route(10);
}
else {
# --
Inbound to outbound
route(11);
};
}
else {
#From
an external domain ->do not check credentials
#Verify
aliases, if found replace R-URI.
lookup("aliases");
if
(is_uri_host_local()) {
#--
Outbound to inbound
route(12);
}
else {
# --
Outbound to outbound
route(13);
};
};
}
route[4] {
#
routing to the public network
if
(!load_gws()) {
sl_send_reply("503",
"Unable to load gateways");
exit;
}
if(!next_gw()){
sl_send_reply("503",
"Unable to find a gateway");
exit;
}
route(5);
exit;
}
route[5]
{
#
# --
4 -- T_relay for gateways
#
##
Forward statefully, if failure load other gateways
t_on_failure("2");
if
(!t_relay()) {
sl_reply_error();
};
exit;
}
route[10]
{
#from
an internal domain -> inbound
#Native SIP destinations are handled using the location table
#Gateway
destinations are handled by regular expressions
append_hf("P-hint:
inbound->inbound \r\n");
if
(uri=~"^sip:[2-9][0-9]{6}@") {
if
(is_user_in("credentials","local")) {
prefix("+1");
route(4);
exit;
}
else {
sl_send_reply("403",
"No permissions for local calls");
exit;
};
};
if
(uri=~"^sip:1[2-9][0-9]{9}@") {
if
(is_user_in("credentials","ld")) {
strip(1);
prefix("+1");
route(4);
exit;
}
else {
sl_send_reply("403",
"No permissions for long distance");
exit;
};
};
if
(uri=~"^sip:011[0-9]*@") {
if
(is_user_in("credentials","int")) {
strip(3);
prefix("+");
route(4);
exit;
}
else {
sl_send_reply("403",
"No perm. for internat.calls");
};
};
if
(!lookup("location")) {
if
(does_uri_exist()) {
##
User not registered at this time.
##
Use the IP Address of your e-mail server
revert_uri();
prefix("u");
rewritehostport("192.168.1.171"); #Use the voicemail IP
route(1);
}
else {
sl_send_reply("404",
"Not Found");
exit;
}
sl_send_reply("404",
"Not Found");
exit;
};
route(1);
}
route[11]
{
#
from an internal domain -> outbound
#
Simply route the call outbound using DNS search
append_hf("P-hint:
inbound->outbound \r\n");
route(1);
}
route[12]
{
#
From an external domain -> inbound
#
Verify aliases, if found replace R-URI.
lookup("aliases");
if
(!lookup("location")) {
sl_send_reply("404",
"Not Found");
exit;
};
route(1);
}
route[13]
{
#From
an external domain outbound
#we
are not accepting these calls
append_hf("P-hint:
outbound->inbound \r\n");
sl_send_reply("403",
"Forbidden");
exit;
}
failure_route[1]
{
##--
##--
If cancelled, exit.
##--
if
(t_check_status("487")) {
exit;
};
##--
##--
If busy send to the e-mail server, prefix the "b"
##--
character to indicate busy.
##--
if
(t_check_status("486")) {
revert_uri();
prefix("b");
xlog("L_ERR","Stepped
into the 486 ruri=<$ru>");
rewritehostport("192.168.1.171");
append_branch();
route(1);
exit;
};
##--
##--
If timeout (408) or unavailable temporarily (480),
##--
prefix the uri with the "u"character to indicate
##--
unanswered and send to the e-mail
##--
sever
##--
if
(t_check_status("408") || t_check_status("480")) {
revert_uri();
prefix("u");
xlog("L_ERR","Stepped
into the 480 ruri=<$ru>");
rewritehostport("192.168.1.171");
append_branch();
route(1);
exit;
};
}
failure_route[2]
{
if(!next_gw())
{
t_reply("503",
"Service not available, no more gateways");
exit;
}
t_on_failure("1");
t_relay();
}