OpenSIPS - Call Dispatcher
1. ในตอนนี้เราจะใช้ OpenSIPS กระจายสายที่เรียกเข้ามาไปยัง IssabelPBX จำนวน 3 servers โดยจะกระจายสายแบบ roundrobin
สามารถกำหนดน้ำหนักได้ ว่าจะให้ IssabelPBX ตัวไหนรับสายมากน้อย คอนฟิกนี้ใช้สำหรับ inbound call center ขนาดใหญ่ที่
ไม่สามารถใช้ IssabelPBX ตัวเดียวรองรับ traffic ทั้งหมดได้
จากรูป calls จาก voice gateway จะถูกส่งไปยัง OpenSIPS แล้ว OpenSIPS จะส่งต่อ calls เหล่านี้ไปยัง IssabelPBX ตัวที่หนึ่ง
สอง สาม ตามลำดับ ถ้า IssabelPBX ตัวไหนไม่ทำงาน OpenSIPS ก็ส่ง calls ไปยังตัวถัดไป
2. OpenSIPS คอนฟิกไฟล์ copy + paste คอนฟิกข้างล่างไปที่ /etc/opensips/opensips.cfg
###################################
####### Global Parameters #########
###################################
log_level=3
log_stderror=no
log_facility=LOG_LOCAL0
children=4
/* uncomment the following lines to enable debugging */
#debug=6
#fork=no
#log_stderror=yes
/* uncomment the next line to enable the auto temporary blacklisting of
not available destinations (default disabled) */
#disable_dns_blacklist=no
/* uncomment the next line to enable IPv6 lookup after IPv4 dns
lookup failures (default disabled) */
#dns_try_ipv6=yes
/* comment the next line to enable the auto discovery of local aliases
based on revers DNS on IPs */
auto_aliases=no
listen=udp:192.168.10.222:5060
################################
####### Modules Section ########
################################
#set module path
mpath="/lib64/opensips/modules/"
#### SIGNALING module
loadmodule "signaling.so"
#### StateLess module
loadmodule "sl.so"
#### Permissions module
loadmodule "permissions.so"
modparam("permissions", "db_url",
"mysql://opensips:opensipsrw@localhost/opensips")
#### Transaction Module
loadmodule "tm.so"
modparam("tm", "fr_timeout", 5)
modparam("tm", "fr_inv_timeout", 30)
modparam("tm", "restart_fr_on_each_reply", 0)
modparam("tm", "onreply_avp_mode", 1)
#### Record Route Module
loadmodule "rr.so"
/* do not append from tag to the RR (no need for this script) */
modparam("rr", "append_fromtag", 0)
#### MAX ForWarD module
loadmodule "maxfwd.so"
#### SIP MSG OPerationS module
loadmodule "sipmsgops.so"
#### FIFO Management Interface
loadmodule "mi_fifo.so"
modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo")
modparam("mi_fifo", "fifo_mode", 0666)
#### URI module
loadmodule "uri.so"
modparam("uri", "use_uri_table", 0)
#### MYSQL module
loadmodule "db_mysql.so"
#### AVPOPS module
loadmodule "avpops.so"
#### ACCounting module
loadmodule "acc.so"
/* what special events should be accounted ? */
modparam("acc", "early_media", 0)
modparam("acc", "report_cancels", 0)
/* by default we do not adjust the direct of the sequential requests.
if you enable this parameter, be sure the enable "append_fromtag"
in "rr" module */
modparam("acc", "detect_direction", 0)
modparam("acc", "db_url",
"mysql://opensips:opensipsrw@localhost/opensips")
#### DISPATCHER module
loadmodule "dispatcher.so"
modparam("dispatcher", "db_url",
"mysql://opensips:opensipsrw@localhost/opensips")
modparam("dispatcher", "ds_ping_method", "OPTIONS")
modparam("dispatcher", "ds_probing_mode", 1)
modparam("dispatcher", "ds_ping_interval", 30)
#### MI_JSON module
loadmodule "mi_json.so"
modparam("mi_json", "mi_json_root", "json")
loadmodule "proto_udp.so"
#### HTTPD module
loadmodule "httpd.so"
modparam("httpd", "port", 8888)
##############################
####### Routing Logic ########
##############################
# main request routing logic
route {
if (!mf_process_maxfwd_header("10")) {
sl_send_reply("483","Too Many Hops");
exit;
}
if (has_totag()) {
# sequential request withing a dialog should
# take the path determined by record-routing
if (loose_route()) {
if (is_method("BYE")) {
setflag(ACC_DO); # do accounting ...
setflag(ACC_FAILED); # ... even if the transaction fails
} else if (is_method("INVITE")) {
# even if in most of the cases is useless, do RR for
# re-INVITEs alos, as some buggy clients do change route set
# during the dialog.
record_route();
}
# route it out to whatever destination was set by loose_route()
# in $du (destination URI).
route(RELAY);
} else {
if ( is_method("ACK") ) {
if ( t_check_trans() ) {
# non loose-route, but stateful ACK; must be an ACK after
# a 487 or e.g. 404 from upstream server
t_relay();
exit;
} else {
# ACK without matching transaction ->
# ignore and discard
exit;
}
}
sl_send_reply("404","Not here");
}
exit;
}
#### INITIAL REQUEST
# CANCEL processing
if (is_method("CANCEL")) {
if (t_check_trans())
t_relay();
exit;
} else if (!is_method("INVITE")) {
send_reply("405","Method Not Allowed");
exit;
}
if ($rU==NULL) {
# request with no Username in RURI
sl_send_reply("484","Address Incomplete");
exit;
}
t_check_trans();
# check source ip address (just before preloaded route checking)
if (!check_source_address("0")) {
xlog("IP address is not allowed $fu");
exit;
}
# preloaded route checking
if (loose_route()) {
xlog("L_ERR",
"Attempt to route with preloaded Route's [$fu/$tu/$ru/$ci]");
if (!is_method("ACK"))
sl_send_reply("403","Preload Route denied");
exit;
}
# record routing
record_route();
setflag(ACC_DO); # do accounting
if ( !ds_select_dst("1","4") ) {
send_reply("500","No Destination available");
exit;
}
t_on_failure("GW_FAILOVER");
route(RELAY);
}
route[RELAY] {
if (!t_relay()) {
sl_reply_error();
};
exit;
}
failure_route[GW_FAILOVER] {
if (t_was_cancelled()) {
exit;
}
# failure detection with redirect to next available trunk
if (t_check_status("(408)|([56][0-9][0-9])")) {
if (t_check_status("(408)|([56][0-9][0-9])")) {
xlog("Failed trunk $rd/$du detected \n");
if ( ds_next_dst() ) {
t_on_failure("GW_FAILOVER");
t_relay();
exit;
}
send_reply("500","All GW are down");
}
}
}
กำหนด Permissions module ให้รับ calls จาก voice gateway (ip = 192.168.10.3) เท่านั้น
กำหนด Dispatcher module ให้ส่ง calls ไป IssabelPBX ip 192.168.10.250 หรือ 192.168.10.251 หรือ 192.168.10.252
ตามรูปเรากำหนดน้ำหนักไว้เท่ากับ 1
3. คอนฟิกนี้สำหรับ inbound calls เท่านั้น ไม่สามารถโทรออกจาก IssabelPBX ⇒ OpenSIPS ⇒ ไปยัง voice gateway ได้
สามารถนำไปใช้ในกรณีที่เป็น inbound call center ที่มีจำนวน calls มากๆ