Merge "pjsip: Fix a few media bugs with reinvites and asymmetric payloads."
authorJoshua Colp <jcolp@digium.com>
Fri, 28 Oct 2016 00:37:47 +0000 (19:37 -0500)
committerGerrit Code Review <gerrit2@gerrit.digium.api>
Fri, 28 Oct 2016 00:37:47 +0000 (19:37 -0500)
CHANGES
apps/app_voicemail.c
cdr/cdr_radius.c
cel/cel_radius.c
channels/chan_pjsip.c
res/res_pjsip_caller_id.c
tests/test_astobj2_thrash.c
third-party/pjproject/Makefile
third-party/pjproject/patches/0000-remove-third-party.patch

diff --git a/CHANGES b/CHANGES
index b1e3985..c9126e1 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -34,6 +34,16 @@ res_pjsip
    preferred codec rather than advertising all joint codec capabilities.
    This limits the other side's codec choice to exactly what we prefer.
 
+cdr_radius
+------------------
+ * To fix a memory leak the syslog channel is now empty if it has not been set
+   and used by a syslog channel in the logger.
+
+cel_radius
+------------------
+ * To fix a memory leak the syslog channel is now empty if it has not been set
+   and used by a syslog channel in the logger.
+
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 14.1.0 to Asterisk 14.2.0 ----------
 ------------------------------------------------------------------------------
index 4727e2e..300dc18 100644 (file)
@@ -12529,6 +12529,7 @@ static int vm_box_exists(struct ast_channel *chan, const char *data)
                context++;
        }
 
+       memset(&svm, 0, sizeof(svm));
        vmu = find_user(&svm, context, args.mbox);
        if (vmu) {
                pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
@@ -12560,6 +12561,7 @@ static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *a
                ast_log(AST_LOG_WARNING, "MAILBOX_EXISTS is deprecated.  Please use ${VM_INFO(%s,exists)} instead.\n", args);
        }
 
+       memset(&svm, 0, sizeof(svm));
        vmu = find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox);
        ast_copy_string(buf, vmu ? "1" : "0", len);
        free_user(vmu);
index e1a639c..ddde5b8 100644 (file)
@@ -265,18 +265,6 @@ static int load_module(void)
        } else
                return AST_MODULE_LOAD_DECLINE;
 
-       /*
-        * start logging
-        *
-        * NOTE: Yes this causes a slight memory leak if the module is
-        * unloaded.  However, it is better than a crash if cdr_radius
-        * and cel_radius are both loaded.
-        */
-       tmp = ast_strdup("asterisk");
-       if (tmp) {
-               rc_openlog((char *) tmp);
-       }
-
        /* read radiusclient-ng config file */
        if (!(rh = rc_read_config(radiuscfg))) {
                ast_log(LOG_NOTICE, "Cannot load radiusclient-ng configuration file %s.\n", radiuscfg);
index 3c20e97..f6ab892 100644 (file)
@@ -237,18 +237,6 @@ static int load_module(void)
                return AST_MODULE_LOAD_DECLINE;
        }
 
-       /*
-        * start logging
-        *
-        * NOTE: Yes this causes a slight memory leak if the module is
-        * unloaded.  However, it is better than a crash if cdr_radius
-        * and cel_radius are both loaded.
-        */
-       tmp = ast_strdup("asterisk");
-       if (tmp) {
-               rc_openlog((char *) tmp);
-       }
-
        /* read radiusclient-ng config file */
        if (!(rh = rc_read_config(radiuscfg))) {
                ast_log(LOG_NOTICE, "Cannot load radiusclient-ng configuration file %s.\n", radiuscfg);
index 0a4e5c2..b0dba1b 100644 (file)
@@ -557,6 +557,12 @@ static int answer(void *data)
        struct ast_sip_session *session = data;
 
        if (session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
+               ast_log(LOG_ERROR, "Session already DISCONNECTED [reason=%d (%s)]\n",
+                       session->inv_session->cause,
+                       pjsip_get_status_text(session->inv_session->cause)->ptr);
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+               pjsip_inv_dec_ref(session->inv_session);
+#endif
                return 0;
        }
 
@@ -573,6 +579,10 @@ static int answer(void *data)
                ast_sip_session_send_response(session, packet);
        }
 
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+       pjsip_inv_dec_ref(session->inv_session);
+#endif
+
        return (status == PJ_SUCCESS) ? 0 : -1;
 }
 
@@ -589,12 +599,23 @@ static int chan_pjsip_answer(struct ast_channel *ast)
        ast_setstate(ast, AST_STATE_UP);
        session = ao2_bump(channel->session);
 
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+       if (pjsip_inv_add_ref(session->inv_session) != PJ_SUCCESS) {
+               ast_log(LOG_ERROR, "Can't increase the session reference counter\n");
+               ao2_ref(session, -1);
+               return -1;
+       }
+#endif
+
        /* the answer task needs to be pushed synchronously otherwise a race condition
           can occur between this thread and bridging (specifically when native bridging
           attempts to do direct media) */
        ast_channel_unlock(ast);
        if (ast_sip_push_task_synchronous(session->serializer, answer, session)) {
                ast_log(LOG_WARNING, "Unable to push answer task to the threadpool. Cannot answer call\n");
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+               pjsip_inv_dec_ref(session->inv_session);
+#endif
                ao2_ref(session, -1);
                ast_channel_lock(ast);
                return -1;
@@ -1116,6 +1137,9 @@ static int indicate(void *data)
                ast_sip_session_send_response(session, packet);
        }
 
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+       pjsip_inv_dec_ref(session->inv_session);
+#endif
        ao2_ref(ind_data, -1);
 
        return 0;
@@ -1143,17 +1167,35 @@ static int transmit_info_with_vidupdate(void *data)
        RAII_VAR(struct ast_sip_session *, session, data, ao2_cleanup);
        struct pjsip_tx_data *tdata;
 
+       if (session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
+               ast_log(LOG_ERROR, "Session already DISCONNECTED [reason=%d (%s)]\n",
+                       session->inv_session->cause,
+                       pjsip_get_status_text(session->inv_session->cause)->ptr);
+               goto failure;
+       }
+
        if (ast_sip_create_request("INFO", session->inv_session->dlg, session->endpoint, NULL, NULL, &tdata)) {
                ast_log(LOG_ERROR, "Could not create text video update INFO request\n");
-               return -1;
+               goto failure;
        }
        if (ast_sip_add_body(tdata, &body)) {
                ast_log(LOG_ERROR, "Could not add body to text video update INFO request\n");
-               return -1;
+               goto failure;
        }
        ast_sip_session_send_request(session, tdata);
 
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+       pjsip_inv_dec_ref(session->inv_session);
+#endif
+
        return 0;
+
+failure:
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+       pjsip_inv_dec_ref(session->inv_session);
+#endif
+       return -1;
+
 }
 
 /*!
@@ -1196,6 +1238,17 @@ static int update_connected_line_information(void *data)
 {
        struct ast_sip_session *session = data;
 
+       if (session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
+               ast_log(LOG_ERROR, "Session already DISCONNECTED [reason=%d (%s)]\n",
+                       session->inv_session->cause,
+                       pjsip_get_status_text(session->inv_session->cause)->ptr);
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+               pjsip_inv_dec_ref(session->inv_session);
+#endif
+               ao2_ref(session, -1);
+               return -1;
+       }
+
        if (ast_channel_state(session->channel) == AST_STATE_UP
                || session->inv_session->role == PJSIP_ROLE_UAC) {
                if (is_colp_update_allowed(session)) {
@@ -1233,6 +1286,10 @@ static int update_connected_line_information(void *data)
                }
        }
 
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+       pjsip_inv_dec_ref(session->inv_session);
+#endif
+
        ao2_ref(session, -1);
        return 0;
 }
@@ -1346,10 +1403,18 @@ static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const voi
                                res = ast_rtp_instance_write(media->rtp, &fr);
                        } else {
                                ao2_ref(channel->session, +1);
-
-                               if (ast_sip_push_task(channel->session->serializer, transmit_info_with_vidupdate, channel->session)) {
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+                               if (pjsip_inv_add_ref(channel->session->inv_session) != PJ_SUCCESS) {
+                                       ast_log(LOG_ERROR, "Can't increase the session reference counter\n");
                                        ao2_cleanup(channel->session);
+                               } else {
+#endif
+                                       if (ast_sip_push_task(channel->session->serializer, transmit_info_with_vidupdate, channel->session)) {
+                                               ao2_cleanup(channel->session);
+                                       }
+#ifdef HAVE_PJSIP_INV_SESSION_REF
                                }
+#endif
                        }
                        ast_test_suite_event_notify("AST_CONTROL_VIDUPDATE", "Result: Success");
                } else {
@@ -1359,7 +1424,17 @@ static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const voi
                break;
        case AST_CONTROL_CONNECTED_LINE:
                ao2_ref(channel->session, +1);
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+               if (pjsip_inv_add_ref(channel->session->inv_session) != PJ_SUCCESS) {
+                       ast_log(LOG_ERROR, "Can't increase the session reference counter\n");
+                       ao2_cleanup(channel->session);
+                       return -1;
+               }
+#endif
                if (ast_sip_push_task(channel->session->serializer, update_connected_line_information, channel->session)) {
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+                       pjsip_inv_dec_ref(channel->session->inv_session);
+#endif
                        ao2_cleanup(channel->session);
                }
                break;
@@ -1452,9 +1527,23 @@ static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const voi
 
        if (response_code) {
                struct indicate_data *ind_data = indicate_data_alloc(channel->session, condition, response_code, data, datalen);
-               if (!ind_data || ast_sip_push_task(channel->session->serializer, indicate, ind_data)) {
+
+               if (!ind_data) {
+                       return -1;
+               }
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+               if (pjsip_inv_add_ref(ind_data->session->inv_session) != PJ_SUCCESS) {
+                       ast_log(LOG_ERROR, "Can't increase the session reference counter\n");
+                       ao2_cleanup(ind_data);
+                       return -1;
+               }
+#endif
+               if (ast_sip_push_task(channel->session->serializer, indicate, ind_data)) {
                        ast_log(LOG_NOTICE, "Cannot send response code %d to endpoint %s. Could not queue task properly\n",
                                        response_code, ast_sorcery_object_get_id(channel->session->endpoint));
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+                       pjsip_inv_dec_ref(ind_data->session->inv_session);
+#endif
                        ao2_cleanup(ind_data);
                        res = -1;
                }
@@ -1575,21 +1664,31 @@ static int transfer(void *data)
        struct ast_sip_contact *contact = NULL;
        const char *target = trnf_data->target;
 
-       /* See if we have an endpoint; if so, use its contact */
-       endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", target);
-       if (endpoint) {
-               contact = ast_sip_location_retrieve_contact_from_aor_list(endpoint->aors);
-               if (contact && !ast_strlen_zero(contact->uri)) {
-                       target = contact->uri;
+       if (trnf_data->session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
+               ast_log(LOG_ERROR, "Session already DISCONNECTED [reason=%d (%s)]\n",
+                       trnf_data->session->inv_session->cause,
+                       pjsip_get_status_text(trnf_data->session->inv_session->cause)->ptr);
+       } else {
+               /* See if we have an endpoint; if so, use its contact */
+               endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", target);
+               if (endpoint) {
+                       contact = ast_sip_location_retrieve_contact_from_aor_list(endpoint->aors);
+                       if (contact && !ast_strlen_zero(contact->uri)) {
+                               target = contact->uri;
+                       }
                }
-       }
 
-       if (ast_channel_state(trnf_data->session->channel) == AST_STATE_RING) {
-               transfer_redirect(trnf_data->session, target);
-       } else {
-               transfer_refer(trnf_data->session, target);
+               if (ast_channel_state(trnf_data->session->channel) == AST_STATE_RING) {
+                       transfer_redirect(trnf_data->session, target);
+               } else {
+                       transfer_refer(trnf_data->session, target);
+               }
        }
 
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+       pjsip_inv_dec_ref(trnf_data->session->inv_session);
+#endif
+
        ao2_ref(trnf_data, -1);
        ao2_cleanup(endpoint);
        ao2_cleanup(contact);
@@ -1606,8 +1705,19 @@ static int chan_pjsip_transfer(struct ast_channel *chan, const char *target)
                return -1;
        }
 
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+       if (pjsip_inv_add_ref(trnf_data->session->inv_session) != PJ_SUCCESS) {
+               ast_log(LOG_ERROR, "Can't increase the session reference counter\n");
+               ao2_cleanup(trnf_data);
+               return -1;
+       }
+#endif
+
        if (ast_sip_push_task(channel->session->serializer, transfer, trnf_data)) {
                ast_log(LOG_WARNING, "Error requesting transfer\n");
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+               pjsip_inv_dec_ref(trnf_data->session->inv_session);
+#endif
                ao2_cleanup(trnf_data);
                return -1;
        }
@@ -1689,9 +1799,16 @@ static int transmit_info_dtmf(void *data)
                .subtype = "dtmf-relay",
        };
 
+       if (session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
+               ast_log(LOG_ERROR, "Session already DISCONNECTED [reason=%d (%s)]\n",
+                       session->inv_session->cause,
+                       pjsip_get_status_text(session->inv_session->cause)->ptr);
+               goto failure;
+       }
+
        if (!(body_text = ast_str_create(32))) {
                ast_log(LOG_ERROR, "Could not allocate buffer for INFO DTMF.\n");
-               return -1;
+               goto failure;
        }
        ast_str_set(&body_text, 0, "Signal=%c\r\nDuration=%u\r\n", dtmf_data->digit, dtmf_data->duration);
 
@@ -1699,16 +1816,27 @@ static int transmit_info_dtmf(void *data)
 
        if (ast_sip_create_request("INFO", session->inv_session->dlg, session->endpoint, NULL, NULL, &tdata)) {
                ast_log(LOG_ERROR, "Could not create DTMF INFO request\n");
-               return -1;
+               goto failure;
        }
        if (ast_sip_add_body(tdata, &body)) {
                ast_log(LOG_ERROR, "Could not add body to DTMF INFO request\n");
                pjsip_tx_data_dec_ref(tdata);
-               return -1;
+               goto failure;
        }
        ast_sip_session_send_request(session, tdata);
 
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+       pjsip_inv_dec_ref(session->inv_session);
+#endif
+
        return 0;
+
+failure:
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+       pjsip_inv_dec_ref(session->inv_session);
+#endif
+       return -1;
+
 }
 
 /*! \brief Function called by core to stop a DTMF digit */
@@ -1728,8 +1856,19 @@ static int chan_pjsip_digit_end(struct ast_channel *ast, char digit, unsigned in
                        return -1;
                }
 
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+               if (pjsip_inv_add_ref(dtmf_data->session->inv_session) != PJ_SUCCESS) {
+                       ast_log(LOG_ERROR, "Can't increase the session reference counter\n");
+                       ao2_cleanup(dtmf_data);
+                       return -1;
+               }
+#endif
+
                if (ast_sip_push_task(channel->session->serializer, transmit_info_dtmf, dtmf_data)) {
                        ast_log(LOG_WARNING, "Error sending DTMF via INFO.\n");
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+                       pjsip_inv_dec_ref(dtmf_data->session->inv_session);
+#endif
                        ao2_cleanup(dtmf_data);
                        return -1;
                }
@@ -2075,11 +2214,21 @@ static int sendtext(void *obj)
                .body_text = data->text
        };
 
-       ast_debug(3, "Sending in dialog SIP message\n");
+       if (data->session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
+               ast_log(LOG_ERROR, "Session already DISCONNECTED [reason=%d (%s)]\n",
+                       data->session->inv_session->cause,
+                       pjsip_get_status_text(data->session->inv_session->cause)->ptr);
+       } else {
+               ast_debug(3, "Sending in dialog SIP message\n");
+
+               ast_sip_create_request("MESSAGE", data->session->inv_session->dlg, data->session->endpoint, NULL, NULL, &tdata);
+               ast_sip_add_body(tdata, &body);
+               ast_sip_send_request(tdata, data->session->inv_session->dlg, data->session->endpoint, NULL, NULL);
+       }
 
-       ast_sip_create_request("MESSAGE", data->session->inv_session->dlg, data->session->endpoint, NULL, NULL, &tdata);
-       ast_sip_add_body(tdata, &body);
-       ast_sip_send_request(tdata, data->session->inv_session->dlg, data->session->endpoint, NULL, NULL);
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+       pjsip_inv_dec_ref(data->session->inv_session);
+#endif
 
        return 0;
 }
@@ -2090,7 +2239,22 @@ static int chan_pjsip_sendtext(struct ast_channel *ast, const char *text)
        struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast);
        struct sendtext_data *data = sendtext_data_create(channel->session, text);
 
-       if (!data || ast_sip_push_task(channel->session->serializer, sendtext, data)) {
+       if (!data) {
+               return -1;
+       }
+
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+       if (pjsip_inv_add_ref(data->session->inv_session) != PJ_SUCCESS) {
+               ast_log(LOG_ERROR, "Can't increase the session reference counter\n");
+               ao2_ref(data, -1);
+               return -1;
+       }
+#endif
+
+       if (ast_sip_push_task(channel->session->serializer, sendtext, data)) {
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+               pjsip_inv_dec_ref(data->session->inv_session);
+#endif
                ao2_ref(data, -1);
                return -1;
        }
index 16b19ec..7948d33 100644 (file)
@@ -523,8 +523,11 @@ static void add_pai_header(const struct ast_sip_session *session, pjsip_tx_data
                }
        }
 
-       base = tdata->msg->type == PJSIP_REQUEST_MSG ? session->saved_from_hdr :
-               PJSIP_MSG_TO_HDR(tdata->msg);
+       if (tdata->msg->type == PJSIP_REQUEST_MSG) {
+               base = session->saved_from_hdr ? session->saved_from_hdr : PJSIP_MSG_FROM_HDR(tdata->msg);
+       } else {
+               base = PJSIP_MSG_TO_HDR(tdata->msg);
+       }
 
        pai_hdr = create_new_id_hdr(&pj_pai_name, base, tdata, id);
        if (!pai_hdr) {
@@ -629,8 +632,11 @@ static void add_rpid_header(const struct ast_sip_session *session, pjsip_tx_data
                }
        }
 
-       base = tdata->msg->type == PJSIP_REQUEST_MSG ? session->saved_from_hdr :
-               PJSIP_MSG_TO_HDR(tdata->msg);
+       if (tdata->msg->type == PJSIP_REQUEST_MSG) {
+               base = session->saved_from_hdr ? session->saved_from_hdr : PJSIP_MSG_FROM_HDR(tdata->msg);
+       } else {
+               base = PJSIP_MSG_TO_HDR(tdata->msg);
+       }
 
        rpid_hdr = create_new_id_hdr(&pj_rpid_name, base, tdata, id);
        if (!rpid_hdr) {
index eaadbb6..ef0da44 100644 (file)
@@ -46,6 +46,13 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/utils.h"
 
 #define MAX_HASH_ENTRIES 15000
+/*
+ * Use one of the online calculators to find the first prime number
+ * greater than MAX_HASH_ENTRIES / 100.
+ */
+#define HASH_BUCKETS 151
+
+#define COUNT_SLEEP_US 500
 #define MAX_TEST_SECONDS 60
 
 struct hash_test {
@@ -207,7 +214,7 @@ static void *hash_test_count(void *d)
 
                if (last_count == count) {
                        /* Allow other threads to run. */
-                       sched_yield();
+                       usleep(COUNT_SLEEP_US);
                } else if (last_count > count) {
                        /* Make sure the ao2 container never shrinks */
                        return "ao2 container unexpectedly shrank";
@@ -261,7 +268,7 @@ AST_TEST_DEFINE(hash_test)
        data.preload = MAX_HASH_ENTRIES / 2;
        data.max_grow = MAX_HASH_ENTRIES - data.preload;
        data.deadline = ast_tvadd(ast_tvnow(), ast_tv(MAX_TEST_SECONDS, 0));
-       data.to_be_thrashed = ao2_container_alloc(MAX_HASH_ENTRIES / 100, hash_string,
+       data.to_be_thrashed = ao2_container_alloc(HASH_BUCKETS, hash_string,
                compare_strings);
 
        if (data.to_be_thrashed == NULL) {
index aaf69bf..07a6c9c 100644 (file)
@@ -1,6 +1,7 @@
 .PHONY: _all all _install install clean distclean echo_cflags configure
 
 include ../versions.mak
+export PJDIR := $(shell pwd -P)/source
 
 SPECIAL_TARGETS :=
 
@@ -85,9 +86,9 @@ $(DOWNLOAD_DIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2: ../versions.mak
 
 source/.unpacked: $(DOWNLOAD_DIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2
        $(ECHO_PREFIX) Unpacking $<
-       -@rm -rf source >/dev/null 2>&1
-       -@mkdir source >/dev/null 2>&1
-       $(CMD_PREFIX) $(TAR) --strip-components=1 -C source -xjf $<
+       -@rm -rf source pjproject-* >/dev/null 2>&1
+       $(CMD_PREFIX) $(TAR) -xjf $<
+       @mv pjproject-$(PJPROJECT_VERSION) source
        $(ECHO_PREFIX) Applying patches
        $(CMD_PREFIX) ./apply_patches $(QUIET_CONFIGURE) patches source
        -@touch source/.unpacked
index 1317751..aca7f01 100644 (file)
@@ -2,6 +2,11 @@ diff --git a/build.mak.in b/build.mak.in
 index 802211c..006d887 100644
 --- a/build.mak.in
 +++ b/build.mak.in
+@@ -1,4 +1,3 @@
+-export PJDIR := @ac_pjdir@
+ include $(PJDIR)/version.mak
+ export PJ_DIR := $(PJDIR)
 @@ -9,7 +9,7 @@ export HOST_NAME := unix
  export CC_NAME := gcc
  export TARGET_NAME := @target@