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. 

Changes between revision 1 and 3

1 2 3
1 2 3

  1. /branches/1.6.0/channels/chan_iax2.c: Loading...
  2. 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;

    
   
1702
			}
1664
		}
1703
		}
1665

    
   

   
1666
		/* This will occur on the first response to a message that we initiated,
1704
			/* This will occur on the first response to a message that we initiated,
1667
		 * such as a PING. */
1705
		 * such as a PING. */
1668
		if (dcallno) {
1706
		if (dcallno) {
1669
			ast_mutex_lock(&iaxsl[dcallno]);
1707
			ast_mutex_lock(&iaxsl[dcallno]);
1670
		}
1708
		}
[+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;
1716
			return res;
1679
		}
1717
		}
1680
		if (dcallno) {
1718
		if (dcallno) {
1681
			ast_mutex_unlock(&iaxsl[dcallno]);
1719
			ast_mutex_unlock(&iaxsl[dcallno]);
1682
		}
1720
		}
1683

    
   

   
1684
#ifdef IAX_OLD_FIND
1721
#ifdef IAX_OLD_FIND
1685
		/* If we get here, we SHOULD NOT find a call structure for this
1722
		/* 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
1723
		   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,
1724
		   has a peer callno but did NOT get entered into the hash table,
1688
		   which is bad.
1725
		   which is bad.
[+20] [20] 619 lines
[+20] [+] retry:
2308

    
   
2345

   
2309
		if (pvt->peercallno) {
2346
		if (pvt->peercallno) {
2310
			remove_by_peercallno(pvt);
2347
			remove_by_peercallno(pvt);
2311
		}
2348
		}
2312

    
   
2349

   

    
   
2350
		if(pvt->transfercallno) {

    
   
2351
			remove_by_transfercallno(pvt);

    
   
2352
		}

    
   
2353

   
2313
		if (!owner) {
2354
		if (!owner) {
2314
			ao2_ref(pvt, -1);
2355
			ao2_ref(pvt, -1);
2315
			pvt = NULL;
2356
			pvt = NULL;
2316
		}
2357
		}
2317
	}
2358
	}
[+20] [20] 4251 lines
[+20] [+] static int try_transfer(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
6569
	memcpy(&pvt->transfer, &new, sizeof(pvt->transfer));
6610
	memcpy(&pvt->transfer, &new, sizeof(pvt->transfer));
6570
	inet_aton(newip, &pvt->transfer.sin_addr);
6611
	inet_aton(newip, &pvt->transfer.sin_addr);
6571
	pvt->transfer.sin_family = AF_INET;
6612
	pvt->transfer.sin_family = AF_INET;
6572
	pvt->transferring = TRANSFER_BEGIN;
6613
	pvt->transferring = TRANSFER_BEGIN;
6573
	pvt->transferid = ies->transferid;
6614
	pvt->transferid = ies->transferid;

    
   
6615
	store_by_transfercallno(pvt);
6574
	if (ies->transferid)
6616
	if (ies->transferid)
6575
		iax_ie_append_int(&ied, IAX_IE_TRANSFERID, ies->transferid);
6617
		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);
6618
	send_command_transfer(pvt, AST_FRAME_IAX, IAX_COMMAND_TXCNT, 0, ied.buf, ied.pos);
6577
	return 0; 
6619
	return 0;
6578
}
6620
}
6579

    
   
6621

   
6580
static int complete_dpreply(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
6622
static int complete_dpreply(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
6581
{
6623
{
6582
	char exten[256] = "";
6624
	char exten[256] = "";
[+20] [20] 53 lines
[+20] [+] static int complete_transfer(int callno, struct iax_ies *ies)
6636

    
   
6678

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

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

    
   
6691

   
6649
	if (pvt->peercallno) {
6692
	if (pvt->peercallno) {
6650
		remove_by_peercallno(pvt);
6693
		remove_by_peercallno(pvt);
6651
	}
6694
	}
6652
	pvt->peercallno = peercallno;
6695
	pvt->peercallno = peercallno;

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

    
   

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

    
   
12178

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

    
   
12220

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

    
   
12224

   

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

    
   
12226
{

    
   
12227
	const struct chan_iax2_pvt *pvt = obj;

    
   
12228

   

    
   
12229
	return pvt->transfercallno;

    
   
12230
}

    
   
12231

   

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

    
   
12233
{

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

    
   
12235

   

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

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

    
   
12238

   

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

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

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

    
   
12258
	iax_transfercallno_pvts = ao2_container_alloc(IAX_MAX_CALLS, transfercallno_pvt_hash_cb, transfercallno_pvt_cmp_cb);
12198
	if (!iax_peercallno_pvts) {
12259
	if (!iax_peercallno_pvts) {
12199
		ao2_ref(peers, -1);
12260
		ao2_ref(peers, -1);
12200
		ao2_ref(users, -1);
12261
		ao2_ref(users, -1);
12201
		return AST_MODULE_LOAD_FAILURE;
12262
		return AST_MODULE_LOAD_FAILURE;
12202
	}
12263
	}
[+20] [20] 101 lines
branches/1.6.0/channels/chan_iax2.c
Diff Revision 1 Diff Revision 3 - File Reverted
 
  1. /branches/1.6.0/channels/chan_iax2.c: Loading...
  2. 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.