From 806bb3c63f5c3cf8c06692051463120a8321767e Mon Sep 17 00:00:00 2001 From: Mark Spencer Date: Thu, 4 Mar 2004 01:11:25 +0000 Subject: [PATCH] Add support for parking with IAX2 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@2318 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- channel.c | 30 ++++----- channels/chan_agent.c | 8 ++- channels/chan_alsa.c | 2 +- channels/chan_h323.c | 8 ++- channels/chan_iax.c | 2 +- channels/chan_iax2.c | 108 ++++++++++++++++++++++++++++++--- channels/chan_local.c | 11 ++-- channels/chan_mgcp.c | 2 +- channels/chan_oss.c | 2 +- channels/chan_sip.c | 11 ++-- channels/chan_skinny.c | 2 +- channels/chan_vpb.c | 2 +- channels/chan_zap.c | 8 ++- include/asterisk/channel.h | 2 + include/asterisk/channel_pvt.h | 2 +- 15 files changed, 152 insertions(+), 48 deletions(-) diff --git a/channel.c b/channel.c index f2f1fd535f..fa14749edf 100755 --- a/channel.c +++ b/channel.c @@ -597,8 +597,6 @@ int ast_softhangup(struct ast_channel *chan, int cause) return res; } -static int ast_do_masquerade(struct ast_channel *original); - static void free_translation(struct ast_channel *clone) { if (clone->pvt->writetrans) @@ -618,7 +616,7 @@ int ast_hangup(struct ast_channel *chan) if someone is going to masquerade as us */ ast_mutex_lock(&chan->lock); if (chan->masq) { - if (ast_do_masquerade(chan)) + if (ast_do_masquerade(chan, 1)) ast_log(LOG_WARNING, "Failed to perform masquerade\n"); } @@ -821,7 +819,7 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, for (x=0;xlock); if (c[x]->masq) { - if (ast_do_masquerade(c[x])) { + if (ast_do_masquerade(c[x], 1)) { ast_log(LOG_WARNING, "Masquerade failed\n"); *ms = -1; ast_mutex_unlock(&c[x]->lock); @@ -1008,7 +1006,7 @@ struct ast_frame *ast_read(struct ast_channel *chan) ast_mutex_lock(&chan->lock); if (chan->masq) { - if (ast_do_masquerade(chan)) { + if (ast_do_masquerade(chan, 1)) { ast_log(LOG_WARNING, "Failed to perform masquerade\n"); f = NULL; } else @@ -1343,7 +1341,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) } /* Handle any pending masquerades */ if (chan->masq) { - if (ast_do_masquerade(chan)) { + if (ast_do_masquerade(chan, 1)) { ast_log(LOG_WARNING, "Failed to perform masquerade\n"); ast_mutex_unlock(&chan->lock); return -1; @@ -1926,7 +1924,7 @@ void ast_change_name(struct ast_channel *chan, char *newname) manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", tmp, chan->name, chan->uniqueid); } -static int ast_do_masquerade(struct ast_channel *original) +int ast_do_masquerade(struct ast_channel *original, int needlock) { int x,i; int res=0; @@ -1951,8 +1949,9 @@ static int ast_do_masquerade(struct ast_channel *original) channel's backend. I'm not sure we're going to keep this function, because while the features are nice, the cost is very high in terms of pure nastiness. XXX */ - /* We need the clone's lock, too */ - ast_mutex_lock(&clone->lock); + if (needlock) + /* We need the clone's lock, too */ + ast_mutex_lock(&clone->lock); ast_log(LOG_DEBUG, "Got clone lock on '%s' at %p\n", clone->name, &clone->lock); @@ -2013,7 +2012,7 @@ static int ast_do_masquerade(struct ast_channel *original) if (clone->pvt->fixup){ - res = clone->pvt->fixup(original, clone); + res = clone->pvt->fixup(original, clone, needlock); if (res) ast_log(LOG_WARNING, "Fixup failed on channel %s, strange things may happen.\n", clone->name); } @@ -2023,7 +2022,8 @@ static int ast_do_masquerade(struct ast_channel *original) res = clone->pvt->hangup(clone); if (res) { ast_log(LOG_WARNING, "Hangup failed! Strange things may happen!\n"); - ast_mutex_unlock(&clone->lock); + if (needlock) + ast_mutex_unlock(&clone->lock); return -1; } @@ -2100,7 +2100,7 @@ static int ast_do_masquerade(struct ast_channel *original) /* Okay. Last thing is to let the channel driver know about all this mess, so he can fix up everything as best as possible */ if (original->pvt->fixup) { - res = original->pvt->fixup(clone, original); + res = original->pvt->fixup(clone, original, needlock); if (res) { ast_log(LOG_WARNING, "Driver for '%s' could not fixup channel %s\n", original->type, original->name); @@ -2115,13 +2115,15 @@ static int ast_do_masquerade(struct ast_channel *original) zombie, then free it now (since it already is considered invalid). */ if (clone->zombie) { ast_log(LOG_DEBUG, "Destroying clone '%s'\n", clone->name); - ast_mutex_unlock(&clone->lock); + if (needlock) + ast_mutex_unlock(&clone->lock); ast_channel_free(clone); manager_event(EVENT_FLAG_CALL, "Hangup", "Channel: %s\r\n", zombn); } else { ast_log(LOG_DEBUG, "Released clone lock on '%s'\n", clone->name); clone->zombie=1; - ast_mutex_unlock(&clone->lock); + if (needlock) + ast_mutex_unlock(&clone->lock); } /* Signal any blocker */ diff --git a/channels/chan_agent.c b/channels/chan_agent.c index 04a4e68c12..e329f5fcbe 100755 --- a/channels/chan_agent.c +++ b/channels/chan_agent.c @@ -380,17 +380,19 @@ static int agent_write(struct ast_channel *ast, struct ast_frame *f) return res; } -static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) +static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, int needlock) { struct agent_pvt *p = newchan->pvt->pvt; - ast_mutex_lock(&p->lock); + if (needlock) + ast_mutex_lock(&p->lock); if (p->owner != oldchan) { ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner); ast_mutex_unlock(&p->lock); return -1; } p->owner = newchan; - ast_mutex_unlock(&p->lock); + if (needlock) + ast_mutex_unlock(&p->lock); return 0; } diff --git a/channels/chan_alsa.c b/channels/chan_alsa.c index 112a20b27a..3751d60924 100755 --- a/channels/chan_alsa.c +++ b/channels/chan_alsa.c @@ -755,7 +755,7 @@ static struct ast_frame *alsa_read(struct ast_channel *chan) return &f; } -static int alsa_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) +static int alsa_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, int needlock) { struct chan_alsa_pvt *p = newchan->pvt->pvt; p->owner = newchan; diff --git a/channels/chan_h323.c b/channels/chan_h323.c index 4077ea6141..f3a7da406c 100755 --- a/channels/chan_h323.c +++ b/channels/chan_h323.c @@ -623,17 +623,19 @@ static int oh323_indicate(struct ast_channel *c, int condition) } // FIXME: WTF is this? Do I need this??? -static int oh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) +static int oh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, int needlock) { struct oh323_pvt *p = newchan->pvt->pvt; - ast_mutex_lock(&p->lock); + if (needlock) + ast_mutex_lock(&p->lock); if (p->owner != oldchan) { ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner); return -1; } p->owner = newchan; - ast_mutex_unlock(&p->lock); + if (needlock) + ast_mutex_unlock(&p->lock); return 0; } diff --git a/channels/chan_iax.c b/channels/chan_iax.c index fc6ef0ff50..2745537aed 100755 --- a/channels/chan_iax.c +++ b/channels/chan_iax.c @@ -1515,7 +1515,7 @@ static int iax_sendhtml(struct ast_channel *c, int subclass, char *data, int dat return send_command(c->pvt->pvt, AST_FRAME_HTML, subclass, 0, data, datalen, -1); } -static int iax_fixup(struct ast_channel *oldchannel, struct ast_channel *newchan) +static int iax_fixup(struct ast_channel *oldchannel, struct ast_channel *newchan, int needlock) { struct chan_iax_pvt *pvt = newchan->pvt->pvt; pvt->owner = newchan; diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index e378270735..1206669cc9 100755 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -1750,15 +1751,17 @@ static int iax2_sendhtml(struct ast_channel *c, int subclass, char *data, int da return send_command_locked(PTR_TO_CALLNO(c->pvt->pvt), AST_FRAME_HTML, subclass, 0, data, datalen, -1); } -static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newchan) +static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newchan, int lock) { unsigned short callno = PTR_TO_CALLNO(newchan->pvt->pvt); - ast_mutex_lock(&iaxsl[callno]); + if (lock) + ast_mutex_lock(&iaxsl[callno]); if (iaxs[callno]) iaxs[callno]->owner = newchan; else ast_log(LOG_WARNING, "Uh, this isn't a good sign...\n"); - ast_mutex_unlock(&iaxsl[callno]); + if (lock) + ast_mutex_unlock(&iaxsl[callno]); return 0; } @@ -4228,7 +4231,7 @@ static void dp_lookup(int callno, char *context, char *callednum, char *callerid memset(&ied1, 0, sizeof(ied1)); mm = ast_matchmore_extension(NULL, context, callednum, 1, callerid); /* Must be started */ - if (ast_exists_extension(NULL, context, callednum, 1, callerid)) { + if (!strcmp(callednum, ast_parking_ext()) || ast_exists_extension(NULL, context, callednum, 1, callerid)) { dpstatus = IAX_DPSTATUS_EXISTS; } else if (ast_canmatch_extension(NULL, context, callednum, 1, callerid)) { dpstatus = IAX_DPSTATUS_CANEXIST; @@ -4281,6 +4284,84 @@ static void spawn_dp_lookup(int callno, char *context, char *callednum, char *ca ast_log(LOG_WARNING, "Out of memory!\n"); } +struct iax_dual { + struct ast_channel *chan1; + struct ast_channel *chan2; +}; + +static void *iax_park_thread(void *stuff) +{ + struct ast_channel *chan1, *chan2; + struct iax_dual *d; + struct ast_frame *f; + int ext; + int res; + d = stuff; + chan1 = d->chan1; + chan2 = d->chan2; + free(d); + f = ast_read(chan1); + if (f) + ast_frfree(f); + res = ast_park_call(chan1, chan2, 0, &ext); + ast_hangup(chan2); + ast_log(LOG_DEBUG, "Parked on extension '%d'\n", ext); + return NULL; +} + +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); + chan2m = ast_channel_alloc(0); + if (chan2m && chan1m) { + snprintf(chan1m->name, sizeof(chan1m->name), "Parking/%s", chan1->name); + /* Make formats okay */ + chan1m->readformat = chan1->readformat; + chan1m->writeformat = chan1->writeformat; + ast_channel_masquerade(chan1m, chan1); + /* Setup the extensions and such */ + strncpy(chan1m->context, chan1->context, sizeof(chan1m->context) - 1); + strncpy(chan1m->exten, chan1->exten, sizeof(chan1m->exten) - 1); + chan1m->priority = chan1->priority; + + /* We make a clone of the peer channel too, so we can play + back the announcement */ + snprintf(chan2m->name, sizeof (chan2m->name), "IAXPeer/%s",chan2->name); + /* Make formats okay */ + chan2m->readformat = chan2->readformat; + chan2m->writeformat = chan2->writeformat; + ast_channel_masquerade(chan2m, chan2); + /* Setup the extensions and such */ + strncpy(chan2m->context, chan2->context, sizeof(chan2m->context) - 1); + strncpy(chan2m->exten, chan2->exten, sizeof(chan2m->exten) - 1); + chan2m->priority = chan2->priority; + if (ast_do_masquerade(chan2m, 0)) { + ast_log(LOG_WARNING, "Masquerade failed :(\n"); + ast_hangup(chan2m); + return -1; + } + } else { + if (chan1m) + ast_hangup(chan1m); + if (chan2m) + ast_hangup(chan2m); + return -1; + } + d = malloc(sizeof(struct iax_dual)); + if (d) { + memset(d, 0, sizeof(*d)); + d->chan1 = chan1m; + d->chan2 = chan2m; + if (!pthread_create(&th, NULL, iax_park_thread, d)) + return 0; + free(d); + } + return -1; +} + static int socket_read(int *id, int fd, short events, void *cbdata) { struct sockaddr_in sin; @@ -4799,12 +4880,19 @@ retryowner: break; case IAX_COMMAND_TRANSFER: if (iaxs[fr.callno]->owner && iaxs[fr.callno]->owner->bridge && ies.called_number) { - if (ast_async_goto(iaxs[fr.callno]->owner->bridge, iaxs[fr.callno]->context, ies.called_number, 1, 1)) - ast_log(LOG_WARNING, "Async goto of '%s' to '%s@%s' failed\n", iaxs[fr.callno]->owner->bridge->name, - ies.called_number, iaxs[fr.callno]->context); - else - ast_log(LOG_DEBUG, "Async goto of '%s' to '%s@%s' started\n", iaxs[fr.callno]->owner->bridge->name, - ies.called_number, iaxs[fr.callno]->context); + if (!strcmp(ies.called_number, ast_parking_ext())) { + if (iax_park(iaxs[fr.callno]->owner->bridge, iaxs[fr.callno]->owner)) { + ast_log(LOG_WARNING, "Failed to park call on '%s'\n", iaxs[fr.callno]->owner->bridge->name); + } else + ast_log(LOG_DEBUG, "Parked call on '%s'\n", iaxs[fr.callno]->owner->bridge->name); + } else { + if (ast_async_goto(iaxs[fr.callno]->owner->bridge, iaxs[fr.callno]->context, ies.called_number, 1, 1)) + ast_log(LOG_WARNING, "Async goto of '%s' to '%s@%s' failed\n", iaxs[fr.callno]->owner->bridge->name, + ies.called_number, iaxs[fr.callno]->context); + else + ast_log(LOG_DEBUG, "Async goto of '%s' to '%s@%s' started\n", iaxs[fr.callno]->owner->bridge->name, + ies.called_number, iaxs[fr.callno]->context); + } } else ast_log(LOG_DEBUG, "Async goto not applicable on call %d\n", fr.callno); break; diff --git a/channels/chan_local.c b/channels/chan_local.c index 2cb73f475d..5244589790 100755 --- a/channels/chan_local.c +++ b/channels/chan_local.c @@ -185,20 +185,23 @@ static int local_write(struct ast_channel *ast, struct ast_frame *f) return res; } -static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) +static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, int needlock) { struct local_pvt *p = newchan->pvt->pvt; - ast_mutex_lock(&p->lock); + if (needlock) + ast_mutex_lock(&p->lock); if ((p->owner != oldchan) && (p->chan != oldchan)) { ast_log(LOG_WARNING, "old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan); - ast_mutex_unlock(&p->lock); + if (needlock) + ast_mutex_unlock(&p->lock); return -1; } if (p->owner == oldchan) p->owner = newchan; else p->chan = newchan; - ast_mutex_unlock(&p->lock); + if (needlock) + ast_mutex_unlock(&p->lock); return 0; } diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c index d4131c656c..6774ac743d 100755 --- a/channels/chan_mgcp.c +++ b/channels/chan_mgcp.c @@ -771,7 +771,7 @@ static int mgcp_write(struct ast_channel *ast, struct ast_frame *frame) return res; } -static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) +static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, int needlock) { struct mgcp_subchannel *sub = newchan->pvt->pvt; ast_log(LOG_NOTICE, "mgcp_fixup(%s, %s)\n", oldchan->name, newchan->name); diff --git a/channels/chan_oss.c b/channels/chan_oss.c index 3557ac0227..a99be00074 100755 --- a/channels/chan_oss.c +++ b/channels/chan_oss.c @@ -661,7 +661,7 @@ static struct ast_frame *oss_read(struct ast_channel *chan) return &f; } -static int oss_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) +static int oss_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, int needlock) { struct chan_oss_pvt *p = newchan->pvt->pvt; p->owner = newchan; diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 275caa703d..49e0bef364 100755 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1364,17 +1364,20 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame) return res; } -static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) +static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, int needlock) { struct sip_pvt *p = newchan->pvt->pvt; - ast_mutex_lock(&p->lock); + if (needlock) + ast_mutex_lock(&p->lock); if (p->owner != oldchan) { ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner); - ast_mutex_unlock(&p->lock); + if (needlock) + ast_mutex_unlock(&p->lock); return -1; } p->owner = newchan; - ast_mutex_unlock(&p->lock); + if (needlock) + ast_mutex_unlock(&p->lock); return 0; } diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index b396605b4a..bb52a739f5 100755 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -1650,7 +1650,7 @@ static int skinny_write(struct ast_channel *ast, struct ast_frame *frame) return res; } -static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) +static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, int needlock) { struct skinny_subchannel *sub = newchan->pvt->pvt; ast_log(LOG_NOTICE, "skinny_fixup(%s, %s)\n", oldchan->name, newchan->name); diff --git a/channels/chan_vpb.c b/channels/chan_vpb.c index b2a54d37cd..53a1b0f6f6 100755 --- a/channels/chan_vpb.c +++ b/channels/chan_vpb.c @@ -651,7 +651,7 @@ static int vpb_indicate(struct ast_channel *ast, int condition) return res; } -static int vpb_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) +static int vpb_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, int needlock) { struct vpb_pvt *p = (struct vpb_pvt *)newchan->pvt->pvt; diff --git a/channels/chan_zap.c b/channels/chan_zap.c index 8b93e744a2..1ce3a6a929 100755 --- a/channels/chan_zap.c +++ b/channels/chan_zap.c @@ -2537,11 +2537,12 @@ static int zt_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, static int zt_indicate(struct ast_channel *chan, int condition); -static int zt_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) +static int zt_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, int needlock) { struct zt_pvt *p = newchan->pvt->pvt; int x; - ast_mutex_lock(&p->lock); + if (needlock) + ast_mutex_lock(&p->lock); ast_log(LOG_DEBUG, "New owner for channel %d is %s\n", p->channel, newchan->name); if (p->owner == oldchan) p->owner = newchan; @@ -2554,7 +2555,8 @@ static int zt_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) if (newchan->_state == AST_STATE_RINGING) zt_indicate(newchan, AST_CONTROL_RINGING); update_conf(p); - ast_mutex_unlock(&p->lock); + if (needlock) + ast_mutex_unlock(&p->lock); return 0; } diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 24699a7d97..c0cd6cd237 100755 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -777,6 +777,8 @@ int ast_settimeout(struct ast_channel *c, int samples, int (*func)(void *data), and 1 if supported and requested */ int ast_transfer(struct ast_channel *chan, char *dest); +int ast_do_masquerade(struct ast_channel *chan, int grablock); + /* Misc. functions below */ //! Waits for activity on a group of channels diff --git a/include/asterisk/channel_pvt.h b/include/asterisk/channel_pvt.h index 366101eea8..9de87541b7 100755 --- a/include/asterisk/channel_pvt.h +++ b/include/asterisk/channel_pvt.h @@ -60,7 +60,7 @@ struct ast_channel_pvt { /*! Indicate a particular condition (e.g. AST_CONTROL_BUSY or AST_CONTROL_RINGING or AST_CONTROL_CONGESTION */ int (*indicate)(struct ast_channel *c, int condition); /*! Fix up a channel: If a channel is consumed, this is called. Basically update any ->owner links */ - int (*fixup)(struct ast_channel *oldchan, struct ast_channel *newchan); + int (*fixup)(struct ast_channel *oldchan, struct ast_channel *newchan, int lock); /*! Set a given option */ int (*setoption)(struct ast_channel *chan, int option, void *data, int datalen); /*! Query a given option */