diff options
-rw-r--r-- | CHANGES | 5 | ||||
-rw-r--r-- | configs/samples/asterisk.conf.sample | 4 | ||||
-rw-r--r-- | configs/samples/musiconhold.conf.sample | 6 | ||||
-rw-r--r-- | include/asterisk/manager.h | 2 | ||||
-rw-r--r-- | include/asterisk/options.h | 1 | ||||
-rw-r--r-- | main/asterisk.c | 5 | ||||
-rw-r--r-- | main/audiohook.c | 2 | ||||
-rw-r--r-- | main/cdr.c | 4 | ||||
-rw-r--r-- | main/rtp_engine.c | 267 | ||||
-rw-r--r-- | makeopts.in | 2 | ||||
-rw-r--r-- | res/res_pjsip_sdp_rtp.c | 4 | ||||
-rw-r--r-- | res/res_xmpp.c | 157 | ||||
-rw-r--r-- | third-party/pjproject/Makefile | 4 |
13 files changed, 286 insertions, 177 deletions
@@ -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 |