OpenSIPS - Call Dispatcher

1. ในตอนนี้เราจะใช้ OpenSIPS กระจายสายที่เรียกเข้ามาไปยัง IssabelPBX จำนวน 3 servers โดยจะกระจายสายแบบ roundrobin

สามารถกำหนดน้ำหนักได้ ว่าจะให้ IssabelPBX ตัวไหนรับสายมากน้อย

 

 

จากรูป calls จาก voice gateway จะถูกส่งไปยัง OpenSIPS แล้ว OpenSIPS จะส่งต่อ calls เหล่านี้ไปยัง IssabelPBX ตัวที่หนึ่ง

สอง สาม ตามลำดับ ถ้า IssabelPBX ตัวไหนไม่ทำงาน OpenSIPS ก็ส่ง calls ไปยังตัวถัดไป

 

2. OpenSIPS คอนฟิกไฟล์ copy + paste คอนฟิกข้างล่างไปที่ /etc/opensips/opensips.cfg

####### Global Parameters #########

debug=3
log_stderror=no
log_facility=LOG_LOCAL0

fork=yes
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.1.222:5060 # change here

disable_tcp=yes

####### 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") # CUSTOMIZE ME

#### 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", "failed_transaction_flag", "ACC_FAILED")
/* account triggers (flags) */
modparam("acc", "log_flag", "ACC_DO")
modparam("acc", "log_missed_flag", "ACC_MISSED")

#### DISPATCHER module
loadmodule "dispatcher.so"
modparam("dispatcher", "db_url",
        "mysql://opensips:opensipsrw@localhost/opensips") # CUSTOMIZE ME
modparam("dispatcher", "ds_ping_method", "OPTIONS")
modparam("dispatcher", "ds_probing_mode", 0)
modparam("dispatcher", "flags", 2)

modparam("dispatcher", "ds_ping_interval", 30)

####### 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 REQUESTS

        # 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.1.200) เท่านั้น

 

 

 

กำหนด Dispatcher module ให้ส่ง calls ไป IssabelPBX ip 192.168.1.250 หรือ 192.168.1.251 หรือ 192.168.1.252

ตามรูปเรากำหนดน้ำหนักไว้เท่ากับ 1

 

3. คอนฟิกนี้สำหรับ inbound calls เท่านั้น ไม่สามารถโทรออกจาก IssabelPBX ⇒ OpenSIPS ⇒ ไปยัง voice gateway ได้

สามารถนำไปใช้ในกรณีที่เป็น inbound call center ที่มีจำนวน calls มากๆ