aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfile <file@f38db490-d61c-443f-a65b-d21fe96a405b>2009-04-03 16:47:27 +0000
committerfile <file@f38db490-d61c-443f-a65b-d21fe96a405b>2009-04-03 16:47:27 +0000
commit27b4657d60732d7a1a15221eca67966921e9fd62 (patch)
tree9a47da9503ee4492361033db1e1d338c3bfd5816
parent80bd42b29c25611e537bae898c30789bafa77aeb (diff)
Add better support for relaying success or failure of the ast_transfer() API call.
This API call now waits for a special frame from the underlying channel driver to indicate success or failure. This allows the return value to truly convey whether the transfer worked or not. In the case of the Transfer() dialplan application this means the value of the TRANSFERSTATUS dialplan variable is actually true. (closes issue #12713) Reported by: davidw Tested by: file git-svn-id: http://svn.digium.com/svn/asterisk/trunk@186382 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r--channels/chan_iax2.c2
-rw-r--r--channels/chan_sip.c27
-rw-r--r--include/asterisk/frame.h6
-rw-r--r--main/channel.c33
4 files changed, 66 insertions, 2 deletions
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 47f1ddc84..860e1d614 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -4413,6 +4413,7 @@ static int iax2_transfer(struct ast_channel *c, const char *dest)
unsigned short callno = PTR_TO_CALLNO(c->tech_pvt);
struct iax_ie_data ied = { "", };
char tmp[256], *context;
+ enum ast_control_transfer message = AST_TRANSFER_SUCCESS;
ast_copy_string(tmp, dest, sizeof(tmp));
context = strchr(tmp, '@');
if (context) {
@@ -4423,6 +4424,7 @@ static int iax2_transfer(struct ast_channel *c, const char *dest)
if (context)
iax_ie_append_str(&ied, IAX_IE_CALLED_CONTEXT, context);
ast_debug(1, "Transferring '%s' to '%s'\n", c->name, dest);
+ ast_queue_control_data(c, AST_CONTROL_TRANSFER, &message, sizeof(message));
return send_command_locked(callno, AST_FRAME_IAX, IAX_COMMAND_TRANSFER, 0, ied.buf, ied.pos, -1);
}
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 4d0f06f4a..4fb164f9c 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -17045,6 +17045,8 @@ static void handle_response_subscribe(struct sip_pvt *p, int resp, char *rest, s
*/
static void handle_response_refer(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno)
{
+ enum ast_control_transfer message = AST_TRANSFER_FAILED;
+
/* If no refer structure exists, then do nothing */
if (!p->refer)
return;
@@ -17064,12 +17066,18 @@ static void handle_response_refer(struct sip_pvt *p, int resp, char *rest, struc
if (ast_strlen_zero(p->authname)) {
ast_log(LOG_WARNING, "Asked to authenticate REFER to %s:%d but we have no matching peer or realm auth!\n",
ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port));
+ if (p->owner) {
+ ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message));
+ }
pvt_set_needdestroy(p, "unable to authenticate REFER");
}
if (p->authtries > 1 || do_proxy_auth(p, req, resp, SIP_REFER, 0)) {
ast_log(LOG_NOTICE, "Failed to authenticate on REFER to '%s'\n", get_header(&p->initreq, "From"));
p->refer->status = REFER_NOAUTH;
- pvt_set_needdestroy(p, "failed to authenticat REFER");
+ if (p->owner) {
+ ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message));
+ }
+ pvt_set_needdestroy(p, "failed to authenticate REFER");
}
break;
case 481: /* Call leg does not exist */
@@ -17090,11 +17098,17 @@ static void handle_response_refer(struct sip_pvt *p, int resp, char *rest, struc
ast_log(LOG_NOTICE, "SIP transfer to %s failed, call miserably fails. \n", p->refer->refer_to);
pvt_set_needdestroy(p, "received 500/501 response");
p->refer->status = REFER_FAILED;
+ if (p->owner) {
+ ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message));
+ }
break;
case 603: /* Transfer declined */
ast_log(LOG_NOTICE, "SIP transfer to %s declined, call miserably fails. \n", p->refer->refer_to);
p->refer->status = REFER_FAILED;
pvt_set_needdestroy(p, "received 603 response");
+ if (p->owner) {
+ ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message));
+ }
break;
}
}
@@ -18129,7 +18143,11 @@ static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, str
if (!success) {
ast_log(LOG_NOTICE, "Transfer failed. Sorry. Nothing further to do with this call\n");
}
-
+
+ if (p->owner) {
+ enum ast_control_transfer message = success ? AST_TRANSFER_SUCCESS : AST_TRANSFER_FAILED;
+ ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message));
+ }
/* Confirm that we received this packet */
transmit_response(p, "200 OK", req);
} else if (p->mwi && !strcmp(event, "message-summary")) {
@@ -24311,6 +24329,11 @@ static int sip_sipredirect(struct sip_pvt *p, const char *dest)
sip_scheddestroy(p, SIP_TRANS_TIMEOUT); /* Make sure we stop send this reply. */
sip_alreadygone(p);
+
+ if (p->owner) {
+ enum ast_control_transfer message = AST_TRANSFER_SUCCESS;
+ ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message));
+ }
/* hangup here */
return 0;
}
diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h
index 62485ced6..cf4474e17 100644
--- a/include/asterisk/frame.h
+++ b/include/asterisk/frame.h
@@ -319,6 +319,7 @@ enum ast_control_frame_type {
AST_CONTROL_VIDUPDATE = 18, /*!< Indicate video frame update */
AST_CONTROL_T38 = 19, /*!< T38 state change request/notification */
AST_CONTROL_SRCUPDATE = 20, /*!< Indicate source of media has changed */
+ AST_CONTROL_TRANSFER = 21, /*!< Indicate status of a transfer request */
};
enum ast_control_t38 {
@@ -329,6 +330,11 @@ enum ast_control_t38 {
AST_T38_REFUSED /*!< T38 refused for some reason (usually rejected by remote end) */
};
+enum ast_control_transfer {
+ AST_TRANSFER_SUCCESS = 0, /*!< Transfer request on the channel worked */
+ AST_TRANSFER_FAILED, /*!< Transfer request on the channel failed */
+};
+
#define AST_SMOOTHER_FLAG_G729 (1 << 0)
#define AST_SMOOTHER_FLAG_BE (1 << 1)
diff --git a/main/channel.c b/main/channel.c
index b492f5113..9b2ad405c 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -2994,6 +2994,7 @@ static int attribute_const is_visible_indication(enum ast_control_frame_type con
case AST_CONTROL_ANSWER:
case AST_CONTROL_HANGUP:
case AST_CONTROL_T38:
+ case AST_CONTROL_TRANSFER:
return 0;
case AST_CONTROL_CONGESTION:
@@ -3080,6 +3081,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
case AST_CONTROL_HOLD:
case AST_CONTROL_UNHOLD:
case AST_CONTROL_T38:
+ case AST_CONTROL_TRANSFER:
/* Nothing left to do for these. */
res = 0;
break;
@@ -3759,6 +3761,37 @@ int ast_transfer(struct ast_channel *chan, char *dest)
res = 0;
}
ast_channel_unlock(chan);
+
+ if (res < 0) {
+ return res;
+ }
+
+ for (;;) {
+ struct ast_frame *fr;
+
+ res = ast_waitfor(chan, -1);
+
+ if (res < 0 || !(fr = ast_read(chan))) {
+ res = -1;
+ break;
+ }
+
+ if (fr->frametype == AST_FRAME_CONTROL && fr->subclass == AST_CONTROL_TRANSFER) {
+ enum ast_control_transfer *message = fr->data.ptr;
+
+ if (*message == AST_TRANSFER_SUCCESS) {
+ res = 1;
+ } else {
+ res = -1;
+ }
+
+ ast_frfree(fr);
+ break;
+ }
+
+ ast_frfree(fr);
+ }
+
return res;
}