Occasionally losing use of B channels in chan_misdn.

I have not been able to reproduce the problem of losing channels.
However, I have seen in the code a reentrancy problem that might give
these symptoms.

The reentrancy patch does several things:
1) Guards B channel and B channel structure allocation.
2) Makes the B channel structure find routines more precise in locating records.
3) Never leave a B channel allocated if we received cause 44.

The last item may cause temporary outgoing call problems, but they should
clear when the line becomes idle.

(closes issue #15490)
Reported by: slutec18
Patches:
      issue15490_channel_alloc_reentrancy.patch uploaded by rmudgett (license 664)
Tested by: rmudgett, slutec18

(closes issue #15458)
Reported by: FabienToune
Patches:
      issue15458_channel_alloc_reentrancy.patch uploaded by rmudgett (license 664)
Tested by: FabienToune, rmudgett, slutec18


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@221769 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.4
Richard Mudgett 16 years ago
parent ae49400957
commit ea14c40ae1

@ -500,6 +500,7 @@ static int find_free_chan_in_stack(struct misdn_stack *stack, struct misdn_bchan
channel--;
pthread_mutex_lock(&stack->st_lock);
if (dec) {
for (i = bnums; i >=0; i--) {
if (i != 15 && (channel < 0 || i == channel)) { /* skip E1 D channel ;) and work with chan preselection */
@ -523,6 +524,7 @@ static int find_free_chan_in_stack(struct misdn_stack *stack, struct misdn_bchan
}
if (!chan) {
pthread_mutex_unlock(&stack->st_lock);
cb_log (1, stack->port, " !! NO FREE CHAN IN STACK\n");
dump_chan_list(stack);
bc->out_cause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
@ -530,10 +532,12 @@ static int find_free_chan_in_stack(struct misdn_stack *stack, struct misdn_bchan
}
if (set_chan_in_stack(stack, chan)<0) {
pthread_mutex_unlock(&stack->st_lock);
cb_log (0, stack->port, "Channel Already in use:%d\n", chan);
bc->out_cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL;
return -1;
}
pthread_mutex_unlock(&stack->st_lock);
bc->channel=chan;
return 0;
@ -777,9 +781,9 @@ static void clear_l3(struct misdn_stack *stack)
for (i=0; i<=stack->b_num; i++) {
if (global_state == MISDN_INITIALIZED) {
cb_event(EVENT_CLEANUP, &stack->bc[i], NULL);
empty_chan_in_stack(stack,i+1);
empty_bc(&stack->bc[i]);
clean_up_bc(&stack->bc[i]);
empty_chan_in_stack(stack, i + 1);
stack->bc[i].in_use = 0;
}
@ -1242,6 +1246,8 @@ static struct misdn_stack *stack_init(int midev, int port, int ptp)
msg_queue_init(&stack->downqueue);
msg_queue_init(&stack->upqueue);
pthread_mutex_init(&stack->st_lock, NULL);
/* query port's requirements */
ret = mISDN_get_stack_info(midev, port, buff, sizeof(buff));
@ -1416,6 +1422,8 @@ static void stack_destroy(struct misdn_stack *stack)
if (stack->upper_id)
mISDN_write_frame(stack->midev, buf, stack->upper_id, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
pthread_mutex_destroy(&stack->st_lock);
}
@ -1461,8 +1469,11 @@ static struct misdn_stack * find_stack_by_mgr(manager_t* mgr_nt)
static struct misdn_bchannel *find_bc_by_masked_l3id(struct misdn_stack *stack, unsigned long l3id, unsigned long mask)
{
int i;
for (i=0; i<=stack->b_num; i++) {
if ( (stack->bc[i].l3_id & mask) == (l3id & mask)) return &stack->bc[i] ;
for (i = 0; i <= stack->b_num; i++) {
if (stack->bc[i].in_use && (stack->bc[i].l3_id & mask) == (l3id & mask)) {
return &stack->bc[i];
}
}
return stack_holder_find(stack,l3id);
}
@ -1471,8 +1482,11 @@ static struct misdn_bchannel *find_bc_by_masked_l3id(struct misdn_stack *stack,
struct misdn_bchannel *find_bc_by_l3id(struct misdn_stack *stack, unsigned long l3id)
{
int i;
for (i=0; i<=stack->b_num; i++) {
if (stack->bc[i].l3_id == l3id) return &stack->bc[i] ;
for (i = 0; i <= stack->b_num; i++) {
if (stack->bc[i].in_use && stack->bc[i].l3_id == l3id) {
return &stack->bc[i];
}
}
return stack_holder_find(stack,l3id);
}
@ -1482,11 +1496,11 @@ static struct misdn_bchannel *find_bc_by_addr(unsigned long addr)
struct misdn_stack *stack;
int i;
for (stack=glob_mgr->stack_list;
stack;
stack=stack->next) {
for (i=0; i<=stack->b_num; i++) {
if ( (stack->bc[i].addr&STACK_ID_MASK)==(addr&STACK_ID_MASK) || stack->bc[i].layer_id== addr ) {
for (stack = glob_mgr->stack_list; stack; stack = stack->next) {
for (i = 0; i <= stack->b_num; i++) {
if (stack->bc[i].in_use
&& ((stack->bc[i].addr & STACK_ID_MASK) == (addr & STACK_ID_MASK)
|| stack->bc[i].layer_id == addr)) {
return &stack->bc[i];
}
}
@ -1500,11 +1514,9 @@ static struct misdn_bchannel *find_bc_by_confid(unsigned long confid)
struct misdn_stack *stack;
int i;
for (stack=glob_mgr->stack_list;
stack;
stack=stack->next) {
for (i=0; i<=stack->b_num; i++) {
if ( stack->bc[i].conf_id==confid ) {
for (stack = glob_mgr->stack_list; stack; stack = stack->next) {
for (i = 0; i <= stack->b_num; i++) {
if (stack->bc[i].in_use && stack->bc[i].conf_id == confid) {
return &stack->bc[i];
}
}
@ -1518,10 +1530,12 @@ static struct misdn_bchannel *find_bc_by_channel(int port, int channel)
struct misdn_stack *stack = find_stack_by_port(port);
int i;
if (!stack) return NULL;
if (!stack) {
return NULL;
}
for (i=0; i<=stack->b_num; i++) {
if ( stack->bc[i].channel== channel ) {
for (i = 0; i <= stack->b_num; i++) {
if (stack->bc[i].in_use && stack->bc[i].channel == channel) {
return &stack->bc[i];
}
}
@ -1588,7 +1602,9 @@ static int handle_event ( struct misdn_bchannel *bc, enum event_e event, iframe_
if (!bc->channel)
cb_log(0, stack->port, "Any Channel Requested, but we have no more!!\n");
else
cb_log(0, stack->port, "Requested Channel Already in Use releasing this call with cause 34!!!!\n");
cb_log(0, stack->port,
"Requested Channel Already in Use releasing this call with cause %d!!!!\n",
bc->out_cause);
/* when the channel is already in use, we can't
* simply clear it, we need to make sure that
@ -1699,6 +1715,7 @@ static int handle_cr ( struct misdn_stack *stack, iframe_t *frm)
/* Empties bc if it's reserved (no SETUP out yet) */
void misdn_lib_release(struct misdn_bchannel *bc)
{
int channel;
struct misdn_stack *stack=get_stack_by_bc(bc);
if (!stack) {
@ -1706,11 +1723,12 @@ void misdn_lib_release(struct misdn_bchannel *bc)
return;
}
if (bc->channel>0)
empty_chan_in_stack(stack,bc->channel);
channel = bc->channel;
empty_bc(bc);
clean_up_bc(bc);
if (channel > 0) {
empty_chan_in_stack(stack, channel);
}
bc->in_use=0;
}
@ -2753,22 +2771,19 @@ handle_frm_bc:
bc->cause=tmpcause;
bc->out_cause=tmp_out_cause;
clean_up_bc(bc);
bc->in_use = 0;
if (tmpcause == AST_CAUSE_REQUESTED_CHAN_UNAVAIL) {
cb_log(0,stack->port,"**** Received CAUSE:%d, so not cleaning up channel %d\n", AST_CAUSE_REQUESTED_CHAN_UNAVAIL, channel);
cb_log(0,stack->port,"**** This channel is now no longer available,\nplease try to restart it with 'misdn send restart <port> <channel>'\n");
set_chan_in_stack(stack, channel);
bc->channel=channel;
cb_log(0, stack->port, "**** Received CAUSE:%d, restarting channel %d\n", AST_CAUSE_REQUESTED_CHAN_UNAVAIL, channel);
misdn_lib_send_restart(stack->port, channel);
} else {
if (channel>0)
empty_chan_in_stack(stack, channel);
}
bc->in_use=0;
if (channel > 0) {
empty_chan_in_stack(stack, channel);
}
}
if (event == EVENT_RESTART) {
cb_log(0, stack->port, "**** Received RESTART_ACK channel:%d\n", bc->restart_channel);
cb_log(0, stack->port, "**** Received RESTART channel:%d\n", bc->restart_channel);
empty_chan_in_stack(stack, bc->restart_channel);
}
@ -3149,11 +3164,12 @@ struct misdn_bchannel *manager_find_bc_by_pid(int pid)
struct misdn_stack *stack;
int i;
for (stack=glob_mgr->stack_list;
stack;
stack=stack->next) {
for (i=0; i<=stack->b_num; i++)
if (stack->bc[i].pid == pid) return &stack->bc[i];
for (stack = glob_mgr->stack_list; stack; stack = stack->next) {
for (i = 0; i <= stack->b_num; i++) {
if (stack->bc[i].in_use && stack->bc[i].pid == pid) {
return &stack->bc[i];
}
}
}
return NULL;
@ -3183,7 +3199,6 @@ static void prepare_bc(struct misdn_bchannel*bc, int channel)
{
bc->channel = channel;
bc->channel_preselected = channel?1:0;
bc->in_use = 1;
bc->need_disconnect=1;
bc->need_release=1;
bc->need_release_complete=1;
@ -3197,6 +3212,8 @@ static void prepare_bc(struct misdn_bchannel*bc, int channel)
bc->b_stid=0;
bc->layer_id=0;
#endif
bc->in_use = 1;
}
struct misdn_bchannel* misdn_lib_get_free_bc(int port, int channel, int inout, int dec)
@ -3209,8 +3226,6 @@ struct misdn_bchannel* misdn_lib_get_free_bc(int port, int channel, int inout, i
return NULL;
}
usleep(1000);
for (stack=glob_mgr->stack_list; stack; stack=stack->next) {
if (stack->port == port) {
@ -3221,21 +3236,25 @@ struct misdn_bchannel* misdn_lib_get_free_bc(int port, int channel, int inout, i
return NULL;
}
pthread_mutex_lock(&stack->st_lock);
if (channel > 0) {
if (channel <= stack->b_num) {
for (i = 0; i < stack->b_num; i++) {
if ( stack->bc[i].channel == channel) {
if (test_inuse(&stack->bc[i])) {
pthread_mutex_unlock(&stack->st_lock);
cb_log(0,port,"Requested channel:%d on port:%d is already in use\n",channel, port);
return NULL;
} else {
prepare_bc(&stack->bc[i], channel);
pthread_mutex_unlock(&stack->st_lock);
return &stack->bc[i];
}
}
}
} else {
pthread_mutex_unlock(&stack->st_lock);
cb_log(0,port,"Requested channel:%d is out of bounds on port:%d\n",channel, port);
return NULL;
}
@ -3252,6 +3271,7 @@ struct misdn_bchannel* misdn_lib_get_free_bc(int port, int channel, int inout, i
prepare_bc(&stack->bc[i], channel);
stack->bc[i].dec=1;
pthread_mutex_unlock(&stack->st_lock);
return &stack->bc[i];
}
}
@ -3263,10 +3283,12 @@ struct misdn_bchannel* misdn_lib_get_free_bc(int port, int channel, int inout, i
stack->bc[i].cw=1;
prepare_bc(&stack->bc[i], channel);
pthread_mutex_unlock(&stack->st_lock);
return &stack->bc[i];
}
}
}
pthread_mutex_unlock(&stack->st_lock);
cb_log(1,port,"There is no free channel on port (%d)\n",port);
return NULL;
@ -3849,7 +3871,7 @@ int misdn_lib_send_restart(int port, int channel)
/* clean up chan in stack, to be sure we don't think it's
* in use anymore */
for (cnt=0; cnt<=stack->b_num; cnt++) {
if (stack->bc[cnt].channel == channel) {
if (stack->bc[cnt].in_use && stack->bc[cnt].channel == channel) {
empty_bc(&stack->bc[cnt]);
clean_up_bc(&stack->bc[cnt]);
stack->bc[cnt].in_use=0;

@ -56,6 +56,9 @@ struct misdn_stack {
manager_t mgr;
pthread_mutex_t nstlock;
/*! \brief Stack struct critical section lock. */
pthread_mutex_t st_lock;
/*! \brief D Channel mISDN driver stack ID (Parent stack ID) */
int d_stid;
@ -121,7 +124,7 @@ struct misdn_stack {
/*! \brief Array of B channels in use (a[0] = B1). TRUE if B channel in use */
int channels[MAX_BCHANS + 1];
/*! \brief List of holded channels */
/*! \brief List of held channels */
struct misdn_bchannel *holding;
/*! \brief Next stack in the list of stacks */

Loading…
Cancel
Save