diff options
Diffstat (limited to 'channels/chan_iax2.c')
-rw-r--r-- | channels/chan_iax2.c | 74 |
1 files changed, 57 insertions, 17 deletions
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 89ec84335..3b6902e13 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -1104,7 +1104,7 @@ static int send_command_final(struct chan_iax2_pvt *, char, int, unsigned int, c static int send_command_immediate(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int); static int send_command_locked(unsigned short callno, char, int, unsigned int, const unsigned char *, int, int); static int send_command_transfer(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int); -static struct ast_channel *iax2_request(const char *type, int format, void *data, int *cause); +static struct ast_channel *iax2_request(const char *type, int format, const struct ast_channel *requestor, void *data, int *cause); static struct ast_frame *iax2_read(struct ast_channel *c); static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly); static struct iax2_user *build_user(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly); @@ -4516,7 +4516,7 @@ static int iax2_getpeertrunk(struct sockaddr_in sin) } /*! \brief Create new call, interface with the PBX core */ -static struct ast_channel *ast_iax2_new(int callno, int state, int capability) +static struct ast_channel *ast_iax2_new(int callno, int state, int capability, const char *linkedid) { struct ast_channel *tmp; struct chan_iax2_pvt *i; @@ -4529,7 +4529,7 @@ static struct ast_channel *ast_iax2_new(int callno, int state, int capability) /* Don't hold call lock */ ast_mutex_unlock(&iaxsl[callno]); - tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, i->amaflags, "IAX2/%s-%d", i->host, i->callno); + tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, linkedid, i->amaflags, "IAX2/%s-%d", i->host, i->callno); ast_mutex_lock(&iaxsl[callno]); if (i != iaxs[callno]) { if (tmp) { @@ -8003,8 +8003,8 @@ static int iax_park(struct ast_channel *chan1, struct ast_channel *chan2) struct iax_dual *d; struct ast_channel *chan1m, *chan2m; pthread_t th; - chan1m = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan2->accountcode, chan1->exten, chan1->context, chan1->amaflags, "Parking/%s", chan1->name); - chan2m = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan2->accountcode, chan2->exten, chan2->context, chan2->amaflags, "IAXPeer/%s",chan2->name); + chan1m = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan2->accountcode, chan1->exten, chan1->context, chan1->linkedid, chan1->amaflags, "Parking/%s", chan1->name); + chan2m = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan2->accountcode, chan2->exten, chan2->context, chan2->linkedid, chan2->amaflags, "IAXPeer/%s", chan2->name); if (chan2m && chan1m) { /* Make formats okay */ chan1m->readformat = chan1->readformat; @@ -8512,6 +8512,35 @@ static struct ast_custom_function iaxvar_function = { .write = acf_iaxvar_write, }; +static void set_hangup_source_and_cause(int callno, unsigned char causecode) +{ + int locked = 0; + 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 (causecode) { + iaxs[callno]->owner->hangupcause = causecode; + } + ast_set_hangupsource(iaxs[callno]->owner, iaxs[callno]->owner->name, 0); + ast_channel_unlock(owner); + } + if (locked) { + ast_channel_unlock(owner); + } +} + + static int socket_process(struct iax2_thread *thread) { struct sockaddr_in sin; @@ -8853,7 +8882,7 @@ static int socket_process(struct iax2_thread *thread) (f.frametype == AST_FRAME_IAX)) { if (ast_test_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)) { + if (!ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->chosenformat, NULL)) { ast_mutex_unlock(&iaxsl[fr->callno]); return 1; } @@ -9276,17 +9305,28 @@ retryowner: case IAX_COMMAND_HANGUP: ast_set_flag64(iaxs[fr->callno], IAX_ALREADYGONE); ast_debug(1, "Immediately destroying %d, having received hangup\n", fr->callno); - /* Set hangup cause according to remote */ - if (ies.causecode && iaxs[fr->callno]->owner) - iaxs[fr->callno]->owner->hangupcause = ies.causecode; + /* Set hangup cause according to remote and hangupsource */ + if (iaxs[fr->callno]->owner) { + set_hangup_source_and_cause(fr->callno, ies.causecode); + if (!iaxs[fr->callno]) { + ast_mutex_unlock(&iaxsl[fr->callno]); + return 1; + } + } + /* Send ack immediately, before we destroy */ send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno); iax2_destroy(fr->callno); break; case IAX_COMMAND_REJECT: - /* Set hangup cause according to remote */ - if (ies.causecode && iaxs[fr->callno]->owner) - iaxs[fr->callno]->owner->hangupcause = ies.causecode; + /* Set hangup cause according to remote and hangup source */ + if (iaxs[fr->callno]->owner) { + set_hangup_source_and_cause(fr->callno, ies.causecode); + if (!iaxs[fr->callno]) { + ast_mutex_unlock(&iaxsl[fr->callno]); + return 1; + } + } if (!ast_test_flag64(iaxs[fr->callno], IAX_PROVISION)) { if (iaxs[fr->callno]->owner && authdebug) @@ -9668,7 +9708,7 @@ retryowner2: using_prefs); ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED); - if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, format))) + if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, format, NULL))) iax2_destroy(fr->callno); else if (ies.vars) { struct ast_datastore *variablestore; @@ -9737,7 +9777,7 @@ immediatedial: ast_verb(3, "Accepting DIAL from %s, formats = 0x%x\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat); ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED); send_command(iaxs[fr->callno], AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, 0, NULL, 0, -1); - if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->peerformat))) + if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->peerformat, NULL))) iax2_destroy(fr->callno); else if (ies.vars) { struct ast_datastore *variablestore; @@ -10570,7 +10610,7 @@ static void free_context(struct iax2_context *con) } } -static struct ast_channel *iax2_request(const char *type, int format, void *data, int *cause) +static struct ast_channel *iax2_request(const char *type, int format, const struct ast_channel *requestor, void *data, int *cause) { int callno; int res; @@ -10622,7 +10662,7 @@ static struct ast_channel *iax2_request(const char *type, int format, void *data if (cai.found) ast_string_field_set(iaxs[callno], host, pds.peer); - c = ast_iax2_new(callno, AST_STATE_DOWN, cai.capability); + c = ast_iax2_new(callno, AST_STATE_DOWN, cai.capability, requestor ? requestor->linkedid : NULL); ast_mutex_unlock(&iaxsl[callno]); @@ -11086,7 +11126,7 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st strsep(&context, "@"); if (ast_strlen_zero(context)) context = "default"; - peer->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, NULL, + peer->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, "IAX MWI subscription", NULL, AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox, AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context, AST_EVENT_IE_END); |