diff options
Diffstat (limited to 'channels/chan_sip.c')
-rw-r--r-- | channels/chan_sip.c | 100 |
1 files changed, 79 insertions, 21 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index bcb4ea73a..4c0e2a66c 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -4262,15 +4262,23 @@ static int sip_setoption(struct ast_channel *chan, int option, void *data, int d int res = -1; struct sip_pvt *p = chan->tech_pvt; + sip_pvt_lock(p); + switch (option) { case AST_OPTION_FORMAT_READ: - res = ast_rtp_instance_set_read_format(p->rtp, (struct ast_format *) data); + if (p->rtp) { + res = ast_rtp_instance_set_read_format(p->rtp, (struct ast_format *) data); + } break; case AST_OPTION_FORMAT_WRITE: - res = ast_rtp_instance_set_write_format(p->rtp, (struct ast_format *) data); + if (p->rtp) { + res = ast_rtp_instance_set_write_format(p->rtp, (struct ast_format *) data); + } break; case AST_OPTION_MAKE_COMPATIBLE: - res = ast_rtp_instance_make_compatible(chan, p->rtp, (struct ast_channel *) data); + if (p->rtp) { + res = ast_rtp_instance_make_compatible(chan, p->rtp, (struct ast_channel *) data); + } break; case AST_OPTION_DIGIT_DETECT: if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) || @@ -4298,6 +4306,8 @@ static int sip_setoption(struct ast_channel *chan, int option, void *data, int d break; } + sip_pvt_unlock(p); + return res; } @@ -4309,16 +4319,16 @@ static int sip_queryoption(struct ast_channel *chan, int option, void *data, int struct sip_pvt *p = (struct sip_pvt *) chan->tech_pvt; char *cp; + sip_pvt_lock(p); + switch (option) { case AST_OPTION_T38_STATE: /* Make sure we got an ast_t38_state enum passed in */ if (*datalen != sizeof(enum ast_t38_state)) { ast_log(LOG_ERROR, "Invalid datalen for AST_OPTION_T38_STATE option. Expected %d, got %d\n", (int)sizeof(enum ast_t38_state), *datalen); - return -1; + break; } - sip_pvt_lock(p); - /* Now if T38 support is enabled we need to look and see what the current state is to get what we want to report back */ if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT)) { switch (p->t38.state) { @@ -4337,8 +4347,6 @@ static int sip_queryoption(struct ast_channel *chan, int option, void *data, int } } - sip_pvt_unlock(p); - *((enum ast_t38_state *) data) = state; res = 0; @@ -4370,6 +4378,8 @@ static int sip_queryoption(struct ast_channel *chan, int option, void *data, int break; } + sip_pvt_unlock(p); + return res; } @@ -5061,6 +5071,7 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog) } ast_rtp_instance_set_timeout(dialog->vrtp, global_rtptimeout); ast_rtp_instance_set_hold_timeout(dialog->vrtp, global_rtpholdtimeout); + ast_rtp_instance_set_keepalive(dialog->vrtp, global_rtpholdtimeout); ast_rtp_instance_set_prop(dialog->vrtp, AST_RTP_PROPERTY_RTCP, 1); } @@ -5071,12 +5082,14 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog) } ast_rtp_instance_set_timeout(dialog->trtp, global_rtptimeout); ast_rtp_instance_set_hold_timeout(dialog->trtp, global_rtpholdtimeout); + ast_rtp_instance_set_keepalive(dialog->trtp, global_rtpholdtimeout); ast_rtp_instance_set_prop(dialog->trtp, AST_RTP_PROPERTY_RTCP, 1); } ast_rtp_instance_set_timeout(dialog->rtp, global_rtptimeout); ast_rtp_instance_set_hold_timeout(dialog->rtp, global_rtpholdtimeout); + ast_rtp_instance_set_keepalive(dialog->rtp, global_rtpkeepalive); ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_RTCP, 1); ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&dialog->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833); @@ -5144,6 +5157,7 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer) ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF_COMPENSATE, ast_test_flag(&dialog->flags[1], SIP_PAGE2_RFC2833_COMPENSATE)); ast_rtp_instance_set_timeout(dialog->rtp, peer->rtptimeout); ast_rtp_instance_set_hold_timeout(dialog->rtp, peer->rtpholdtimeout); + ast_rtp_instance_set_keepalive(dialog->rtp, peer->rtpkeepalive); /* Set Frame packetization */ ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(dialog->rtp), dialog->rtp, &dialog->prefs); dialog->autoframing = peer->autoframing; @@ -5151,10 +5165,12 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer) if (dialog->vrtp) { /* Video */ ast_rtp_instance_set_timeout(dialog->vrtp, peer->rtptimeout); ast_rtp_instance_set_hold_timeout(dialog->vrtp, peer->rtpholdtimeout); + ast_rtp_instance_set_keepalive(dialog->vrtp, peer->rtpkeepalive); } if (dialog->trtp) { /* Realtime text */ ast_rtp_instance_set_timeout(dialog->trtp, peer->rtptimeout); ast_rtp_instance_set_hold_timeout(dialog->trtp, peer->rtpholdtimeout); + ast_rtp_instance_set_keepalive(dialog->trtp, peer->rtpkeepalive); } /* XXX TODO: get fields directly from peer only as they are needed using dialog->relatedpeer */ @@ -6344,7 +6360,11 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame) } if (p) { sip_pvt_lock(p); - if (p->rtp) { + if (p->t38.state == T38_ENABLED) { + /* drop frame, can't sent VOICE frames while in T.38 mode */ + sip_pvt_unlock(p); + break; + } else if (p->rtp) { /* If channel is not up, activate early media session */ if ((ast->_state != AST_STATE_UP) && !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) && @@ -6355,12 +6375,9 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame) transmit_provisional_response(p, "183 Session Progress", &p->initreq, TRUE); ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT); } - } else if (p->t38.state == T38_ENABLED) { - /* drop frame, can't sent VOICE frames while in T.38 mode */ - } else { - p->lastrtptx = time(NULL); - res = ast_rtp_instance_write(p->rtp, frame); } + p->lastrtptx = time(NULL); + res = ast_rtp_instance_write(p->rtp, frame); } sip_pvt_unlock(p); } @@ -7274,12 +7291,19 @@ static struct ast_frame *sip_read(struct ast_channel *ast) /* If we detect a CNG tone and fax detection is enabled then send us off to the fax extension */ if (faxdetected && ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT_CNG)) { - ast_channel_lock(ast); if (strcmp(ast->exten, "fax")) { const char *target_context = S_OR(ast->macrocontext, ast->context); + /* 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. + */ + sip_pvt_unlock(p); ast_channel_unlock(ast); if (ast_exists_extension(ast, target_context, "fax", 1, S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, NULL))) { + ast_channel_lock(ast); + sip_pvt_lock(p); ast_verbose(VERBOSE_PREFIX_2 "Redirecting '%s' to fax extension due to CNG detection\n", ast->name); pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten); if (ast_async_goto(ast, target_context, "fax", 1)) { @@ -7287,10 +7311,10 @@ static struct ast_frame *sip_read(struct ast_channel *ast) } 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"); } - } else { - ast_channel_unlock(ast); } } @@ -15749,8 +15773,12 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of, p->callingpres = peer->callingpres; } ast_string_field_set(p, fullcontact, peer->fullcontact); - if (!ast_strlen_zero(peer->context)) + if (!ast_strlen_zero(peer->context)) { ast_string_field_set(p, context, peer->context); + } + if (!ast_strlen_zero(peer->messagecontext)) { + ast_string_field_set(p, messagecontext, peer->messagecontext); + } ast_string_field_set(p, peersecret, peer->secret); ast_string_field_set(p, peermd5secret, peer->md5secret); ast_string_field_set(p, language, peer->language); @@ -16080,6 +16108,10 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a if (ast_strlen_zero(peer->secret) && ast_strlen_zero(peer->md5secret)) { ast_string_field_set(p, context, peer->context); } + if (!ast_strlen_zero(peer->messagecontext)) { + ast_string_field_set(p, messagecontext, peer->messagecontext); + } + ast_string_field_set(p, peername, peer->name); peer = unref_peer(peer, "from find_peer() in receive_message"); } } @@ -16100,7 +16132,19 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a res = ast_msg_set_to(msg, "%s", to); res |= ast_msg_set_from(msg, "%s", get_in_brackets(from)); res |= ast_msg_set_body(msg, "%s", ast_str_buffer(buf)); - res |= ast_msg_set_context(msg, "%s", p->context); + + if (!ast_strlen_zero(p->messagecontext)) { + res |= ast_msg_set_context(msg, "%s", p->messagecontext); + } else if (!ast_strlen_zero(sip_cfg.messagecontext)) { + res |= ast_msg_set_context(msg, "%s", sip_cfg.messagecontext); + } else { + res |= ast_msg_set_context(msg, "%s", p->context); + } + + if (!ast_strlen_zero(p->peername)) { + res |= ast_msg_set_var(msg, "SIP_PEERNAME", p->peername); + } + res |= ast_msg_set_exten(msg, "%s", p->exten); if (res) { @@ -25368,11 +25412,19 @@ static void check_rtp_timeout(struct sip_pvt *dialog, time_t t) } /* If we have no timers set, return now */ - if (!ast_rtp_instance_get_timeout(dialog->rtp) && !ast_rtp_instance_get_hold_timeout(dialog->rtp)) { + if (!ast_rtp_instance_get_keepalive(dialog->rtp) && !ast_rtp_instance_get_timeout(dialog->rtp) && !ast_rtp_instance_get_hold_timeout(dialog->rtp)) { dialog_unlink_rtpcheck(dialog); return; } + /* Check AUDIO RTP keepalives */ + if (dialog->lastrtptx && ast_rtp_instance_get_keepalive(dialog->rtp) && + (t > dialog->lastrtptx + ast_rtp_instance_get_keepalive(dialog->rtp))) { + /* Need to send an empty RTP packet */ + dialog->lastrtptx = time(NULL); + ast_rtp_instance_sendcng(dialog->rtp, 0); + } + /*! \todo Check video RTP keepalives Do we need to move the lastrtptx to the RTP structure to have one for audio and one @@ -26671,6 +26723,7 @@ static void set_peer_defaults(struct sip_peer *peer) ast_copy_flags(&peer->flags[1], &global_flags[1], SIP_PAGE2_FLAGS_TO_COPY); ast_copy_flags(&peer->flags[2], &global_flags[2], SIP_PAGE3_FLAGS_TO_COPY); ast_string_field_set(peer, context, sip_cfg.default_context); + ast_string_field_set(peer, messagecontext, sip_cfg.messagecontext); ast_string_field_set(peer, subscribecontext, sip_cfg.default_subscribecontext); ast_string_field_set(peer, language, default_language); ast_string_field_set(peer, mohinterpret, default_mohinterpret); @@ -26965,6 +27018,8 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str } else if (!strcasecmp(v->name, "context")) { ast_string_field_set(peer, context, v->value); ast_set_flag(&peer->flags[1], SIP_PAGE2_HAVEPEERCONTEXT); + } else if (!strcasecmp(v->name, "outofcall_message_context")) { + ast_string_field_set(peer, messagecontext, v->value); } else if (!strcasecmp(v->name, "subscribecontext")) { ast_string_field_set(peer, subscribecontext, v->value); } else if (!strcasecmp(v->name, "fromdomain")) { @@ -27351,7 +27406,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str * specified, use that address instead. */ /* XXX May need to revisit the final argument; does the realtime DB store whether * the original contact was over TLS or not? XXX */ - if (!ast_test_flag(&peer->flags[0], SIP_NAT_RPORT_PRESENT) || ast_sockaddr_isnull(&peer->addr)) { + if (!ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT) || ast_sockaddr_isnull(&peer->addr)) { __set_address_from_contact(fullcontact->str, &peer->addr, 0); } } @@ -27653,6 +27708,7 @@ static int reload_config(enum channelreloadreason reason) sip_cfg.alwaysauthreject = DEFAULT_ALWAYSAUTHREJECT; sip_cfg.auth_options_requests = DEFAULT_AUTH_OPTIONS; sip_cfg.auth_message_requests = DEFAULT_AUTH_MESSAGE; + sip_cfg.messagecontext[0] = '\0'; sip_cfg.accept_outofcall_message = DEFAULT_ACCEPT_OUTOFCALL_MESSAGE; sip_cfg.allowsubscribe = FALSE; sip_cfg.disallowed_methods = SIP_UNKNOWN; @@ -27906,6 +27962,8 @@ static int reload_config(enum channelreloadreason reason) sip_cfg.auth_message_requests = ast_true(v->value) ? 1 : 0; } else if (!strcasecmp(v->name, "accept_outofcall_message")) { sip_cfg.accept_outofcall_message = ast_true(v->value) ? 1 : 0; + } else if (!strcasecmp(v->name, "outofcall_message_context")) { + ast_copy_string(sip_cfg.messagecontext, v->value, sizeof(sip_cfg.messagecontext)); } else if (!strcasecmp(v->name, "mohinterpret")) { ast_copy_string(default_mohinterpret, v->value, sizeof(default_mohinterpret)); } else if (!strcasecmp(v->name, "mohsuggest")) { |