OpenSIPS离线消息功能配置

按照项目的需求,需要使用OpenSIPS的离线功能,现在将配置过程记录以备后用。

OpenSIPS离线消息功能依赖于msilo模块(http://www.opensips.org/html/docs/modules/1.11.x/msilo.html)

修改OpenSIPS的配置文件opensips.cfg添加

loadmodule "msilo.so"
#加载msilo模块
modparam("msilo", "db_table", "silo")
#配置离线消息存储的表silo
modparam("msilo", "db_url","mysql://opensips:[email protected]/opensips")
#配置数据库路径
modparam("msilo", "add_date", 1)
#配置是否显示[offline message +时间]
modparam("msilo","content_type_hdr","Content-Type: text/plain\r\n")
#配置存储类型

配置路由部分:

#注释以下这段:
/*      if ( !(is_method("REGISTER")  ) ) {
                if (from_uri==myself)
                {
                        # authenticate if from local subscriber
                        # authenticate all initial non-REGISTER request that pretend to be
                        # generated by local subscriber (domain from FROM URI is local)
                        if (!proxy_authorize("", "subscriber")) {
                                proxy_challenge("", "0");
                                exit;
                        }
                        if (!db_check_from()) {
                                sl_send_reply("403","Forbidden auth ID");
                                exit;
                        }
                        consume_credentials();
                        # caller authenticated
                } else {
                        # if caller is not local, then called number must be local
                        if (!uri==myself) {
                                send_reply("403","Rely forbidden");
                                exit;
                        }
                }
        }
*/

#修改一下这段
        if (is_method("REGISTER"))
        {

                # authenticate the REGISTER requests
                if (!www_authorize("", "subscriber"))
                {
                        www_challenge("", "0");
                        exit;
                }

                if (!db_check_to())
                {
                        sl_send_reply("403","Forbidden auth ID");
                        exit;
                }

                if (   0 ) setflag(TCP_PERSISTENT);

                if (!save("location"))
                        sl_reply_error();
                #增加部分--start
                if (m_dump()){
                        log("MSILO:offline message dumped\n");
                }else{
                        log("MSILO:no offline message dumped\n");
                }
                #增加部分--end
                exit;
        }

 
 #修改这段
         if (!lookup("location","m")) {
                if (!db_does_uri_exist()) {
                        send_reply("420","Bad Extension");
                        exit;
                }

                #从这里开始修改
                if(! t_newtran()){
                        sl_reply_error();
                        exit;
                }
                #以下为增加部分
                if (!method=="MESSAGE")
                {
                        if (!t_reply("404", "Not found"))
                        {
                                 sl_reply_error();
                        };
                        exit;
                };
                log("MSILO:Message received -> storing using MSILO\n");
                if (m_store("$ru")){
                        log("MSILO:offline message stored\n");
                        if (!t_reply("202","Accepted")){
                                sl_reply_error();
                        };
                }else{
                        log("MSILO:offline message NOT stroed\n");
                        if(!t_reply("503","Service Unavailable")){
                                sl_reply_error();
                        };
                };
                exit;
        }
        t_on_failure("1");   #增加这句
        if (isbflagset(NAT)) setflag(NAT);   
       
#在配置文件最后增加:
failure_route[1] {
    # forwarding failed -- check if the request was a MESSAGE
    if (!method=="MESSAGE")
    {
        exit;
    };

    log(1,"MSILO:the downstream UA doesn‘t support MESSAGEs\n");
    # we have changed the R-URI with the contact address, ignore it now
    if (m_store("$ou"))
    {
        log("MSILO: offline message stored\n");
        t_reply("202", "Accepted");
    }else{
        log("MSILO: offline message NOT stored\n");
        t_reply("503", "Service Unavailable");
    };
}

到这里离线消息功能配置完成,为方便其他朋友,特意贴出全部配置文件(注意红色部分)

#
# $Id$
#
# OpenSIPS residential configuration script
#     by OpenSIPS Solutions <[email protected]>
#
# This script was generated via "make menuconfig", from
#   the "Residential" scenario.
# You can enable / disable more features / functionalities by
#   re-generating the scenario with different options.#
#
# Please refer to the Core CookBook at:
#      http://www.opensips.org/Resources/DocsCookbooks
# for a explanation of possible statements, functions and parameters.
#

####### 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:eth0:5060   # CUSTOMIZE ME

#disable_tcp=yes

#disable_tls=yes

####### Modules Section ########

#set module path
mpath="/data/opensips1.11.4/lib64/opensips/modules/"

#### SIGNALING module
loadmodule "signaling.so"

#### StateLess module
loadmodule "sl.so"

#### 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)
modparam("uri", "db_url","mysql://opensips:[email protected]/opensips")

loadmodule "msilo.so"
modparam("msilo", "db_table", "silo")
modparam("msilo", "db_url","mysql://opensips:[email protected]/opensips")
modparam("msilo", "add_date", 1)
modparam("msilo","content_type_hdr","Content-Type: text/plain\r\n")

#### MYSQL module
loadmodule "db_mysql.so"

#### USeR LOCation module
loadmodule "usrloc.so"
modparam("usrloc", "nat_bflag", "NAT")
modparam("usrloc", "db_mode",   2)
modparam("usrloc", "db_url",
    "mysql://opensips:[email protected]/opensips") # CUSTOMIZE ME

#### REGISTRAR module
loadmodule "registrar.so"
modparam("registrar", "tcp_persistent_flag", "TCP_PERSISTENT")
modparam("registrar", "received_avp", "$avp(received_nh)")
/* uncomment the next line not to allow more than 10 contacts per AOR */
#modparam("registrar", "max_contacts", 10)

#### 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", "db_flag", "ACC_DO")
modparam("acc", "db_missed_flag", "ACC_MISSED")
modparam("acc", "db_url",
    "mysql://opensips:[email protected]/opensips") # CUSTOMIZE ME

#### AUTHentication modules
loadmodule "auth.so"
loadmodule "auth_db.so"
modparam("auth_db", "calculate_ha1", no)
modparam("auth_db", "password_column", "ha1")
modparam("auth_db", "db_url",
    "mysql://opensips:[email protected]/opensips") # CUSTOMIZE ME
modparam("auth_db", "load_credentials", "")

#### ALIAS module
loadmodule "alias_db.so"
modparam("alias_db", "db_url",
    "mysql://opensips:[email protected]/opensips") # CUSTOMIZE ME

#### DIALOG module
loadmodule "dialog.so"
modparam("dialog", "dlg_match_mode", 1)
modparam("dialog", "default_timeout", 21600)  # 6 hours timeout
modparam("dialog", "db_mode", 2)
modparam("dialog", "db_url",
    "mysql://opensips:[email protected]/opensips") # CUSTOMIZE ME

####  NAT modules
loadmodule "nathelper.so"
modparam("nathelper", "natping_interval", 10)
modparam("nathelper", "ping_nated_only", 1)
modparam("nathelper", "received_avp", "$avp(received_nh)")

loadmodule "rtpproxy.so"
modparam("rtpproxy", "rtpproxy_sock", "udp:localhost:12221") # CUSTOMIZE ME

####### Routing Logic ########

# main request routing logic

route{
    force_rport();
    if (nat_uac_test("23")) {
        if (is_method("REGISTER")) {
            fix_nated_register();
            setbflag(NAT);
        } else {
            fix_nated_contact();
            setflag(NAT);
        }
    }

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()) {
            
            # validate the sequential request against dialog
            if ( $DLG_status!=NULL && !validate_dialog() ) {
                xlog("In-Dialog $rm from $si (callid=$ci) is not valid according to dialog\n");
                ## exit;
            }
            
            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();
            }

if (check_route_param("nat=yes"))
                setflag(NAT);

# 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;
    }

# CANCEL processing
    if (is_method("CANCEL"))
    {
        if (t_check_trans())
            t_relay();
        exit;
    }

t_check_trans();

/*    if ( !(is_method("REGISTER")  ) ) {
        
        if (from_uri==myself)
        
        {
            
            # authenticate if from local subscriber
            # authenticate all initial non-REGISTER request that pretend to be
            # generated by local subscriber (domain from FROM URI is local)
            if (!proxy_authorize("", "subscriber")) {
                proxy_challenge("", "0");
                exit;
            }
            if (!db_check_from()) {
                sl_send_reply("403","Forbidden auth ID");
                exit;
            }
        
            consume_credentials();
            # caller authenticated

} else {
            # if caller is not local, then called number must be local
            
            if (!uri==myself) {
                send_reply("403","Rely forbidden");
                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
    if (!is_method("REGISTER|MESSAGE"))
        record_route();

# account only INVITEs
    if (is_method("INVITE")) {
        
        # create dialog with timeout
        if ( !create_dialog("B") ) {
            send_reply("500","Internal Server Error");
            exit;
        }
        
        setflag(ACC_DO); # do accounting
    }

if (!uri==myself) {
        append_hf("P-hint: outbound\r\n");
        
        route(relay);
    }

# requests for my domain
    
    if (is_method("PUBLISH|SUBSCRIBE"))
    {
        sl_send_reply("503", "Service Unavailable");
        exit;
    }

if (is_method("REGISTER"))
    {
        
        # authenticate the REGISTER requests
        if (!www_authorize("", "subscriber"))
        {
            www_challenge("", "0");
            exit;
        }
        
        if (!db_check_to())
        {
            sl_send_reply("403","Forbidden auth ID");
            exit;
        }

if (   0 ) setflag(TCP_PERSISTENT);

if (!save("location"))
            sl_reply_error();

if (m_dump()){
                        log("MSILO:offline message dumped\n");
                }else{
                        log("MSILO:no offline message dumped\n");
                }

exit;
    }

if ($rU==NULL) {
        # request with no Username in RURI
        sl_send_reply("484","Address Incomplete");
        exit;
    }

# apply DB based aliases
    alias_db_lookup("dbaliases");

# do lookup with method filtering
    if (!lookup("location","m")) {
        if (!db_does_uri_exist()) {
            send_reply("420","Bad Extension");
            exit;
        }

if(! t_newtran()){
            sl_reply_error();
            exit;
        }
        if (!method=="MESSAGE")
        {
                    if (!t_reply("404", "Not found"))
                    {
                            sl_reply_error();
                       };
                    exit;
                };
        log("MSILO:Message received -> storing using MSILO\n");
        if (m_store("$ru")){
            log("MSILO:offline message stored\n");
            if (!t_reply("202","Accepted")){
                sl_reply_error();
            };
        }else{
            log("MSILO:offline message NOT stroed\n");
            if(!t_reply("503","Service Unavailable")){
                sl_reply_error();
            };
        };
        exit;
    }
    t_on_failure("1");
    if (isbflagset(NAT)) setflag(NAT);

# when routing via usrloc, log the missed calls also
    setflag(ACC_MISSED);
    route(relay);
}

route[relay] {
    # for INVITEs enable some additional helper routes
    if (is_method("INVITE")) {
        
        if (isflagset(NAT)) {
            rtpproxy_offer("ro");
        }

t_on_branch("per_branch_ops");
        t_on_reply("handle_nat");
        t_on_failure("missed_call");
    }

if (isflagset(NAT)) {
        add_rr_param(";nat=yes");
        }

if (!t_relay()) {
        send_reply("500","Internal Error");
    };
    exit;
}

branch_route[per_branch_ops] {
    xlog("new branch at $ru\n");
}

onreply_route[handle_nat] {
    if (nat_uac_test("1"))
        fix_nated_contact();
    if ( isflagset(NAT) )
        rtpproxy_answer("ro");
    xlog("incoming reply\n");
}

failure_route[missed_call] {
    if (t_was_cancelled()) {
        exit;
    }

# uncomment the following lines if you want to block client
    # redirect based on 3xx replies.
    ##if (t_check_status("3[0-9][0-9]")) {
    ##t_reply("404","Not found");
    ##    exit;
    ##}

}

local_route {
    if (is_method("BYE") && $DLG_dir=="UPSTREAM") {
        
        acc_db_request("200 Dialog Timeout", "acc");
        
    }
}

failure_route[1] {
    # forwarding failed -- check if the request was a MESSAGE
    if (!method=="MESSAGE")
    {
        exit;
    };
    
    log(1,"MSILO:the downstream UA doesn‘t support MESSAGEs\n");
    # we have changed the R-URI with the contact address, ignore it now
    if (m_store("$ou"))
    {
        log("MSILO: offline message stored\n");
        t_reply("202", "Accepted");
    }else{
        log("MSILO: offline message NOT stored\n");
        t_reply("503", "Service Unavailable");
    };
}

时间: 2024-10-28 16:15:38

OpenSIPS离线消息功能配置的相关文章

【转】可在广域网部署运行的QQ高仿版 -- GG叽叽V3.2,增加离线消息、离线文件功能(源码)

(几句题外话:虽然就如何将GG发展为一个有商业价值的产品,我还没有很清晰明确的思路,但是从GG发布以来,通过GG认识了一些朋友,也接了一些小单子,赚了一点小钱.有了一点甜头,目前和2.3个好朋友一起做做小项目也是不错的,这未尝不是一条养家糊口之路了?呵呵) 距离上次更新(GG叽叽V3.0,完善基础功能)正好有1个月了,在这个月中,我主要为GG增加了离线消息和离线文件的功能.之所以将这两个功能提前实现,是因为至GG发布以来,就有很多朋友问我在GG的基础上如何实现离线消息和离线文件.看来作为一个能用

可在广域网部署运行的QQ高仿版 -- GG叽叽V3.2,增加离线消息、离线文件功能(源码)

(几句题外话:虽然就如何将GG发展为一个有商业价值的产品,我还没有很清晰明确的思路,但是从GG发布以来,通过GG认识了一些朋友,也接了一些小单子,赚了一点小钱.有了一点甜头,目前和2.3个好朋友一起做做小项目也是不错的,这未尝不是一条养家糊口之路了?呵呵) 距离上次更新(GG叽叽V3.0,完善基础功能)正好有1个月了,在这个月中,我主要为GG增加了离线消息和离线文件的功能.之所以将这两个功能提前实现,是因为至GG发布以来,就有很多朋友问我在GG的基础上如何实现离线消息和离线文件.看来作为一个能用

如何在App中实现IM功能之二快速实现离线消息模块——箭扣科技Arrownock

如何在App中实现IM功能 之二 快速实现离线消息模块 一个App在实际使用聊天功能的时候,并非是一直呆在一个界面的,在等待好友发消息来的同时,有可能已经跳转到其他界面,也有可能切换到其他App. 在当前的App进入后台.好友发来消息时,需要给设备推送一条消息.以安卓为例,收取离线消息通知需要绑定anPush,具体做法是调用anIM.bindAnPushService(anID, AppKey, anPushType). 在App进入后台时,调用anIM.disconnect():在App回到前

如何在App中实现IM功能之三快速实现离线消息推送模块——箭扣科技Arrownock

如何在App中实现IM功能 之三 快速实现离线消息推送模块 推送是社交功能里最常见的功能之一,许多使用IM++平台的开发者都会用到,本节我们将为大家带来如何使用IM++平台快速实现离线推送. 使用过Arrownock产品的开发者应该知道,如果要实现离线消息推送在Android设备上有4个步骤,iOS设备上有3个步骤. Android的步骤是: l anIM.connect,anPush.register,anPush.enable,anIM.bindAnPushService iOS的步骤是:

Skype for business 离线消息

配置Skype for business Server 2015离线消息,目前只有office 365客户端支持该功能:Skype for business client 2016没有这个功能. PS C:\Users\lyncadmin> Set-CsClientPolicy -Identity Global -EnableIMAutoArchiving $true -DisableSavingIM $true Get-CsImConfiguration 它利用 Exchange Web 服务

springmvc(18)使用WebSocket 和 STOMP 实现消息功能

[0]README 1)本文旨在 介绍如何 利用 WebSocket 和 STOMP 实现消息功能: 2)要知道, WebSocket 是发送和接收消息的 底层API,而SockJS 是在 WebSocket 之上的 API:最后 STOMP(面向消息的简单文本协议)是基于 SockJS 的高级API (干货--简而言之,WebSocket 是底层协议,SockJS 是WebSocket 的备选方案,也是 底层协议,而 STOMP 是基于 WebSocket(SockJS) 的上层协议) 3)b

Skype For Business Server 2015 离线消息

对于之前使用Lync或Skype的用户都会经常吐槽无法发送离线消息,那么对Skype For Business Server 2015 CU3开始就支持了离线IM,但是对客户端同样是有很高要求的. 离线 IM是 Skype for Business 客户端(2016C2R 内部版本 16.0.6701.1000 或更高版本)中内置的一项客户端功能,它利用 Exchange Web 服务 (EWS) 从 Skype for Business 客户端向用户的 Exchange 邮箱发送消息.离线 I

xmpp和OpenFire示例,即时聊天室,支持离线消息

让我说说为什么写这个博客,这是因为我在上周末的研究XMPP和OpenFire,从互联网上下载Demo,但跑不起来.它花了很长的时间.它被改造.抬高.篇博文也是希望后边学习XMPP和OpenFire的同学下载后直接执行.少走弯路了.时间就是金钱,不要花费不必要的时间,也希望大家都能有分享精神.,有问题能够发邮件给我([email protected]) 关于xmpp和openfire的资料请百度百科一下 下面展示一个聊天程序.所谓万事都要有Helloworld嘛,这个demo能够做为学习xmpp和

离线消息如何实现?-- ESFramework 4.0 快速上手(02)

在ESFramework 4.0 快速上手一文中,主要介绍了如何使用ESPlus.Rapid命名空间中的引擎来快速地构建基于TCP的网络通信系统,即使是使用ESPlus.Rapid来进行ESFramework快速开发,也还有很多可以介绍的内容,于是,我想再多写几篇文章来说明现实通信系统中的一些常见需求如何使用ESFramework快速实现.本文是为第一篇,介绍离线消息的原理和实现. 一.如何截获离线消息 阅读了ESFramework 4.0 快速上手朋友都知道,一个在线用户给另一个用户发送文本信