diff options
-rw-r--r-- | README-SERIOUSLY.bestpractices.md | 4 | ||||
-rw-r--r-- | README.md | 7 | ||||
-rw-r--r-- | channels/chan_pjsip.c | 5 | ||||
-rw-r--r-- | channels/chan_sip.c | 17 | ||||
-rw-r--r-- | channels/pjsip/dialplan_functions.c | 50 | ||||
-rw-r--r-- | configs/samples/iax.conf.sample | 12 | ||||
-rw-r--r-- | include/asterisk/res_pjsip_session.h | 2 | ||||
-rw-r--r-- | main/asterisk.c | 38 | ||||
-rw-r--r-- | menuselect/Makefile | 5 | ||||
-rw-r--r-- | res/res_pjsip/config_transport.c | 10 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_options.c | 53 | ||||
-rw-r--r-- | res/res_pjsip_dlg_options.c | 1 | ||||
-rw-r--r-- | res/res_pjsip_outbound_publish.c | 1 | ||||
-rw-r--r-- | res/res_pjsip_phoneprov_provider.c | 1 | ||||
-rw-r--r-- | res/res_pjsip_publish_asterisk.c | 1 | ||||
-rw-r--r-- | res/res_pjsip_sdp_rtp.c | 3 | ||||
-rw-r--r-- | res/res_pjsip_session.c | 15 | ||||
-rw-r--r-- | res/res_rtp_asterisk.c | 8 | ||||
-rw-r--r-- | third-party/pjproject/patches/0050-dont_terminate_session_early.patch | 71 |
19 files changed, 226 insertions, 78 deletions
diff --git a/README-SERIOUSLY.bestpractices.md b/README-SERIOUSLY.bestpractices.md index 7e18c4aa8..ec36fac98 100644 --- a/README-SERIOUSLY.bestpractices.md +++ b/README-SERIOUSLY.bestpractices.md @@ -17,7 +17,8 @@ change over time as best practices are defined. Recognizing potential issues with certain classes of authorization * [Avoid Privilege Escalations]: Disable the ability to execute functions that may escalate privileges - +* [Important Security Considerations]: + More information on the Asterisk Wiki ## Additional Links @@ -386,3 +387,4 @@ In Asterisk 12 and later, live_dangerously defaults to no. [Reducing Pattern Match Typos]: #reducing-pattern-match-typos [Manager Class Authorizations]: #manager-class-authorizations [Avoid Privilege Escalations]: #avoid-privilege-escalations +[Important Security Considerations]: https://wiki.asterisk.org/wiki/display/AST/Important+Security+Considerations @@ -9,10 +9,7 @@ the security information document before you attempt to configure and run an Asterisk server. - If you downloaded Asterisk as a tarball, see the security section in the PDF -version of the documentation in doc/tex/asterisk.pdf. Alternatively, pull up -the HTML version of the documentation in doc/tex/asterisk/index.html. The -source for the security document is available in doc/tex/security.tex. +See [Important Security Considerations] for more information. ## WHAT IS ASTERISK ? @@ -269,4 +266,4 @@ Asterisk is a trademark of Digium, Inc. [CHANGES]: CHANGES [configs]: configs [doc]: doc - +[Important Security Considerations]: https://wiki.asterisk.org/wiki/display/AST/Important+Security+Considerations diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index e4e8fa586..69bcc187f 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -605,6 +605,11 @@ static struct ast_channel *chan_pjsip_new(struct ast_sip_session *session, int s ast_party_id_copy(&ast_channel_caller(chan)->id, &session->id); ast_party_id_copy(&ast_channel_caller(chan)->ani, &session->id); + if (!ast_strlen_zero(exten)) { + /* Set provided DNID on the new channel. */ + ast_channel_dialed(chan)->number.str = ast_strdup(exten); + } + ast_channel_priority_set(chan, 1); ast_channel_callgroup_set(chan, session->endpoint->pickup.callgroup); diff --git a/channels/chan_sip.c b/channels/chan_sip.c index a6e5493c2..4bae39da0 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -30125,6 +30125,7 @@ static int sip_send_keepalive(const void *data) struct sip_peer *peer = (struct sip_peer*) data; int res = 0; const char keepalive[] = "\r\n"; + size_t count = sizeof(keepalive) - 1; peer->keepalivesend = -1; @@ -30135,12 +30136,12 @@ static int sip_send_keepalive(const void *data) /* Send the packet out using the proper method for this peer */ if ((peer->socket.fd != -1) && (peer->socket.type == AST_TRANSPORT_UDP)) { - res = ast_sendto(peer->socket.fd, keepalive, sizeof(keepalive), 0, &peer->addr); + res = ast_sendto(peer->socket.fd, keepalive, count, 0, &peer->addr); } else if ((peer->socket.type & (AST_TRANSPORT_TCP | AST_TRANSPORT_TLS)) && peer->socket.tcptls_session) { - res = sip_tcptls_write(peer->socket.tcptls_session, keepalive, sizeof(keepalive)); + res = sip_tcptls_write(peer->socket.tcptls_session, keepalive, count); } else if (peer->socket.type == AST_TRANSPORT_UDP) { - res = ast_sendto(sipsock, keepalive, sizeof(keepalive), 0, &peer->addr); + res = ast_sendto(sipsock, keepalive, count, 0, &peer->addr); } if (res == -1) { @@ -30154,7 +30155,7 @@ static int sip_send_keepalive(const void *data) } } - if (res != sizeof(keepalive)) { + if (res != count) { ast_log(LOG_WARNING, "sip_send_keepalive to %s returned %d: %s\n", ast_sockaddr_stringify(&peer->addr), res, strerror(errno)); } @@ -30554,6 +30555,14 @@ static struct ast_channel *sip_request_call(const char *type, struct ast_format_ } } + /* If stripping the DNID left us with nothing, bail out */ + if (ast_strlen_zero(tmp)) { + dialog_unlink_all(p); + dialog_unref(p, "unref dialog p from bad destination"); + *cause = AST_CAUSE_DESTINATION_OUT_OF_ORDER; + return NULL; + } + /* Divvy up the items separated by slashes */ AST_NONSTANDARD_APP_ARGS(args, tmp, '/'); diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c index 861edf72d..aa376f892 100644 --- a/channels/pjsip/dialplan_functions.c +++ b/channels/pjsip/dialplan_functions.c @@ -388,7 +388,7 @@ </enumlist> </enum> <enum name="target_uri"> - <para>The request URI of the <literal>INVITE</literal> request associated with the creation of this channel.</para> + <para>The contact URI where requests are sent.</para> </enum> <enum name="local_uri"> <para>The local URI.</para> @@ -402,6 +402,10 @@ <enum name="remote_tag"> <para>Tag in To header</para> </enum> + <enum name="request_uri"> + <para>The request URI of the incoming <literal>INVITE</literal> + associated with the creation of this channel.</para> + </enum> <enum name="t38state"> <para>The current state of any T.38 fax on this channel.</para> <enumlist> @@ -656,6 +660,27 @@ static int channel_read_rtcp(struct ast_channel *chan, const char *type, const c return 0; } +static int print_escaped_uri(struct ast_channel *chan, const char *type, + pjsip_uri_context_e context, const void *uri, char *buf, size_t size) +{ + int res; + char *buf_copy; + + res = pjsip_uri_print(context, uri, buf, size); + if (res < 0) { + ast_log(LOG_ERROR, "Channel %s: Unescaped %s too long for %d byte buffer\n", + ast_channel_name(chan), type, (int) size); + + /* Empty buffer that likely is not terminated. */ + buf[0] = '\0'; + return -1; + } + + buf_copy = ast_strdupa(buf); + ast_escape_quoted(buf_copy, buf, size); + return 0; +} + /*! * \internal \brief Handle reading signalling information */ @@ -664,6 +689,7 @@ static int channel_read_pjsip(struct ast_channel *chan, const char *type, const struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan); char *buf_copy; pjsip_dialog *dlg; + int res = 0; if (!channel) { ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan)); @@ -689,25 +715,27 @@ static int channel_read_pjsip(struct ast_channel *chan, const char *type, const return -1; #endif } else if (!strcmp(type, "target_uri")) { - pjsip_uri_print(PJSIP_URI_IN_REQ_URI, dlg->target, buf, buflen); - buf_copy = ast_strdupa(buf); - ast_escape_quoted(buf_copy, buf, buflen); + res = print_escaped_uri(chan, type, PJSIP_URI_IN_REQ_URI, dlg->target, buf, + buflen); } else if (!strcmp(type, "local_uri")) { - pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, dlg->local.info->uri, buf, buflen); - buf_copy = ast_strdupa(buf); - ast_escape_quoted(buf_copy, buf, buflen); + res = print_escaped_uri(chan, type, PJSIP_URI_IN_FROMTO_HDR, dlg->local.info->uri, + buf, buflen); } else if (!strcmp(type, "local_tag")) { ast_copy_pj_str(buf, &dlg->local.info->tag, buflen); buf_copy = ast_strdupa(buf); ast_escape_quoted(buf_copy, buf, buflen); } else if (!strcmp(type, "remote_uri")) { - pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, dlg->remote.info->uri, buf, buflen); - buf_copy = ast_strdupa(buf); - ast_escape_quoted(buf_copy, buf, buflen); + res = print_escaped_uri(chan, type, PJSIP_URI_IN_FROMTO_HDR, + dlg->remote.info->uri, buf, buflen); } else if (!strcmp(type, "remote_tag")) { ast_copy_pj_str(buf, &dlg->remote.info->tag, buflen); buf_copy = ast_strdupa(buf); ast_escape_quoted(buf_copy, buf, buflen); + } else if (!strcmp(type, "request_uri")) { + if (channel->session->request_uri) { + res = print_escaped_uri(chan, type, PJSIP_URI_IN_REQ_URI, + channel->session->request_uri, buf, buflen); + } } else if (!strcmp(type, "t38state")) { ast_copy_string(buf, t38state_to_string[channel->session->t38state], buflen); } else if (!strcmp(type, "local_addr")) { @@ -743,7 +771,7 @@ static int channel_read_pjsip(struct ast_channel *chan, const char *type, const return -1; } - return 0; + return res; } /*! \brief Struct used to push function arguments to task processor */ diff --git a/configs/samples/iax.conf.sample b/configs/samples/iax.conf.sample index ebe4d7fdc..c6da46179 100644 --- a/configs/samples/iax.conf.sample +++ b/configs/samples/iax.conf.sample @@ -576,12 +576,12 @@ inkeys=freeworlddialup ; ; Peers may also be specified, with a secret and a remote hostname. ; -[demo] -type=peer -username=asterisk -secret=supersecret -host=216.207.245.47 -description=Demo System At Digium ; Description of this peer, as listed by +;[demo] +;type=peer +;username=asterisk +;secret=supersecret +;host=192.168.10.10 +;description=My IAX2 Peer ; Description of this peer, as listed by ; 'iax2 show peers' ;sendani=no ;host=asterisk.linux-support.net diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index de6589abd..6d506a35b 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -211,6 +211,8 @@ struct ast_sip_session { unsigned int ended_while_deferred:1; /*! DTMF mode to use with this session, from endpoint but can change */ enum ast_sip_dtmf_mode dtmf; + /*! Initial incoming INVITE Request-URI. NULL otherwise. */ + pjsip_uri *request_uri; }; typedef int (*ast_sip_session_request_creation_cb)(struct ast_sip_session *session, pjsip_tx_data *tdata); diff --git a/main/asterisk.c b/main/asterisk.c index 187a8ad6b..006a1b03a 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -733,6 +733,27 @@ static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cl int totalswap = 0; #if defined(HAVE_SYSINFO) struct sysinfo sys_info; +#elif defined(HAVE_SYSCTL) + static int pageshift; + struct vmtotal vmtotal; + struct timeval boottime; + time_t now; + int mib[2], pagesize, usedswap = 0; + size_t len; +#endif + + switch (cmd) { + case CLI_INIT: + e->command = "core show sysinfo"; + e->usage = + "Usage: core show sysinfo\n" + " List current system information.\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + +#if defined(HAVE_SYSINFO) sysinfo(&sys_info); uptime = sys_info.uptime / 3600; physmem = sys_info.totalram * sys_info.mem_unit; @@ -741,12 +762,6 @@ static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cl freeswap = (sys_info.freeswap * sys_info.mem_unit) / 1024; nprocs = sys_info.procs; #elif defined(HAVE_SYSCTL) - static int pageshift; - struct vmtotal vmtotal; - struct timeval boottime; - time_t now; - int mib[2], pagesize, usedswap = 0; - size_t len; /* calculate the uptime by looking at boottime */ time(&now); mib[0] = CTL_KERN; @@ -794,17 +809,6 @@ static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cl #endif #endif - switch (cmd) { - case CLI_INIT: - e->command = "core show sysinfo"; - e->usage = - "Usage: core show sysinfo\n" - " List current system information.\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - ast_cli(a->fd, "\nSystem Statistics\n"); ast_cli(a->fd, "-----------------\n"); ast_cli(a->fd, " System Uptime: %ld hours\n", uptime); diff --git a/menuselect/Makefile b/menuselect/Makefile index 96c574eb8..c6a6facb6 100644 --- a/menuselect/Makefile +++ b/menuselect/Makefile @@ -64,7 +64,10 @@ all: $(ALL_TGTS) $(OBJS) $(C_OBJS) $(N_OBJS) $(G_OBJS) $(M_OBJS): autoconfig.h menuselect.h -makeopts autoconfig.h: autoconfig.h.in makeopts.in +makeopts: makeopts.in +autoconfig.h: autoconfig.h.in + +makeopts autoconfig.h: @./configure $(CONFIGURE_SILENT) @echo "****" @echo "**** The configure script was just executed, so 'make' needs to be" diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c index 2f29456ab..a9a90ac92 100644 --- a/res/res_pjsip/config_transport.c +++ b/res/res_pjsip/config_transport.c @@ -917,6 +917,12 @@ static int transport_tls_method_handler(const struct aco_option *opt, struct ast state->tls.method = PJSIP_SSL_UNSPECIFIED_METHOD; } else if (!strcasecmp(var->value, "tlsv1")) { state->tls.method = PJSIP_TLSV1_METHOD; +#ifdef HAVE_PJSIP_TLS_TRANSPORT_PROTO + } else if (!strcasecmp(var->value, "tlsv1_1")) { + state->tls.method = PJSIP_TLSV1_1_METHOD; + } else if (!strcasecmp(var->value, "tlsv1_2")) { + state->tls.method = PJSIP_TLSV1_2_METHOD; +#endif } else if (!strcasecmp(var->value, "sslv2")) { state->tls.method = PJSIP_SSLV2_METHOD; } else if (!strcasecmp(var->value, "sslv3")) { @@ -933,6 +939,10 @@ static int transport_tls_method_handler(const struct aco_option *opt, struct ast static const char *tls_method_map[] = { [PJSIP_SSL_UNSPECIFIED_METHOD] = "unspecified", [PJSIP_TLSV1_METHOD] = "tlsv1", +#ifdef HAVE_PJSIP_TLS_TRANSPORT_PROTO + [PJSIP_TLSV1_1_METHOD] = "tlsv1_1", + [PJSIP_TLSV1_2_METHOD] = "tlsv1_2", +#endif [PJSIP_SSLV2_METHOD] = "sslv2", [PJSIP_SSLV3_METHOD] = "sslv3", [PJSIP_SSLV23_METHOD] = "sslv23", diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 662166c89..fbe07d53d 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -1147,7 +1147,24 @@ static int qualify_and_schedule_cb_with_aor(void *obj, void *arg, int flags) static int qualify_and_schedule_cb_without_aor(void *obj, void *arg, int flags) { - qualify_and_schedule_contact((struct ast_sip_contact *) obj); + /* + * These are really dynamic contacts. We need to retrieve the aor associated + * with the contact since it's possible some of the aor's fields were updated + * since last load. + */ + struct ast_sip_contact *contact = obj; + struct ast_sip_aor *aor = ast_sip_location_retrieve_aor(contact->aor); + + if (aor) { + qualify_and_schedule_cb_with_aor(obj, aor, flags); + ao2_ref(aor, -1); + } else { + ast_log(LOG_WARNING, "Unable to locate AOR for contact '%s'. Keeping old " + "associated settings: frequency=%d, timeout=%f, authenticate=%s\n", + contact->uri, contact->qualify_frequency, contact->qualify_timeout, + contact->authenticate_qualify ? "yes" : "no"); + qualify_and_schedule_contact(contact); + } return 0; } @@ -1175,32 +1192,21 @@ static int qualify_and_schedule_all_cb(void *obj, void *arg, int flags) return 0; } -/*! - * \internal - * \brief Unschedule all existing contacts - */ -static int unschedule_all_cb(void *obj, void *arg, int flags) -{ - struct sched_data *data = obj; - - AST_SCHED_DEL_UNREF(sched, data->id, ao2_ref(data, -1)); - - return CMP_MATCH; -} - static void qualify_and_schedule_all(void) { - struct ast_variable *var = ast_variable_new("qualify_frequency >", "0", ""); struct ao2_container *aors; struct ao2_container *contacts; - if (!var) { - return; - } - aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), - "aor", AST_RETRIEVE_FLAG_MULTIPLE, var); + /* + * It's possible that the AOR had some of it's fields updated prior to a + * reload. For instance qualifying could have been turned on or off by + * setting the qualify_frequency. Due to this we have to iterate through + * all contacts (static and dynamic), and not just ones where the frequency + * is greater than zero, updating any contact fields with the AOR's values. + */ - ao2_callback(sched_qualifies, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, unschedule_all_cb, NULL); + aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), + "aor", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); if (aors) { ao2_callback(aors, OBJ_NODATA, qualify_and_schedule_all_cb, NULL); @@ -1208,14 +1214,11 @@ static void qualify_and_schedule_all(void) } contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), - "contact", AST_RETRIEVE_FLAG_MULTIPLE, var); + "contact", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); if (contacts) { ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb_without_aor, NULL); ao2_ref(contacts, -1); } - - ast_variables_destroy(var); - } int ast_sip_format_contact_ami(void *obj, void *arg, int flags) diff --git a/res/res_pjsip_dlg_options.c b/res/res_pjsip_dlg_options.c index e2ed29a2c..de1ac97ef 100644 --- a/res/res_pjsip_dlg_options.c +++ b/res/res_pjsip_dlg_options.c @@ -99,6 +99,7 @@ static int unload_module(void) } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SIP OPTIONS in dialog handler", + .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index f1f49d510..e5f12951f 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -1697,6 +1697,7 @@ static int reload_module(void) } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "PJSIP Outbound Publish Support", + .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .reload = reload_module, .unload = unload_module, diff --git a/res/res_pjsip_phoneprov_provider.c b/res/res_pjsip_phoneprov_provider.c index eef3a082f..7e082c4b5 100644 --- a/res/res_pjsip_phoneprov_provider.c +++ b/res/res_pjsip_phoneprov_provider.c @@ -413,6 +413,7 @@ static int reload_module(void) } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Phoneprov Provider", + .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .reload = reload_module, .unload = unload_module, diff --git a/res/res_pjsip_publish_asterisk.c b/res/res_pjsip_publish_asterisk.c index 72e1e4d7e..53ee60fe4 100644 --- a/res/res_pjsip_publish_asterisk.c +++ b/res/res_pjsip_publish_asterisk.c @@ -929,6 +929,7 @@ static int unload_module(void) } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Asterisk Event PUBLISH Support", + .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .reload = reload_module, .unload = unload_module, diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index a87758267..854ed1459 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -1253,7 +1253,8 @@ static int add_crypto_to_stream(struct ast_sip_session *session, /* If this is an answer we need to use our current state, if it's an offer we need to use * the configured value. */ - if (pjmedia_sdp_neg_get_state(session->inv_session->neg) != PJMEDIA_SDP_NEG_STATE_DONE) { + if (session->inv_session->neg + && pjmedia_sdp_neg_get_state(session->inv_session->neg) != PJMEDIA_SDP_NEG_STATE_DONE) { setup = dtls->get_setup(session_media->rtp); } else { setup = session->endpoint->media.rtp.dtls_cfg.default_setup; diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 781d3e4eb..958f2254b 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -2818,6 +2818,12 @@ static enum sip_get_destination_result get_destination(struct ast_sip_session *s ast_copy_pj_str(domain, &sip_ruri->host, size); pbx_builtin_setvar_helper(session->channel, "SIPDOMAIN", domain); + /* + * Save off the INVITE Request-URI in case it is + * needed: CHANNEL(pjsip,request_uri) + */ + session->request_uri = pjsip_uri_clone(session->inv_session->pool, ruri); + return SIP_GET_DEST_EXTEN_FOUND; } @@ -3872,10 +3878,15 @@ static struct pjmedia_sdp_session *create_local_sdp(pjsip_inv_session *inv, stru if (!session->pending_media_state->topology || !ast_stream_topology_get_count(session->pending_media_state->topology)) { /* We've encountered a situation where we have been told to create a local SDP but noone has given us any indication - * of what kind of stream topology they would like. As a fallback we use the topology from the configured endpoint. + * of what kind of stream topology they would like. We try to not alter the current state of the SDP negotiation + * by using what is currently negotiated. If this is unavailable we fall back to what is configured on the endpoint. */ ast_stream_topology_free(session->pending_media_state->topology); - session->pending_media_state->topology = ast_stream_topology_clone(session->endpoint->media.topology); + if (session->active_media_state->topology) { + session->pending_media_state->topology = ast_stream_topology_clone(session->active_media_state->topology); + } else { + session->pending_media_state->topology = ast_stream_topology_clone(session->endpoint->media.topology); + } if (!session->pending_media_state->topology) { return NULL; } diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 16eb7dddf..bdc83301e 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -5169,7 +5169,6 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c unsigned int first_word; /*! True if we have seen an acceptable SSRC to learn the remote RTCP address */ unsigned int ssrc_seen; - int report_counter = 0; struct ast_rtp_rtcp_report_block *report_block; struct ast_frame *f = &ast_null_frame; @@ -5413,7 +5412,7 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c } return &ast_null_frame; } - rtcp_report->report_block[report_counter] = report_block; + rtcp_report->report_block[0] = report_block; report_block->source_ssrc = ntohl(rtcpheader[i]); report_block->lost_count.packets = ntohl(rtcpheader[i + 1]) & 0x00ffffff; report_block->lost_count.fraction = ((ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24); @@ -5450,7 +5449,6 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c ast_verbose(" DLSR: %4.4f (sec)\n",(double)report_block->dlsr / 65536.0); ast_verbose(" RTT: %4.4f(sec)\n", rtp->rtcp->rtt); } - report_counter++; } /* If and when we handle more than one report block, this should occur outside * this loop. @@ -5475,9 +5473,9 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c /* There's always a single report block stored, here */ struct ast_rtp_rtcp_report *rtcp_report2; report_block = transport_rtp->f.data.ptr + transport_rtp->f.datalen + sizeof(struct ast_rtp_rtcp_report_block *); - memcpy(report_block, rtcp_report->report_block[report_counter-1], sizeof(struct ast_rtp_rtcp_report_block)); + memcpy(report_block, rtcp_report->report_block[0], sizeof(struct ast_rtp_rtcp_report_block)); rtcp_report2 = (struct ast_rtp_rtcp_report *)transport_rtp->f.data.ptr; - rtcp_report2->report_block[report_counter-1] = report_block; + rtcp_report2->report_block[0] = report_block; transport_rtp->f.datalen += sizeof(struct ast_rtp_rtcp_report_block); } transport_rtp->f.offset = AST_FRIENDLY_OFFSET; diff --git a/third-party/pjproject/patches/0050-dont_terminate_session_early.patch b/third-party/pjproject/patches/0050-dont_terminate_session_early.patch new file mode 100644 index 000000000..718968c79 --- /dev/null +++ b/third-party/pjproject/patches/0050-dont_terminate_session_early.patch @@ -0,0 +1,71 @@ +commit ca0b723e92bd76bbda1bbd14477a829eaeeb675e +Author: Joshua Colp <jcolp@digium.com> +Date: Wed Dec 13 10:58:57 2017 +0000 + + Ignore transport error on completed transaction. + Don't disconnect call if transport error happens on transaction that is not initial INVITE transaction. + + Scenario: + + DNS lookup returning two servers. + Sending INVITE to first server over TCP. + Response received with code 503 (Service Unavailable). + Failover to second server, sending second INVITE after restarting the session. + TCP connection for the first INVITE getting disconnected and causing call disconnection (while second INVITE is still outstanding). + + This is a backport of 5714 from upstream PJSIP. + +diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c +index ac4d1949..0173cb4c 100644 +--- a/pjsip/src/pjsip-ua/sip_inv.c ++++ b/pjsip/src/pjsip-ua/sip_inv.c +@@ -4254,8 +4254,7 @@ static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e) + if ((tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST && + tsx->method.id != PJSIP_CANCEL_METHOD) || + tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT || +- tsx->status_code == PJSIP_SC_TSX_TIMEOUT || +- tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR) ++ tsx->status_code == PJSIP_SC_TSX_TIMEOUT) + { + inv_set_cause(inv, tsx->status_code, &tsx->status_text); + inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); +diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c +index 7ac3d1b7..d52b12a7 100644 +--- a/pjsip/src/pjsip/sip_transaction.c ++++ b/pjsip/src/pjsip/sip_transaction.c +@@ -2044,9 +2044,14 @@ static void transport_callback(void *token, pjsip_tx_data *tdata, + */ + lock_timer(tsx); + tsx->transport_err = (pj_status_t)-sent; +- tsx_cancel_timer(tsx, &tsx->timeout_timer); +- tsx_schedule_timer(tsx, &tsx->timeout_timer, &delay, +- TRANSPORT_ERR_TIMER); ++ /* Don't cancel timeout timer if tsx state is already ++ * PJSIP_TSX_STATE_COMPLETED (see #2076). ++ */ ++ if (tsx->state < PJSIP_TSX_STATE_COMPLETED) { ++ tsx_cancel_timer(tsx, &tsx->timeout_timer); ++ tsx_schedule_timer(tsx, &tsx->timeout_timer, &delay, ++ TRANSPORT_ERR_TIMER); ++ } + unlock_timer(tsx); + } + +@@ -2077,9 +2082,14 @@ static void tsx_tp_state_callback( pjsip_transport *tp, + */ + lock_timer(tsx); + tsx->transport_err = info->status; +- tsx_cancel_timer(tsx, &tsx->timeout_timer); +- tsx_schedule_timer(tsx, &tsx->timeout_timer, &delay, +- TRANSPORT_ERR_TIMER); ++ /* Don't cancel timeout timer if tsx state is already ++ * PJSIP_TSX_STATE_COMPLETED (see #2076). ++ */ ++ if (tsx->state < PJSIP_TSX_STATE_COMPLETED) { ++ tsx_cancel_timer(tsx, &tsx->timeout_timer); ++ tsx_schedule_timer(tsx, &tsx->timeout_timer, &delay, ++ TRANSPORT_ERR_TIMER); ++ } + unlock_timer(tsx); + } + } |