aboutsummaryrefslogtreecommitdiffstats
path: root/channels
diff options
context:
space:
mode:
authordvossel <dvossel@f38db490-d61c-443f-a65b-d21fe96a405b>2009-02-03 23:35:55 +0000
committerdvossel <dvossel@f38db490-d61c-443f-a65b-d21fe96a405b>2009-02-03 23:35:55 +0000
commit5d5f1c433a1dfed30f7dddf2bbeeb0d2da0172f8 (patch)
tree0c59ad076b2e60bc038d4612e2ef39c1e47b9003 /channels
parenta1abb0ab3a207a53c61ac56ae64b7b35f462a16b (diff)
Fixes issue with IAX2 transfer not handing off calls.
Fixes issue with IAX2 transfers not taking place. As it was, a call that was being transfered would never be handed off correctly to the call ends because of how call numbers were stored in a hash table. The hash table, "iax_peercallno_pvt", storing all the current call numbers did not take into account the complications associated with transferring a call, so a separate hash table was required. This second hash table "iax_transfercallno_pvt" handles calls being transfered, once the call transfer is complete the call is removed from the transfer hash table and added to the peer hash table resuming normal operations. Addition functions were created to handle storing, removing, and comparing items in the iax_transfercallno_pvt table. (issue #13468) Review: http://reviewboard.digium.com/r/140/ git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.4@173248 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_iax2.c119
1 files changed, 93 insertions, 26 deletions
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 511f71879..9e32f9fd8 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -823,6 +823,13 @@ static struct timeval lastused[ARRAY_LEN(iaxs)];
*/
static struct ao2_container *iax_peercallno_pvts;
+/*!
+ * * \brief Another container of iax2_pvt structures
+ *
+ * Active IAX2 pvt stucts used during transfering a call are stored here.
+ */
+static struct ao2_container *iax_transfercallno_pvts;
+
/* Flag to use with trunk calls, keeping these calls high up. It halves our effective use
but keeps the division between trunked and non-trunked better. */
#define TRUNK_CALL_START ARRAY_LEN(iaxs) / 2
@@ -1247,6 +1254,25 @@ static void iax2_destroy_helper(struct chan_iax2_pvt *pvt)
AST_SCHED_DEL(sched, pvt->jbid);
}
+static void store_by_transfercallno(struct chan_iax2_pvt *pvt)
+{
+ if (!pvt->transfercallno) {
+ ast_log(LOG_ERROR, "This should not be called without a transfer call number.\n");
+ return;
+ }
+
+ ao2_link(iax_transfercallno_pvts, pvt);
+}
+
+static void remove_by_transfercallno(struct chan_iax2_pvt *pvt)
+{
+ if (!pvt->transfercallno) {
+ ast_log(LOG_ERROR, "This should not be called without a transfer call number.\n");
+ return;
+ }
+
+ ao2_unlink(iax_transfercallno_pvts, pvt);
+}
static void store_by_peercallno(struct chan_iax2_pvt *pvt)
{
if (!pvt->peercallno) {
@@ -1329,6 +1355,10 @@ retry:
remove_by_peercallno(pvt);
}
+ if (pvt->transfercallno) {
+ remove_by_transfercallno(pvt);
+ }
+
if (!owner) {
ao2_ref(pvt, -1);
pvt = NULL;
@@ -1551,28 +1581,40 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s
char host[80];
if (new <= NEW_ALLOW) {
- if (callno) {
- struct chan_iax2_pvt *pvt;
- struct chan_iax2_pvt tmp_pvt = {
- .callno = dcallno,
- .peercallno = callno,
- /* hack!! */
- .frames_received = check_dcallno,
- };
-
- memcpy(&tmp_pvt.addr, sin, sizeof(tmp_pvt.addr));
-
- if ((pvt = ao2_find(iax_peercallno_pvts, &tmp_pvt, OBJ_POINTER))) {
- if (return_locked) {
- ast_mutex_lock(&iaxsl[pvt->callno]);
- }
- res = pvt->callno;
- ao2_ref(pvt, -1);
- pvt = NULL;
- return res;
- }
- }
-
+ if (callno) {
+ struct chan_iax2_pvt *pvt;
+ struct chan_iax2_pvt tmp_pvt = {
+ .callno = dcallno,
+ .peercallno = callno,
+ .transfercallno = callno,
+ /* hack!! */
+ .frames_received = check_dcallno,
+ };
+
+ memcpy(&tmp_pvt.addr, sin, sizeof(tmp_pvt.addr));
+ /* this works for finding normal call numbers not involving transfering */
+ if ((pvt = ao2_find(iax_peercallno_pvts, &tmp_pvt, OBJ_POINTER))) {
+ if (return_locked) {
+ ast_mutex_lock(&iaxsl[pvt->callno]);
+ }
+ res = pvt->callno;
+ ao2_ref(pvt, -1);
+ pvt = NULL;
+ return res;
+ }
+ /* this searches for transfer call numbers that might not get caught otherwise */
+ memset(&tmp_pvt.addr, 0, sizeof(tmp_pvt.addr));
+ memcpy(&tmp_pvt.transfer, sin, sizeof(tmp_pvt.addr));
+ if ((pvt = ao2_find(iax_transfercallno_pvts, &tmp_pvt, OBJ_POINTER))) {
+ if (return_locked) {
+ ast_mutex_lock(&iaxsl[pvt->callno]);
+ }
+ res = pvt->callno;
+ ao2_ref(pvt, -1);
+ pvt = NULL;
+ return res;
+ }
+ }
/* This will occur on the first response to a message that we initiated,
* such as a PING. */
if (dcallno) {
@@ -1590,7 +1632,6 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s
if (dcallno) {
ast_mutex_unlock(&iaxsl[dcallno]);
}
-
#ifdef IAX_OLD_FIND
/* If we get here, we SHOULD NOT find a call structure for this
callno; if we do, it means that there is a call structure that
@@ -5885,10 +5926,11 @@ static int try_transfer(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
pvt->transfer.sin_family = AF_INET;
pvt->transferring = TRANSFER_BEGIN;
pvt->transferid = ies->transferid;
+ store_by_transfercallno(pvt);
if (ies->transferid)
iax_ie_append_int(&ied, IAX_IE_TRANSFERID, ies->transferid);
send_command_transfer(pvt, AST_FRAME_IAX, IAX_COMMAND_TXCNT, 0, ied.buf, ied.pos);
- return 0;
+ return 0;
}
static int complete_dpreply(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
@@ -5965,6 +6007,7 @@ static int complete_transfer(int callno, struct iax_ies *ies)
ast_log(LOG_WARNING, "Invalid transfer request\n");
return -1;
}
+ remove_by_transfercallno(pvt);
memcpy(&pvt->addr, &pvt->transfer, sizeof(pvt->addr));
memset(&pvt->transfer, 0, sizeof(pvt->transfer));
/* Reset sequence numbers */
@@ -5977,8 +6020,8 @@ static int complete_transfer(int callno, struct iax_ies *ies)
remove_by_peercallno(pvt);
}
pvt->peercallno = peercallno;
+ /*this is where the transfering call swiches hash tables */
store_by_peercallno(pvt);
-
pvt->transferring = TRANSFER_NONE;
pvt->svoiceformat = -1;
pvt->voiceformat = 0;
@@ -11187,6 +11230,7 @@ static int __unload_module(void)
ao2_ref(peers, -1);
ao2_ref(users, -1);
ao2_ref(iax_peercallno_pvts, -1);
+ ao2_ref(iax_transfercallno_pvts, -1);
return 0;
}
@@ -11225,6 +11269,23 @@ static int pvt_cmp_cb(void *obj, void *arg, int flags)
pvt2->frames_received) ? CMP_MATCH | CMP_STOP : 0;
}
+static int transfercallno_pvt_hash_cb(const void *obj, const int flags)
+{
+ const struct chan_iax2_pvt *pvt = obj;
+
+ return pvt->transfercallno;
+}
+
+static int transfercallno_pvt_cmp_cb(void *obj, void *arg, int flags)
+{
+ struct chan_iax2_pvt *pvt = obj, *pvt2 = arg;
+
+ /* The frames_received field is used to hold whether we're matching
+ * against a full frame or not ... */
+
+ return match(&pvt2->transfer, pvt2->transfercallno, pvt2->callno, pvt,
+ pvt2->frames_received) ? CMP_MATCH | CMP_STOP : 0;
+}
/*! \brief Load IAX2 module, load configuraiton ---*/
static int load_module(void)
{
@@ -11247,7 +11308,13 @@ static int load_module(void)
ao2_ref(users, -1);
return AST_MODULE_LOAD_FAILURE;
}
-
+ iax_transfercallno_pvts = ao2_container_alloc(IAX_MAX_CALLS, transfercallno_pvt_hash_cb, transfercallno_pvt_cmp_cb);
+ if (!iax_transfercallno_pvts) {
+ ao2_ref(peers, -1);
+ ao2_ref(users, -1);
+ ao2_ref(iax_peercallno_pvts, -1);
+ return AST_MODULE_LOAD_FAILURE;
+ }
ast_custom_function_register(&iaxpeer_function);
iax_set_output(iax_debug_output);