Merged revisions 288194 via svnmerge from

https://origsvn.digium.com/svn/asterisk/branches/1.8

................
  r288194 | rmudgett | 2010-09-21 19:06:21 -0500 (Tue, 21 Sep 2010) | 40 lines
  
  Merged revisions 288193 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.6.2
  
  ................
    r288193 | rmudgett | 2010-09-21 19:03:37 -0500 (Tue, 21 Sep 2010) | 33 lines
    
    Merged revisions 288192 via svnmerge from 
    https://origsvn.digium.com/svn/asterisk/branches/1.4
    
    ........
      r288192 | rmudgett | 2010-09-21 18:55:58 -0500 (Tue, 21 Sep 2010) | 26 lines
      
      In chan_iax2.c:schedule_delivery() calls ast_bridged_channel() on an unlocked channel.
      
      Near the beginning of schedule_delivery(), ast_bridged_channel() is called
      on iaxs[fr->callno]->owner.  However, the channel is not locked, which can
      result in ast_bridged_channel() crashing should owner->tech change to a
      technology that doesn't implement bridged_channel.
      
      I also fixed the other calls to ast_bridged_channel() in chan_iax2.c since
      the owner lock was not held there either.
      
      Converted the existing channel deadlock avoidance to use
      iax2_lock_owner().  Using the new function simplified some awkward code.
      
      In the process of fixing the locking on ast_bridged_channel(), I also
      found a memory leak in socket_process() for v1.6.2 and v1.8.  The local
      struct variable ies.vars is not freed on early/abnormal function exits.
      
      (closes issue #17919)
      Reported by: rain
      Patches:
            issue17919_v1.4.patch uploaded by rmudgett (license 664)
            issue17919_w_leak_v1.6.2.patch uploaded by rmudgett (license 664)
            issue17919_w_leak_v1.8.patch uploaded by rmudgett (license 664)
      
      Review: https://reviewboard.asterisk.org/r/926/
    ........
  ................
................


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@288195 65c4cc65-6c06-0410-ace0-fbb531ad65f3
10-digiumphones
Richard Mudgett 15 years ago
parent 949e81e6e5
commit c5f5c24103

@ -1237,6 +1237,39 @@ static const struct ast_channel_tech iax2_tech = {
.func_channel_read = acf_channel_read, .func_channel_read = acf_channel_read,
}; };
/*!
* \internal
* \brief Obtain the owner channel lock if the owner exists.
*
* \param callno IAX2 call id.
*
* \note Assumes the iaxsl[callno] lock is already obtained.
*
* \note
* IMPORTANT NOTE!!! Any time this function is used, even if
* iaxs[callno] was valid before calling it, it may no longer be
* valid after calling it. This function may unlock and lock
* the mutex associated with this callno, meaning that another
* thread may grab it and destroy the call.
*
* \return Nothing
*/
static void iax2_lock_owner(int callno)
{
for (;;) {
if (!iaxs[callno] || !iaxs[callno]->owner) {
/* There is no owner lock to get. */
break;
}
if (!ast_channel_trylock(iaxs[callno]->owner)) {
/* We got the lock */
break;
}
/* Avoid deadlock by pausing and trying again */
DEADLOCK_AVOIDANCE(&iaxsl[callno]);
}
}
static void mwi_event_cb(const struct ast_event *event, void *userdata) static void mwi_event_cb(const struct ast_event *event, void *userdata)
{ {
/* The MWI subscriptions exist just so the core knows we care about those /* The MWI subscriptions exist just so the core knows we care about those
@ -2890,18 +2923,10 @@ static int find_callno_locked(unsigned short callno, unsigned short dcallno, str
*/ */
static int iax2_queue_frame(int callno, struct ast_frame *f) static int iax2_queue_frame(int callno, struct ast_frame *f)
{ {
for (;;) { iax2_lock_owner(callno);
if (iaxs[callno] && iaxs[callno]->owner) { if (iaxs[callno] && iaxs[callno]->owner) {
if (ast_channel_trylock(iaxs[callno]->owner)) { ast_queue_frame(iaxs[callno]->owner, f);
/* Avoid deadlock by pausing and trying again */ ast_channel_unlock(iaxs[callno]->owner);
DEADLOCK_AVOIDANCE(&iaxsl[callno]);
} else {
ast_queue_frame(iaxs[callno]->owner, f);
ast_channel_unlock(iaxs[callno]->owner);
break;
}
} else
break;
} }
return 0; return 0;
} }
@ -2921,18 +2946,10 @@ static int iax2_queue_frame(int callno, struct ast_frame *f)
*/ */
static int iax2_queue_hangup(int callno) static int iax2_queue_hangup(int callno)
{ {
for (;;) { iax2_lock_owner(callno);
if (iaxs[callno] && iaxs[callno]->owner) { if (iaxs[callno] && iaxs[callno]->owner) {
if (ast_channel_trylock(iaxs[callno]->owner)) { ast_queue_hangup(iaxs[callno]->owner);
/* Avoid deadlock by pausing and trying again */ ast_channel_unlock(iaxs[callno]->owner);
DEADLOCK_AVOIDANCE(&iaxsl[callno]);
} else {
ast_queue_hangup(iaxs[callno]->owner);
ast_channel_unlock(iaxs[callno]->owner);
break;
}
} else
break;
} }
return 0; return 0;
} }
@ -2953,18 +2970,10 @@ static int iax2_queue_hangup(int callno)
static int iax2_queue_control_data(int callno, static int iax2_queue_control_data(int callno,
enum ast_control_frame_type control, const void *data, size_t datalen) enum ast_control_frame_type control, const void *data, size_t datalen)
{ {
for (;;) { iax2_lock_owner(callno);
if (iaxs[callno] && iaxs[callno]->owner) { if (iaxs[callno] && iaxs[callno]->owner) {
if (ast_channel_trylock(iaxs[callno]->owner)) { ast_queue_control_data(iaxs[callno]->owner, control, data, datalen);
/* Avoid deadlock by pausing and trying again */ ast_channel_unlock(iaxs[callno]->owner);
DEADLOCK_AVOIDANCE(&iaxsl[callno]);
} else {
ast_queue_control_data(iaxs[callno]->owner, control, data, datalen);
ast_channel_unlock(iaxs[callno]->owner);
break;
}
} else
break;
} }
return 0; return 0;
} }
@ -4143,6 +4152,12 @@ static int schedule_delivery(struct iax_frame *fr, int updatehistory, int fromtr
return -1; return -1;
} }
iax2_lock_owner(fr->callno);
if (!iaxs[fr->callno]) {
/* The call dissappeared so discard this frame that we could not send. */
iax2_frame_free(fr);
return -1;
}
if ((owner = iaxs[fr->callno]->owner)) if ((owner = iaxs[fr->callno]->owner))
bridge = ast_bridged_channel(owner); bridge = ast_bridged_channel(owner);
@ -4151,6 +4166,8 @@ static int schedule_delivery(struct iax_frame *fr, int updatehistory, int fromtr
if ( (!ast_test_flag64(iaxs[fr->callno], IAX_FORCEJITTERBUF)) && owner && bridge && (bridge->tech->properties & AST_CHAN_TP_WANTSJITTER) ) { if ( (!ast_test_flag64(iaxs[fr->callno], IAX_FORCEJITTERBUF)) && owner && bridge && (bridge->tech->properties & AST_CHAN_TP_WANTSJITTER) ) {
jb_frame frame; jb_frame frame;
ast_channel_unlock(owner);
/* deliver any frames in the jb */ /* deliver any frames in the jb */
while (jb_getall(iaxs[fr->callno]->jb, &frame) == JB_OK) { while (jb_getall(iaxs[fr->callno]->jb, &frame) == JB_OK) {
__do_deliver(frame.data); __do_deliver(frame.data);
@ -4169,6 +4186,9 @@ static int schedule_delivery(struct iax_frame *fr, int updatehistory, int fromtr
__do_deliver(fr); __do_deliver(fr);
return -1; return -1;
} }
if (owner) {
ast_channel_unlock(owner);
}
/* insert into jitterbuffer */ /* insert into jitterbuffer */
/* TODO: Perhaps we could act immediately if it's not droppable and late */ /* TODO: Perhaps we could act immediately if it's not droppable and late */
@ -9708,27 +9728,13 @@ static struct ast_custom_function iaxvar_function = {
static void set_hangup_source_and_cause(int callno, unsigned char causecode) static void set_hangup_source_and_cause(int callno, unsigned char causecode)
{ {
int locked = 0; iax2_lock_owner(callno);
struct ast_channel *owner=NULL;
do {
if (ast_channel_trylock(iaxs[callno]->owner)) {
DEADLOCK_AVOIDANCE(&iaxsl[callno]);
} else {
locked = 1;
owner = iaxs[callno]->owner;
}
}
while (!locked && iaxs[callno] && iaxs[callno]->owner);
if (iaxs[callno] && iaxs[callno]->owner) { if (iaxs[callno] && iaxs[callno]->owner) {
if (causecode) { if (causecode) {
iaxs[callno]->owner->hangupcause = causecode; iaxs[callno]->owner->hangupcause = causecode;
} }
ast_set_hangupsource(iaxs[callno]->owner, iaxs[callno]->owner->name, 0); ast_set_hangupsource(iaxs[callno]->owner, iaxs[callno]->owner->name, 0);
ast_channel_unlock(owner); ast_channel_unlock(iaxs[callno]->owner);
} else if(locked) {
ast_channel_unlock(owner);
} }
} }
@ -9845,6 +9851,7 @@ static int socket_process(struct iax2_thread *thread)
if (f.frametype == AST_FRAME_IAX) { if (f.frametype == AST_FRAME_IAX) {
if (iax_parse_ies(&ies, thread->buf + sizeof(struct ast_iax2_full_hdr), f.datalen)) { if (iax_parse_ies(&ies, thread->buf + sizeof(struct ast_iax2_full_hdr), f.datalen)) {
ast_log(LOG_WARNING, "Undecodable frame received from '%s'\n", ast_inet_ntoa(sin.sin_addr)); ast_log(LOG_WARNING, "Undecodable frame received from '%s'\n", ast_inet_ntoa(sin.sin_addr));
ast_variables_destroy(ies.vars);
return 1; return 1;
} }
f.data.ptr = NULL; f.data.ptr = NULL;
@ -9864,6 +9871,7 @@ static int socket_process(struct iax2_thread *thread)
if (!dcallno && iax2_allow_new(f.frametype, f.subclass.integer, 1)) { if (!dcallno && iax2_allow_new(f.frametype, f.subclass.integer, 1)) {
/* only set NEW_ALLOW if calltoken checks out */ /* only set NEW_ALLOW if calltoken checks out */
if (handle_call_token(fh, &ies, &sin, fd)) { if (handle_call_token(fh, &ies, &sin, fd)) {
ast_variables_destroy(ies.vars);
return 1; return 1;
} }
@ -9881,6 +9889,7 @@ static int socket_process(struct iax2_thread *thread)
/* Don't know anything about it yet */ /* Don't know anything about it yet */
f.frametype = AST_FRAME_NULL; f.frametype = AST_FRAME_NULL;
f.subclass.integer = 0; f.subclass.integer = 0;
memset(&ies, 0, sizeof(ies));
} }
if (!fr->callno) { if (!fr->callno) {
@ -9904,6 +9913,7 @@ static int socket_process(struct iax2_thread *thread)
} else if (f.frametype == AST_FRAME_IAX && (f.subclass.integer == IAX_COMMAND_REGREQ || f.subclass.integer == IAX_COMMAND_REGREL)) { } else if (f.frametype == AST_FRAME_IAX && (f.subclass.integer == IAX_COMMAND_REGREQ || f.subclass.integer == IAX_COMMAND_REGREL)) {
send_apathetic_reply(1, ntohs(fh->scallno), &sin, IAX_COMMAND_REGREJ, ntohl(fh->ts), fh->iseqno + 1, fd, NULL); send_apathetic_reply(1, ntohs(fh->scallno), &sin, IAX_COMMAND_REGREJ, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
} }
ast_variables_destroy(ies.vars);
return 1; return 1;
} }
} }
@ -9926,11 +9936,13 @@ static int socket_process(struct iax2_thread *thread)
} }
if (fr->callno > 0) if (fr->callno > 0)
ast_mutex_unlock(&iaxsl[fr->callno]); ast_mutex_unlock(&iaxsl[fr->callno]);
ast_variables_destroy(ies.vars);
return 1; return 1;
} }
if (ast_test_flag64(iaxs[fr->callno], IAX_ENCRYPTED) && !decrypted) { if (ast_test_flag64(iaxs[fr->callno], IAX_ENCRYPTED) && !decrypted) {
if (decrypt_frame(fr->callno, fh, &f, &res)) { if (decrypt_frame(fr->callno, fh, &f, &res)) {
ast_log(LOG_NOTICE, "Packet Decrypt Failed!\n"); ast_log(LOG_NOTICE, "Packet Decrypt Failed!\n");
ast_variables_destroy(ies.vars);
ast_mutex_unlock(&iaxsl[fr->callno]); ast_mutex_unlock(&iaxsl[fr->callno]);
return 1; return 1;
} }
@ -10020,6 +10032,7 @@ static int socket_process(struct iax2_thread *thread)
/* Send a VNAK requesting retransmission */ /* Send a VNAK requesting retransmission */
iax2_vnak(fr->callno); iax2_vnak(fr->callno);
} }
ast_variables_destroy(ies.vars);
ast_mutex_unlock(&iaxsl[fr->callno]); ast_mutex_unlock(&iaxsl[fr->callno]);
return 1; return 1;
} }
@ -10083,6 +10096,7 @@ static int socket_process(struct iax2_thread *thread)
iaxs[fr->callno]->rseqno = fr->iseqno; iaxs[fr->callno]->rseqno = fr->iseqno;
else { else {
/* Stop processing now */ /* Stop processing now */
ast_variables_destroy(ies.vars);
ast_mutex_unlock(&iaxsl[fr->callno]); ast_mutex_unlock(&iaxsl[fr->callno]);
return 1; return 1;
} }
@ -10095,6 +10109,7 @@ static int socket_process(struct iax2_thread *thread)
((f.subclass.integer != IAX_COMMAND_TXACC) && ((f.subclass.integer != IAX_COMMAND_TXACC) &&
(f.subclass.integer != IAX_COMMAND_TXCNT)))) { (f.subclass.integer != IAX_COMMAND_TXCNT)))) {
/* Only messages we accept from a transfer host are TXACC and TXCNT */ /* Only messages we accept from a transfer host are TXACC and TXCNT */
ast_variables_destroy(ies.vars);
ast_mutex_unlock(&iaxsl[fr->callno]); ast_mutex_unlock(&iaxsl[fr->callno]);
return 1; return 1;
} }
@ -10108,6 +10123,7 @@ static int socket_process(struct iax2_thread *thread)
if (ast_test_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART)) { if (ast_test_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART)) {
ast_clear_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART); ast_clear_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART);
if (!ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->chosenformat, NULL)) { if (!ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->chosenformat, NULL)) {
ast_variables_destroy(ies.vars);
ast_mutex_unlock(&iaxsl[fr->callno]); ast_mutex_unlock(&iaxsl[fr->callno]);
return 1; return 1;
} }
@ -10117,6 +10133,13 @@ static int socket_process(struct iax2_thread *thread)
struct ast_datastore *variablestore = NULL; struct ast_datastore *variablestore = NULL;
struct ast_variable *var, *prev = NULL; struct ast_variable *var, *prev = NULL;
AST_LIST_HEAD(, ast_var_t) *varlist; AST_LIST_HEAD(, ast_var_t) *varlist;
iax2_lock_owner(fr->callno);
if (!iaxs[fr->callno]) {
ast_variables_destroy(ies.vars);
ast_mutex_unlock(&iaxsl[fr->callno]);
return 1;
}
if ((c = iaxs[fr->callno]->owner)) { if ((c = iaxs[fr->callno]->owner)) {
varlist = ast_calloc(1, sizeof(*varlist)); varlist = ast_calloc(1, sizeof(*varlist));
variablestore = ast_datastore_alloc(&iax2_variable_datastore_info, NULL); variablestore = ast_datastore_alloc(&iax2_variable_datastore_info, NULL);
@ -10153,6 +10176,7 @@ static int socket_process(struct iax2_thread *thread)
ast_free(varlist); ast_free(varlist);
} }
} }
ast_channel_unlock(c);
} else { } else {
/* No channel yet, so transfer the variables directly over to the pvt, /* No channel yet, so transfer the variables directly over to the pvt,
* for later inheritance. */ * for later inheritance. */
@ -10182,14 +10206,11 @@ static int socket_process(struct iax2_thread *thread)
iaxs[fr->callno]->voiceformat = f.subclass.codec; iaxs[fr->callno]->voiceformat = f.subclass.codec;
ast_debug(1, "Ooh, voice format changed to '%s'\n", ast_getformatname(f.subclass.codec)); ast_debug(1, "Ooh, voice format changed to '%s'\n", ast_getformatname(f.subclass.codec));
if (iaxs[fr->callno]->owner) { if (iaxs[fr->callno]->owner) {
format_t orignative; iax2_lock_owner(fr->callno);
retryowner:
if (ast_channel_trylock(iaxs[fr->callno]->owner)) {
DEADLOCK_AVOIDANCE(&iaxsl[fr->callno]);
if (iaxs[fr->callno] && iaxs[fr->callno]->owner) goto retryowner;
}
if (iaxs[fr->callno]) { if (iaxs[fr->callno]) {
if (iaxs[fr->callno]->owner) { if (iaxs[fr->callno]->owner) {
format_t orignative;
orignative = iaxs[fr->callno]->owner->nativeformats; orignative = iaxs[fr->callno]->owner->nativeformats;
iaxs[fr->callno]->owner->nativeformats = f.subclass.codec; iaxs[fr->callno]->owner->nativeformats = f.subclass.codec;
if (iaxs[fr->callno]->owner->readformat) if (iaxs[fr->callno]->owner->readformat)
@ -10261,22 +10282,32 @@ retryowner:
ast_set_flag64(iaxs[fr->callno], IAX_QUELCH); ast_set_flag64(iaxs[fr->callno], IAX_QUELCH);
if (ies.musiconhold) { if (ies.musiconhold) {
if (iaxs[fr->callno]->owner && ast_bridged_channel(iaxs[fr->callno]->owner)) { iax2_lock_owner(fr->callno);
if (!iaxs[fr->callno] || !iaxs[fr->callno]->owner) {
break;
}
if (ast_bridged_channel(iaxs[fr->callno]->owner)) {
const char *moh_suggest = iaxs[fr->callno]->mohsuggest; const char *moh_suggest = iaxs[fr->callno]->mohsuggest;
/*
* We already hold the owner lock so we do not
* need to check iaxs[fr->callno] after it returns.
*/
iax2_queue_control_data(fr->callno, AST_CONTROL_HOLD, iax2_queue_control_data(fr->callno, AST_CONTROL_HOLD,
S_OR(moh_suggest, NULL), S_OR(moh_suggest, NULL),
!ast_strlen_zero(moh_suggest) ? strlen(moh_suggest) + 1 : 0); !ast_strlen_zero(moh_suggest) ? strlen(moh_suggest) + 1 : 0);
if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]);
return 1;
}
} }
ast_channel_unlock(iaxs[fr->callno]->owner);
} }
} }
break; break;
case IAX_COMMAND_UNQUELCH: case IAX_COMMAND_UNQUELCH:
if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) { if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
/* Generate Manager Unhold event, if necessary*/ iax2_lock_owner(fr->callno);
if (!iaxs[fr->callno]) {
break;
}
/* Generate Manager Unhold event, if necessary */
if (iaxs[fr->callno]->owner && ast_test_flag64(iaxs[fr->callno], IAX_QUELCH)) { if (iaxs[fr->callno]->owner && ast_test_flag64(iaxs[fr->callno], IAX_QUELCH)) {
ast_manager_event(iaxs[fr->callno]->owner, EVENT_FLAG_CALL, "Hold", ast_manager_event(iaxs[fr->callno]->owner, EVENT_FLAG_CALL, "Hold",
"Status: Off\r\n" "Status: Off\r\n"
@ -10287,13 +10318,17 @@ retryowner:
} }
ast_clear_flag64(iaxs[fr->callno], IAX_QUELCH); ast_clear_flag64(iaxs[fr->callno], IAX_QUELCH);
if (iaxs[fr->callno]->owner && ast_bridged_channel(iaxs[fr->callno]->owner)) { if (!iaxs[fr->callno]->owner) {
break;
}
if (ast_bridged_channel(iaxs[fr->callno]->owner)) {
/*
* We already hold the owner lock so we do not
* need to check iaxs[fr->callno] after it returns.
*/
iax2_queue_control_data(fr->callno, AST_CONTROL_UNHOLD, NULL, 0); iax2_queue_control_data(fr->callno, AST_CONTROL_UNHOLD, NULL, 0);
if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]);
return 1;
}
} }
ast_channel_unlock(iaxs[fr->callno]->owner);
} }
break; break;
case IAX_COMMAND_TXACC: case IAX_COMMAND_TXACC:
@ -10320,8 +10355,7 @@ retryowner:
check_provisioning(&sin, fd, ies.serviceident, ies.provver); check_provisioning(&sin, fd, ies.serviceident, ies.provver);
ast_mutex_lock(&iaxsl[fr->callno]); ast_mutex_lock(&iaxsl[fr->callno]);
if (!iaxs[fr->callno]) { if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]); break;
return 1;
} }
} }
/* If we're in trunk mode, do it now, and update the trunk number in our frame before continuing */ /* If we're in trunk mode, do it now, and update the trunk number in our frame before continuing */
@ -10358,8 +10392,7 @@ retryowner:
ast_mutex_lock(&iaxsl[fr->callno]); ast_mutex_lock(&iaxsl[fr->callno]);
if (!iaxs[fr->callno]) { if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]); break;
return 1;
} }
} else } else
exists = 0; exists = 0;
@ -10372,8 +10405,7 @@ retryowner:
iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION); iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION);
send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1); send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
if (!iaxs[fr->callno]) { if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]); break;
return 1;
} }
if (authdebug) if (authdebug)
ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context); ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
@ -10419,8 +10451,7 @@ retryowner:
iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL); iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1); send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
if (!iaxs[fr->callno]) { if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]); break;
return 1;
} }
if (authdebug) { if (authdebug) {
char tmp[256], tmp2[256], tmp3[256]; char tmp[256], tmp2[256], tmp3[256];
@ -10473,8 +10504,7 @@ retryowner:
ast_log(LOG_ERROR, "No best format in '%s'???\n", ast_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability)); ast_log(LOG_ERROR, "No best format in '%s'???\n", ast_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability));
send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1); send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
if (!iaxs[fr->callno]) { if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]); break;
return 1;
} }
if (authdebug) { if (authdebug) {
ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n", ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n",
@ -10531,10 +10561,6 @@ retryowner:
iaxs[fr->callno]->encmethods = 0; iaxs[fr->callno]->encmethods = 0;
if (!authenticate_request(fr->callno) && iaxs[fr->callno]) if (!authenticate_request(fr->callno) && iaxs[fr->callno])
ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED); ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED);
if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]);
return 1;
}
break; break;
case IAX_COMMAND_DPREQ: case IAX_COMMAND_DPREQ:
/* Request status in the dialplan */ /* Request status in the dialplan */
@ -10556,8 +10582,7 @@ retryowner:
if (iaxs[fr->callno]->owner) { if (iaxs[fr->callno]->owner) {
set_hangup_source_and_cause(fr->callno, ies.causecode); set_hangup_source_and_cause(fr->callno, ies.causecode);
if (!iaxs[fr->callno]) { if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]); break;
return 1;
} }
} }
@ -10570,8 +10595,7 @@ retryowner:
if (iaxs[fr->callno]->owner) { if (iaxs[fr->callno]->owner) {
set_hangup_source_and_cause(fr->callno, ies.causecode); set_hangup_source_and_cause(fr->callno, ies.causecode);
if (!iaxs[fr->callno]) { if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]); break;
return 1;
} }
} }
@ -10593,40 +10617,54 @@ retryowner:
case IAX_COMMAND_TRANSFER: case IAX_COMMAND_TRANSFER:
{ {
struct ast_channel *bridged_chan; struct ast_channel *bridged_chan;
struct ast_channel *owner;
if (iaxs[fr->callno]->owner && (bridged_chan = ast_bridged_channel(iaxs[fr->callno]->owner)) && ies.called_number) { iax2_lock_owner(fr->callno);
/* Set BLINDTRANSFER channel variables */ if (!iaxs[fr->callno]) {
/* Initiating call went away before we could transfer. */
break;
}
owner = iaxs[fr->callno]->owner;
bridged_chan = owner ? ast_bridged_channel(owner) : NULL;
if (bridged_chan && ies.called_number) {
ast_mutex_unlock(&iaxsl[fr->callno]); ast_mutex_unlock(&iaxsl[fr->callno]);
pbx_builtin_setvar_helper(iaxs[fr->callno]->owner, "BLINDTRANSFER", bridged_chan->name);
ast_mutex_lock(&iaxsl[fr->callno]);
if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]);
return 1;
}
pbx_builtin_setvar_helper(bridged_chan, "BLINDTRANSFER", iaxs[fr->callno]->owner->name); /* Set BLINDTRANSFER channel variables */
pbx_builtin_setvar_helper(owner, "BLINDTRANSFER", bridged_chan->name);
pbx_builtin_setvar_helper(bridged_chan, "BLINDTRANSFER", owner->name);
if (ast_parking_ext_valid(ies.called_number, c, iaxs[fr->callno]->context)) { if (ast_parking_ext_valid(ies.called_number, c, iaxs[fr->callno]->context)) {
struct ast_channel *saved_channel = iaxs[fr->callno]->owner; ast_debug(1, "Parking call '%s'\n", bridged_chan->name);
ast_mutex_unlock(&iaxsl[fr->callno]); if (iax_park(bridged_chan, owner, ies.called_number)) {
if (iax_park(bridged_chan, saved_channel, ies.called_number)) { ast_log(LOG_WARNING, "Failed to park call '%s'\n",
ast_log(LOG_WARNING, "Failed to park call on '%s'\n", bridged_chan->name); bridged_chan->name);
} else {
ast_debug(1, "Parked call on '%s'\n", ast_bridged_channel(iaxs[fr->callno]->owner)->name);
} }
ast_mutex_lock(&iaxsl[fr->callno]); ast_mutex_lock(&iaxsl[fr->callno]);
} else { } else {
if (ast_async_goto(bridged_chan, iaxs[fr->callno]->context, ies.called_number, 1)) ast_mutex_lock(&iaxsl[fr->callno]);
ast_log(LOG_WARNING, "Async goto of '%s' to '%s@%s' failed\n", bridged_chan->name,
ies.called_number, iaxs[fr->callno]->context); if (iaxs[fr->callno]) {
else { if (ast_async_goto(bridged_chan, iaxs[fr->callno]->context,
ast_debug(1, "Async goto of '%s' to '%s@%s' started\n", bridged_chan->name, ies.called_number, 1)) {
ies.called_number, iaxs[fr->callno]->context); ast_log(LOG_WARNING,
"Async goto of '%s' to '%s@%s' failed\n",
bridged_chan->name, ies.called_number,
iaxs[fr->callno]->context);
} else {
ast_debug(1, "Async goto of '%s' to '%s@%s' started\n",
bridged_chan->name, ies.called_number,
iaxs[fr->callno]->context);
}
} else {
/* Initiating call went away before we could transfer. */
} }
} }
} else { } else {
ast_debug(1, "Async goto not applicable on call %d\n", fr->callno); ast_debug(1, "Async goto not applicable on call %d\n", fr->callno);
} }
if (owner) {
ast_channel_unlock(owner);
}
break; break;
} }
@ -10655,8 +10693,7 @@ retryowner:
iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL); iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1); send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
if (!iaxs[fr->callno]) { if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]); break;
return 1;
} }
if (authdebug) { if (authdebug) {
char tmp1[256], tmp2[256]; char tmp1[256], tmp2[256];
@ -10667,24 +10704,18 @@ retryowner:
} }
} else { } else {
ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED); ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
if (iaxs[fr->callno]->owner) { iax2_lock_owner(fr->callno);
if (iaxs[fr->callno] && iaxs[fr->callno]->owner) {
/* Switch us to use a compatible format */ /* Switch us to use a compatible format */
iaxs[fr->callno]->owner->nativeformats = iaxs[fr->callno]->peerformat; iaxs[fr->callno]->owner->nativeformats = iaxs[fr->callno]->peerformat;
ast_verb(3, "Format for call is %s\n", ast_getformatname(iaxs[fr->callno]->owner->nativeformats)); ast_verb(3, "Format for call is %s\n", ast_getformatname(iaxs[fr->callno]->owner->nativeformats));
retryowner2:
if (ast_channel_trylock(iaxs[fr->callno]->owner)) { /* Setup read/write formats properly. */
DEADLOCK_AVOIDANCE(&iaxsl[fr->callno]); if (iaxs[fr->callno]->owner->writeformat)
if (iaxs[fr->callno] && iaxs[fr->callno]->owner) goto retryowner2; ast_set_write_format(iaxs[fr->callno]->owner, iaxs[fr->callno]->owner->writeformat);
} if (iaxs[fr->callno]->owner->readformat)
ast_set_read_format(iaxs[fr->callno]->owner, iaxs[fr->callno]->owner->readformat);
if (iaxs[fr->callno] && iaxs[fr->callno]->owner) { ast_channel_unlock(iaxs[fr->callno]->owner);
/* Setup read/write formats properly. */
if (iaxs[fr->callno]->owner->writeformat)
ast_set_write_format(iaxs[fr->callno]->owner, iaxs[fr->callno]->owner->writeformat);
if (iaxs[fr->callno]->owner->readformat)
ast_set_read_format(iaxs[fr->callno]->owner, iaxs[fr->callno]->owner->readformat);
ast_channel_unlock(iaxs[fr->callno]->owner);
}
} }
} }
if (iaxs[fr->callno]) { if (iaxs[fr->callno]) {
@ -10698,10 +10729,6 @@ retryowner2:
case IAX_COMMAND_POKE: case IAX_COMMAND_POKE:
/* Send back a pong packet with the original timestamp */ /* Send back a pong packet with the original timestamp */
send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_PONG, fr->ts, NULL, 0, -1); send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_PONG, fr->ts, NULL, 0, -1);
if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]);
return 1;
}
break; break;
case IAX_COMMAND_PING: case IAX_COMMAND_PING:
{ {
@ -10801,10 +10828,6 @@ retryowner2:
ies.username ? ies.username : "<unknown>", ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr)); ies.username ? ies.username : "<unknown>", ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr));
iax2_queue_frame(fr->callno, &hangup_fr); iax2_queue_frame(fr->callno, &hangup_fr);
} }
if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]);
return 1;
}
break; break;
case IAX_COMMAND_AUTHREP: case IAX_COMMAND_AUTHREP:
/* For security, always ack immediately */ /* For security, always ack immediately */
@ -10835,8 +10858,7 @@ retryowner2:
iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION); iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION);
send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1); send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
if (!iaxs[fr->callno]) { if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]); break;
return 1;
} }
} else { } else {
/* Select an appropriate format */ /* Select an appropriate format */
@ -10894,8 +10916,7 @@ retryowner2:
iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL); iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1); send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
if (!iaxs[fr->callno]) { if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]); break;
return 1;
} }
} else { } else {
/* Pick one... */ /* Pick one... */
@ -10948,8 +10969,7 @@ retryowner2:
iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL); iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1); send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
if (!iaxs[fr->callno]) { if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]); break;
return 1;
} }
} }
} }
@ -11042,8 +11062,7 @@ immediatedial:
iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION); iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION);
send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1); send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
if (!iaxs[fr->callno]) { if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]); break;
return 1;
} }
} else { } else {
char tmp[256]; char tmp[256];
@ -11111,16 +11130,14 @@ immediatedial:
send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno); send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
if (register_verify(fr->callno, &sin, &ies)) { if (register_verify(fr->callno, &sin, &ies)) {
if (!iaxs[fr->callno]) { if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]); break;
return 1;
} }
/* Send delayed failure */ /* Send delayed failure */
auth_fail(fr->callno, IAX_COMMAND_REGREJ); auth_fail(fr->callno, IAX_COMMAND_REGREJ);
break; break;
} }
if (!iaxs[fr->callno]) { if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]); break;
return 1;
} }
if ((ast_strlen_zero(iaxs[fr->callno]->secret) && ast_strlen_zero(iaxs[fr->callno]->inkeys)) || if ((ast_strlen_zero(iaxs[fr->callno]->secret) && ast_strlen_zero(iaxs[fr->callno]->inkeys)) ||
ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED)) { ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED)) {
@ -11130,25 +11147,16 @@ immediatedial:
if (update_registry(&sin, fr->callno, ies.devicetype, fd, ies.refresh)) if (update_registry(&sin, fr->callno, ies.devicetype, fd, ies.refresh))
ast_log(LOG_WARNING, "Registry error\n"); ast_log(LOG_WARNING, "Registry error\n");
if (!iaxs[fr->callno]) { if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]); break;
return 1;
} }
if (ies.provverpres && ies.serviceident && sin.sin_addr.s_addr) { if (ies.provverpres && ies.serviceident && sin.sin_addr.s_addr) {
ast_mutex_unlock(&iaxsl[fr->callno]); ast_mutex_unlock(&iaxsl[fr->callno]);
check_provisioning(&sin, fd, ies.serviceident, ies.provver); check_provisioning(&sin, fd, ies.serviceident, ies.provver);
ast_mutex_lock(&iaxsl[fr->callno]); ast_mutex_lock(&iaxsl[fr->callno]);
if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]);
return 1;
}
} }
break; break;
} }
registry_authrequest(fr->callno); registry_authrequest(fr->callno);
if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]);
return 1;
}
break; break;
case IAX_COMMAND_REGACK: case IAX_COMMAND_REGACK:
if (iax2_ack_registry(&ies, &sin, fr->callno)) if (iax2_ack_registry(&ies, &sin, fr->callno))
@ -11176,10 +11184,6 @@ immediatedial:
iax_ie_append_str(&ied0, IAX_IE_CAUSE, "No authority found"); iax_ie_append_str(&ied0, IAX_IE_CAUSE, "No authority found");
iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_FACILITY_NOT_SUBSCRIBED); iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_FACILITY_NOT_SUBSCRIBED);
send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1); send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]);
return 1;
}
} }
break; break;
case IAX_COMMAND_TXREJ: case IAX_COMMAND_TXREJ:
@ -11301,10 +11305,6 @@ immediatedial:
send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_FWDATA, 0, ied0.buf, ied0.pos, -1); send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_FWDATA, 0, ied0.buf, ied0.pos, -1);
else else
send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_FWDATA, 0, ied0.buf, ied0.pos, -1); send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_FWDATA, 0, ied0.buf, ied0.pos, -1);
if (!iaxs[fr->callno]) {
ast_mutex_unlock(&iaxsl[fr->callno]);
return 1;
}
break; break;
case IAX_COMMAND_CALLTOKEN: case IAX_COMMAND_CALLTOKEN:
{ {
@ -11350,6 +11350,7 @@ immediatedial:
else { else {
ast_log(LOG_WARNING, "Received mini frame before first full video frame\n"); ast_log(LOG_WARNING, "Received mini frame before first full video frame\n");
iax2_vnak(fr->callno); iax2_vnak(fr->callno);
ast_variables_destroy(ies.vars);
ast_mutex_unlock(&iaxsl[fr->callno]); ast_mutex_unlock(&iaxsl[fr->callno]);
return 1; return 1;
} }
@ -11372,12 +11373,14 @@ immediatedial:
else { else {
ast_debug(1, "Received mini frame before first full voice frame\n"); ast_debug(1, "Received mini frame before first full voice frame\n");
iax2_vnak(fr->callno); iax2_vnak(fr->callno);
ast_variables_destroy(ies.vars);
ast_mutex_unlock(&iaxsl[fr->callno]); ast_mutex_unlock(&iaxsl[fr->callno]);
return 1; return 1;
} }
f.datalen = res - sizeof(struct ast_iax2_mini_hdr); f.datalen = res - sizeof(struct ast_iax2_mini_hdr);
if (f.datalen < 0) { if (f.datalen < 0) {
ast_log(LOG_WARNING, "Datalen < 0?\n"); ast_log(LOG_WARNING, "Datalen < 0?\n");
ast_variables_destroy(ies.vars);
ast_mutex_unlock(&iaxsl[fr->callno]); ast_mutex_unlock(&iaxsl[fr->callno]);
return 1; return 1;
} }
@ -11395,6 +11398,7 @@ immediatedial:
} }
/* Don't pass any packets until we're started */ /* Don't pass any packets until we're started */
if (!ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) { if (!ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
ast_variables_destroy(ies.vars);
ast_mutex_unlock(&iaxsl[fr->callno]); ast_mutex_unlock(&iaxsl[fr->callno]);
return 1; return 1;
} }
@ -11403,6 +11407,7 @@ immediatedial:
struct ast_party_connected_line connected; struct ast_party_connected_line connected;
if (!ast_test_flag64(iaxs[fr->callno], IAX_RECVCONNECTEDLINE)) { if (!ast_test_flag64(iaxs[fr->callno], IAX_RECVCONNECTEDLINE)) {
ast_variables_destroy(ies.vars);
ast_mutex_unlock(&iaxsl[fr->callno]); ast_mutex_unlock(&iaxsl[fr->callno]);
return 1; return 1;
} }
@ -11465,6 +11470,7 @@ immediatedial:
} }
/* Always run again */ /* Always run again */
ast_variables_destroy(ies.vars);
ast_mutex_unlock(&iaxsl[fr->callno]); ast_mutex_unlock(&iaxsl[fr->callno]);
return 1; return 1;
} }

Loading…
Cancel
Save