Add support for parking with IAX2
authorMark Spencer <markster@digium.com>
Thu, 4 Mar 2004 01:11:25 +0000 (01:11 +0000)
committerMark Spencer <markster@digium.com>
Thu, 4 Mar 2004 01:11:25 +0000 (01:11 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@2318 65c4cc65-6c06-0410-ace0-fbb531ad65f3

15 files changed:
channel.c
channels/chan_agent.c
channels/chan_alsa.c
channels/chan_h323.c
channels/chan_iax.c
channels/chan_iax2.c
channels/chan_local.c
channels/chan_mgcp.c
channels/chan_oss.c
channels/chan_sip.c
channels/chan_skinny.c
channels/chan_vpb.c
channels/chan_zap.c
include/asterisk/channel.h
include/asterisk/channel_pvt.h

index f2f1fd5..fa14749 100755 (executable)
--- 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;x<n;x++) {
                ast_mutex_lock(&c[x]->lock);
                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 */
index 04a4e68..e329f5f 100755 (executable)
@@ -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;
 }
 
index 112a20b..3751d60 100755 (executable)
@@ -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;
index 4077ea6..f3a7da4 100755 (executable)
@@ -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;
 }
 
index fc6ef0f..2745537 100755 (executable)
@@ -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;
index e378270..1206669 100755 (executable)
@@ -33,6 +33,7 @@
 #include <asterisk/app.h>
 #include <asterisk/astdb.h>
 #include <asterisk/musiconhold.h>
+#include <asterisk/parking.h>
 #include <sys/mman.h>
 #include <arpa/inet.h>
 #include <dirent.h>
@@ -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;
index 2cb73f4..5244589 100755 (executable)
@@ -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;
 }
 
index d4131c6..6774ac7 100755 (executable)
@@ -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);
index 3557ac0..a99be00 100755 (executable)
@@ -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;
index 275caa7..49e0bef 100755 (executable)
@@ -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;
 }
 
index b396605..bb52a73 100755 (executable)
@@ -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);
index b2a54d3..53a1b0f 100755 (executable)
@@ -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;
 
index 8b93e74..1ce3a6a 100755 (executable)
@@ -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;
 }
 
index 24699a7..c0cd6cd 100755 (executable)
@@ -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
index 366101e..9de8754 100755 (executable)
@@ -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 */