summaryrefslogtreecommitdiffstats
path: root/chan_lcr.c
diff options
context:
space:
mode:
authorPeter Schlaile2008-09-27 22:03:44 +0200
committerroot2008-09-27 22:03:44 +0200
commit08f7138ac0d13805e61ff3303a50bdb5ed9a7bb7 (patch)
tree9966ca370e77ee156a65b49419e19489c8256fea /chan_lcr.c
parentadded options.c to automake, so that chan_lcr gets built correctly (diff)
downloadlcr-08f7138ac0d13805e61ff3303a50bdb5ed9a7bb7.tar.gz
lcr-08f7138ac0d13805e61ff3303a50bdb5ed9a7bb7.tar.xz
lcr-08f7138ac0d13805e61ff3303a50bdb5ed9a7bb7.zip
chan_lcr: fixed race condition in new ref assignment
LCR assumes, that any call in the list, that has ref set to 0 is waiting for a ref to be assigned. That can cause trouble, if we have one call waiting for a ref to be assigned and another call hanging in the list, that was just released in the same moment. Both have ref == 0 and in some circumstances, the new ref message picks the wrong one for assignment... This patch makes chan_lcr distinguish between calls waiting for a new ref and those, that only have their ref removed due to release. (It is not enough, to check for state, since new calls can change into release state immediately! That is also one of the race conditions, when this can get you into trouble: asterisk receives call1 by LCR, makes a SETUP call2 immediately through LCR and then receives a release for call1 by LCR before call2 got it's ref assigned!) This patch also removes some dead code, that was #ifdef'd out. End user notice: if you ever got into the situation, that _all_ calls from asterisk to LCR got released immediately and only a restart of asterisk got you out of the situation, then you might need this fix :)
Diffstat (limited to 'chan_lcr.c')
-rw-r--r--chan_lcr.c43
1 files changed, 11 insertions, 32 deletions
diff --git a/chan_lcr.c b/chan_lcr.c
index b28965a..b00bc7e 100644
--- a/chan_lcr.c
+++ b/chan_lcr.c
@@ -205,46 +205,24 @@ void chan_lcr_log(int type, const char *file, int line, const char *function, st
*/
struct chan_call *call_first;
-struct chan_call *find_call_ref(unsigned int ref)
-{
- struct chan_call *call = call_first;
-
- while(call)
- {
- if (call->ref == ref)
- break;
- call = call->next;
- }
- return(call);
-}
-
-#if 0
-struct chan_call *find_call_ast(struct ast_channel *ast)
-{
- struct chan_call *call = call_first;
-
- while(call)
- {
- if (call->ast == ast)
- break;
- call = call->next;
- }
- return(call);
-}
+/*
+ * find call by ref
+ * special case: 0: find new ref, that has not been assigned a ref yet
+ */
-struct chan_call *find_call_handle(unsigned int handle)
+struct chan_call *find_call_ref(unsigned int ref)
{
struct chan_call *call = call_first;
-
+ int assigned = (ref > 0);
+
while(call)
{
- if (call->bchannel_handle == handle)
+ if (call->ref == ref && call->ref_was_assigned == assigned)
break;
call = call->next;
}
return(call);
}
-#endif
void free_call(struct chan_call *call)
{
@@ -300,7 +278,6 @@ struct chan_call *alloc_call(void)
return(*callp);
}
-
unsigned short new_bridge_id(void)
{
struct chan_call *call;
@@ -948,7 +925,7 @@ static void lcr_in_disconnect(struct chan_call *call, int message_type, union pa
}
/*
- * incoming setup acknowledge from LCR
+ * incoming release from LCR
*/
static void lcr_in_release(struct chan_call *call, int message_type, union parameter *param)
{
@@ -1199,6 +1176,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
call->state = CHAN_LCR_STATE_IN_PREPARE;
/* set ref */
call->ref = ref;
+ call->ref_was_assigned = 1;
/* wait for setup (or release from asterisk) */
} else
{
@@ -1214,6 +1192,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
}
/* store new ref */
call->ref = ref;
+ call->ref_was_assigned = 1;
/* send pending setup info */
if (call->state == CHAN_LCR_STATE_OUT_PREPARE)
send_setup_to_lcr(call);