diff options
Diffstat (limited to 'channels/chan_sip.c')
-rw-r--r-- | channels/chan_sip.c | 213 |
1 files changed, 103 insertions, 110 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 8f3296adf..9cc6252fd 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -4200,19 +4200,6 @@ static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, uint32_t seqno, in p->pendinginvite = seqno; } - /* If the transport is something reliable (TCP or TLS) then don't really send this reliably */ - /* I removed the code from retrans_pkt that does the same thing so it doesn't get loaded into the scheduler */ - /*! \todo According to the RFC some packets need to be retransmitted even if its TCP, so this needs to get revisited */ - if (!(p->socket.type & AST_TRANSPORT_UDP)) { - xmitres = __sip_xmit(p, data); /* Send packet */ - if (xmitres == XMIT_ERROR) { /* Serious network trouble, no need to try again */ - append_history(p, "XmitErr", "%s", fatal ? "(Critical)" : "(Non-critical)"); - return AST_FAILURE; - } else { - return AST_SUCCESS; - } - } - pkt = ao2_alloc_options(sizeof(*pkt), sip_pkt_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK); if (!pkt) { return AST_FAILURE; @@ -4249,6 +4236,10 @@ static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, uint32_t seqno, in pkt->time_sent = ast_tvnow(); /* time packet was sent */ pkt->retrans_stop_time = 64 * (pkt->timer_t1 ? pkt->timer_t1 : DEFAULT_TIMER_T1); /* time in ms after pkt->time_sent to stop retransmission */ + if (!(p->socket.type & AST_TRANSPORT_UDP)) { + pkt->retrans_stop = 1; + } + /* Schedule retransmission */ ao2_t_ref(pkt, +1, "Schedule packet retransmission"); pkt->retransid = ast_sched_add_variable(sched, siptimer_a, retrans_pkt, pkt, 1); @@ -7665,7 +7656,8 @@ static int interpret_t38_parameters(struct sip_pvt *p, const struct ast_control_ ast_udptl_set_local_max_ifp(p->udptl, p->t38.our_parms.max_ifp); change_t38_state(p, T38_ENABLED); transmit_response_with_t38_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL); - } else if (p->t38.state != T38_ENABLED) { + } else if ((p->t38.state != T38_ENABLED) || ((p->t38.state == T38_ENABLED) && + (parameters->request_response == AST_T38_REQUEST_NEGOTIATE))) { p->t38.our_parms = *parameters; ast_udptl_set_local_max_ifp(p->udptl, p->t38.our_parms.max_ifp); change_t38_state(p, T38_LOCAL_REINVITE); @@ -8606,29 +8598,31 @@ static struct ast_frame *sip_read(struct ast_channel *ast) if (faxdetected && ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT_CNG)) { if (strcmp(ast_channel_exten(ast), "fax")) { const char *target_context = S_OR(ast_channel_macrocontext(ast), ast_channel_context(ast)); - /* We need to unlock 'ast' here because + /* + * We need to unlock 'ast' here because * ast_exists_extension has the potential to start and * stop an autoservice on the channel. Such action is * prone to deadlock if the channel is locked. + * + * ast_async_goto() has its own restriction on not holding + * the channel lock. */ sip_pvt_unlock(p); ast_channel_unlock(ast); + ast_frfree(fr); + fr = &ast_null_frame; if (ast_exists_extension(ast, target_context, "fax", 1, S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, NULL))) { - ast_channel_lock(ast); - sip_pvt_lock(p); ast_verb(2, "Redirecting '%s' to fax extension due to CNG detection\n", ast_channel_name(ast)); pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast)); if (ast_async_goto(ast, target_context, "fax", 1)) { ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast), target_context); } - ast_frfree(fr); - fr = &ast_null_frame; } else { - ast_channel_lock(ast); - sip_pvt_lock(p); ast_log(LOG_NOTICE, "FAX CNG detected but no fax extension\n"); } + ast_channel_lock(ast); + sip_pvt_lock(p); } } @@ -11334,25 +11328,7 @@ static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_ ast_rtp_codecs_payloads_unset(newaudiortp, NULL, codec); } - if (ast_format_cmp(format, ast_format_siren7) == AST_FORMAT_CMP_EQUAL) { - if (sscanf(fmtp_string, "bitrate=%30u", &bit_rate) == 1) { - if (bit_rate != 32000) { - ast_log(LOG_WARNING, "Got Siren7 offer at %u bps, but only 32000 bps supported; ignoring.\n", bit_rate); - ast_rtp_codecs_payloads_unset(newaudiortp, NULL, codec); - } else { - found = TRUE; - } - } - } else if (ast_format_cmp(format, ast_format_siren14) == AST_FORMAT_CMP_EQUAL) { - if (sscanf(fmtp_string, "bitrate=%30u", &bit_rate) == 1) { - if (bit_rate != 48000) { - ast_log(LOG_WARNING, "Got Siren14 offer at %u bps, but only 48000 bps supported; ignoring.\n", bit_rate); - ast_rtp_codecs_payloads_unset(newaudiortp, NULL, codec); - } else { - found = TRUE; - } - } - } else if (ast_format_cmp(format, ast_format_g719) == AST_FORMAT_CMP_EQUAL) { + if (ast_format_cmp(format, ast_format_g719) == AST_FORMAT_CMP_EQUAL) { if (sscanf(fmtp_string, "bitrate=%30u", &bit_rate) == 1) { if (bit_rate != 64000) { ast_log(LOG_WARNING, "Got G.719 offer at %u bps, but only 64000 bps supported; ignoring.\n", bit_rate); @@ -13011,12 +12987,6 @@ static void add_codec_to_sdp(const struct sip_pvt *p, } else if (ast_format_cmp(format, ast_format_g723) == AST_FORMAT_CMP_EQUAL) { /* Indicate that we don't support VAD (G.723.1 annex A) */ ast_str_append(a_buf, 0, "a=fmtp:%d annexa=no\r\n", rtp_code); - } else if (ast_format_cmp(format, ast_format_siren7) == AST_FORMAT_CMP_EQUAL) { - /* Indicate that we only expect 32Kbps */ - ast_str_append(a_buf, 0, "a=fmtp:%d bitrate=32000\r\n", rtp_code); - } else if (ast_format_cmp(format, ast_format_siren14) == AST_FORMAT_CMP_EQUAL) { - /* Indicate that we only expect 48Kbps */ - ast_str_append(a_buf, 0, "a=fmtp:%d bitrate=48000\r\n", rtp_code); } else if (ast_format_cmp(format, ast_format_g719) == AST_FORMAT_CMP_EQUAL) { /* Indicate that we only expect 64Kbps */ ast_str_append(a_buf, 0, "a=fmtp:%d bitrate=64000\r\n", rtp_code); @@ -14156,9 +14126,10 @@ static void build_contact(struct sip_pvt *p, struct sip_request *req, int incomi /*! \brief Initiate new SIP request to peer/user */ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, const char * const explicit_uri) { - struct ast_str *invite = ast_str_alloca(256); - char from[256]; - char to[256]; +#define SIPHEADER 256 + struct ast_str *invite = ast_str_create(SIPHEADER); + struct ast_str *from = ast_str_create(SIPHEADER); + struct ast_str *to = ast_str_create(SIPHEADER); char tmp_n[SIPBUFSIZE/2]; /* build a local copy of 'n' if needed */ char tmp_l[SIPBUFSIZE/2]; /* build a local copy of 'l' if needed */ const char *l = NULL; /* XXX what is this, exactly ? */ @@ -14260,34 +14231,40 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho ourport = (p->fromdomainport && (p->fromdomainport != STANDARD_SIP_PORT)) ? p->fromdomainport : ast_sockaddr_port(&p->ourip); if (!sip_standard_port(p->socket.type, ourport)) { - ret = snprintf(from, sizeof(from), "<sip:%s@%s:%d>;tag=%s", tmp_l, d, ourport, p->tag); + ret = ast_str_set(&from, 0, "<sip:%s@%s:%d>;tag=%s", tmp_l, d, ourport, p->tag); } else { - ret = snprintf(from, sizeof(from), "<sip:%s@%s>;tag=%s", tmp_l, d, p->tag); + ret = ast_str_set(&from, 0, "<sip:%s@%s>;tag=%s", tmp_l, d, p->tag); } - if (ret < 0 || ret >= sizeof(from)) { /* a return value of size or more means that the output was truncated */ + if (ret == AST_DYNSTR_BUILD_FAILED) { /* We don't have an escape path from here... */ ast_log(LOG_ERROR, "The From header was truncated in call '%s'. This call setup will fail.\n", p->callid); + /* Make sure that the field contains something non-broken. + See https://issues.asterisk.org/jira/browse/ASTERISK-26069 + */ + ast_str_set(&from, 3, "<>"); + } /* If a caller id name was specified, prefix a display name, if there is enough room. */ if (cid_has_name || !cid_has_num) { - size_t written = strlen(from); - ssize_t left = sizeof(from) - written - 4; /* '"" \0' */ - if (left > 0) { - size_t name_len; - if (sip_cfg.pedanticsipchecking) { - ast_escape_quoted(n, tmp_n, MIN(left + 1, sizeof(tmp_n))); - n = tmp_n; - } - name_len = strlen(n); - if (left < name_len) { - name_len = left; - } - memmove(from + name_len + 3, from, written + 1); - from[0] = '"'; - memcpy(from + 1, n, name_len); - from[name_len + 1] = '"'; - from[name_len + 2] = ' '; + size_t written = ast_str_strlen(from); + size_t name_len; + if (sip_cfg.pedanticsipchecking) { + ast_escape_quoted(n, tmp_n, sizeof(tmp_n)); + n = tmp_n; + } + name_len = strlen(n); + ret = ast_str_make_space(&from, name_len + written + 4); + + if (ret == 0) { + /* needed again, as ast_str_make_space coud've changed the pointer */ + char *from_buf = ast_str_buffer(from); + + memmove(from_buf + name_len + 3, from_buf, written + 1); + from_buf[0] = '"'; + memcpy(from_buf + 1, n, name_len); + from_buf[name_len + 1] = '"'; + from_buf[name_len + 2] = ' '; } } @@ -14330,24 +14307,28 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho /*! \todo Need to add back the VXML URL here at some point, possibly use build_string for all this junk */ if (!strchr(p->todnid, '@')) { /* We have no domain in the dnid */ - ret = snprintf(to, sizeof(to), "<sip:%s@%s>%s%s", p->todnid, p->tohost, ast_strlen_zero(p->theirtag) ? "" : ";tag=", p->theirtag); + ret = ast_str_set(&to, 0, "<sip:%s@%s>%s%s", p->todnid, p->tohost, ast_strlen_zero(p->theirtag) ? "" : ";tag=", p->theirtag); } else { - ret = snprintf(to, sizeof(to), "<sip:%s>%s%s", p->todnid, ast_strlen_zero(p->theirtag) ? "" : ";tag=", p->theirtag); + ret = ast_str_set(&to, 0, "<sip:%s>%s%s", p->todnid, ast_strlen_zero(p->theirtag) ? "" : ";tag=", p->theirtag); } } else { if (sipmethod == SIP_NOTIFY && !ast_strlen_zero(p->theirtag)) { /* If this is a NOTIFY, use the From: tag in the subscribe (RFC 3265) */ - ret = snprintf(to, sizeof(to), "<%s%s>;tag=%s", (strncasecmp(p->uri, "sip:", 4) ? "sip:" : ""), p->uri, p->theirtag); + ret = ast_str_set(&to, 0, "<%s%s>;tag=%s", (strncasecmp(p->uri, "sip:", 4) ? "sip:" : ""), p->uri, p->theirtag); } else if (p->options && p->options->vxml_url) { /* If there is a VXML URL append it to the SIP URL */ - ret = snprintf(to, sizeof(to), "<%s>;%s", p->uri, p->options->vxml_url); + ret = ast_str_set(&to, 0, "<%s>;%s", p->uri, p->options->vxml_url); } else { - ret = snprintf(to, sizeof(to), "<%s>", p->uri); + ret = ast_str_set(&to, 0, "<%s>", p->uri); } } - if (ret < 0 || ret >= sizeof(to)) { /* a return value of size or more means that the output was truncated */ + if (ret == AST_DYNSTR_BUILD_FAILED) { /* We don't have an escape path from here... */ ast_log(LOG_ERROR, "The To header was truncated in call '%s'. This call setup will fail.\n", p->callid); + /* Make sure that the field contains something non-broken. + See https://issues.asterisk.org/jira/browse/ASTERISK-26069 + */ + ast_str_set(&to, 3, "<>"); } init_req(req, sipmethod, p->uri); @@ -14362,8 +14343,8 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho */ add_route(req, &p->route, 0); - add_header(req, "From", from); - add_header(req, "To", to); + add_header(req, "From", ast_str_buffer(from)); + add_header(req, "To", ast_str_buffer(to)); ast_string_field_set(p, exten, l); build_contact(p, req, 0); add_header(req, "Contact", p->our_contact); @@ -14372,6 +14353,10 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho if (!ast_strlen_zero(global_useragent)) { add_header(req, "User-Agent", global_useragent); } + + ast_free(from); + ast_free(to); + ast_free(invite); } /*! \brief Add "Diversion" header to outgoing message @@ -17196,10 +17181,8 @@ static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct struct sip_peer *peer = sip_find_peer(peer_name, NULL, TRUE, FINDALLDEVICES, FALSE, 0); if (stasis_subscription_final_message(sub, msg)) { - if (peer) { - /* configuration reloaded */ - return; - } + /* peer can be non-NULL during reload. */ + ao2_cleanup(peer); ast_free(peer_name); return; } @@ -18353,7 +18336,7 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re static int get_sip_pvt_from_replaces(const char *callid, const char *totag, const char *fromtag, struct sip_pvt **out_pvt, struct ast_channel **out_chan) { - struct sip_pvt *sip_pvt_ptr; + RAII_VAR(struct sip_pvt *, sip_pvt_ptr, NULL, ao2_cleanup); struct sip_pvt tmp_dialog = { .callid = callid, }; @@ -18428,6 +18411,9 @@ static int get_sip_pvt_from_replaces(const char *callid, const char *totag, } } + /* If we're here sip_pvt_ptr has been copied to *out_pvt, prevent RAII_VAR cleanup */ + sip_pvt_ptr = NULL; + return 0; } @@ -21287,15 +21273,13 @@ static char *sip_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_arg } /*! \brief Callback for show_chanstats */ -static int show_chanstats_cb(void *__cur, void *__arg, int flags) +static int show_chanstats_cb(struct sip_pvt *cur, struct __show_chan_arg *arg) { #define FORMAT2 "%-15.15s %-11.11s %-8.8s %-10.10s %-10.10s ( %%) %-6.6s %-10.10s %-10.10s ( %%) %-6.6s\n" #define FORMAT "%-15.15s %-11.11s %-8.8s %-10.10u%-1.1s %-10.10u (%5.2f%%) %-6.4lf %-10.10u%-1.1s %-10.10u (%5.2f%%) %-6.4lf\n" - struct sip_pvt *cur = __cur; struct ast_rtp_instance_stats stats; char durbuf[10]; struct ast_channel *c; - struct __show_chan_arg *arg = __arg; int fd = arg->fd; sip_pvt_lock(cur); @@ -21355,6 +21339,8 @@ static int show_chanstats_cb(void *__cur, void *__arg, int flags) static char *sip_show_channelstats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct __show_chan_arg arg = { .fd = a->fd, .numchans = 0 }; + struct sip_pvt *cur; + struct ao2_iterator i; switch (cmd) { case CLI_INIT: @@ -21372,8 +21358,14 @@ static char *sip_show_channelstats(struct ast_cli_entry *e, int cmd, struct ast_ return CLI_SHOWUSAGE; ast_cli(a->fd, FORMAT2, "Peer", "Call ID", "Duration", "Recv: Pack", "Lost", "Jitter", "Send: Pack", "Lost", "Jitter"); + /* iterate on the container and invoke the callback on each item */ - ao2_t_callback(dialogs, OBJ_NODATA, show_chanstats_cb, &arg, "callback to sip show chanstats"); + i = ao2_iterator_init(dialogs, 0); + for (; (cur = ao2_iterator_next(&i)); ao2_ref(cur, -1)) { + show_chanstats_cb(cur, &arg); + } + ao2_iterator_destroy(&i); + ast_cli(a->fd, "%d active SIP channel%s\n", arg.numchans, (arg.numchans != 1) ? "s" : ""); return CLI_SUCCESS; } @@ -21689,10 +21681,8 @@ static const struct cfsubscription_types *find_subscription_type(enum subscripti #define FORMAT "%-15.15s %-15.15s %-15.15s %-15.15s %-3.3s %-3.3s %-15.15s %-10.10s %-10.10s\n" /*! \brief callback for show channel|subscription */ -static int show_channels_cb(void *__cur, void *__arg, int flags) +static int show_channels_cb(struct sip_pvt *cur, struct __show_chan_arg *arg) { - struct sip_pvt *cur = __cur; - struct __show_chan_arg *arg = __arg; const struct ast_sockaddr *dst; sip_pvt_lock(cur); @@ -21744,7 +21734,8 @@ static int show_channels_cb(void *__cur, void *__arg, int flags) static char *sip_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct __show_chan_arg arg = { .fd = a->fd, .numchans = 0 }; - + struct sip_pvt *cur; + struct ao2_iterator i; if (cmd == CLI_INIT) { e->command = "sip show {channels|subscriptions}"; @@ -21766,7 +21757,11 @@ static char *sip_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_ ast_cli(arg.fd, FORMAT3, "Peer", "User", "Call ID", "Extension", "Last state", "Type", "Mailbox", "Expiry"); /* iterate on the container and invoke the callback on each item */ - ao2_t_callback(dialogs, OBJ_NODATA, show_channels_cb, &arg, "callback to show channels"); + i = ao2_iterator_init(dialogs, 0); + for (; (cur = ao2_iterator_next(&i)); ao2_ref(cur, -1)) { + show_channels_cb(cur, &arg); + } + ao2_iterator_destroy(&i); /* print summary information */ ast_cli(arg.fd, "%d active SIP %s%s\n", arg.numchans, @@ -24590,6 +24585,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc char *c_copy = ast_strdupa(c); /* Skip the Cseq and its subsequent spaces */ const char *msg = ast_skip_blanks(ast_skip_nonblanks(c_copy)); + int ack_res = FALSE; if (!msg) msg = ""; @@ -24618,28 +24614,24 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc ast_channel_hangupcause_set(owner, hangup_sip2cause(resp)); } - if (p->socket.type == AST_TRANSPORT_UDP) { - int ack_res = FALSE; - - /* Acknowledge whatever it is destined for */ - if ((resp >= 100) && (resp <= 199)) { - /* NON-INVITE messages do not ack a 1XX response. RFC 3261 section 17.1.2.2 */ - if (sipmethod == SIP_INVITE) { - ack_res = __sip_semi_ack(p, seqno, 0, sipmethod); - } - } else { - ack_res = __sip_ack(p, seqno, 0, sipmethod); + /* Acknowledge whatever it is destined for */ + if ((resp >= 100) && (resp <= 199)) { + /* NON-INVITE messages do not ack a 1XX response. RFC 3261 section 17.1.2.2 */ + if (sipmethod == SIP_INVITE) { + ack_res = __sip_semi_ack(p, seqno, 0, sipmethod); } + } else { + ack_res = __sip_ack(p, seqno, 0, sipmethod); + } - if (ack_res == FALSE) { - /* RFC 3261 13.2.2.4 and 17.1.1.2 - We must re-send ACKs to re-transmitted final responses */ - if (sipmethod == SIP_INVITE && resp >= 200) { - transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, resp < 300 ? TRUE: FALSE); - } - - append_history(p, "Ignore", "Ignoring this retransmit\n"); - return; + if (ack_res == FALSE) { + /* RFC 3261 13.2.2.4 and 17.1.1.2 - We must re-send ACKs to re-transmitted final responses */ + if (sipmethod == SIP_INVITE && resp >= 200) { + transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, resp < 300 ? TRUE: FALSE); } + + append_history(p, "Ignore", "Ignoring this retransmit\n"); + return; } /* If this is a NOTIFY for a subscription clear the flag that indicates that we have a NOTIFY pending */ @@ -31041,6 +31033,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str return NULL; } if (!(peer->endpoint = ast_endpoint_create("SIP", name))) { + ao2_t_ref(peer, -1, "failed to allocate endpoint, drop peer"); return NULL; } if (!(peer->caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { |