Review Board 1.7.16


IAX2 Transfer Fix

Review Request #140 - Created Feb. 3, 2009 and submitted

David Vossel
1.6.0
0013468
Reviewers
asterisk-dev
russell
Asterisk
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. 
this patch has been tested on both 1.6.0 and 1.4.  1.6.1 and trunk have issues of there own that must be fixed before this patch can be applied to them. 

Diff revision 2

This is not the most recent revision of the diff. The latest diff is revision 3. See what's changed.

1 2 3
1 2 3

  1. /branches/1.6.0/channels/chan_iax2.c: Loading...
/branches/1.6.0/channels/chan_iax2.c
Revision 173167 New Change
[20] 879 lines
[+20] [+] static ast_mutex_t iaxsl[ARRAY_LEN(iaxs)];
880
 * The specified time that we must wait before reusing a local call number is
880
 * The specified time that we must wait before reusing a local call number is
881
 * defined as MIN_REUSE_TIME, with a default of 60 seconds.
881
 * defined as MIN_REUSE_TIME, with a default of 60 seconds.
882
 */
882
 */
883
static struct timeval lastused[ARRAY_LEN(iaxs)];
883
static struct timeval lastused[ARRAY_LEN(iaxs)];
884

    
   
884

   

    
   
885
/*!

    
   
886
 *  * \brief Another container of iax2_pvt structures

    
   
887
 *  

    
   
888
 *  Active IAX2 pvt stucts used during transfering a call are stored here.  

    
   
889
 */

    
   
890
static struct ao2_container *iax_transfercallno_pvts;

    
   
891

   
885
/* Flag to use with trunk calls, keeping these calls high up.  It halves our effective use
892
/* Flag to use with trunk calls, keeping these calls high up.  It halves our effective use
886
   but keeps the division between trunked and non-trunked better. */
893
   but keeps the division between trunked and non-trunked better. */
887
#define TRUNK_CALL_START	ARRAY_LEN(iaxs) / 2
894
#define TRUNK_CALL_START	ARRAY_LEN(iaxs) / 2
888

    
   
895

   
889
static int maxtrunkcall = TRUNK_CALL_START;
896
static int maxtrunkcall = TRUNK_CALL_START;
[+20] [20] 718 lines
[+20] [+] static int make_trunk(unsigned short callno, int locked)
1608
	update_max_trunk();
1615
	update_max_trunk();
1609
	update_max_nontrunk();
1616
	update_max_nontrunk();
1610
	return res;
1617
	return res;
1611
}
1618
}
1612

    
   
1619

   

    
   
1620
static void store_by_transfercallno(struct chan_iax2_pvt *pvt)

    
   
1621
{

    
   
1622
	if (!pvt->transfercallno) {

    
   
1623
		ast_log(LOG_ERROR, "This should not be called without a transfer call number.\n");

    
   
1624
		return;

    
   
1625
	}

    
   
1626

   

    
   
1627
	ao2_link(iax_transfercallno_pvts, pvt);

    
   
1628
}

    
   
1629

   

    
   
1630
static void remove_by_transfercallno(struct chan_iax2_pvt *pvt)

    
   
1631
{

    
   
1632
	if (!pvt->transfercallno) {

    
   
1633
		ast_log(LOG_ERROR, "This should not be called without a transfer call number.\n");

    
   
1634
		return;

    
   
1635
	}

    
   
1636

   

    
   
1637
	ao2_unlink(iax_transfercallno_pvts, pvt);

    
   
1638
}
1613
static void store_by_peercallno(struct chan_iax2_pvt *pvt)
1639
static void store_by_peercallno(struct chan_iax2_pvt *pvt)
1614
{
1640
{
1615
	if (!pvt->peercallno) {
1641
	if (!pvt->peercallno) {
1616
		ast_log(LOG_ERROR, "This should not be called without a peer call number.\n");
1642
		ast_log(LOG_ERROR, "This should not be called without a peer call number.\n");
1617
		return;
1643
		return;
[+20] [20] 26 lines
[+20] [+] static int __find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int return_locked, int check_dcallno)
1644
		if (callno) {
1670
 		if (callno) {
1645
			struct chan_iax2_pvt *pvt;
1671
 			struct chan_iax2_pvt *pvt;
1646
			struct chan_iax2_pvt tmp_pvt = {
1672
 			struct chan_iax2_pvt tmp_pvt = {
1647
				.callno = dcallno,
1673
 				.callno = dcallno,
1648
				.peercallno = callno,
1674
 				.peercallno = callno,

    
   
1675
				.transfercallno = callno,
1649
				/* hack!! */
1676
 				/* hack!! */
1650
				.frames_received = check_dcallno,
1677
 				.frames_received = check_dcallno,
1651
			};
1678
 			};
1652

    
   
1679
 
1653
			memcpy(&tmp_pvt.addr, sin, sizeof(tmp_pvt.addr));
1680
 			memcpy(&tmp_pvt.addr, sin, sizeof(tmp_pvt.addr));
1654

    
   
1681
			/* this works for finding normal call numbers not involving transfering */
1655
			if ((pvt = ao2_find(iax_peercallno_pvts, &tmp_pvt, OBJ_POINTER))) {
1682
 			if ((pvt = ao2_find(iax_peercallno_pvts, &tmp_pvt, OBJ_POINTER))) {
1656
				if (return_locked) {
1683
 				if (return_locked) {
1657
					ast_mutex_lock(&iaxsl[pvt->callno]);
1684
 					ast_mutex_lock(&iaxsl[pvt->callno]);
1658
				}
1685
 				}
1659
				res = pvt->callno;
1686
 				res = pvt->callno;
1660
				ao2_ref(pvt, -1);
1687
 				ao2_ref(pvt, -1);
1661
				pvt = NULL;
1688
 				pvt = NULL;
1662
				return res;
1689
 				return res;
1663
			}
1690
 			}

    
   
1691
			/* this searches for transfer call numbers that might not get caught otherwise */

    
   
1692
			memset(&tmp_pvt.addr, 0, sizeof(tmp_pvt.addr));

    
   
1693
			memcpy(&tmp_pvt.transfer, sin, sizeof(tmp_pvt.addr));

    
   
1694
			if ((pvt = ao2_find(iax_transfercallno_pvts, &tmp_pvt, OBJ_POINTER))) {

    
   
1695
 				if (return_locked) {

    
   
1696
 					ast_mutex_lock(&iaxsl[pvt->callno]);

    
   
1697
 				}

    
   
1698
 				res = pvt->callno;

    
   
1699
 				ao2_ref(pvt, -1);

    
   
1700
 				pvt = NULL;

    
   
1701
 				return res;
1664
		}
1702
 			}
1665

    
   
1703

   

    
   
1704
 		}
1666
		/* This will occur on the first response to a message that we initiated,
1705
			/* This will occur on the first response to a message that we initiated,
1667
		 * such as a PING. */
1706
		 * such as a PING. */
1668
		if (dcallno) {
1707
		if (dcallno) {
1669
			ast_mutex_lock(&iaxsl[dcallno]);
1708
			ast_mutex_lock(&iaxsl[dcallno]);
1670
		}
1709
		}
[+20] [20] 7 lines
[+20] static int __find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int return_locked, int check_dcallno)
1678
			return res;
1717
			return res;
1679
		}
1718
		}
1680
		if (dcallno) {
1719
		if (dcallno) {
1681
			ast_mutex_unlock(&iaxsl[dcallno]);
1720
			ast_mutex_unlock(&iaxsl[dcallno]);
1682
		}
1721
		}
1683

    
   

   
1684
#ifdef IAX_OLD_FIND
1722
#ifdef IAX_OLD_FIND
1685
		/* If we get here, we SHOULD NOT find a call structure for this
1723
		/* If we get here, we SHOULD NOT find a call structure for this
1686
		   callno; if we do, it means that there is a call structure that
1724
		   callno; if we do, it means that there is a call structure that
1687
		   has a peer callno but did NOT get entered into the hash table,
1725
		   has a peer callno but did NOT get entered into the hash table,
1688
		   which is bad.
1726
		   which is bad.
[+20] [20] 4880 lines
[+20] [+] static int try_transfer(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
6569
	memcpy(&pvt->transfer, &new, sizeof(pvt->transfer));
6607
	memcpy(&pvt->transfer, &new, sizeof(pvt->transfer));
6570
	inet_aton(newip, &pvt->transfer.sin_addr);
6608
	inet_aton(newip, &pvt->transfer.sin_addr);
6571
	pvt->transfer.sin_family = AF_INET;
6609
	pvt->transfer.sin_family = AF_INET;
6572
	pvt->transferring = TRANSFER_BEGIN;
6610
	pvt->transferring = TRANSFER_BEGIN;
6573
	pvt->transferid = ies->transferid;
6611
	pvt->transferid = ies->transferid;

    
   
6612
	store_by_transfercallno(pvt);
6574
	if (ies->transferid)
6613
	if (ies->transferid)
6575
		iax_ie_append_int(&ied, IAX_IE_TRANSFERID, ies->transferid);
6614
		iax_ie_append_int(&ied, IAX_IE_TRANSFERID, ies->transferid);
6576
	send_command_transfer(pvt, AST_FRAME_IAX, IAX_COMMAND_TXCNT, 0, ied.buf, ied.pos);
6615
	send_command_transfer(pvt, AST_FRAME_IAX, IAX_COMMAND_TXCNT, 0, ied.buf, ied.pos);
6577
	return 0; 
6616
	return 0; 
6578
}
6617
}
[+20] [20] 57 lines
[+20] [+] static int complete_transfer(int callno, struct iax_ies *ies)
6636

    
   
6675

   
6637
	if (peercallno < 1) {
6676
	if (peercallno < 1) {
6638
		ast_log(LOG_WARNING, "Invalid transfer request\n");
6677
		ast_log(LOG_WARNING, "Invalid transfer request\n");
6639
		return -1;
6678
		return -1;
6640
	}
6679
	}

    
   
6680
	remove_by_transfercallno(pvt);
6641
	memcpy(&pvt->addr, &pvt->transfer, sizeof(pvt->addr));
6681
	memcpy(&pvt->addr, &pvt->transfer, sizeof(pvt->addr));
6642
	memset(&pvt->transfer, 0, sizeof(pvt->transfer));
6682
	memset(&pvt->transfer, 0, sizeof(pvt->transfer));
6643
	/* Reset sequence numbers */
6683
	/* Reset sequence numbers */
6644
	pvt->oseqno = 0;
6684
	pvt->oseqno = 0;
6645
	pvt->rseqno = 0;
6685
	pvt->rseqno = 0;
6646
	pvt->iseqno = 0;
6686
	pvt->iseqno = 0;
6647
	pvt->aseqno = 0;
6687
	pvt->aseqno = 0;
6648

    
   
6688

   
6649
	if (pvt->peercallno) {
6689
	if (pvt->peercallno) {
6650
		remove_by_peercallno(pvt);
6690
		remove_by_peercallno(pvt);
6651
	}
6691
	}
6652
	pvt->peercallno = peercallno;
6692
	pvt->peercallno = peercallno;

    
   
6693
	/*this is where the transfering call swiches hash tables */
6653
	store_by_peercallno(pvt);
6694
	store_by_peercallno(pvt);
6654

    
   

   
6655
	pvt->transferring = TRANSFER_NONE;
6695
	pvt->transferring = TRANSFER_NONE;
6656
	pvt->svoiceformat = -1;
6696
	pvt->svoiceformat = -1;
6657
	pvt->voiceformat = 0;
6697
	pvt->voiceformat = 0;
6658
	pvt->svideoformat = -1;
6698
	pvt->svideoformat = -1;
6659
	pvt->videoformat = 0;
6699
	pvt->videoformat = 0;
[+20] [20] 5474 lines
[+20] [+] static int __unload_module(void)
12134
	}
12174
	}
12135

    
   
12175

   
12136
	ao2_ref(peers, -1);
12176
	ao2_ref(peers, -1);
12137
	ao2_ref(users, -1);
12177
	ao2_ref(users, -1);
12138
	ao2_ref(iax_peercallno_pvts, -1);
12178
	ao2_ref(iax_peercallno_pvts, -1);
12139
	
12179
	ao2_ref(iax_transfercallno_pvts, -1);
12140
	con = ast_context_find(regcontext);
12180
	con = ast_context_find(regcontext);
12141
	if (con)
12181
	if (con)
12142
		ast_context_destroy(con, "IAX2");
12182
		ast_context_destroy(con, "IAX2");
12143
	
12183
	
12144
	return 0;
12184
	return 0;
[+20] [20] 32 lines
[+20] [+] static int pvt_cmp_cb(void *obj, void *arg, int flags)
12177

    
   
12217

   
12178
	return match(&pvt2->addr, pvt2->peercallno, pvt2->callno, pvt, 
12218
	return match(&pvt2->addr, pvt2->peercallno, pvt2->callno, pvt, 
12179
		pvt2->frames_received) ? CMP_MATCH : 0;
12219
		pvt2->frames_received) ? CMP_MATCH : 0;
12180
}
12220
}
12181

    
   
12221

   

    
   
12222
static int transfercallno_pvt_hash_cb(const void *obj, const int flags)

    
   
12223
{

    
   
12224
	const struct chan_iax2_pvt *pvt = obj;

    
   
12225

   

    
   
12226
	return pvt->transfercallno;

    
   
12227
}

    
   
12228

   

    
   
12229
static int transfercallno_pvt_cmp_cb(void *obj, void *arg, int flags)

    
   
12230
{

    
   
12231
	struct chan_iax2_pvt *pvt = obj, *pvt2 = arg;

    
   
12232

   

    
   
12233
	/* The frames_received field is used to hold whether we're matching

    
   
12234
	 * against a full frame or not ... */

    
   
12235

   

    
   
12236
	return match(&pvt2->transfer, pvt2->transfercallno, pvt2->callno, pvt, 

    
   
12237
		pvt2->frames_received) ? CMP_MATCH | CMP_STOP : 0;

    
   
12238
}
12182
/*! \brief Load IAX2 module, load configuraiton ---*/
12239
/*! \brief Load IAX2 module, load configuraiton ---*/
12183
static int load_module(void)
12240
static int load_module(void)
12184
{
12241
{
12185
	char *config = "iax.conf";
12242
	char *config = "iax.conf";
12186
	int x = 0;
12243
	int x = 0;
[+20] [20] 6 lines
[+20] static int load_module(void)
12193
	if (!users) {
12250
	if (!users) {
12194
		ao2_ref(peers, -1);
12251
		ao2_ref(peers, -1);
12195
		return AST_MODULE_LOAD_FAILURE;
12252
		return AST_MODULE_LOAD_FAILURE;
12196
	}
12253
	}
12197
	iax_peercallno_pvts = ao2_container_alloc(IAX_MAX_CALLS, pvt_hash_cb, pvt_cmp_cb);
12254
	iax_peercallno_pvts = ao2_container_alloc(IAX_MAX_CALLS, pvt_hash_cb, pvt_cmp_cb);

    
   
12255
	iax_transfercallno_pvts = ao2_container_alloc(IAX_MAX_CALLS, transfercallno_pvt_hash_cb, transfercallno_pvt_cmp_cb);
12198
	if (!iax_peercallno_pvts) {
12256
	if (!iax_peercallno_pvts) {
12199
		ao2_ref(peers, -1);
12257
		ao2_ref(peers, -1);
12200
		ao2_ref(users, -1);
12258
		ao2_ref(users, -1);
12201
		return AST_MODULE_LOAD_FAILURE;
12259
		return AST_MODULE_LOAD_FAILURE;
12202
	}
12260
	}
[+20] [20] 101 lines
  1. /branches/1.6.0/channels/chan_iax2.c: Loading...

https://reviewboard.asterisk.org/ runs on a server provided by Digium, Inc. and uses bandwidth donated to the open source Asterisk community by API Digital Communications in Huntsville, AL USA.
Please report problems with this site to asteriskteam@digium.com.