summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES7
-rw-r--r--addons/cdr_mysql.c1
-rw-r--r--apps/app_originate.c32
-rw-r--r--channels/chan_vpb.cc2
-rw-r--r--configs/samples/pjsip.conf.sample10
-rw-r--r--configs/samples/res_config_sqlite.conf.sample2
-rwxr-xr-xcontrib/scripts/sip_to_pjsip/sip_to_pjsip.py30
-rw-r--r--include/asterisk/cdr.h44
-rw-r--r--include/asterisk/res_pjsip_session.h7
-rw-r--r--include/asterisk/vector.h8
-rw-r--r--main/cdr.c214
-rw-r--r--main/tcptls.c3
-rw-r--r--res/res_ari.c2
-rw-r--r--res/res_pjproject.c2
-rw-r--r--res/res_pjsip.c55
-rw-r--r--res/res_pjsip/include/res_pjsip_private.h26
-rw-r--r--res/res_pjsip/pjsip_configuration.c18
-rw-r--r--res/res_pjsip/pjsip_message_filter.c24
-rw-r--r--res/res_pjsip/pjsip_session.c121
-rw-r--r--res/res_pjsip_registrar.c156
-rw-r--r--res/res_pjsip_session.c70
21 files changed, 579 insertions, 255 deletions
diff --git a/CHANGES b/CHANGES
index dc665ac2a..2cc8ad10a 100644
--- a/CHANGES
+++ b/CHANGES
@@ -34,6 +34,13 @@ res_pjsip
unsolicited MWI NOTIFY requests and make them available to other modules via
the stasis message bus.
+ * The "remove_existing" option now allows a registration to succeed by
+ displacing any existing contacts that now exceed the "max_contacts" count.
+ Any removed contacts are the next to expire. The behaviour change is
+ beneficial when "rewrite_contact" is enabled and "max_contacts" is greater
+ than one. The removed contact is likely the old contact created by
+ "rewrite_contact" that the device is refreshing.
+
res_musiconhold
------------------
* By default, when res_musiconhold reloads or unloads, it sends a HUP signal
diff --git a/addons/cdr_mysql.c b/addons/cdr_mysql.c
index 667e6a2bf..07849b0c1 100644
--- a/addons/cdr_mysql.c
+++ b/addons/cdr_mysql.c
@@ -512,7 +512,6 @@ static int my_load_module(int reload)
} else {
calldate_compat = 0;
}
- ast_free(compat);
if (res < 0) {
if (reload) {
diff --git a/apps/app_originate.c b/apps/app_originate.c
index 88245f0a6..6093f30fd 100644
--- a/apps/app_originate.c
+++ b/apps/app_originate.c
@@ -110,6 +110,7 @@ static int originate_exec(struct ast_channel *chan, const char *data)
char *parse;
char *chantech, *chandata;
int res = -1;
+ int continue_in_dialplan = 0;
int outgoing_status = 0;
unsigned int timeout = 30;
static const char default_exten[] = "s";
@@ -159,6 +160,12 @@ static int originate_exec(struct ast_channel *chan, const char *data)
goto return_cleanup;
}
+ if (strcasecmp(args.type, "exten") && strcasecmp(args.type, "app")) {
+ ast_log(LOG_ERROR, "Incorrect type, it should be 'exten' or 'app': %s\n",
+ args.type);
+ goto return_cleanup;
+ }
+
if (!strcasecmp(args.type, "exten")) {
int priority = 1; /* Initialized in case priority not specified */
const char *exten = args.arg2;
@@ -177,23 +184,30 @@ static int originate_exec(struct ast_channel *chan, const char *data)
ast_debug(1, "Originating call to '%s/%s' and connecting them to extension %s,%s,%d\n",
chantech, chandata, args.arg1, exten, priority);
- ast_pbx_outgoing_exten(chantech, cap_slin, chandata,
+ res = ast_pbx_outgoing_exten(chantech, cap_slin, chandata,
timeout * 1000, args.arg1, exten, priority, &outgoing_status,
AST_OUTGOING_WAIT, NULL, NULL, NULL, NULL, NULL, 0, NULL);
- } else if (!strcasecmp(args.type, "app")) {
+ } else {
ast_debug(1, "Originating call to '%s/%s' and connecting them to %s(%s)\n",
chantech, chandata, args.arg1, S_OR(args.arg2, ""));
- ast_pbx_outgoing_app(chantech, cap_slin, chandata,
+ res = ast_pbx_outgoing_app(chantech, cap_slin, chandata,
timeout * 1000, args.arg1, args.arg2, &outgoing_status,
AST_OUTGOING_WAIT, NULL, NULL, NULL, NULL, NULL, NULL);
- } else {
- ast_log(LOG_ERROR, "Incorrect type, it should be 'exten' or 'app': %s\n",
- args.type);
- goto return_cleanup;
}
- res = 0;
+ /*
+ * Getting here means that we have passed the various validation checks and
+ * have at least attempted the dial. If we have a reason (outgoing_status),
+ * we clear our error indicator so that we ultimately report the right thing
+ * to the caller.
+ */
+ if (res && outgoing_status) {
+ res = 0;
+ }
+
+ /* We need to exit cleanly if we've gotten this far */
+ continue_in_dialplan = 1;
return_cleanup:
if (res) {
@@ -226,7 +240,7 @@ return_cleanup:
ao2_cleanup(cap_slin);
ast_autoservice_stop(chan);
- return res;
+ return continue_in_dialplan ? 0 : -1;
}
static int unload_module(void)
diff --git a/channels/chan_vpb.cc b/channels/chan_vpb.cc
index 1f4b861c1..545cb53bd 100644
--- a/channels/chan_vpb.cc
+++ b/channels/chan_vpb.cc
@@ -1787,7 +1787,7 @@ static int vpb_digit_end(struct ast_channel *ast, char digit, unsigned int durat
ast_verb(4, "%s: vpb_digit: asked to play digit[%s]\n", p->dev, s);
ast_mutex_lock(&p->play_dtmf_lock);
- strncat(p->play_dtmf, s, sizeof(*p->play_dtmf) - strlen(p->play_dtmf) - 1);
+ strncat(p->play_dtmf, s, sizeof(p->play_dtmf) - strlen(p->play_dtmf) - 1);
ast_mutex_unlock(&p->play_dtmf_lock);
ast_mutex_unlock(&p->lock);
diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample
index 536c9f1ec..8f739d4a0 100644
--- a/configs/samples/pjsip.conf.sample
+++ b/configs/samples/pjsip.conf.sample
@@ -902,7 +902,13 @@
;max_contacts=0 ; Maximum number of contacts that can bind to an AoR (default:
; "0")
;minimum_expiration=60 ; Minimum keep alive time for an AoR (default: "60")
-;remove_existing=no ; Determines whether new contacts replace existing ones
+;remove_existing=no ; Allow a registration to succeed by displacing any existing
+ ; contacts that now exceed the max_contacts count. Any
+ ; removed contacts are the next to expire. The behaviour is
+ ; beneficial when rewrite_contact is enabled and max_contacts
+ ; is greater than one. The removed contact is likely the old
+ ; contact created by rewrite_contact that the device is
+ ; refreshing.
; (default: "no")
;type= ; Must be of type aor (default: "")
;qualify_frequency=0 ; Interval at which to qualify an AoR (default: "0")
@@ -1141,7 +1147,7 @@
;outbound_auth= ; Authentication object(s) to be used for outbound
; publishes.
- ; This is a comma-delimited list of auth sections
+ ; This is a comma-delimited list of auth sections
; defined in pjsip.conf used to respond to outbound
; authentication challenges.
; Using the same auth section for inbound and
diff --git a/configs/samples/res_config_sqlite.conf.sample b/configs/samples/res_config_sqlite.conf.sample
index 04e6ae2e7..2d14d46a3 100644
--- a/configs/samples/res_config_sqlite.conf.sample
+++ b/configs/samples/res_config_sqlite.conf.sample
@@ -8,4 +8,4 @@ dbfile => /var/lib/asterisk/sqlite.db
; extconfig.conf, the value given here is used. If cdr_table is omitted, CDR
; support is simply disabled.
config_table => ast_config
-cdr_table => ast_cdr
+; cdr_table => ast_cdr
diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py
index 98a5e9546..eb3aab3b8 100755
--- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py
+++ b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py
@@ -116,6 +116,27 @@ def set_dtmfmode(key, val, section, pjsip, nmapped):
set_value(key, 'none', section, pjsip, nmapped)
+def setup_udptl(section, pjsip, nmapped):
+ """Sets values from udptl into the appropriate pjsip.conf options."""
+ try:
+ val = sip.get(section, 't38pt_udptl')[0]
+ except LookupError:
+ try:
+ val = sip.get('general', 't38pt_udptl')[0]
+ except LookupError:
+ return
+
+ ec = 'none'
+ if 'yes' in val:
+ set_value('t38_udptl', 'yes', section, pjsip, nmapped)
+ if 'no' in val:
+ set_value('t38_udptl', 'no', section, pjsip, nmapped)
+ if 'redundancy' in val:
+ ec = 'redundancy'
+ if 'fec' in val:
+ ec = 'fec'
+ set_value('t38_udptl_ec', ec, section, pjsip, nmapped)
+
def from_nat(key, val, section, pjsip, nmapped):
"""Sets values from nat into the appropriate pjsip.conf options."""
# nat from sip.conf can be comma separated list of values:
@@ -387,6 +408,7 @@ peer_map = [
['allow', merge_value],
['nat', from_nat], # rtp_symmetric, force_rport,
# rewrite_contact
+ ['rtptimeout', set_value('rtp_timeout')],
['icesupport', set_value('ice_support')],
['autoframing', set_value('use_ptime')],
['outboundproxy', set_value('outbound_proxy')],
@@ -1068,6 +1090,7 @@ def map_peer(sip, section, pjsip, nmapped):
except LookupError:
pass # key not found in sip.conf
+ setup_udptl(section, pjsip, nmapped)
def find_non_mapped(sections, nmapped):
"""
@@ -1101,6 +1124,13 @@ def map_system(sip, pjsip, nmapped):
except LookupError:
pass
+
+ try:
+ sipdebug = sip.get('general', 'sipdebug')[0]
+ set_value('debug', sipdebug, 'global', pjsip, nmapped, 'global')
+ except LookupError:
+ pass
+
try:
useroption_parsing = sip.get('general', 'legacy_useroption_parsing')[0]
set_value('ignore_uri_user_options', useroption_parsing, 'global', pjsip, nmapped, 'global')
diff --git a/include/asterisk/cdr.h b/include/asterisk/cdr.h
index f752f7f9f..e10da8223 100644
--- a/include/asterisk/cdr.h
+++ b/include/asterisk/cdr.h
@@ -217,19 +217,19 @@
/*! \brief CDR engine settings */
enum ast_cdr_settings {
- CDR_ENABLED = 1 << 0, /*< Enable CDRs */
- CDR_BATCHMODE = 1 << 1, /*< Whether or not we should dispatch CDRs in batches */
- CDR_UNANSWERED = 1 << 2, /*< Log unanswered CDRs */
- CDR_CONGESTION = 1 << 3, /*< Treat congestion as if it were a failed call */
- CDR_END_BEFORE_H_EXTEN = 1 << 4, /*< End the CDR before the 'h' extension runs */
- CDR_INITIATED_SECONDS = 1 << 5, /*< Include microseconds into the billing time */
- CDR_DEBUG = 1 << 6, /*< Enables extra debug statements */
+ CDR_ENABLED = 1 << 0, /*!< Enable CDRs */
+ CDR_BATCHMODE = 1 << 1, /*!< Whether or not we should dispatch CDRs in batches */
+ CDR_UNANSWERED = 1 << 2, /*!< Log unanswered CDRs */
+ CDR_CONGESTION = 1 << 3, /*!< Treat congestion as if it were a failed call */
+ CDR_END_BEFORE_H_EXTEN = 1 << 4, /*!< End the CDR before the 'h' extension runs */
+ CDR_INITIATED_SECONDS = 1 << 5, /*!< Include microseconds into the billing time */
+ CDR_DEBUG = 1 << 6, /*!< Enables extra debug statements */
};
/*! \brief CDR Batch Mode settings */
enum ast_cdr_batch_mode_settings {
- BATCH_MODE_SCHEDULER_ONLY = 1 << 0, /*< Don't spawn a thread to handle the batches - do it on the scheduler */
- BATCH_MODE_SAFE_SHUTDOWN = 1 << 1, /*< During safe shutdown, submit the batched CDRs */
+ BATCH_MODE_SCHEDULER_ONLY = 1 << 0, /*!< Don't spawn a thread to handle the batches - do it on the scheduler */
+ BATCH_MODE_SAFE_SHUTDOWN = 1 << 1, /*!< During safe shutdown, submit the batched CDRs */
};
/*!
@@ -237,14 +237,14 @@ enum ast_cdr_batch_mode_settings {
* state of a CDR object based on these flags.
*/
enum ast_cdr_options {
- AST_CDR_FLAG_KEEP_VARS = (1 << 0), /*< Copy variables during the operation */
- AST_CDR_FLAG_DISABLE = (1 << 1), /*< Disable the current CDR */
- AST_CDR_FLAG_DISABLE_ALL = (3 << 1), /*< Disable the CDR and all future CDRs */
- AST_CDR_FLAG_PARTY_A = (1 << 3), /*< Set the channel as party A */
- AST_CDR_FLAG_FINALIZE = (1 << 4), /*< Finalize the current CDRs */
- AST_CDR_FLAG_SET_ANSWER = (1 << 5), /*< If the channel is answered, set the answer time to now */
- AST_CDR_FLAG_RESET = (1 << 6), /*< If set, set the start and answer time to now */
- AST_CDR_LOCK_APP = (1 << 7), /*< Prevent any further changes to the application field/data field for this CDR */
+ AST_CDR_FLAG_KEEP_VARS = (1 << 0), /*!< Copy variables during the operation */
+ AST_CDR_FLAG_DISABLE = (1 << 1), /*!< Disable the current CDR */
+ AST_CDR_FLAG_DISABLE_ALL = (3 << 1), /*!< Disable the CDR and all future CDRs */
+ AST_CDR_FLAG_PARTY_A = (1 << 3), /*!< Set the channel as party A */
+ AST_CDR_FLAG_FINALIZE = (1 << 4), /*!< Finalize the current CDRs */
+ AST_CDR_FLAG_SET_ANSWER = (1 << 5), /*!< If the channel is answered, set the answer time to now */
+ AST_CDR_FLAG_RESET = (1 << 6), /*!< If set, set the start and answer time to now */
+ AST_CDR_LOCK_APP = (1 << 7), /*!< Prevent any further changes to the application field/data field for this CDR */
};
/*!
@@ -262,11 +262,11 @@ enum ast_cdr_disposition {
/*! \brief The global options available for CDRs */
struct ast_cdr_config {
- struct ast_flags settings; /*< CDR settings */
+ struct ast_flags settings; /*!< CDR settings */
struct batch_settings {
- unsigned int time; /*< Time between batches */
- unsigned int size; /*< Size to trigger a batch */
- struct ast_flags settings; /*< Settings for batches */
+ unsigned int time; /*!< Time between batches */
+ unsigned int size; /*!< Size to trigger a batch */
+ struct ast_flags settings; /*!< Settings for batches */
} batch_settings;
};
@@ -312,7 +312,7 @@ struct ast_cdr {
unsigned int flags;
/*! Unique Channel Identifier */
char uniqueid[AST_MAX_UNIQUEID];
- /* Linked group Identifier */
+ /*! Linked group Identifier */
char linkedid[AST_MAX_UNIQUEID];
/*! User field */
char userfield[AST_MAX_USER_FIELD];
diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h
index d275c256e..7d6b30229 100644
--- a/include/asterisk/res_pjsip_session.h
+++ b/include/asterisk/res_pjsip_session.h
@@ -544,6 +544,13 @@ int ast_sip_session_register_supplement(struct ast_sip_session_supplement *suppl
void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement);
/*!
+ * \brief Add supplements to a SIP session
+ *
+ * \param session The session to initialize
+ */
+int ast_sip_session_add_supplements(struct ast_sip_session *session);
+
+/*!
* \brief Alternative for ast_datastore_alloc()
*
* There are two major differences between this and ast_datastore_alloc()
diff --git a/include/asterisk/vector.h b/include/asterisk/vector.h
index 1e6fe038c..68ce13065 100644
--- a/include/asterisk/vector.h
+++ b/include/asterisk/vector.h
@@ -548,6 +548,14 @@ AST_VECTOR(ast_vector_int, int);
#define AST_VECTOR_SIZE(vec) (vec)->current
/*!
+ * \brief Get the maximum number of elements the vector can currently hold.
+ *
+ * \param vec Vector to query.
+ * \return Maximum number of elements the vector can currently hold.
+ */
+#define AST_VECTOR_MAX_SIZE(vec) (vec)->max
+
+/*!
* \brief Reset vector.
*
* \param vec Vector to reset.
diff --git a/main/cdr.c b/main/cdr.c
index 4bcfc05b3..06cadcd8b 100644
--- a/main/cdr.c
+++ b/main/cdr.c
@@ -223,7 +223,7 @@ static int cdr_toggle_runtime_options(void);
/*! \brief The configuration settings for this module */
struct module_config {
- struct ast_cdr_config *general; /*< CDR global settings */
+ struct ast_cdr_config *general; /*!< CDR global settings */
};
/*! \brief The container for the module configuration */
@@ -754,11 +754,7 @@ static void free_variables(struct varshead *headp)
*/
static void cdr_object_snapshot_copy(struct cdr_object_snapshot *dst, struct cdr_object_snapshot *src)
{
- if (dst->snapshot) {
- ao2_t_ref(dst->snapshot, -1, "release old snapshot during copy");
- }
- dst->snapshot = src->snapshot;
- ao2_t_ref(dst->snapshot, +1, "bump new snapshot during copy");
+ ao2_t_replace(dst->snapshot, src->snapshot, "CDR snapshot copy");
strcpy(dst->userfield, src->userfield);
dst->flags = src->flags;
copy_variables(&dst->variables, &src->variables);
@@ -788,11 +784,11 @@ static int cdr_object_channel_hash_fn(const void *obj, const int flags)
const struct cdr_object *cdr;
const char *key;
- switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
- case OBJ_KEY:
+ switch (flags & OBJ_SEARCH_MASK) {
+ case OBJ_SEARCH_KEY:
key = obj;
break;
- case OBJ_POINTER:
+ case OBJ_SEARCH_OBJECT:
cdr = obj;
key = cdr->uniqueid;
break;
@@ -813,14 +809,14 @@ static int cdr_object_channel_cmp_fn(void *obj, void *arg, int flags)
const char *right_key = arg;
int cmp;
- switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
- case OBJ_POINTER:
+ switch (flags & OBJ_SEARCH_MASK) {
+ case OBJ_SEARCH_OBJECT:
right_key = right->uniqueid;
/* Fall through */
- case OBJ_KEY:
+ case OBJ_SEARCH_KEY:
cmp = strcmp(left->uniqueid, right_key);
break;
- case OBJ_PARTIAL_KEY:
+ case OBJ_SEARCH_PARTIAL_KEY:
/*
* We could also use a partial key struct containing a length
* so strlen() does not get called for every comparison instead.
@@ -1361,11 +1357,7 @@ static void cdr_object_swap_snapshot(struct cdr_object_snapshot *old_snapshot,
struct ast_channel_snapshot *new_snapshot)
{
cdr_object_update_cid(old_snapshot, new_snapshot);
- if (old_snapshot->snapshot) {
- ao2_t_ref(old_snapshot->snapshot, -1, "Drop ref for swap");
- }
- ao2_t_ref(new_snapshot, +1, "Bump ref for swap");
- old_snapshot->snapshot = new_snapshot;
+ ao2_t_replace(old_snapshot->snapshot, new_snapshot, "Swap CDR shapshot");
}
/* BASE METHOD IMPLEMENTATIONS */
@@ -1461,7 +1453,8 @@ static int base_process_parked_channel(struct cdr_object *cdr, struct ast_parked
/* SINGLE STATE */
-static void single_state_init_function(struct cdr_object *cdr) {
+static void single_state_init_function(struct cdr_object *cdr)
+{
cdr->start = ast_tvnow();
cdr_object_check_party_a_answer(cdr);
}
@@ -1574,11 +1567,10 @@ static enum process_bridge_enter_results single_state_process_bridge_enter(struc
for (it_cdrs = ao2_iterator_init(bridge->channels, 0);
!success && (channel_id = ao2_iterator_next(&it_cdrs));
ao2_ref(channel_id, -1)) {
- RAII_VAR(struct cdr_object *, cand_cdr_master,
- ao2_find(active_cdrs_by_channel, channel_id, OBJ_KEY),
- ao2_cleanup);
+ struct cdr_object *cand_cdr_master;
struct cdr_object *cand_cdr;
+ cand_cdr_master = ao2_find(active_cdrs_by_channel, channel_id, OBJ_SEARCH_KEY);
if (!cand_cdr_master) {
continue;
}
@@ -1600,6 +1592,7 @@ static enum process_bridge_enter_results single_state_process_bridge_enter(struc
break;
}
ao2_unlock(cand_cdr_master);
+ ao2_cleanup(cand_cdr_master);
}
ao2_iterator_destroy(&it_cdrs);
@@ -1626,11 +1619,9 @@ static int single_state_process_parking_bridge_enter(struct cdr_object *cdr, str
static void dial_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
{
ast_assert(snapshot != NULL);
+ ast_assert(cdr->party_b.snapshot
+ && !strcasecmp(cdr->party_b.snapshot->name, snapshot->name));
- if (!cdr->party_b.snapshot
- || strcasecmp(cdr->party_b.snapshot->name, snapshot->name)) {
- return;
- }
cdr_object_swap_snapshot(&cdr->party_b, snapshot);
/* If party B hangs up, finalize this CDR */
@@ -1724,11 +1715,10 @@ static enum process_bridge_enter_results dial_state_process_bridge_enter(struct
for (it_cdrs = ao2_iterator_init(bridge->channels, 0);
!success && (channel_id = ao2_iterator_next(&it_cdrs));
ao2_ref(channel_id, -1)) {
- RAII_VAR(struct cdr_object *, cand_cdr_master,
- ao2_find(active_cdrs_by_channel, channel_id, OBJ_KEY),
- ao2_cleanup);
+ struct cdr_object *cand_cdr_master;
struct cdr_object *cand_cdr;
+ cand_cdr_master = ao2_find(active_cdrs_by_channel, channel_id, OBJ_SEARCH_KEY);
if (!cand_cdr_master) {
continue;
}
@@ -1763,6 +1753,7 @@ static enum process_bridge_enter_results dial_state_process_bridge_enter(struct
break;
}
ao2_unlock(cand_cdr_master);
+ ao2_cleanup(cand_cdr_master);
}
ao2_iterator_destroy(&it_cdrs);
@@ -1826,10 +1817,9 @@ static int dialed_pending_state_process_dial_begin(struct cdr_object *cdr, struc
static void bridge_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
{
- if (!cdr->party_b.snapshot
- || strcasecmp(cdr->party_b.snapshot->name, snapshot->name)) {
- return;
- }
+ ast_assert(cdr->party_b.snapshot
+ && !strcasecmp(cdr->party_b.snapshot->name, snapshot->name));
+
cdr_object_swap_snapshot(&cdr->party_b, snapshot);
/* If party B hangs up, finalize this CDR */
@@ -1934,7 +1924,7 @@ static int dial_status_end(const char *dialstatus)
static void handle_dial_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
{
RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
- RAII_VAR(struct cdr_object *, cdr, NULL, ao2_cleanup);
+ struct cdr_object *cdr;
struct ast_multi_channel_blob *payload = stasis_message_data(message);
struct ast_channel_snapshot *caller;
struct ast_channel_snapshot *peer;
@@ -1948,6 +1938,10 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str
if (!peer && !caller) {
return;
}
+ if (filter_channel_snapshot(peer) || (caller && filter_channel_snapshot(caller))) {
+ return;
+ }
+
dial_status_blob = ast_json_object_get(ast_multi_channel_blob_get_json(payload), "dialstatus");
if (dial_status_blob) {
dial_status = ast_json_string_get(dial_status_blob);
@@ -1960,17 +1954,12 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str
(unsigned int)stasis_message_timestamp(message)->tv_sec,
(unsigned int)stasis_message_timestamp(message)->tv_usec);
- if (filter_channel_snapshot(peer) || (caller && filter_channel_snapshot(caller))) {
- return;
- }
-
/* Figure out who is running this show */
if (caller) {
- cdr = ao2_find(active_cdrs_by_channel, caller->uniqueid, OBJ_KEY);
+ cdr = ao2_find(active_cdrs_by_channel, caller->uniqueid, OBJ_SEARCH_KEY);
} else {
- cdr = ao2_find(active_cdrs_by_channel, peer->uniqueid, OBJ_KEY);
+ cdr = ao2_find(active_cdrs_by_channel, peer->uniqueid, OBJ_SEARCH_KEY);
}
-
if (!cdr) {
ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", caller ? caller->name : peer->name);
ast_assert(0);
@@ -2010,15 +1999,12 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str
struct cdr_object *new_cdr;
new_cdr = cdr_object_create_and_append(cdr);
- if (!new_cdr) {
- ao2_unlock(cdr);
- return;
+ if (new_cdr) {
+ new_cdr->fn_table->process_dial_begin(new_cdr, caller, peer);
}
- new_cdr->fn_table->process_dial_begin(new_cdr,
- caller,
- peer);
}
ao2_unlock(cdr);
+ ao2_cleanup(cdr);
}
static int cdr_object_finalize_party_b(void *obj, void *arg, int flags)
@@ -2026,6 +2012,7 @@ static int cdr_object_finalize_party_b(void *obj, void *arg, int flags)
struct cdr_object *cdr = obj;
struct ast_channel_snapshot *party_b = arg;
struct cdr_object *it_cdr;
+
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
if (it_cdr->party_b.snapshot
&& !strcasecmp(it_cdr->party_b.snapshot->name, party_b->name)) {
@@ -2043,6 +2030,7 @@ static int cdr_object_update_party_b(void *obj, void *arg, int flags)
struct cdr_object *cdr = obj;
struct ast_channel_snapshot *party_b = arg;
struct cdr_object *it_cdr;
+
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
if (!it_cdr->fn_table->process_party_b) {
continue;
@@ -2090,13 +2078,11 @@ static int check_new_cdr_needed(struct ast_channel_snapshot *old_snapshot,
*/
static void handle_channel_cache_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
{
- RAII_VAR(struct cdr_object *, cdr, NULL, ao2_cleanup);
+ struct cdr_object *cdr;
RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
struct stasis_cache_update *update = stasis_message_data(message);
struct ast_channel_snapshot *old_snapshot;
struct ast_channel_snapshot *new_snapshot;
- const char *uniqueid;
- const char *name;
struct cdr_object *it_cdr;
ast_assert(update != NULL);
@@ -2104,8 +2090,6 @@ static void handle_channel_cache_message(void *data, struct stasis_subscription
old_snapshot = stasis_message_data(update->old_snapshot);
new_snapshot = stasis_message_data(update->new_snapshot);
- uniqueid = new_snapshot ? new_snapshot->uniqueid : old_snapshot->uniqueid;
- name = new_snapshot ? new_snapshot->name : old_snapshot->name;
if (filter_channel_cache_message(old_snapshot, new_snapshot)) {
return;
@@ -2118,19 +2102,25 @@ static void handle_channel_cache_message(void *data, struct stasis_subscription
}
cdr->is_root = 1;
ao2_link(active_cdrs_by_channel, cdr);
+ } else {
+ const char *uniqueid;
+
+ uniqueid = new_snapshot ? new_snapshot->uniqueid : old_snapshot->uniqueid;
+ cdr = ao2_find(active_cdrs_by_channel, uniqueid, OBJ_SEARCH_KEY);
}
/* Handle Party A */
if (!cdr) {
- cdr = ao2_find(active_cdrs_by_channel, uniqueid, OBJ_KEY);
- }
- if (!cdr) {
+ const char *name;
+
+ name = new_snapshot ? new_snapshot->name : old_snapshot->name;
ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", name);
ast_assert(0);
} else {
ao2_lock(cdr);
if (new_snapshot) {
int all_reject = 1;
+
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
if (!it_cdr->fn_table->process_party_a) {
continue;
@@ -2140,6 +2130,7 @@ static void handle_channel_cache_message(void *data, struct stasis_subscription
if (all_reject && check_new_cdr_needed(old_snapshot, new_snapshot)) {
/* We're not hung up and we have a new snapshot - we need a new CDR */
struct cdr_object *new_cdr;
+
new_cdr = cdr_object_create_and_append(cdr);
if (new_cdr) {
new_cdr->fn_table->process_party_a(new_cdr, new_snapshot);
@@ -2165,6 +2156,7 @@ static void handle_channel_cache_message(void *data, struct stasis_subscription
old_snapshot);
}
+ ao2_cleanup(cdr);
}
struct bridge_leave_data {
@@ -2227,9 +2219,7 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription *
struct ast_channel_snapshot *channel = update->channel;
RAII_VAR(struct module_config *, mod_cfg,
ao2_global_obj_ref(module_configs), ao2_cleanup);
- RAII_VAR(struct cdr_object *, cdr,
- ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_KEY),
- ao2_cleanup);
+ struct cdr_object *cdr;
struct cdr_object *it_cdr;
struct bridge_leave_data leave_data = {
.bridge = bridge,
@@ -2250,6 +2240,7 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription *
(unsigned int)stasis_message_timestamp(message)->tv_sec,
(unsigned int)stasis_message_timestamp(message)->tv_usec);
+ cdr = ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_SEARCH_KEY);
if (!cdr) {
ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name);
ast_assert(0);
@@ -2270,16 +2261,16 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription *
}
}
ao2_unlock(cdr);
- if (!left_bridge) {
- return;
- }
- if (strcmp(bridge->subclass, "parking")) {
- /* Party B */
+ /* Party B */
+ if (left_bridge
+ && strcmp(bridge->subclass, "parking")) {
ao2_callback(active_cdrs_by_channel, OBJ_NODATA,
- cdr_object_party_b_left_bridge_cb,
- &leave_data);
+ cdr_object_party_b_left_bridge_cb,
+ &leave_data);
}
+
+ ao2_cleanup(cdr);
}
/*!
@@ -2384,17 +2375,14 @@ static void handle_bridge_pairings(struct cdr_object *cdr, struct ast_bridge_sna
it_channels = ao2_iterator_init(bridge->channels, 0);
while ((channel_id = ao2_iterator_next(&it_channels))) {
- RAII_VAR(struct cdr_object *, cand_cdr,
- ao2_find(active_cdrs_by_channel, channel_id, OBJ_KEY),
- ao2_cleanup);
+ struct cdr_object *cand_cdr;
- if (!cand_cdr) {
- ao2_ref(channel_id, -1);
- continue;
+ cand_cdr = ao2_find(active_cdrs_by_channel, channel_id, OBJ_SEARCH_KEY);
+ if (cand_cdr) {
+ bridge_candidate_process(cdr, cand_cdr);
+ ao2_ref(cand_cdr, -1);
}
- bridge_candidate_process(cdr, cand_cdr);
-
ao2_ref(channel_id, -1);
}
ao2_iterator_destroy(&it_channels);
@@ -2530,9 +2518,7 @@ static void handle_bridge_enter_message(void *data, struct stasis_subscription *
struct ast_bridge_blob *update = stasis_message_data(message);
struct ast_bridge_snapshot *bridge = update->bridge;
struct ast_channel_snapshot *channel = update->channel;
- RAII_VAR(struct cdr_object *, cdr,
- ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_KEY),
- ao2_cleanup);
+ struct cdr_object *cdr;
RAII_VAR(struct module_config *, mod_cfg,
ao2_global_obj_ref(module_configs), ao2_cleanup);
@@ -2549,6 +2535,7 @@ static void handle_bridge_enter_message(void *data, struct stasis_subscription *
(unsigned int)stasis_message_timestamp(message)->tv_sec,
(unsigned int)stasis_message_timestamp(message)->tv_usec);
+ cdr = ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_SEARCH_KEY);
if (!cdr) {
ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name);
ast_assert(0);
@@ -2560,6 +2547,7 @@ static void handle_bridge_enter_message(void *data, struct stasis_subscription *
} else {
handle_standard_bridge_enter_message(cdr, bridge, channel);
}
+ ao2_cleanup(cdr);
}
/*!
@@ -2574,7 +2562,7 @@ static void handle_parked_call_message(void *data, struct stasis_subscription *s
{
struct ast_parked_call_payload *payload = stasis_message_data(message);
struct ast_channel_snapshot *channel = payload->parkee;
- RAII_VAR(struct cdr_object *, cdr, NULL, ao2_cleanup);
+ struct cdr_object *cdr;
RAII_VAR(struct module_config *, mod_cfg,
ao2_global_obj_ref(module_configs), ao2_cleanup);
int unhandled = 1;
@@ -2599,7 +2587,7 @@ static void handle_parked_call_message(void *data, struct stasis_subscription *s
(unsigned int)stasis_message_timestamp(message)->tv_sec,
(unsigned int)stasis_message_timestamp(message)->tv_usec);
- cdr = ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_KEY);
+ cdr = ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_SEARCH_KEY);
if (!cdr) {
ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name);
ast_assert(0);
@@ -2616,7 +2604,9 @@ static void handle_parked_call_message(void *data, struct stasis_subscription *s
if (unhandled) {
/* Nothing handled the messgae - we need a new one! */
- struct cdr_object *new_cdr = cdr_object_create_and_append(cdr);
+ struct cdr_object *new_cdr;
+
+ new_cdr = cdr_object_create_and_append(cdr);
if (new_cdr) {
/* As the new CDR is created in the single state, it is guaranteed
* to have a function for the parked call message and will handle
@@ -2627,6 +2617,7 @@ static void handle_parked_call_message(void *data, struct stasis_subscription *s
ao2_unlock(cdr);
+ ao2_cleanup(cdr);
}
/*!
@@ -2915,7 +2906,7 @@ void ast_cdr_format_var(struct ast_cdr *cdr, const char *name, char **ret, char
}
}
-/*
+/*!
* \internal
* \brief Callback that finds all CDRs that reference a particular channel by name
*/
@@ -2931,7 +2922,7 @@ static int cdr_object_select_all_by_name_cb(void *obj, void *arg, int flags)
return 0;
}
-/*
+/*!
* \internal
* \brief Callback that finds a CDR by channel name
*/
@@ -3119,15 +3110,16 @@ static struct cdr_object *cdr_object_get_by_name(const char *name)
int ast_cdr_getvar(const char *channel_name, const char *name, char *value, size_t length)
{
- RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
+ struct cdr_object *cdr;
struct cdr_object *cdr_obj;
- if (!cdr) {
- ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
+ if (ast_strlen_zero(name)) {
return 1;
}
- if (ast_strlen_zero(name)) {
+ cdr = cdr_object_get_by_name(channel_name);
+ if (!cdr) {
+ ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
return 1;
}
@@ -3141,18 +3133,20 @@ int ast_cdr_getvar(const char *channel_name, const char *name, char *value, size
ao2_unlock(cdr);
+ ao2_cleanup(cdr);
return 0;
}
int ast_cdr_serialize_variables(const char *channel_name, struct ast_str **buf, char delim, char sep)
{
- RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
+ struct cdr_object *cdr;
struct cdr_object *it_cdr;
struct ast_var_t *variable;
const char *var;
char workspace[256];
int total = 0, x = 0, i;
+ cdr = cdr_object_get_by_name(channel_name);
if (!cdr) {
RAII_VAR(struct module_config *, mod_cfg,
ao2_global_obj_ref(module_configs), ao2_cleanup);
@@ -3168,8 +3162,9 @@ int ast_cdr_serialize_variables(const char *channel_name, struct ast_str **buf,
ao2_lock(cdr);
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
- if (++x > 1)
+ if (++x > 1) {
ast_str_append(buf, 0, "\n");
+ }
AST_LIST_TRAVERSE(&it_cdr->party_a.variables, variable, entries) {
if (!(var = ast_var_name(variable))) {
@@ -3200,6 +3195,7 @@ int ast_cdr_serialize_variables(const char *channel_name, struct ast_str **buf,
}
}
ao2_unlock(cdr);
+ ao2_cleanup(cdr);
return total;
}
@@ -3252,6 +3248,7 @@ static int cdr_object_update_party_b_userfield_cb(void *obj, void *arg, int flag
struct cdr_object *cdr = obj;
struct party_b_userfield_update *info = arg;
struct cdr_object *it_cdr;
+
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) {
continue;
@@ -3266,7 +3263,7 @@ static int cdr_object_update_party_b_userfield_cb(void *obj, void *arg, int flag
void ast_cdr_setuserfield(const char *channel_name, const char *userfield)
{
- RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
+ struct cdr_object *cdr;
struct party_b_userfield_update party_b_info = {
.channel_name = channel_name,
.userfield = userfield,
@@ -3274,6 +3271,7 @@ void ast_cdr_setuserfield(const char *channel_name, const char *userfield)
struct cdr_object *it_cdr;
/* Handle Party A */
+ cdr = cdr_object_get_by_name(channel_name);
if (cdr) {
ao2_lock(cdr);
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
@@ -3290,6 +3288,7 @@ void ast_cdr_setuserfield(const char *channel_name, const char *userfield)
cdr_object_update_party_b_userfield_cb,
&party_b_info);
+ ao2_cleanup(cdr);
}
static void post_cdr(struct ast_cdr *cdr)
@@ -3328,9 +3327,10 @@ static void post_cdr(struct ast_cdr *cdr)
int ast_cdr_set_property(const char *channel_name, enum ast_cdr_options option)
{
- RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
+ struct cdr_object *cdr;
struct cdr_object *it_cdr;
+ cdr = cdr_object_get_by_name(channel_name);
if (!cdr) {
return -1;
}
@@ -3348,14 +3348,16 @@ int ast_cdr_set_property(const char *channel_name, enum ast_cdr_options option)
}
ao2_unlock(cdr);
+ ao2_cleanup(cdr);
return 0;
}
int ast_cdr_clear_property(const char *channel_name, enum ast_cdr_options option)
{
- RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
+ struct cdr_object *cdr;
struct cdr_object *it_cdr;
+ cdr = cdr_object_get_by_name(channel_name);
if (!cdr) {
return -1;
}
@@ -3369,15 +3371,17 @@ int ast_cdr_clear_property(const char *channel_name, enum ast_cdr_options option
}
ao2_unlock(cdr);
+ ao2_cleanup(cdr);
return 0;
}
int ast_cdr_reset(const char *channel_name, int keep_variables)
{
- RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
+ struct cdr_object *cdr;
struct ast_var_t *vardata;
struct cdr_object *it_cdr;
+ cdr = cdr_object_get_by_name(channel_name);
if (!cdr) {
return -1;
}
@@ -3405,6 +3409,7 @@ int ast_cdr_reset(const char *channel_name, int keep_variables)
}
ao2_unlock(cdr);
+ ao2_cleanup(cdr);
return 0;
}
@@ -3814,7 +3819,7 @@ static void cli_show_channel(struct ast_cli_args *a)
char answer_time_buffer[64];
char end_time_buffer[64];
const char *channel_name = a->argv[3];
- RAII_VAR(struct cdr_object *, cdr, NULL, ao2_cleanup);
+ struct cdr_object *cdr;
#define TITLE_STRING "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"
#define FORMAT_STRING "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
@@ -3833,6 +3838,7 @@ static void cli_show_channel(struct ast_cli_args *a)
ao2_lock(cdr);
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
struct timeval end;
+
if (snapshot_is_dialed(it_cdr->party_a.snapshot)) {
continue;
}
@@ -3858,6 +3864,9 @@ static void cli_show_channel(struct ast_cli_args *a)
(long)ast_tvdiff_ms(end, it_cdr->start) / 1000);
}
ao2_unlock(cdr);
+
+ ao2_cleanup(cdr);
+
#undef FORMAT_STRING
#undef TITLE_STRING
}
@@ -4249,8 +4258,8 @@ int ast_cdr_engine_init(void)
stasis_message_router_add(stasis_router, ast_parked_call_type(), handle_parked_call_message, NULL);
stasis_message_router_add(stasis_router, cdr_sync_message_type(), handle_cdr_sync_message, NULL);
- active_cdrs_by_channel = ao2_container_alloc(NUM_CDR_BUCKETS,
- cdr_object_channel_hash_fn, cdr_object_channel_cmp_fn);
+ active_cdrs_by_channel = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+ NUM_CDR_BUCKETS, cdr_object_channel_hash_fn, NULL, cdr_object_channel_cmp_fn);
if (!active_cdrs_by_channel) {
return -1;
}
@@ -4272,8 +4281,6 @@ int ast_cdr_engine_init(void)
void ast_cdr_engine_term(void)
{
RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
- RAII_VAR(void *, payload, NULL, ao2_cleanup);
- RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
/* Since this is called explicitly during process shutdown, we might not have ever
* been initialized. If so, the config object will be NULL.
@@ -4283,9 +4290,16 @@ void ast_cdr_engine_term(void)
}
if (cdr_sync_message_type()) {
+ void *payload;
+ struct stasis_message *message;
+
+ if (!stasis_router) {
+ return;
+ }
+
/* Make sure we have the needed items */
payload = ao2_alloc(sizeof(*payload), NULL);
- if (!stasis_router || !payload) {
+ if (!payload) {
return;
}
@@ -4295,6 +4309,8 @@ void ast_cdr_engine_term(void)
if (message) {
stasis_message_router_publish_sync(stasis_router, message);
}
+ ao2_cleanup(message);
+ ao2_cleanup(payload);
}
if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
@@ -4307,7 +4323,7 @@ int ast_cdr_engine_reload(void)
RAII_VAR(struct module_config *, old_mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
RAII_VAR(struct module_config *, mod_cfg, NULL, ao2_cleanup);
- if (process_config(1)) {
+ if (!old_mod_cfg || process_config(1)) {
return -1;
}
@@ -4323,5 +4339,3 @@ int ast_cdr_engine_reload(void)
return cdr_toggle_runtime_options();
}
-
-
diff --git a/main/tcptls.c b/main/tcptls.c
index 0d172f149..e237dc7bb 100644
--- a/main/tcptls.c
+++ b/main/tcptls.c
@@ -1147,7 +1147,8 @@ struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_s
/* if a local address was specified, bind to it so the connection will
originate from the desired address */
- if (!ast_sockaddr_isnull(&desc->local_address)) {
+ if (!ast_sockaddr_isnull(&desc->local_address) &&
+ !ast_sockaddr_is_any(&desc->local_address)) {
setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
if (ast_bind(desc->accept_fd, &desc->local_address)) {
ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n",
diff --git a/res/res_ari.c b/res/res_ari.c
index c6fbc6c50..d99150b7a 100644
--- a/res/res_ari.c
+++ b/res/res_ari.c
@@ -886,7 +886,7 @@ static int ast_ari_callback(struct ast_tcptls_session_instance *ser,
RAII_VAR(struct ast_variable *, post_vars, NULL, ast_variables_destroy);
struct ast_variable *var;
const char *app_name = NULL;
- RAII_VAR(struct ast_json *, body, ast_json_null(), ast_json_free);
+ RAII_VAR(struct ast_json *, body, ast_json_null(), ast_json_unref);
int debug_app = 0;
if (!response_body) {
diff --git a/res/res_pjproject.c b/res/res_pjproject.c
index 2566baf78..93694fae1 100644
--- a/res/res_pjproject.c
+++ b/res/res_pjproject.c
@@ -546,7 +546,7 @@ static int unload_module(void)
pj_log_set_log_func(log_cb_orig);
pj_log_set_decor(decor_orig);
- AST_VECTOR_REMOVE_CMP_UNORDERED(&buildopts, NULL, NOT_EQUALS, ast_free);
+ AST_VECTOR_CALLBACK_VOID(&buildopts, ast_free);
AST_VECTOR_FREE(&buildopts);
ast_debug(3, "Stopped PJPROJECT logging to Asterisk logger\n");
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index 4d5c5cb83..9e436ae3c 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -1411,6 +1411,18 @@
It only limits contacts added through external interaction, such as
registration.
</para>
+ <note><para>The <replaceable>rewrite_contact</replaceable> option
+ registers the source address as the contact address to help with
+ NAT and reusing connection oriented transports such as TCP and
+ TLS. Unfortunately, refreshing a registration may register a
+ different contact address and exceed
+ <replaceable>max_contacts</replaceable>. The
+ <replaceable>remove_existing</replaceable> option can help by
+ removing the soonest to expire contact(s) over
+ <replaceable>max_contacts</replaceable> which is likely the
+ old <replaceable>rewrite_contact</replaceable> contact source
+ address being refreshed.
+ </para></note>
<note><para>This should be set to <literal>1</literal> and
<replaceable>remove_existing</replaceable> set to <literal>yes</literal> if you
wish to stick with the older <literal>chan_sip</literal> behaviour.
@@ -1420,15 +1432,29 @@
<configOption name="minimum_expiration" default="60">
<synopsis>Minimum keep alive time for an AoR</synopsis>
<description><para>
- Minimum time to keep a peer with an explict expiration. Time in seconds.
+ Minimum time to keep a peer with an explicit expiration. Time in seconds.
</para></description>
</configOption>
<configOption name="remove_existing" default="no">
<synopsis>Determines whether new contacts replace existing ones.</synopsis>
<description><para>
- On receiving a new registration to the AoR should it remove
- the existing contact that was registered against it?
+ On receiving a new registration to the AoR should it remove enough
+ existing contacts not added or updated by the registration to
+ satisfy <replaceable>max_contacts</replaceable>? Any removed
+ contacts will expire the soonest.
</para>
+ <note><para>The <replaceable>rewrite_contact</replaceable> option
+ registers the source address as the contact address to help with
+ NAT and reusing connection oriented transports such as TCP and
+ TLS. Unfortunately, refreshing a registration may register a
+ different contact address and exceed
+ <replaceable>max_contacts</replaceable>. The
+ <replaceable>remove_existing</replaceable> option can help by
+ removing the soonest to expire contact(s) over
+ <replaceable>max_contacts</replaceable> which is likely the
+ old <replaceable>rewrite_contact</replaceable> contact source
+ address being refreshed.
+ </para></note>
<note><para>This should be set to <literal>yes</literal> and
<replaceable>max_contacts</replaceable> set to <literal>1</literal> if you
wish to stick with the older <literal>chan_sip</literal> behaviour.
@@ -3476,7 +3502,7 @@ int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg,
AST_RWLIST_HEAD_STATIC(supplements, ast_sip_supplement);
-int ast_sip_register_supplement(struct ast_sip_supplement *supplement)
+void internal_sip_register_supplement(struct ast_sip_supplement *supplement)
{
struct ast_sip_supplement *iter;
int inserted = 0;
@@ -3494,22 +3520,39 @@ int ast_sip_register_supplement(struct ast_sip_supplement *supplement)
if (!inserted) {
AST_RWLIST_INSERT_TAIL(&supplements, supplement, next);
}
+}
+
+int ast_sip_register_supplement(struct ast_sip_supplement *supplement)
+{
+ internal_sip_register_supplement(supplement);
ast_module_ref(ast_module_info->self);
+
return 0;
}
-void ast_sip_unregister_supplement(struct ast_sip_supplement *supplement)
+int internal_sip_unregister_supplement(struct ast_sip_supplement *supplement)
{
struct ast_sip_supplement *iter;
SCOPED_LOCK(lock, &supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
+ int res = -1;
+
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&supplements, iter, next) {
if (supplement == iter) {
AST_RWLIST_REMOVE_CURRENT(next);
- ast_module_unref(ast_module_info->self);
+ res = 0;
break;
}
}
AST_RWLIST_TRAVERSE_SAFE_END;
+
+ return res;
+}
+
+void ast_sip_unregister_supplement(struct ast_sip_supplement *supplement)
+{
+ if (!internal_sip_unregister_supplement(supplement)) {
+ ast_module_unref(ast_module_info->self);
+ }
}
static int send_in_dialog_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg)
diff --git a/res/res_pjsip/include/res_pjsip_private.h b/res/res_pjsip/include/res_pjsip_private.h
index 9fd7aed97..5ce3c6faf 100644
--- a/res/res_pjsip/include/res_pjsip_private.h
+++ b/res/res_pjsip/include/res_pjsip_private.h
@@ -328,6 +328,18 @@ int internal_sip_unregister_service(pjsip_module *module);
/*!
* \internal
+ * \brief Used by res_pjsip.so to register a supplement without adding a self reference
+ */
+void internal_sip_register_supplement(struct ast_sip_supplement *supplement);
+
+/*!
+ * \internal
+ * \brief Used by res_pjsip.so to unregister a supplement without removing a self reference
+ */
+int internal_sip_unregister_supplement(struct ast_sip_supplement *supplement);
+
+/*!
+ * \internal
* \brief Used by res_pjsip.so to register an endpoint formatter without adding a self reference
*/
void internal_sip_register_endpoint_formatter(struct ast_sip_endpoint_formatter *obj);
@@ -338,6 +350,20 @@ void internal_sip_register_endpoint_formatter(struct ast_sip_endpoint_formatter
*/
int internal_sip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter *obj);
+struct ast_sip_session_supplement;
+
+/*!
+ * \internal
+ * \brief Used by res_pjsip.so to register a session supplement without adding a self reference
+ */
+void internal_sip_session_register_supplement(struct ast_sip_session_supplement *supplement);
+
+/*!
+ * \internal
+ * \brief Used by res_pjsip.so to unregister a session supplement without removing a self reference
+ */
+int internal_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement);
+
/*!
* \internal
* \brief Finds or creates contact_status for a contact
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index 437476631..a39102305 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -1314,6 +1314,14 @@ static struct ast_endpoint *persistent_endpoint_find_or_create(const struct ast_
ast_endpoint_set_state(persistent->endpoint, AST_ENDPOINT_OFFLINE);
ao2_link_flags(persistent_endpoints, persistent, OBJ_NOLOCK);
+ } else if (strcmp(persistent->aors, endpoint->aors)) {
+ char *new_aors = ast_strdup(endpoint->aors);
+
+ /* make sure we don't NULL persistent->aors if allocation fails. */
+ if (new_aors) {
+ ast_free(persistent->aors);
+ persistent->aors = new_aors;
+ }
}
ao2_ref(persistent->endpoint, +1);
@@ -1790,20 +1798,12 @@ static struct ast_cli_entry cli_commands[] = {
struct ast_sip_cli_formatter_entry *channel_formatter;
struct ast_sip_cli_formatter_entry *endpoint_formatter;
-static int on_load_endpoint(void *obj, void *arg, int flags)
-{
- return sip_endpoint_apply_handler(sip_sorcery, obj);
-}
-
static void load_all_endpoints(void)
{
struct ao2_container *endpoints;
endpoints = ast_sorcery_retrieve_by_fields(sip_sorcery, "endpoint", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
- if (endpoints) {
- ao2_callback(endpoints, OBJ_NODATA, on_load_endpoint, NULL);
- ao2_ref(endpoints, -1);
- }
+ ao2_cleanup(endpoints);
}
int ast_res_pjsip_initialize_configuration(void)
diff --git a/res/res_pjsip/pjsip_message_filter.c b/res/res_pjsip/pjsip_message_filter.c
index d2f9b9562..978aeb070 100644
--- a/res/res_pjsip/pjsip_message_filter.c
+++ b/res/res_pjsip/pjsip_message_filter.c
@@ -505,32 +505,24 @@ static pj_bool_t filter_on_rx_message(pjsip_rx_data *rdata)
void ast_res_pjsip_cleanup_message_filter(void)
{
- ast_sip_unregister_service(&filter_module_tsx);
- ast_sip_unregister_service(&filter_module_transport);
- ast_sip_unregister_supplement(&filter_supplement);
- ast_sip_session_unregister_supplement(&filter_session_supplement);
+ internal_sip_unregister_service(&filter_module_tsx);
+ internal_sip_unregister_service(&filter_module_transport);
+ internal_sip_unregister_supplement(&filter_supplement);
+ internal_sip_session_unregister_supplement(&filter_session_supplement);
}
int ast_res_pjsip_init_message_filter(void)
{
- if (ast_sip_session_register_supplement(&filter_session_supplement)) {
- ast_log(LOG_ERROR, "Could not register message filter session supplement for outgoing requests\n");
- return -1;
- }
-
- if (ast_sip_register_supplement(&filter_supplement)) {
- ast_log(LOG_ERROR, "Could not register message filter supplement for outgoing requests\n");
- ast_res_pjsip_cleanup_message_filter();
- return -1;
- }
+ internal_sip_session_register_supplement(&filter_session_supplement);
+ internal_sip_register_supplement(&filter_supplement);
- if (ast_sip_register_service(&filter_module_transport)) {
+ if (internal_sip_register_service(&filter_module_transport)) {
ast_log(LOG_ERROR, "Could not register message filter module for incoming and outgoing requests\n");
ast_res_pjsip_cleanup_message_filter();
return -1;
}
- if (ast_sip_register_service(&filter_module_tsx)) {
+ if (internal_sip_register_service(&filter_module_tsx)) {
ast_log(LOG_ERROR, "Could not register message filter module for incoming and outgoing requests\n");
ast_res_pjsip_cleanup_message_filter();
return -1;
diff --git a/res/res_pjsip/pjsip_session.c b/res/res_pjsip/pjsip_session.c
new file mode 100644
index 000000000..cea72436a
--- /dev/null
+++ b/res/res_pjsip/pjsip_session.c
@@ -0,0 +1,121 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2017, CFWare, LLC
+ *
+ * Corey Farrell <git@cfware.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.
+ */
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+#include <pjsip_ua.h>
+#include <pjlib.h>
+
+#include "asterisk/res_pjsip.h"
+#include "asterisk/res_pjsip_session.h"
+#include "include/res_pjsip_private.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/lock.h"
+#include "asterisk/module.h"
+
+
+AST_RWLIST_HEAD_STATIC(session_supplements, ast_sip_session_supplement);
+
+void internal_sip_session_register_supplement(struct ast_sip_session_supplement *supplement)
+{
+ struct ast_sip_session_supplement *iter;
+ int inserted = 0;
+ SCOPED_LOCK(lock, &session_supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
+
+ if (!supplement->response_priority) {
+ supplement->response_priority = AST_SIP_SESSION_BEFORE_MEDIA;
+ }
+
+ AST_RWLIST_TRAVERSE_SAFE_BEGIN(&session_supplements, iter, next) {
+ if (iter->priority > supplement->priority) {
+ AST_RWLIST_INSERT_BEFORE_CURRENT(supplement, next);
+ inserted = 1;
+ break;
+ }
+ }
+ AST_RWLIST_TRAVERSE_SAFE_END;
+
+ if (!inserted) {
+ AST_RWLIST_INSERT_TAIL(&session_supplements, supplement, next);
+ }
+}
+
+int ast_sip_session_register_supplement(struct ast_sip_session_supplement *supplement)
+{
+ internal_sip_session_register_supplement(supplement);
+ ast_module_ref(AST_MODULE_SELF);
+
+ return 0;
+}
+
+int internal_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement)
+{
+ struct ast_sip_session_supplement *iter;
+ int res = -1;
+ SCOPED_LOCK(lock, &session_supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
+
+ AST_RWLIST_TRAVERSE_SAFE_BEGIN(&session_supplements, iter, next) {
+ if (supplement == iter) {
+ AST_RWLIST_REMOVE_CURRENT(next);
+ res = 0;
+ break;
+ }
+ }
+ AST_RWLIST_TRAVERSE_SAFE_END;
+
+ return res;
+}
+
+void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement)
+{
+ if (!internal_sip_session_unregister_supplement(supplement)) {
+ ast_module_unref(AST_MODULE_SELF);
+ }
+}
+
+static struct ast_sip_session_supplement *supplement_dup(const struct ast_sip_session_supplement *src)
+{
+ struct ast_sip_session_supplement *dst = ast_calloc(1, sizeof(*dst));
+
+ if (!dst) {
+ return NULL;
+ }
+ /* Will need to revisit if shallow copy becomes an issue */
+ *dst = *src;
+
+ return dst;
+}
+
+int ast_sip_session_add_supplements(struct ast_sip_session *session)
+{
+ struct ast_sip_session_supplement *iter;
+ SCOPED_LOCK(lock, &session_supplements, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
+
+ AST_RWLIST_TRAVERSE(&session_supplements, iter, next) {
+ struct ast_sip_session_supplement *copy = supplement_dup(iter);
+
+ if (!copy) {
+ return -1;
+ }
+ AST_LIST_INSERT_TAIL(&session->supplements, copy, next);
+ }
+
+ return 0;
+}
+
diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c
index ba1c074b3..32906011a 100644
--- a/res/res_pjsip_registrar.c
+++ b/res/res_pjsip_registrar.c
@@ -129,7 +129,8 @@ static int registrar_find_contact(void *obj, void *arg, int flags)
/*! \brief Internal function which validates provided Contact headers to confirm that they are acceptable, and returns number of contacts */
static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_container *contacts, struct ast_sip_aor *aor, int *added, int *updated, int *deleted)
{
- pjsip_contact_hdr *previous = NULL, *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
+ pjsip_contact_hdr *previous = NULL;
+ pjsip_contact_hdr *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
struct registrar_contact_details details = {
.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256),
};
@@ -140,15 +141,18 @@ static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_co
while ((contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next))) {
int expiration = registrar_get_expiration(aor, contact, rdata);
- RAII_VAR(struct ast_sip_contact *, existing, NULL, ao2_cleanup);
+ struct ast_sip_contact *existing;
char contact_uri[pjsip_max_url_size];
if (contact->star) {
/* The expiration MUST be 0 when a '*' contact is used and there must be no other contact */
- if ((expiration != 0) || previous) {
+ if (expiration != 0 || previous) {
pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
return -1;
}
+ /* Count all contacts to delete */
+ *deleted = ao2_container_count(contacts);
+ previous = contact;
continue;
} else if (previous && previous->star) {
/* If there is a previous contact and it is a '*' this is a deal breaker */
@@ -177,14 +181,16 @@ static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_co
}
/* Determine if this is an add, update, or delete for policy enforcement purposes */
- if (!(existing = ao2_callback(contacts, 0, registrar_find_contact, &details))) {
+ existing = ao2_callback(contacts, 0, registrar_find_contact, &details);
+ ao2_cleanup(existing);
+ if (!existing) {
if (expiration) {
- (*added)++;
+ ++*added;
}
} else if (expiration) {
- (*updated)++;
+ ++*updated;
} else {
- (*deleted)++;
+ ++*deleted;
}
}
@@ -219,7 +225,7 @@ static int registrar_delete_contact(void *obj, void *arg, int flags)
contact->user_agent);
}
- return 0;
+ return CMP_MATCH;
}
/*! \brief Internal function which adds a contact to a response */
@@ -351,6 +357,96 @@ static void register_contact_transport_shutdown_cb(void *data)
ao2_ref(aor, -1);
}
+AST_VECTOR(excess_contact_vector, struct ast_sip_contact *);
+
+static int vec_contact_cmp(struct ast_sip_contact *left, struct ast_sip_contact *right)
+{
+ struct ast_sip_contact *left_contact = left;
+ struct ast_sip_contact *right_contact = right;
+
+ /* Sort from soonest to expire to last to expire */
+ return ast_tvcmp(left_contact->expiration_time, right_contact->expiration_time);
+}
+
+static int vec_contact_add(void *obj, void *arg, int flags)
+{
+ struct ast_sip_contact *contact = obj;
+ struct excess_contact_vector *contact_vec = arg;
+
+ /*
+ * Performance wise, an insertion sort is fine because we
+ * shouldn't need to remove more than a handful of contacts.
+ * I expect we'll typically be removing only one contact.
+ */
+ AST_VECTOR_ADD_SORTED(contact_vec, contact, vec_contact_cmp);
+ if (AST_VECTOR_SIZE(contact_vec) == AST_VECTOR_MAX_SIZE(contact_vec)) {
+ /*
+ * We added a contact over the number we need to remove.
+ * Remove the longest to expire contact from the vector
+ * which is the last element in the vector. It may be
+ * the one we just added or the one we just added pushed
+ * out an earlier contact from removal consideration.
+ */
+ --AST_VECTOR_SIZE(contact_vec);
+ }
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Remove excess existing contacts that expire the soonest.
+ * \since 13.18.0
+ *
+ * \param contacts Container of unmodified contacts that could remove.
+ * \param to_remove Maximum number of contacts to remove.
+ *
+ * \return Nothing
+ */
+static void remove_excess_contacts(struct ao2_container *contacts, unsigned int to_remove)
+{
+ struct excess_contact_vector contact_vec;
+
+ /*
+ * Create a sorted vector to hold the to_remove soonest to
+ * expire contacts. The vector has an extra space to
+ * temporarily hold the longest to expire contact that we
+ * won't remove.
+ */
+ if (AST_VECTOR_INIT(&contact_vec, to_remove + 1)) {
+ return;
+ }
+ ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, vec_contact_add, &contact_vec);
+
+ /*
+ * The vector should always be populated with the number
+ * of contacts we need to remove. Just in case, we will
+ * remove all contacts in the vector even if the contacts
+ * container had fewer contacts than there should be.
+ */
+ ast_assert(AST_VECTOR_SIZE(&contact_vec) == to_remove);
+ to_remove = AST_VECTOR_SIZE(&contact_vec);
+
+ /* Remove the excess contacts that expire the soonest */
+ while (to_remove--) {
+ struct ast_sip_contact *contact;
+
+ contact = AST_VECTOR_GET(&contact_vec, to_remove);
+
+ ast_sip_location_delete_contact(contact);
+ ast_verb(3, "Removed contact '%s' from AOR '%s' due to remove_existing\n",
+ contact->uri, contact->aor);
+ ast_test_suite_event_notify("AOR_CONTACT_REMOVED",
+ "Contact: %s\r\n"
+ "AOR: %s\r\n"
+ "UserAgent: %s",
+ contact->uri,
+ contact->aor,
+ contact->user_agent);
+ }
+
+ AST_VECTOR_FREE(&contact_vec);
+}
+
static int register_aor_core(pjsip_rx_data *rdata,
struct ast_sip_endpoint *endpoint,
struct ast_sip_aor *aor,
@@ -359,7 +455,10 @@ static int register_aor_core(pjsip_rx_data *rdata,
{
static const pj_str_t USER_AGENT = { "User-Agent", 10 };
- int added = 0, updated = 0, deleted = 0;
+ int added = 0;
+ int updated = 0;
+ int deleted = 0;
+ int contact_count;
pjsip_contact_hdr *contact_hdr = NULL;
struct registrar_contact_details details = { 0, };
pjsip_tx_data *tdata;
@@ -396,7 +495,14 @@ static int register_aor_core(pjsip_rx_data *rdata,
return PJ_TRUE;
}
- if ((MAX(added - deleted, 0) + (!aor->remove_existing ? ao2_container_count(contacts) : 0)) > aor->max_contacts) {
+ if (aor->remove_existing) {
+ /* Cumulative number of contacts affected by this registration */
+ contact_count = MAX(updated + added - deleted, 0);
+ } else {
+ /* Total contacts after this registration */
+ contact_count = ao2_container_count(contacts) + added - deleted;
+ }
+ if (contact_count > aor->max_contacts) {
/* Enforce the maximum number of contacts */
pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_exceeds_maximum_configured_contacts");
@@ -405,7 +511,9 @@ static int register_aor_core(pjsip_rx_data *rdata,
return PJ_TRUE;
}
- if (!(details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256))) {
+ details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
+ "Contact Comparison", 256, 256);
+ if (!details.pool) {
pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
return PJ_TRUE;
}
@@ -446,7 +554,8 @@ static int register_aor_core(pjsip_rx_data *rdata,
if (contact_hdr->star) {
/* A star means to unregister everything, so do so for the possible contacts */
- ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, (void *)aor_name);
+ ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE,
+ registrar_delete_contact, (void *)aor_name);
break;
}
@@ -459,7 +568,8 @@ static int register_aor_core(pjsip_rx_data *rdata,
details.uri = pjsip_uri_get_uri(contact_hdr->uri);
pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri));
- if (!(contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details))) {
+ contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details);
+ if (!contact) {
int prune_on_boot = 0;
pj_str_t host_name;
@@ -600,15 +710,29 @@ static int register_aor_core(pjsip_rx_data *rdata,
pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
- /* If the AOR is configured to remove any existing contacts that have not been updated/added as a result of this REGISTER
- * do so
+ /*
+ * If the AOR is configured to remove any contacts over max_contacts
+ * that have not been updated/added/deleted as a result of this
+ * REGISTER do so.
+ *
+ * The contacts container currently holds the existing contacts that
+ * were not affected by this REGISTER.
*/
if (aor->remove_existing) {
- ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, NULL);
+ /* Total contacts after this registration */
+ contact_count = ao2_container_count(contacts) + updated + added;
+ if (contact_count > aor->max_contacts) {
+ /* Remove excess existing contacts that expire the soonest */
+ remove_excess_contacts(contacts, contact_count - aor->max_contacts);
+ }
}
/* Re-retrieve contacts. Caller will clean up the original container. */
contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor);
+ if (!contacts) {
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
+ return PJ_TRUE;
+ }
response_contact = ao2_callback(contacts, 0, NULL, NULL);
/* Send a response containing all of the contacts (including static) that are present on this AOR */
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index 496c4763a..f84d60e14 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -396,59 +396,6 @@ static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_
return -1;
}
-AST_RWLIST_HEAD_STATIC(session_supplements, ast_sip_session_supplement);
-
-int ast_sip_session_register_supplement(struct ast_sip_session_supplement *supplement)
-{
- struct ast_sip_session_supplement *iter;
- int inserted = 0;
- SCOPED_LOCK(lock, &session_supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
-
- if (!supplement->response_priority) {
- supplement->response_priority = AST_SIP_SESSION_BEFORE_MEDIA;
- }
-
- AST_RWLIST_TRAVERSE_SAFE_BEGIN(&session_supplements, iter, next) {
- if (iter->priority > supplement->priority) {
- AST_RWLIST_INSERT_BEFORE_CURRENT(supplement, next);
- inserted = 1;
- break;
- }
- }
- AST_RWLIST_TRAVERSE_SAFE_END;
-
- if (!inserted) {
- AST_RWLIST_INSERT_TAIL(&session_supplements, supplement, next);
- }
- ast_module_ref(ast_module_info->self);
- return 0;
-}
-
-void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement)
-{
- struct ast_sip_session_supplement *iter;
- SCOPED_LOCK(lock, &session_supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
- AST_RWLIST_TRAVERSE_SAFE_BEGIN(&session_supplements, iter, next) {
- if (supplement == iter) {
- AST_RWLIST_REMOVE_CURRENT(next);
- ast_module_unref(ast_module_info->self);
- break;
- }
- }
- AST_RWLIST_TRAVERSE_SAFE_END;
-}
-
-static struct ast_sip_session_supplement *supplement_dup(const struct ast_sip_session_supplement *src)
-{
- struct ast_sip_session_supplement *dst = ast_calloc(1, sizeof(*dst));
- if (!dst) {
- return NULL;
- }
- /* Will need to revisit if shallow copy becomes an issue */
- *dst = *src;
- return dst;
-}
-
#define DATASTORE_BUCKETS 53
#define MEDIA_BUCKETS 7
@@ -1380,21 +1327,6 @@ static void session_destructor(void *obj)
ast_test_suite_event_notify("SESSION_DESTROYED", "Endpoint: %s", endpoint_name);
}
-static int add_supplements(struct ast_sip_session *session)
-{
- struct ast_sip_session_supplement *iter;
- SCOPED_LOCK(lock, &session_supplements, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
-
- AST_RWLIST_TRAVERSE(&session_supplements, iter, next) {
- struct ast_sip_session_supplement *copy = supplement_dup(iter);
- if (!copy) {
- return -1;
- }
- AST_LIST_INSERT_TAIL(&session->supplements, copy, next);
- }
- return 0;
-}
-
static int add_session_media(void *obj, void *arg, int flags)
{
struct sdp_handler_list *handler_list = obj;
@@ -1523,7 +1455,7 @@ struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint,
session->dtmf = endpoint->dtmf;
- if (add_supplements(session)) {
+ if (ast_sip_session_add_supplements(session)) {
/* Release the ref held by session->inv_session */
ao2_ref(session, -1);
return NULL;