res_pjsip_empty_info: Respond to empty SIP INFO packets
authorsnuffy <snuffy22@gmail.com>
Tue, 10 May 2016 02:40:08 +0000 (12:40 +1000)
committerJoshua Colp <jcolp@digium.com>
Thu, 19 May 2016 12:08:37 +0000 (09:08 -0300)
Some SBCs require responses to empty SIP INFO packets
after establishing call via INVITE, if not responded to
they may drop your call after unspecified timeout of X minutes.

They are identified by having no Content-Type, check for this
and respond with 200 - OK message.

ASTERISK-24986 #close
Reported-by: Ilya Trikoz, Federico Santulli

Change-Id: Ib27e4f07151e5aef28fa587e4ead36c5b87c43e0

CHANGES
res/res_pjsip_dtmf_info.c
res/res_pjsip_empty_info.c [new file with mode: 0644]
res/res_pjsip_one_touch_record_info.c

diff --git a/CHANGES b/CHANGES
index 91f5ce5..a22c0cd 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -252,6 +252,12 @@ res_pjsip
    will be used instead. The new SIP resolver provides NAPTR support, improved
    SRV support, and AAAA record support.
 
+res_pjsip_info_empty
+--------------------
+ * A new module that can respond to empty Content-Type INFO packets during call.
+   Some SBCs will terminate a call if their empty INFO packets are not responded
+   to within a predefined time.
+
 res_pjsip_outbound_registration
 -------------------------------
 * A new 'fatal_retry_interval' option has been added to outbound registration.
@@ -264,6 +270,7 @@ res_pjsip_outbound_publish
  * Added a new multi_user option that when set to 'yes' allows a given configuration
    to be used for multiple users.
 
+
 CEL Backends
 ------------------
 
index 47ccd1a..e534f3e 100644 (file)
@@ -103,13 +103,13 @@ static int dtmf_info_incoming_request(struct ast_sip_session *session, struct pj
        if (!body || !body->len) {
                /* need to return 200 OK on empty body */
                send_response(session, rdata, 200);
-               return 0;
+               return 1;
        }
 
        res = body->print_body(body, buf, body->len);
        if (res < 0) {
                send_response(session, rdata, 500);
-               return 0;
+               return 1;
        }
        buf[res] = '\0';
 
@@ -150,11 +150,12 @@ static int dtmf_info_incoming_request(struct ast_sip_session *session, struct pj
        }
 
        send_response(session, rdata, event ? 200 : 500);
-       return event ? 0 : -1;
+       return 1;
 }
 
 static struct ast_sip_session_supplement dtmf_info_supplement = {
        .method = "INFO",
+       .priority = AST_SIP_SUPPLEMENT_PRIORITY_FIRST,
        .incoming_request = dtmf_info_incoming_request,
 };
 
diff --git a/res/res_pjsip_empty_info.c b/res/res_pjsip_empty_info.c
new file mode 100644 (file)
index 0000000..09109ba
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2016, Digium, Inc.
+ *
+ * Bradley Latus <brad.latus@gmail.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*** MODULEINFO
+       <depend>pjproject</depend>
+       <depend>res_pjsip</depend>
+       <depend>res_pjsip_session</depend>
+       <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_REGISTER_FILE()
+
+#include <pjsip.h>
+#include <pjsip_ua.h>
+
+#include "asterisk/res_pjsip.h"
+#include "asterisk/res_pjsip_session.h"
+#include "asterisk/module.h"
+
+static void send_response(struct ast_sip_session *session,
+               struct pjsip_rx_data *rdata, int code)
+{
+       pjsip_tx_data *tdata;
+       pjsip_dialog *dlg = session->inv_session->dlg;
+
+       if (pjsip_dlg_create_response(dlg, rdata, code, NULL, &tdata) == PJ_SUCCESS) {
+               struct pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
+               pjsip_dlg_send_response(dlg, tsx, tdata);
+       }
+}
+
+static int empty_info_incoming_request(struct ast_sip_session *session,
+               struct pjsip_rx_data *rdata)
+{
+       if (!rdata->msg_info.ctype) {
+               /* Need to return 200 OK on empty body */
+               /* Some SBCs use empty INFO as a KEEPALIVE */
+               send_response(session, rdata, 200);
+               return 1;
+       }
+
+       /* Let another module respond */
+       return 0;
+
+}
+
+static struct ast_sip_session_supplement empty_info_supplement = {
+       .method = "INFO",
+       .priority = AST_SIP_SUPPLEMENT_PRIORITY_LAST,
+       .incoming_request = empty_info_incoming_request,
+};
+
+static int load_module(void)
+{
+       CHECK_PJSIP_SESSION_MODULE_LOADED();
+
+       ast_sip_session_register_supplement(&empty_info_supplement);
+       return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+       ast_sip_session_unregister_supplement(&empty_info_supplement);
+       return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Empty INFO Support",
+       .support_level = AST_MODULE_SUPPORT_CORE,
+       .load = load_module,
+       .unload = unload_module,
+       .load_pri = AST_MODPRI_APP_DEPEND,
+);
index 30dfcaa..2d53fd4 100644 (file)
@@ -72,13 +72,13 @@ static int handle_incoming_request(struct ast_sip_session *session, struct pjsip
 
        if (!session->channel) {
                send_response(session, 481, rdata);
-               return 0;
+               return 1;
        }
 
        /* Is this endpoint configured with One Touch Recording? */
        if (!session->endpoint->info.recording.enabled || ast_strlen_zero(feature)) {
                send_response(session, 403, rdata);
-               return 0;
+               return 1;
        }
 
        ast_channel_lock(session->channel);
@@ -87,7 +87,7 @@ static int handle_incoming_request(struct ast_sip_session *session, struct pjsip
 
        if (feature_res || ast_strlen_zero(feature_code)) {
                send_response(session, 403, rdata);
-               return 0;
+               return 1;
        }
 
        for (digit = feature_code; *digit; ++digit) {
@@ -97,11 +97,12 @@ static int handle_incoming_request(struct ast_sip_session *session, struct pjsip
 
        send_response(session, 200, rdata);
 
-       return 0;
+       return 1;
 }
 
 static struct ast_sip_session_supplement info_supplement = {
        .method = "INFO",
+       .priority = AST_SIP_SUPPLEMENT_PRIORITY_FIRST,
        .incoming_request = handle_incoming_request,
 };