summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES5
-rw-r--r--configs/samples/asterisk.conf.sample4
-rw-r--r--configs/samples/musiconhold.conf.sample6
-rw-r--r--include/asterisk/manager.h2
-rw-r--r--include/asterisk/options.h1
-rw-r--r--main/asterisk.c5
-rw-r--r--main/audiohook.c2
-rw-r--r--main/cdr.c4
-rw-r--r--main/rtp_engine.c267
-rw-r--r--makeopts.in2
-rw-r--r--res/res_pjsip_sdp_rtp.c4
-rw-r--r--res/res_xmpp.c157
-rw-r--r--third-party/pjproject/Makefile4
13 files changed, 286 insertions, 177 deletions
diff --git a/CHANGES b/CHANGES
index 5720883ab..5d14c97d1 100644
--- a/CHANGES
+++ b/CHANGES
@@ -62,6 +62,11 @@ RTP
when you use more than 32 formats and calls are not accepted by a remote
implementation, please report this and go back to rtp_pt_dynamic = 96.
+ * A new setting, "rtp_use_dynamic", has been added in asterisk.conf". When set
+ to "yes" RTP dynamic payload types are assigned dynamically per RTP instance.
+ When set to "no" RTP dynamic payload types are globally initialized to pre-
+ designated numbers and function similar to static payload types.
+
app_originate
------------------
* Added support to gosub predial routines on both original channel and on the
diff --git a/configs/samples/asterisk.conf.sample b/configs/samples/asterisk.conf.sample
index e13a944b0..30934e4a9 100644
--- a/configs/samples/asterisk.conf.sample
+++ b/configs/samples/asterisk.conf.sample
@@ -97,6 +97,10 @@ documentation_language = en_US ; Set the language you want documentation
; This is currently is used by DUNDi and
; Exchanging Device and Mailbox State
; using protocols: XMPP, Corosync and PJSIP.
+;rtp_use_dynamic = yes ; When set to "yes" RTP dynamic payload types
+ ; are assigned dynamically per RTP instance vs.
+ ; allowing Asterisk to globally initialize them
+ ; to pre-designated numbers (defaults to "yes").
;rtp_pt_dynamic = 35 ; Normally the Dynamic RTP Payload Type numbers
; are 96-127, which allow just 32 formats. The
; starting point 35 enables the range 35-63 and
diff --git a/configs/samples/musiconhold.conf.sample b/configs/samples/musiconhold.conf.sample
index 3df29bf69..b2980fc1d 100644
--- a/configs/samples/musiconhold.conf.sample
+++ b/configs/samples/musiconhold.conf.sample
@@ -85,7 +85,11 @@ directory=moh
;[ulawstream]
;mode=custom
;application=/usr/bin/streamplayer 192.168.100.52 888
-;format=ulaw
+;format=ulaw ; The 'format' option specifies the audio format that the
+; ; 'application' will provide to Asterisk. In this example,
+; ; streamplayer will output ulaw samples so we need to set the
+; ; format to ulaw so that Asterisk knows how to interpret the
+; ; incoming audio.
; mpg123 on Solaris does not always exit properly; madplay may be a better
; choice
diff --git a/include/asterisk/manager.h b/include/asterisk/manager.h
index 60c51de85..3de7b1d17 100644
--- a/include/asterisk/manager.h
+++ b/include/asterisk/manager.h
@@ -54,7 +54,7 @@
- \ref manager.c Main manager code file
*/
-#define AMI_VERSION "3.1.0"
+#define AMI_VERSION "3.2.0"
#define DEFAULT_MANAGER_PORT 5038 /* Default port for Asterisk management via TCP */
#define DEFAULT_MANAGER_TLS_PORT 5039 /* Default port for Asterisk management via TCP */
diff --git a/include/asterisk/options.h b/include/asterisk/options.h
index 05ad6c560..0a20f10a8 100644
--- a/include/asterisk/options.h
+++ b/include/asterisk/options.h
@@ -196,6 +196,7 @@ extern int dahdi_chan_name_len;
extern int ast_language_is_prefix;
+extern int ast_option_rtpusedynamic;
extern unsigned int ast_option_rtpptdynamic;
#if defined(__cplusplus) || defined(c_plusplus)
diff --git a/main/asterisk.c b/main/asterisk.c
index 69183c1f3..68859ab2f 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -339,6 +339,7 @@ unsigned int option_dtmfminduration; /*!< Minimum duration of DTMF. */
#if defined(HAVE_SYSINFO)
long option_minmemfree; /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
#endif
+int ast_option_rtpusedynamic;
unsigned int ast_option_rtpptdynamic;
/*! @} */
@@ -602,6 +603,7 @@ static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_c
ast_cli(a->fd, " Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE) ? "Enabled" : "Disabled");
ast_cli(a->fd, " Generic PLC: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC) ? "Enabled" : "Disabled");
ast_cli(a->fd, " Min DTMF duration:: %u\n", option_dtmfminduration);
+ ast_cli(a->fd, " RTP use dynamic payloads: %u\n", ast_option_rtpusedynamic);
if (ast_option_rtpptdynamic == AST_RTP_PT_LAST_REASSIGN) {
ast_cli(a->fd, " RTP dynamic payload types: %u,%u-%u\n",
@@ -3499,6 +3501,7 @@ static void ast_readconfig(void)
/* Set default value */
option_dtmfminduration = AST_MIN_DTMF_DURATION;
+ ast_option_rtpusedynamic = 1;
ast_option_rtpptdynamic = 35;
/* init with buildtime config */
@@ -3655,6 +3658,8 @@ static void ast_readconfig(void)
if (sscanf(v->value, "%30u", &option_dtmfminduration) != 1) {
option_dtmfminduration = AST_MIN_DTMF_DURATION;
}
+ } else if (!strcasecmp(v->name, "rtp_use_dynamic")) {
+ ast_option_rtpusedynamic = ast_true(v->value);
/* http://www.iana.org/assignments/rtp-parameters
* RTP dynamic payload types start at 96 normally; extend down to 0 */
} else if (!strcasecmp(v->name, "rtp_pt_dynamic")) {
diff --git a/main/audiohook.c b/main/audiohook.c
index 836ae0496..986f11f84 100644
--- a/main/audiohook.c
+++ b/main/audiohook.c
@@ -185,7 +185,7 @@ int ast_audiohook_write_frame(struct ast_audiohook *audiohook, enum ast_audiohoo
other_factory_samples = ast_slinfactory_available(other_factory);
other_factory_ms = other_factory_samples / (audiohook->hook_internal_samp_rate / 1000);
- if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC) && other_factory_samples && (our_factory_ms - other_factory_ms > AST_AUDIOHOOK_SYNC_TOLERANCE)) {
+ if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC) && (our_factory_ms - other_factory_ms > AST_AUDIOHOOK_SYNC_TOLERANCE)) {
ast_debug(1, "Flushing audiohook %p so it remains in sync\n", audiohook);
ast_slinfactory_flush(factory);
ast_slinfactory_flush(other_factory);
diff --git a/main/cdr.c b/main/cdr.c
index 60fe977a8..363a2c6b1 100644
--- a/main/cdr.c
+++ b/main/cdr.c
@@ -3251,7 +3251,7 @@ static int cdr_object_update_party_b_userfield_cb(void *obj, void *arg, int flag
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) {
+ if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) {
continue;
}
if (it_cdr->party_b.snapshot
@@ -3275,7 +3275,7 @@ void ast_cdr_setuserfield(const char *channel_name, const char *userfield)
if (cdr) {
ao2_lock(cdr);
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
- if (it_cdr->fn_table == &finalized_state_fn_table) {
+ if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) {
continue;
}
strcpy(it_cdr->party_a.userfield, userfield);
diff --git a/main/rtp_engine.c b/main/rtp_engine.c
index 931f89d7c..00f9d595f 100644
--- a/main/rtp_engine.c
+++ b/main/rtp_engine.c
@@ -266,14 +266,28 @@ static void rtp_payload_type_dtor(void *obj)
ao2_cleanup(payload->format);
}
-struct ast_rtp_payload_type *ast_rtp_engine_alloc_payload_type(void)
+static struct ast_rtp_payload_type *rtp_payload_type_alloc(struct ast_format *format,
+ int payload, int rtp_code, int primary_mapping)
{
- struct ast_rtp_payload_type *payload;
+ struct ast_rtp_payload_type *type = ao2_alloc_options(
+ sizeof(*type), rtp_payload_type_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);
- payload = ao2_alloc_options(sizeof(*payload), rtp_payload_type_dtor,
- AO2_ALLOC_OPT_LOCK_NOLOCK);
+ if (!type) {
+ return NULL;
+ }
- return payload;
+ type->format = ao2_bump(format);
+ type->asterisk_format = type->format != NULL;
+ type->payload = payload;
+ type->rtp_code = rtp_code;
+ type->primary_mapping = primary_mapping;
+
+ return type;
+}
+
+struct ast_rtp_payload_type *ast_rtp_engine_alloc_payload_type(void)
+{
+ return rtp_payload_type_alloc(NULL, 0, 0, 0);
}
int ast_rtp_engine_register2(struct ast_rtp_engine *engine, struct ast_module *module)
@@ -1250,31 +1264,112 @@ static int find_static_payload_type(int asterisk_format, const struct ast_format
/*!
* \internal
- * \brief Find the first unused dynamic rx payload type.
- * \since 14.0.0
+ * \brief Find the first unused payload type in a given range
*
- * \param codecs Codecs structure to look in
+ * \param codecs The codec structure to look in
+ * \param start Starting index
+ * \param end Ending index
+ * \param ignore Skip these payloads types
*
- * \note It is assumed that codecs is at least read locked before calling.
+ * \note The static_RTP_PT_lock object must be locked before calling
*
* \retval Numerical payload type
* \retval -1 if not found.
*/
-static int rtp_codecs_find_empty_dynamic_rx(struct ast_rtp_codecs *codecs)
+static int find_unused_payload_in_range(const struct ast_rtp_codecs *codecs,
+ int start, int end, struct ast_rtp_payload_type *ignore[])
{
- struct ast_rtp_payload_type *type;
- int idx;
- int payload = -1;
+ int x;
- idx = AST_RTP_PT_FIRST_DYNAMIC;
- for (; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_rx); ++idx) {
- type = AST_VECTOR_GET(&codecs->payload_mapping_rx, idx);
+ for (x = start; x < end; ++x) {
+ struct ast_rtp_payload_type *type;
+
+ if (ignore[x]) {
+ continue;
+ } else if (!codecs || x >= AST_VECTOR_SIZE(&codecs->payload_mapping_rx)) {
+ return x;
+ }
+
+ type = AST_VECTOR_GET(&codecs->payload_mapping_rx, x);
if (!type) {
- payload = idx;
- break;
+ return x;
}
}
- return payload;
+ return -1;
+}
+
+/*!
+ * \internal
+ * \brief Find an unused payload type
+ *
+ * \param codecs Codecs structure to look in
+ *
+ * \note Both static_RTP_PT_lock and codecs (if given) must be at least
+ * read locked before calling.
+ *
+ * \retval Numerical payload type
+ * \retval -1 if not found.
+ */
+static int find_unused_payload(const struct ast_rtp_codecs *codecs)
+{
+ int res;
+
+ /* find next available dynamic payload slot */
+ res = find_unused_payload_in_range(
+ codecs, AST_RTP_PT_FIRST_DYNAMIC, AST_RTP_MAX_PT, static_RTP_PT);
+ if (res != -1) {
+ return res;
+ }
+
+ if (ast_option_rtpusedynamic) {
+ /*
+ * We're using default values for some dynamic types. So if an unused
+ * slot was not found try again, but this time ignore the default
+ * values declared for dynamic types (except for 101 and 121) .
+ */
+ static struct ast_rtp_payload_type *ignore[AST_RTP_MAX_PT] = {0};
+
+ ignore[101] = static_RTP_PT[101];
+ ignore[121] = static_RTP_PT[121];
+
+ res = find_unused_payload_in_range(
+ codecs, AST_RTP_PT_FIRST_DYNAMIC, AST_RTP_MAX_PT, ignore);
+ if (res != -1) {
+ return res;
+ }
+ }
+
+ /* http://www.iana.org/assignments/rtp-parameters
+ * RFC 3551, Section 3: "[...] applications which need to define more
+ * than 32 dynamic payload types MAY bind codes below 96, in which case
+ * it is RECOMMENDED that unassigned payload type numbers be used
+ * first". Updated by RFC 5761, Section 4: "[...] values in the range
+ * 64-95 MUST NOT be used [to avoid conflicts with RTCP]". Summaries:
+ * https://tools.ietf.org/html/draft-roach-mmusic-unified-plan#section-3.2.1.2
+ * https://tools.ietf.org/html/draft-wu-avtcore-dynamic-pt-usage#section-3
+ */
+ res = find_unused_payload_in_range(codecs, MAX(ast_option_rtpptdynamic, 35),
+ AST_RTP_PT_LAST_REASSIGN, static_RTP_PT);
+ if (res != -1) {
+ return res;
+ }
+
+ /* Yet, reusing mappings below 35 is not supported in Asterisk because
+ * when Compact Headers are activated, no rtpmap is send for those below
+ * 35. If you want to use 35 and below
+ * A) do not use Compact Headers,
+ * B) remove that code in chan_sip/res_pjsip, or
+ * C) add a flag that this RTP Payload Type got reassigned dynamically
+ * and requires a rtpmap even with Compact Headers enabled.
+ */
+ res = find_unused_payload_in_range(
+ codecs, MAX(ast_option_rtpptdynamic, 20), 35, static_RTP_PT);
+ if (res != -1) {
+ return res;
+ }
+
+ return find_unused_payload_in_range(
+ codecs, MAX(ast_option_rtpptdynamic, 0), 20, static_RTP_PT);
}
/*!
@@ -1331,30 +1426,26 @@ static int rtp_codecs_assign_payload_code_rx(struct ast_rtp_codecs *codecs, int
struct ast_rtp_payload_type *new_type;
payload = find_static_payload_type(asterisk_format, format, code);
- if (payload < 0) {
+
+ if (payload < 0 && (!asterisk_format || ast_option_rtpusedynamic)) {
return payload;
}
- new_type = ast_rtp_engine_alloc_payload_type();
+ new_type = rtp_payload_type_alloc(format, payload, code, 1);
if (!new_type) {
return -1;
}
- new_type->format = ao2_bump(format);
- new_type->asterisk_format = asterisk_format;
- new_type->rtp_code = code;
- new_type->payload = payload;
- new_type->primary_mapping = 1;
ast_rwlock_wrlock(&codecs->codecs_lock);
- if (payload < AST_RTP_PT_FIRST_DYNAMIC
+ if (payload > -1 && (payload < AST_RTP_PT_FIRST_DYNAMIC
|| AST_VECTOR_SIZE(&codecs->payload_mapping_rx) <= payload
- || !AST_VECTOR_GET(&codecs->payload_mapping_rx, payload)) {
+ || !AST_VECTOR_GET(&codecs->payload_mapping_rx, payload))) {
/*
* The payload type is a static assignment
* or our default dynamic position is available.
*/
- rtp_codecs_payload_replace_rx(codecs, payload, new_type);
- } else if (-1 < (payload = rtp_codecs_find_empty_dynamic_rx(codecs))
+ rtp_codecs_payload_replace_rx(codecs, payload, new_type);
+ } else if (-1 < (payload = find_unused_payload(codecs))
|| -1 < (payload = rtp_codecs_find_non_primary_dynamic_rx(codecs))) {
/*
* We found the first available empty dynamic position
@@ -1370,7 +1461,8 @@ static int rtp_codecs_assign_payload_code_rx(struct ast_rtp_codecs *codecs, int
*
* I don't think this is really possible.
*/
- ast_log(LOG_WARNING, "No dynamic RTP payload type values available!\n");
+ ast_log(LOG_WARNING, "No dynamic RTP payload type values available "
+ "for %s - %d!\n", format ? ast_format_get_name(format) : "", code);
}
ast_rwlock_unlock(&codecs->codecs_lock);
@@ -2293,95 +2385,47 @@ static void set_next_mime_type(struct ast_format *format, int rtp_code, const ch
ast_rwlock_unlock(&mime_types_lock);
}
-static void add_static_payload(int map, struct ast_format *format, int rtp_code)
+static void add_static_payload(int payload, struct ast_format *format, int rtp_code)
{
- int x;
struct ast_rtp_payload_type *type;
/*
* ARRAY_LEN's result is cast to an int so 'map' is not autocast to a size_t,
* which if negative would cause an assertion.
*/
- ast_assert(map < (int)ARRAY_LEN(static_RTP_PT));
+ ast_assert(payload < (int)ARRAY_LEN(static_RTP_PT));
+ if (ast_option_rtpusedynamic && payload < 0) {
+ /*
+ * We're going to build dynamic payloads dynamically. An RTP code is
+ * required otherwise one will be dynamically allocated per instance.
+ */
+ return;
+ }
+
+ /*
+ * Either the given payload is truly a static type, or Asterisk is
+ * globally storing the dynamic payloads in the static_RTP_PT object.
+ */
ast_rwlock_wrlock(&static_RTP_PT_lock);
- if (map < 0) {
- /* find next available dynamic payload slot */
- for (x = AST_RTP_PT_FIRST_DYNAMIC; x < AST_RTP_MAX_PT; ++x) {
- if (!static_RTP_PT[x]) {
- map = x;
- break;
- }
- }
- /* http://www.iana.org/assignments/rtp-parameters
- * RFC 3551, Section 3: "[...] applications which need to define more
- * than 32 dynamic payload types MAY bind codes below 96, in which case
- * it is RECOMMENDED that unassigned payload type numbers be used
- * first". Updated by RFC 5761, Section 4: "[...] values in the range
- * 64-95 MUST NOT be used [to avoid conflicts with RTCP]". Summaries:
- * https://tools.ietf.org/html/draft-roach-mmusic-unified-plan#section-3.2.1.2
- * https://tools.ietf.org/html/draft-wu-avtcore-dynamic-pt-usage#section-3
- */
- if (map < 0) {
- for (x = MAX(ast_option_rtpptdynamic, 35); x <= AST_RTP_PT_LAST_REASSIGN; ++x) {
- if (!static_RTP_PT[x]) {
- map = x;
- break;
- }
- }
- }
- /* Yet, reusing mappings below 35 is not supported in Asterisk because
- * when Compact Headers are activated, no rtpmap is send for those below
- * 35. If you want to use 35 and below
- * A) do not use Compact Headers,
- * B) remove that code in chan_sip/res_pjsip, or
- * C) add a flag that this RTP Payload Type got reassigned dynamically
- * and requires a rtpmap even with Compact Headers enabled.
+ if (payload < 0) {
+ /*
+ * This is a dynamic payload that will be stored globally,
+ * so find the next available empty slot.
*/
- if (map < 0) {
- for (x = MAX(ast_option_rtpptdynamic, 20); x < 35; ++x) {
- if (!static_RTP_PT[x]) {
- map = x;
- break;
- }
- }
- }
- if (map < 0) {
- for (x = MAX(ast_option_rtpptdynamic, 0); x < 20; ++x) {
- if (!static_RTP_PT[x]) {
- map = x;
- break;
- }
- }
- }
-
- if (map < 0) {
- if (format) {
- ast_log(LOG_WARNING, "No Dynamic RTP mapping available for format %s\n",
- ast_format_get_name(format));
- } else {
- ast_log(LOG_WARNING, "No Dynamic RTP mapping available for RTP code %d\n",
- rtp_code);
- }
- ast_rwlock_unlock(&static_RTP_PT_lock);
+ payload = find_unused_payload(NULL);
+ if (payload < 0) {
+ ast_log(LOG_WARNING, "No dynamic RTP payload type values available "
+ "for %s - %d!\n", format ? ast_format_get_name(format) : "", rtp_code);
return;
}
}
- type = ast_rtp_engine_alloc_payload_type();
+ type = rtp_payload_type_alloc(format, payload, rtp_code, 1);
if (type) {
- if (format) {
- ao2_ref(format, +1);
- type->format = format;
- type->asterisk_format = 1;
- } else {
- type->rtp_code = rtp_code;
- }
- type->payload = map;
- type->primary_mapping = 1;
- ao2_cleanup(static_RTP_PT[map]);
- static_RTP_PT[map] = type;
+ ao2_cleanup(static_RTP_PT[payload]);
+ static_RTP_PT[payload] = type;
}
ast_rwlock_unlock(&static_RTP_PT_lock);
}
@@ -2797,23 +2841,34 @@ int ast_rtp_engine_init(void)
add_static_payload(26, ast_format_jpeg, 0);
add_static_payload(31, ast_format_h261, 0);
add_static_payload(34, ast_format_h263, 0);
+
+ /*
+ * Dynamic payload types - Even when dynamically assigning them we'll fall
+ * back to using the statically declared values as the default number.
+ */
+ add_static_payload(96, ast_format_slin192, 0);
add_static_payload(97, ast_format_ilbc, 0);
add_static_payload(98, ast_format_h263p, 0);
add_static_payload(99, ast_format_h264, 0);
+ add_static_payload(100, ast_format_vp8, 0);
add_static_payload(101, NULL, AST_RTP_DTMF);
add_static_payload(102, ast_format_siren7, 0);
add_static_payload(103, ast_format_h263p, 0);
add_static_payload(104, ast_format_mp4, 0);
add_static_payload(105, ast_format_t140_red, 0); /* Real time text chat (with redundancy encoding) */
add_static_payload(106, ast_format_t140, 0); /* Real time text chat */
+ add_static_payload(107, ast_format_opus, 0);
+
add_static_payload(110, ast_format_speex, 0);
add_static_payload(111, ast_format_g726, 0);
add_static_payload(112, ast_format_g726_aal2, 0);
+
add_static_payload(115, ast_format_siren14, 0);
add_static_payload(116, ast_format_g719, 0);
add_static_payload(117, ast_format_speex16, 0);
add_static_payload(118, ast_format_slin16, 0); /* 16 Khz signed linear */
add_static_payload(119, ast_format_speex32, 0);
+
add_static_payload(121, NULL, AST_RTP_CISCO_DTMF); /* Must be type 121 */
add_static_payload(122, ast_format_slin12, 0);
add_static_payload(123, ast_format_slin24, 0);
@@ -2822,10 +2877,6 @@ int ast_rtp_engine_init(void)
add_static_payload(126, ast_format_slin48, 0);
add_static_payload(127, ast_format_slin96, 0);
/* payload types above 127 are not valid */
- add_static_payload(96, ast_format_slin192, 0);
- /* Opus and VP8 */
- add_static_payload(100, ast_format_vp8, 0);
- add_static_payload(107, ast_format_opus, 0);
return 0;
}
diff --git a/makeopts.in b/makeopts.in
index 6a1164c32..5bc5258da 100644
--- a/makeopts.in
+++ b/makeopts.in
@@ -28,7 +28,7 @@ WGET=@WGET@
FETCH=@FETCH@
DOWNLOAD=@DOWNLOAD@
DOWNLOAD_TO_STDOUT=@DOWNLOAD_TO_STDOUT@
-DOWNLOAD_MAX_TIMEOUT=@DOWNLOAD_MAX_TIMEOUT@
+DOWNLOAD_TIMEOUT=@DOWNLOAD_TIMEOUT@
SOUNDS_CACHE_DIR=@SOUNDS_CACHE_DIR@
EXTERNALS_CACHE_DIR=@EXTERNALS_CACHE_DIR@
RUBBER=@RUBBER@
diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c
index a82475774..b66c1aeb8 100644
--- a/res/res_pjsip_sdp_rtp.c
+++ b/res/res_pjsip_sdp_rtp.c
@@ -163,6 +163,10 @@ static int rtp_check_timeout(const void *data)
ast_log(LOG_NOTICE, "Disconnecting channel '%s' for lack of RTP activity in %d seconds\n",
ast_channel_name(chan), elapsed);
+ ast_channel_lock(chan);
+ ast_channel_hangupcause_set(chan, AST_CAUSE_REQUESTED_CHAN_UNAVAIL);
+ ast_channel_unlock(chan);
+
ast_softhangup(chan, AST_SOFTHANGUP_DEV);
ast_channel_unref(chan);
diff --git a/res/res_xmpp.c b/res/res_xmpp.c
index ab4ee9e4f..cc9d56f32 100644
--- a/res/res_xmpp.c
+++ b/res/res_xmpp.c
@@ -1629,6 +1629,35 @@ static int xmpp_resource_immediate(void *obj, void *arg, int flags)
return CMP_MATCH | CMP_STOP;
}
+#define BUDDY_OFFLINE 6
+#define BUDDY_NOT_IN_ROSTER 7
+
+static int get_buddy_status(struct ast_xmpp_client_config *clientcfg, char *screenname, char *resource)
+{
+ int status = BUDDY_OFFLINE;
+ struct ast_xmpp_resource *res;
+ struct ast_xmpp_buddy *buddy = ao2_find(clientcfg->client->buddies, screenname, OBJ_KEY);
+
+ if (!buddy) {
+ return BUDDY_NOT_IN_ROSTER;
+ }
+
+ res = ao2_callback(
+ buddy->resources,
+ 0,
+ ast_strlen_zero(resource) ? xmpp_resource_immediate : xmpp_resource_cmp,
+ resource);
+
+ if (res) {
+ status = res->status;
+ }
+
+ ao2_cleanup(res);
+ ao2_cleanup(buddy);
+
+ return status;
+}
+
/*
* \internal
* \brief Dial plan function status(). puts the status of watched user
@@ -1642,10 +1671,7 @@ static int xmpp_status_exec(struct ast_channel *chan, const char *data)
{
RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
- struct ast_xmpp_buddy *buddy;
- struct ast_xmpp_resource *resource;
char *s = NULL, status[2];
- int stat = 7;
static int deprecation_warning = 0;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(sender);
@@ -1684,25 +1710,7 @@ static int xmpp_status_exec(struct ast_channel *chan, const char *data)
return -1;
}
- if (!(buddy = ao2_find(clientcfg->client->buddies, jid.screenname, OBJ_KEY))) {
- ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
- return -1;
- }
-
- if (ast_strlen_zero(jid.resource) || !(resource = ao2_callback(buddy->resources, 0, xmpp_resource_cmp, jid.resource))) {
- resource = ao2_callback(buddy->resources, OBJ_NODATA, xmpp_resource_immediate, NULL);
- }
-
- ao2_ref(buddy, -1);
-
- if (resource) {
- stat = resource->status;
- ao2_ref(resource, -1);
- } else {
- ast_log(LOG_NOTICE, "Resource '%s' of buddy '%s' was not found\n", jid.resource, jid.screenname);
- }
-
- snprintf(status, sizeof(status), "%d", stat);
+ snprintf(status, sizeof(status), "%d", get_buddy_status(clientcfg, jid.screenname, jid.resource));
pbx_builtin_setvar_helper(chan, args.variable, status);
return 0;
@@ -1721,9 +1729,6 @@ static int acf_jabberstatus_read(struct ast_channel *chan, const char *name, cha
{
RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
- struct ast_xmpp_buddy *buddy;
- struct ast_xmpp_resource *resource;
- int stat = 7;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(sender);
AST_APP_ARG(jid);
@@ -1755,25 +1760,7 @@ static int acf_jabberstatus_read(struct ast_channel *chan, const char *name, cha
return -1;
}
- if (!(buddy = ao2_find(clientcfg->client->buddies, jid.screenname, OBJ_KEY))) {
- ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
- return -1;
- }
-
- if (ast_strlen_zero(jid.resource) || !(resource = ao2_callback(buddy->resources, 0, xmpp_resource_cmp, jid.resource))) {
- resource = ao2_callback(buddy->resources, OBJ_NODATA, xmpp_resource_immediate, NULL);
- }
-
- ao2_ref(buddy, -1);
-
- if (resource) {
- stat = resource->status;
- ao2_ref(resource, -1);
- } else {
- ast_log(LOG_NOTICE, "Resource %s of buddy %s was not found.\n", jid.resource, jid.screenname);
- }
-
- snprintf(buf, buflen, "%d", stat);
+ snprintf(buf, buflen, "%d", get_buddy_status(clientcfg, jid.screenname, jid.resource));
return 0;
}
@@ -2561,10 +2548,16 @@ static void xmpp_log_hook(void *data, const char *xmpp, size_t size, int incomin
static int xmpp_client_send_raw_message(struct ast_xmpp_client *client, const char *message)
{
int ret;
-#ifdef HAVE_OPENSSL
- int len = strlen(message);
+ if (client->state == XMPP_STATE_DISCONNECTED) {
+ /* iks_send_raw will crash without a connection */
+ return IKS_NET_NOCONN;
+ }
+
+#ifdef HAVE_OPENSSL
if (xmpp_is_secure(client)) {
+ int len = strlen(message);
+
ret = SSL_write(client->ssl_session, message, len);
if (ret) {
/* Log the message here, because iksemel's logHook is
@@ -2628,12 +2621,31 @@ static int xmpp_client_request_tls(struct ast_xmpp_client *client, struct ast_xm
#endif
}
+#ifdef HAVE_OPENSSL
+static char *openssl_error_string(void)
+{
+ char *buf = NULL, *ret;
+ size_t len;
+ BIO *bio = BIO_new(BIO_s_mem());
+
+ ERR_print_errors(bio);
+ len = BIO_get_mem_data(bio, &buf);
+ ret = ast_calloc(1, len + 1);
+ if (ret) {
+ memcpy(ret, buf, len);
+ }
+ BIO_free(bio);
+ return ret;
+}
+#endif
+
/*! \brief Internal function called when we receive a response to our TLS initiation request */
static int xmpp_client_requested_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
{
#ifdef HAVE_OPENSSL
int sock;
long ssl_opts;
+ char *err;
#endif
if (!strcmp(iks_name(node), "success")) {
@@ -2669,7 +2681,7 @@ static int xmpp_client_requested_tls(struct ast_xmpp_client *client, struct ast_
goto failure;
}
- if (!SSL_connect(client->ssl_session)) {
+ if (SSL_connect(client->ssl_session) <= 0) {
goto failure;
}
@@ -2689,7 +2701,10 @@ static int xmpp_client_requested_tls(struct ast_xmpp_client *client, struct ast_
return 0;
failure:
- ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be established. OpenSSL initialization failed.\n", client->name);
+ err = openssl_error_string();
+ ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be established. "
+ "OpenSSL initialization failed: %s\n", client->name, err);
+ ast_free(err);
return -1;
#endif
}
@@ -3564,6 +3579,7 @@ int ast_xmpp_client_disconnect(struct ast_xmpp_client *client)
{
if ((client->thread != AST_PTHREADT_NULL) && !pthread_equal(pthread_self(), client->thread)) {
xmpp_client_change_state(client, XMPP_STATE_DISCONNECTING);
+ pthread_cancel(client->thread);
pthread_join(client->thread, NULL);
client->thread = AST_PTHREADT_NULL;
}
@@ -3743,22 +3759,37 @@ static int xmpp_client_receive(struct ast_xmpp_client *client, unsigned int time
return IKS_OK;
}
+static void sleep_with_backoff(unsigned int *sleep_time)
+{
+ /* We're OK with our thread dying here */
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+
+ sleep(*sleep_time);
+ *sleep_time = MIN(60, *sleep_time * 2);
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+}
+
/*! \brief XMPP client connection thread */
static void *xmpp_client_thread(void *data)
{
struct ast_xmpp_client *client = data;
int res = IKS_NET_RWERR;
+ unsigned int sleep_time = 1;
+
+ /* We only allow cancellation while sleeping */
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
do {
if (client->state == XMPP_STATE_DISCONNECTING) {
- ast_debug(1, "JABBER: Disconnecting client '%s'\n", client->name);
+ ast_debug(1, "[%s] Disconnecting\n", client->name);
break;
}
if (res == IKS_NET_RWERR || client->timeout == 0) {
- ast_debug(3, "Connecting client '%s'\n", client->name);
+ ast_debug(3, "[%s] Connecting\n", client->name);
if ((res = xmpp_client_reconnect(client)) != IKS_OK) {
- sleep(4);
+ sleep_with_backoff(&sleep_time);
res = IKS_NET_RWERR;
}
continue;
@@ -3773,9 +3804,9 @@ static void *xmpp_client_thread(void *data)
}
if (res == IKS_HOOK) {
- ast_debug(2, "JABBER: Got hook event.\n");
+ ast_debug(2, "[%s] Got hook event\n", client->name);
} else if (res == IKS_NET_TLSFAIL) {
- ast_log(LOG_ERROR, "JABBER: Failure in TLS.\n");
+ ast_log(LOG_ERROR, "[%s] TLS failure\n", client->name);
} else if (!client->timeout && client->state == XMPP_STATE_CONNECTED) {
RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
@@ -3793,22 +3824,26 @@ static void *xmpp_client_thread(void *data)
if (res == IKS_OK) {
client->timeout = 50;
} else {
- ast_log(LOG_WARNING, "JABBER: Network Timeout\n");
+ ast_log(LOG_WARNING, "[%s] Network timeout\n", client->name);
}
} else if (res == IKS_NET_RWERR) {
- ast_log(LOG_WARNING, "JABBER: socket read error\n");
+ ast_log(LOG_WARNING, "[%s] Socket read error\n", client->name);
+ ast_xmpp_client_disconnect(client);
+ sleep_with_backoff(&sleep_time);
} else if (res == IKS_NET_NOSOCK) {
- ast_log(LOG_WARNING, "JABBER: No Socket\n");
+ ast_log(LOG_WARNING, "[%s] No socket\n", client->name);
} else if (res == IKS_NET_NOCONN) {
- ast_log(LOG_WARNING, "JABBER: No Connection\n");
+ ast_log(LOG_WARNING, "[%s] No connection\n", client->name);
} else if (res == IKS_NET_NODNS) {
- ast_log(LOG_WARNING, "JABBER: No DNS\n");
+ ast_log(LOG_WARNING, "[%s] No DNS\n", client->name);
} else if (res == IKS_NET_NOTSUPP) {
- ast_log(LOG_WARNING, "JABBER: Not Supported\n");
+ ast_log(LOG_WARNING, "[%s] Not supported\n", client->name);
} else if (res == IKS_NET_DROPPED) {
- ast_log(LOG_WARNING, "JABBER: Dropped?\n");
+ ast_log(LOG_WARNING, "[%s] Dropped?\n", client->name);
} else if (res == IKS_NET_UNKNOWN) {
- ast_debug(5, "JABBER: Unknown\n");
+ ast_debug(5, "[%s] Unknown\n", client->name);
+ } else if (res == IKS_OK) {
+ sleep_time = 1;
}
} while (1);
diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile
index 99c22fa8b..e691f2242 100644
--- a/third-party/pjproject/Makefile
+++ b/third-party/pjproject/Makefile
@@ -96,9 +96,9 @@ endef
define download_from_pjproject
($(SHELL_ECHO_PREFIX) Downloading $(TARBALL_URL) to $(TARBALL) ;\
- $(DOWNLOAD_TO_STDOUT) $(call DOWNLOAD_TIMEOUT,5,10) $(TARBALL_URL) > $(TARBALL) &&\
+ $(DOWNLOAD_TO_STDOUT) $(call DOWNLOAD_TIMEOUT,5,60) $(TARBALL_URL) > $(TARBALL) &&\
$(SHELL_ECHO_PREFIX) Downloading $(PJPROJECT_URL)/MD5SUM to $(PJMD5SUM) &&\
- $(DOWNLOAD_TO_STDOUT) $(call DOWNLOAD_TIMEOUT,5,10) $(PJPROJECT_URL)/MD5SUM.TXT > $(PJMD5SUM) &&\
+ $(DOWNLOAD_TO_STDOUT) $(call DOWNLOAD_TIMEOUT,5,60) $(PJPROJECT_URL)/MD5SUM.TXT > $(PJMD5SUM) &&\
$(verify_tarball))
endef