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

注:以下文章如需转载,请注明所属作者,转载地址,谢谢!

实现呼叫盲转(Implementing Blind Call Forwarding

首先,让我们来实现呼叫盲转服务。在INVITE请求的处理过程中,我们将从数据库中的用户优先表中加载名称为callfwdAVP。如果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的呼叫都呼给URIsip:1004@yourdomain

Lab——实现呼叫盲转(Lab——Implementing Blind Call Forwarding

步骤1:让我们使用在第六章里第一次见到的SerMyAdmin接口来插入AVP对。

你的浏览器中访问SerWEB的管理接口为:

http://<your-ip-server-address>:8080/serMyAdmin

步骤2:使用一个具有“全局管理员”角色的用户登录接口。

步骤3:点击用户喜好(User preferences)标签。在这个菜单中,点击“New Preference”按钮,为你想要前转通话的用户来创建AVP;在这个例子中,应该是1000@sermyadmin.org。它的属性比较取名为callfwd,值是你要前转通话的URI这里应该设置成1004@sermyadmin.org


步骤4:编辑openser.cfg以包含上面做的那些说明解释。文件应该以下面的代码结束。在openser.cfg文件中包含下面的代码行。或是简单地从http://www.sermayadmin.org/openser拷贝openser.callfwd1openser.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:注册分机10011004。使用1001打给1000,这时候这通通话就应该按照usr_preferences表中说明被前转到1004

在忙线或无人接听的时候实现呼叫前转( Implementing Call Forward on Busy or Unanswered

这是这一章的第二部分。现在我们将介绍两个新的重要概念。第一个是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使用bbusy)前缀来告诉asterisk服务器播放busy消息,使用uunanswered)来播放无应答消息。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 http://www.openser.org/dokuwiki/doku.php

# 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();

}

<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
阅读(1522) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值