aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoroej <oej@f38db490-d61c-443f-a65b-d21fe96a405b>2006-04-18 15:09:01 +0000
committeroej <oej@f38db490-d61c-443f-a65b-d21fe96a405b>2006-04-18 15:09:01 +0000
commitac1154dd8290a6a2e8ef49258678d80fbc738b5a (patch)
tree5df5ee30ae80f8a761901e3ecbe0061ae4b899dd
parent8864116d9d9ab65ff5c3950149a78610b40ae6a7 (diff)
- call parking improvements (part of the siptransfer branch)
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@21157 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r--channels/chan_sip.c151
1 files changed, 98 insertions, 53 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 1806c67c5..364b27876 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -5505,16 +5505,17 @@ static int transmit_sip_request(struct sip_pvt *p,struct sip_request *req)
return send_request(p, req, 0, p->ocseq);
}
-/*! \brief Notify a transferring party of the status of transfer
- */
-static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *message)
+/*! \brief Notify a transferring party of the status of transfer */
+static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *message, int terminate)
{
struct sip_request req;
- char tmp[50];
+ char tmp[BUFSIZ/2];
+
reqprep(&req, p, SIP_NOTIFY, 0, 1);
snprintf(tmp, sizeof(tmp), "refer;id=%d", cseq);
add_header(&req, "Event", tmp);
- add_header(&req, "Subscription-state", "terminated;reason=noresource");
+ if (terminate)
+ add_header(&req, "Subscription-state", "terminated;reason=noresource");
add_header(&req, "Content-Type", "message/sipfrag;version=2.0");
add_header(&req, "Allow", ALLOWED_METHODS);
add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
@@ -5523,6 +5524,11 @@ static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *messa
add_header_contentLength(&req, strlen(tmp));
add_line(&req, tmp);
+
+ snprintf(tmp, sizeof(tmp), "SIP/2.0 %s\r\n", message);
+ add_header_contentLength(&req, strlen(tmp));
+ add_line(&req, tmp);
+
if (!p->initreq.headers)
initialize_initreq(p, &req);
@@ -10566,85 +10572,124 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
/*! \brief Park SIP call support function */
static void *sip_park_thread(void *stuff)
{
- struct ast_channel *chan1, *chan2;
+ struct ast_channel *transferee, *transferer; /* Chan1: The transferee, Chan2: The transferer */
struct sip_dual *d;
struct sip_request req;
int ext;
int res;
+
d = stuff;
- chan1 = d->chan1;
- chan2 = d->chan2;
+ transferee = d->chan1;
+ transferer = d->chan2;
copy_request(&req, &d->req);
free(d);
- ast_channel_lock(chan1);
- ast_do_masquerade(chan1);
- ast_channel_unlock(chan1);
- res = ast_park_call(chan1, chan2, 0, &ext);
- /* Then hangup */
- ast_hangup(chan2);
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "Parked on extension '%d'\n", ext);
+ ast_channel_lock(transferee);
+ if (ast_do_masquerade(transferee)) {
+ ast_log(LOG_WARNING, "Masquerade failed.\n");
+ transmit_response(transferer->tech_pvt, "503 Internal error", &req);
+ ast_channel_unlock(transferee);
+ return NULL;
+ }
+ ast_channel_unlock(transferee);
+
+ res = ast_park_call(transferee, transferer, 0, &ext);
+
+#ifdef WHEN_WE_KNOW_THAT_THE_CLIENT_SUPPORTS_MESSAGE
+ if (!res) {
+ transmit_message_with_text(transferer->tech_pvt, "Unable to park call.\n");
+ } else {
+ /* Then tell the transferer what happened */
+ sprintf(buf, "Call parked on extension '%d'", ext);
+ transmit_message_with_text(transferer->tech_pvt, buf);
+ }
+#endif
+
+ /* Any way back to the current call??? */
+ transmit_response(transferer->tech_pvt, "202 Accepted", &req);
+ if (!res) {
+ /* Transfer succeeded */
+ transmit_notify_with_sipfrag(transferer->tech_pvt, d->seqno, "200 OK", 1);
+ transferer->hangupcause = AST_CAUSE_NORMAL_CLEARING;
+ ast_hangup(transferer); /* This will cause a BYE */
+ if (option_debug)
+ ast_log(LOG_DEBUG, "SIP Call parked on extension '%d'\n", ext);
+ } else {
+ transmit_notify_with_sipfrag(transferer->tech_pvt, d->seqno, "503 Service Unavailable", 1);
+ if (option_debug)
+ ast_log(LOG_DEBUG, "SIP Call parked failed \n");
+ /* Do not hangup call */
+ }
return NULL;
}
/*! \brief Park a call */
-static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req)
+static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno)
{
struct sip_dual *d;
- struct ast_channel *chan1m, *chan2m;
+ struct ast_channel *transferee, *transferer;
+ /* Chan2m: The transferer, chan1m: The transferee */
pthread_t th;
- chan1m = ast_channel_alloc(0);
- chan2m = ast_channel_alloc(0);
- if ((!chan2m) || (!chan1m)) {
- if (chan1m) {
- chan1m->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
- ast_hangup(chan1m);
+
+ transferee = ast_channel_alloc(0);
+ transferer = ast_channel_alloc(0);
+ if ((!transferer) || (!transferee)) {
+ if (transferee) {
+ transferee->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
+ ast_hangup(transferee);
}
- if (chan2m) {
- chan2m->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
- ast_hangup(chan2m);
+ if (transferer) {
+ transferer->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
+ ast_hangup(transferer);
}
return -1;
}
- ast_string_field_build(chan1m, name, "Parking/%s", chan1->name);
+ ast_string_field_build(transferee, name, "Parking/%s", chan1->name);
+
/* Make formats okay */
- chan1m->readformat = chan1->readformat;
- chan1m->writeformat = chan1->writeformat;
- ast_channel_masquerade(chan1m, chan1);
+ transferee->readformat = chan1->readformat;
+ transferee->writeformat = chan1->writeformat;
+ ast_channel_masquerade(transferee, chan1);
+
/* Setup the extensions and such */
- ast_copy_string(chan1m->context, chan1->context, sizeof(chan1m->context));
- ast_copy_string(chan1m->exten, chan1->exten, sizeof(chan1m->exten));
- chan1m->priority = chan1->priority;
+ ast_copy_string(transferee->context, chan1->context, sizeof(transferee->context));
+ ast_copy_string(transferee->exten, chan1->exten, sizeof(transferee->exten));
+ transferee->priority = chan1->priority;
/* We make a clone of the peer channel too, so we can play
back the announcement */
- ast_string_field_build(chan2m, name, "SIPPeer/%s",chan2->name);
+ ast_string_field_build(transferer, name, "SIPPeer/%s", chan2->name);
+
/* Make formats okay */
- chan2m->readformat = chan2->readformat;
- chan2m->writeformat = chan2->writeformat;
- ast_channel_masquerade(chan2m, chan2);
+ transferer->readformat = chan2->readformat;
+ transferer->writeformat = chan2->writeformat;
+ ast_channel_masquerade(transferer, chan2);
+
/* Setup the extensions and such */
- ast_copy_string(chan2m->context, chan2->context, sizeof(chan2m->context));
- ast_copy_string(chan2m->exten, chan2->exten, sizeof(chan2m->exten));
- chan2m->priority = chan2->priority;
- ast_channel_lock(chan2m);
- if (ast_do_masquerade(chan2m)) {
+ ast_copy_string(transferer->context, chan2->context, sizeof(transferer->context));
+ ast_copy_string(transferer->exten, chan2->exten, sizeof(transferer->exten));
+ transferer->priority = chan2->priority;
+
+ ast_channel_lock(transferer);
+ if (ast_do_masquerade(transferer)) {
ast_log(LOG_WARNING, "Masquerade failed :(\n");
- ast_channel_unlock(chan2m);
- chan2m->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
- ast_hangup(chan2m);
+ ast_channel_unlock(transferer);
+ transferer->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
+ ast_hangup(transferer);
return -1;
}
- ast_channel_unlock(chan2m);
+ ast_channel_unlock(transferer);
if ((d = ast_calloc(1, sizeof(*d)))) {
/* Save original request for followup */
copy_request(&d->req, req);
- d->chan1 = chan1m;
- d->chan2 = chan2m;
- if (!ast_pthread_create(&th, NULL, sip_park_thread, d))
+ d->chan1 = transferee; /* Transferee */
+ d->chan2 = transferer; /* Transferer */
+ d->seqno = seqno;
+ if (!ast_pthread_create(&th, NULL, sip_park_thread, d)) {
+ free(d);
return 0;
+ }
free(d);
- }
+ }
return -1;
}
@@ -11245,7 +11290,7 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int
be accessible after the transfer! */
*nounlock = 1;
ast_channel_unlock(c);
- sip_park(transfer_to, c, req);
+ sip_park(transfer_to, c, req, seqno);
nobye = 1;
} else {
/* Must release c's lock now, because it will not longer
@@ -11262,7 +11307,7 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int
ast_set_flag(&p->flags[0], SIP_GOTREFER);
}
transmit_response(p, "202 Accepted", req);
- transmit_notify_with_sipfrag(p, seqno, "200 OK");
+ transmit_notify_with_sipfrag(p, seqno, "200 OK", 1);
/* Always increment on a BYE */
if (!nobye) {
transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1);