[asterisk-commits] murf: branch murf/bug11210 r99023 - /team/murf/bug11210/channels/chan_iax2.c
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Jan 18 10:09:43 CST 2008
Author: murf
Date: Fri Jan 18 10:09:43 2008
New Revision: 99023
URL: http://svn.digium.com/view/asterisk?view=rev&rev=99023
Log:
A checkpoint in keeping the findcall hash tables up to date
Modified:
team/murf/bug11210/channels/chan_iax2.c
Modified: team/murf/bug11210/channels/chan_iax2.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug11210/channels/chan_iax2.c?view=diff&rev=99023&r1=99022&r2=99023
==============================================================================
--- team/murf/bug11210/channels/chan_iax2.c (original)
+++ team/murf/bug11210/channels/chan_iax2.c Fri Jan 18 10:09:43 2008
@@ -674,6 +674,48 @@
find_callno routine -- Any time one of the keys is modified, the pvt must
be removed from the table, updated, and relinked into the table. */
+/* Design:
+ At the time I implemented this, the match() routine (If you explode the
+ conditionals, did these 4 tests, and in this order:
+
+ 1. same(sin,cur->addr) && callno == cur->peercallno
+ 2. same(sin,cur->addr) && callno == 0 && dcallno == cur->callno
+ 3. same(sin,cur->transfer) && cur->transferring != 0 && dcallno == cur->callno
+ 4. same(sin,cur->transfer) && cur->transferring == TRANSFER_MEDIAPASS && callno == cur->transfercallno
+
+Any of the terms above that involve callno, dcallno, or sin, can be determined at run time,
+and are not involved in the hash tables themselves, so you can ignore them, sort of, when you
+try to figure out what the hash mech should track. the fields in cur that we will end up using
+as keys are:
+ addr, transfer, callno, transfercallno, peercallno, transferring.
+
+The 4 tables follow the above 4 conditionals, and serve as the lookup mechanism, for each
+corresponding conditional.
+
+In the find_callno routine, the idea will be to consult the 4 tables in sequence,
+with the appropriate data set up for the comparison, and to end the search with the
+first success.
+
+The trickiest/messiest part of this, will be to keep the hash tables in sync with the current
+state of the channel driver. Important to note, is that many of the key fields can change.
+Thus we need to unlink, update, and relink each entry in each table as appropriate, whenever
+it's key field is modified.
+
+Special conditions for findcall3: only those callno's are entered, that have cur->transferring set to non-zero.
+ findcall4: only those callno's are entered, that have cur->transferring set to MEDIAPASS
+
+Work scope: Probable number of places to make changes:
+
+->peercallno set in ~5 places
+->callno set in ~20 places
+->transfercallno set in ~2 places
+->addr ~3 places; address passed to functions ~8 times
+->transfer ~7 places, addr passed to functions ~3 times.
+->transferring ~14 places
+
+
+*/
+
static struct ao2_container *findcall1; /* keys: pvt->addr & pvt->peercallno */
static struct ao2_container *findcall2; /* keys: pvt->addr & pvt->callno */
static struct ao2_container *findcall3; /* keys: pvt->transfer & pvt->callno */
@@ -1268,10 +1310,10 @@
return !strcasecmp(user->name, user2->name) ? CMP_MATCH : 0;
}
-/*!
- * \note The only members of the pvt passed here guaranteed to be set are the addr and peercallno fields
- */
-static int findcall1_hash_cb(const void *obj, const int flags)
+ /*!
+ * \note The keys are the addr and peercallno fields
+ */
+ static int findcall1_hash_cb(const void *obj, const int flags)
{
const struct chan_iax2_pvt *pvt = obj;
int x = pvt->addr.sin_addr.s_addr + pvt->addr.sin_port + pvt->peercallno;
@@ -1282,7 +1324,7 @@
}
/*!
- * \note The only members of the pvt passed here guaranteed to be set are the addr and peercallno fields
+ * \note The keys are the addr and peercallno fields
*/
static int findcall1_cmp_cb(void *obj, void *arg, int flags)
{
@@ -1298,7 +1340,7 @@
}
/*!
- * \note The only members of the pvt passed here guaranteed to be set are the addr and callno fields
+ * \note The keys are the addr and callno fields
*/
static int findcall2_hash_cb(const void *obj, const int flags)
{
@@ -1311,7 +1353,7 @@
}
/*!
- * \note The only members of the pvt passed here guaranteed to be set are the addr and callno fields
+ * \note The keys are the addr and callno fields
*/
static int findcall2_cmp_cb(void *obj, void *arg, int flags)
{
@@ -1327,7 +1369,7 @@
}
/*!
- * \note The only members of the pvt passed here guaranteed to be set are the transfer and callno fields
+ * \note The keys are the transfer and transfercallno fields
*/
static int findcall3_hash_cb(const void *obj, const int flags)
{
@@ -1340,7 +1382,7 @@
}
/*!
- * \note The only members of the pvt passed here guaranteed to be set are the transfer and transfercallno fields
+ * \note The keys are the transfer and transfercallno fields
*/
static int findcall3_cmp_cb(void *obj, void *arg, int flags)
{
@@ -1356,7 +1398,7 @@
}
/*!
- * \note The only members of the pvt passed here guaranteed to be set are the addr and peercallno fields
+ * \note The keys are the addr and peercallno fields
*/
static int findcall4_hash_cb(const void *obj, const int flags)
{
@@ -1369,7 +1411,7 @@
}
/*!
- * \note The only members of the pvt passed here guaranteed to be set are the addr and peercallno fields
+ * \note The keys are the addr and peercallno fields
*/
static int findcall4_cmp_cb(void *obj, void *arg, int flags)
{
@@ -1694,11 +1736,15 @@
ast_string_field_set(iaxs[x], accountcode, accountcode);
ast_string_field_set(iaxs[x], mohinterpret, mohinterpret);
ast_string_field_set(iaxs[x], mohsuggest, mohsuggest);
+ ao2_t_link(findcall1, iaxs[x], "a new pvt is borne!");
+ ao2_t_link(findcall2, iaxs[x], "a new pvt is borne!");
+ /* it appears that findcall3 and findcall4 will not be linked, as the transferring field is 0 */
} else {
ast_log(LOG_WARNING, "Out of resources\n");
ast_mutex_unlock(&iaxsl[x]);
return 0;
}
+
ast_mutex_unlock(&iaxsl[x]);
res = x;
}
@@ -3737,6 +3783,9 @@
struct iax_ie_data ied0;
struct iax_ie_data ied1;
unsigned int transferid = (unsigned int)ast_random();
+ int old0 = iaxs[callno0]->transferring;
+ int old1 = iaxs[callno1]->transferring;
+
memset(&ied0, 0, sizeof(ied0));
iax_ie_append_addr(&ied0, IAX_IE_APPARENT_ADDR, &iaxs[callno1]->addr);
iax_ie_append_short(&ied0, IAX_IE_CALLNO, iaxs[callno1]->peercallno);
@@ -3755,6 +3804,14 @@
return -1;
iaxs[callno0]->transferring = mediaonly ? TRANSFER_MBEGIN : TRANSFER_BEGIN;
iaxs[callno1]->transferring = mediaonly ? TRANSFER_MBEGIN : TRANSFER_BEGIN;
+ if (!old0)
+ ao2_t_link(findcall3,iaxs[callno0],"adding to findcall3 (callno0) because transfer is beginning");
+ if (!old1)
+ ao2_t_link(findcall3,iaxs[callno1],"adding to findcall3 (callno1) because transfer is beginning");
+ if (old0 == TRANSFER_MEDIAPASS) /* seems improbable, but I'd better be complete for the moment... */
+ ao2_t_unlink(findcall4,iaxs[callno0],"removing from findcall4 (callno0) because transfer is beginning, but was in MEDIAPASS");
+ if (old1 == TRANSFER_MEDIAPASS)
+ ao2_t_unlink(findcall4,iaxs[callno1],"removing from findcall4 (callno1) because transfer is beginning, but was in MEDIAPASS");
return 0;
}
@@ -6313,7 +6370,7 @@
char newip[256];
struct iax_ie_data ied;
struct sockaddr_in new;
-
+ int old1 = pvt->transferring;
memset(&ied, 0, sizeof(ied));
if (ies->apparent_addr)
@@ -6329,6 +6386,9 @@
inet_aton(newip, &pvt->transfer.sin_addr);
pvt->transfer.sin_family = AF_INET;
pvt->transferring = TRANSFER_BEGIN;
+ if (!old1)
+ ao2_t_link(findcall3,pvt,"adding this entry to findcall3, because transferring was previously 0");
+
pvt->transferid = ies->transferid;
if (ies->transferid)
iax_ie_append_int(&ied, IAX_IE_TRANSFERID, ies->transferid);
@@ -6394,6 +6454,12 @@
ast_log(LOG_WARNING, "Invalid transfer request\n");
return -1;
}
+ if (pvt->transferring == TRANSFER_MEDIAPASS)
+ ao2_t_unlink(findcall4, pvt, "Removing pvt from findcall4; was MEDIAPASS, now 0");
+ if (pvt->transferring)
+ ao2_t_unlink(findcall3, pvt, "Removing pvt from findcall3; was non-0, now 0");
+ ao2_t_unlink(findcall1, pvt, "Removing pvt from findcall1, we are going to change addr");
+ ao2_t_unlink(findcall2, pvt, "Removing pvt from findcall2, we are going to change addr");
memcpy(&pvt->addr, &pvt->transfer, sizeof(pvt->addr));
memset(&pvt->transfer, 0, sizeof(pvt->transfer));
/* Reset sequence numbers */
@@ -6401,6 +6467,7 @@
pvt->rseqno = 0;
pvt->iseqno = 0;
pvt->aseqno = 0;
+ ao2_t_unlink(findcall1, pvt, "remove pvt from findcall1 so we can set peercallno");
pvt->peercallno = peercallno;
pvt->transferring = TRANSFER_NONE;
pvt->svoiceformat = -1;
@@ -6419,6 +6486,9 @@
pvt->lastsent = 0;
pvt->nextpred = 0;
pvt->pingtime = DEFAULT_RETRY_TIME;
+ ao2_t_link(findcall1, pvt, "Adding pvt back to findcall1, we changed addr/peercallno");
+ ao2_t_link(findcall2, pvt, "Removing pvt from findcall2, we changed addr");
+
AST_LIST_LOCK(&frame_queue);
AST_LIST_TRAVERSE(&frame_queue, cur, list) {
/* We must cancel any packets that would have been transmitted
@@ -7861,7 +7931,10 @@
if (!inaddrcmp(&sin, &iaxs[fr->callno]->addr) && !minivid &&
f.subclass != IAX_COMMAND_TXCNT && /* for attended transfer */
f.subclass != IAX_COMMAND_TXACC) { /* for attended transfer */
+ if (iaxs[fr->callno]->peercallno)
+ ao2_t_unlink(findcall1,iaxs[fr->callno],"remove pvt from findcall1, we are changing the peercallno field");
iaxs[fr->callno]->peercallno = (unsigned short)(ntohs(mh->callno) & ~IAX_FLAG_FULL);
+ ao2_t_link(findcall1,iaxs[fr->callno],"replace pvt in findcall1, we are changing the peercallno field");
}
if (ntohs(mh->callno) & IAX_FLAG_FULL) {
if (iaxdebug)
@@ -9015,7 +9088,7 @@
ast_verb(3, "Attempting media bridge of %s and %s\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : "<Unknown>",
iaxs[iaxs[fr->callno]->bridgecallno]->owner ? iaxs[iaxs[fr->callno]->bridgecallno]->owner->name : "<Unknown>");
- iaxs[iaxs[fr->callno]->bridgecallno]->transferring = TRANSFER_MEDIA;
+ iaxs[iaxs[fr->callno]->bridgecallno]->transferring = TRANSFER_MEDIA; /* no action required in findcall3/4 */
iaxs[fr->callno]->transferring = TRANSFER_MEDIA;
memset(&ied0, 0, sizeof(ied0));
@@ -9025,13 +9098,24 @@
send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied0.buf, ied0.pos, -1);
send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied1.buf, ied1.pos, -1);
} else {
+ int oldbdg = iaxs[iaxs[fr->callno]->bridgecallno]->transferring;
+ int oldfr = iaxs[fr->callno]->transferring;
+
ast_verb(3, "Releasing %s and %s\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : "<Unknown>",
iaxs[iaxs[fr->callno]->bridgecallno]->owner ? iaxs[iaxs[fr->callno]->bridgecallno]->owner->name : "<Unknown>");
-
+ if (oldbdg == TRANSFER_MEDIAPASS)
+ ao2_t_unlink(findcall4,iaxs[iaxs[fr->callno]->bridgecallno],"changing from transferring MEDIAPASS to TRANSFER_RELEASED");
+ if (oldfr == TRANSFER_MEDIAPASS)
+ ao2_t_unlink(findcall4,iaxs[fr->callno],"changing from transferring MEDIAPASS to TRANSFER_RELEASED");
+
iaxs[iaxs[fr->callno]->bridgecallno]->transferring = TRANSFER_RELEASED;
iaxs[fr->callno]->transferring = TRANSFER_RELEASED;
ast_set_flag(iaxs[iaxs[fr->callno]->bridgecallno], IAX_ALREADYGONE);
ast_set_flag(iaxs[fr->callno], IAX_ALREADYGONE);
+ if (!oldbdg)
+ ao2_t_link(findcall3,iaxs[iaxs[fr->callno]->bridgecallno],"changing from !transferring TRANSFER_RELEASED");
+ if (!oldfr)
+ ao2_t_unlink(findcall3,iaxs[fr->callno],"changing from transferring MEDIAPASS to TRANSFER_RELEASED");
/* Stop doing lag & ping requests */
stop_stuff(fr->callno);
@@ -9073,6 +9157,7 @@
AST_LIST_UNLOCK(&frame_queue);
/* Start sending our media to the transfer address, but otherwise leave the call as-is */
iaxs[fr->callno]->transferring = TRANSFER_MEDIAPASS;
+ ao2_t_link(findcall4, iaxs[fr->callno], "This pvt is being set in MEDIAPASS state, adding to findcall4");
}
break;
case IAX_COMMAND_DPREP:
More information about the asterisk-commits
mailing list