- call parking improvements (part of the siptransfer branch)

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@21157 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Olle Johansson 2006-04-18 15:09:01 +00:00
parent 2af3d42e9b
commit fc2d28805b
1 changed files with 98 additions and 53 deletions

View File

@ -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); return send_request(p, req, 0, p->ocseq);
} }
/*! \brief Notify a transferring party of the status of transfer /*! \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)
static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *message)
{ {
struct sip_request req; struct sip_request req;
char tmp[50]; char tmp[BUFSIZ/2];
reqprep(&req, p, SIP_NOTIFY, 0, 1); reqprep(&req, p, SIP_NOTIFY, 0, 1);
snprintf(tmp, sizeof(tmp), "refer;id=%d", cseq); snprintf(tmp, sizeof(tmp), "refer;id=%d", cseq);
add_header(&req, "Event", tmp); 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, "Content-Type", "message/sipfrag;version=2.0");
add_header(&req, "Allow", ALLOWED_METHODS); add_header(&req, "Allow", ALLOWED_METHODS);
add_header(&req, "Supported", SUPPORTED_EXTENSIONS); 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_header_contentLength(&req, strlen(tmp));
add_line(&req, 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) if (!p->initreq.headers)
initialize_initreq(p, &req); 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 */ /*! \brief Park SIP call support function */
static void *sip_park_thread(void *stuff) 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_dual *d;
struct sip_request req; struct sip_request req;
int ext; int ext;
int res; int res;
d = stuff; d = stuff;
chan1 = d->chan1; transferee = d->chan1;
chan2 = d->chan2; transferer = d->chan2;
copy_request(&req, &d->req); copy_request(&req, &d->req);
free(d); free(d);
ast_channel_lock(chan1); ast_channel_lock(transferee);
ast_do_masquerade(chan1); if (ast_do_masquerade(transferee)) {
ast_channel_unlock(chan1); ast_log(LOG_WARNING, "Masquerade failed.\n");
res = ast_park_call(chan1, chan2, 0, &ext); transmit_response(transferer->tech_pvt, "503 Internal error", &req);
/* Then hangup */ ast_channel_unlock(transferee);
ast_hangup(chan2); return NULL;
if (option_debug > 1) }
ast_log(LOG_DEBUG, "Parked on extension '%d'\n", ext); 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; return NULL;
} }
/*! \brief Park a call */ /*! \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 sip_dual *d;
struct ast_channel *chan1m, *chan2m; struct ast_channel *transferee, *transferer;
/* Chan2m: The transferer, chan1m: The transferee */
pthread_t th; pthread_t th;
chan1m = ast_channel_alloc(0);
chan2m = ast_channel_alloc(0); transferee = ast_channel_alloc(0);
if ((!chan2m) || (!chan1m)) { transferer = ast_channel_alloc(0);
if (chan1m) { if ((!transferer) || (!transferee)) {
chan1m->hangupcause = AST_CAUSE_SWITCH_CONGESTION; if (transferee) {
ast_hangup(chan1m); transferee->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
ast_hangup(transferee);
} }
if (chan2m) { if (transferer) {
chan2m->hangupcause = AST_CAUSE_SWITCH_CONGESTION; transferer->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
ast_hangup(chan2m); ast_hangup(transferer);
} }
return -1; 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 */ /* Make formats okay */
chan1m->readformat = chan1->readformat; transferee->readformat = chan1->readformat;
chan1m->writeformat = chan1->writeformat; transferee->writeformat = chan1->writeformat;
ast_channel_masquerade(chan1m, chan1); ast_channel_masquerade(transferee, chan1);
/* Setup the extensions and such */ /* Setup the extensions and such */
ast_copy_string(chan1m->context, chan1->context, sizeof(chan1m->context)); ast_copy_string(transferee->context, chan1->context, sizeof(transferee->context));
ast_copy_string(chan1m->exten, chan1->exten, sizeof(chan1m->exten)); ast_copy_string(transferee->exten, chan1->exten, sizeof(transferee->exten));
chan1m->priority = chan1->priority; transferee->priority = chan1->priority;
/* We make a clone of the peer channel too, so we can play /* We make a clone of the peer channel too, so we can play
back the announcement */ 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 */ /* Make formats okay */
chan2m->readformat = chan2->readformat; transferer->readformat = chan2->readformat;
chan2m->writeformat = chan2->writeformat; transferer->writeformat = chan2->writeformat;
ast_channel_masquerade(chan2m, chan2); ast_channel_masquerade(transferer, chan2);
/* Setup the extensions and such */ /* Setup the extensions and such */
ast_copy_string(chan2m->context, chan2->context, sizeof(chan2m->context)); ast_copy_string(transferer->context, chan2->context, sizeof(transferer->context));
ast_copy_string(chan2m->exten, chan2->exten, sizeof(chan2m->exten)); ast_copy_string(transferer->exten, chan2->exten, sizeof(transferer->exten));
chan2m->priority = chan2->priority; transferer->priority = chan2->priority;
ast_channel_lock(chan2m);
if (ast_do_masquerade(chan2m)) { ast_channel_lock(transferer);
if (ast_do_masquerade(transferer)) {
ast_log(LOG_WARNING, "Masquerade failed :(\n"); ast_log(LOG_WARNING, "Masquerade failed :(\n");
ast_channel_unlock(chan2m); ast_channel_unlock(transferer);
chan2m->hangupcause = AST_CAUSE_SWITCH_CONGESTION; transferer->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
ast_hangup(chan2m); ast_hangup(transferer);
return -1; return -1;
} }
ast_channel_unlock(chan2m); ast_channel_unlock(transferer);
if ((d = ast_calloc(1, sizeof(*d)))) { if ((d = ast_calloc(1, sizeof(*d)))) {
/* Save original request for followup */ /* Save original request for followup */
copy_request(&d->req, req); copy_request(&d->req, req);
d->chan1 = chan1m; d->chan1 = transferee; /* Transferee */
d->chan2 = chan2m; d->chan2 = transferer; /* Transferer */
if (!ast_pthread_create(&th, NULL, sip_park_thread, d)) d->seqno = seqno;
if (!ast_pthread_create(&th, NULL, sip_park_thread, d)) {
free(d);
return 0; return 0;
}
free(d); free(d);
} }
return -1; 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! */ be accessible after the transfer! */
*nounlock = 1; *nounlock = 1;
ast_channel_unlock(c); ast_channel_unlock(c);
sip_park(transfer_to, c, req); sip_park(transfer_to, c, req, seqno);
nobye = 1; nobye = 1;
} else { } else {
/* Must release c's lock now, because it will not longer /* 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); ast_set_flag(&p->flags[0], SIP_GOTREFER);
} }
transmit_response(p, "202 Accepted", req); 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 */ /* Always increment on a BYE */
if (!nobye) { if (!nobye) {
transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1); transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1);