--- svn_chan_sip.c 2008-10-29 23:15:56.093750000 +0100 +++ patched_chan_sip.c 2008-10-29 23:49:53.531250000 +0100 @@ -1942,6 +1942,9 @@ SDP_T38_ACCEPT, /*!< Remote side accepted our T38 request */ }; +/*! \brief Protect the callcounters inuse,inringing and the corresponding flags */ +AST_MUTEX_DEFINE_STATIC(callctrlock); + /*---------------------------- Forward declarations of functions in chan_sip.c */ /* Note: This is added to help splitting up chan_sip.c into several files in coming releases. */ @@ -4899,6 +4902,8 @@ int *inuse = NULL, *call_limit = NULL, *inringing = NULL; int outgoing = fup->outgoing_call; struct sip_peer *p = NULL; + int ctrproblem=FALSE; + int ctrdebug=0; ast_debug(3, "Updating call counter for %s call\n", outgoing ? "outgoing" : "incoming"); @@ -4926,20 +4931,50 @@ /* incoming and outgoing affects the inUse counter */ case DEC_CALL_LIMIT: /* Decrement inuse count if applicable */ - if (inuse && *inuse > 0 && ast_test_flag(&fup->flags[0], SIP_INC_COUNT)) { - ast_atomic_fetchadd_int(inuse, -1); - ast_clear_flag(&fup->flags[0], SIP_INC_COUNT); - } else - *inuse = 0; + ctrproblem=FALSE; + if (inuse) { + ast_mutex_lock(&callctrlock); + if((*inuse > 0) && ast_test_flag(&fup->flags[0], SIP_INC_COUNT)) { + (*inuse)--; + ast_clear_flag(&fup->flags[0], SIP_INC_COUNT); + } else if (*inuse < 0) { + ctrproblem=TRUE; + ctrdebug=*inuse; + *inuse = 0; + } + ast_mutex_unlock(&callctrlock); + } + if(ctrproblem) { + ast_debug(2, "Bug13668: inuse %i corrected to 0 @1\n", ctrdebug); + ctrproblem=FALSE; + } + /* Decrement ringing count if applicable */ - if (inringing && *inringing > 0 && ast_test_flag(&fup->flags[0], SIP_INC_RINGING)) { - ast_atomic_fetchadd_int(inringing, -1); - ast_clear_flag(&fup->flags[0], SIP_INC_RINGING); + if (inringing) { + ast_mutex_lock(&callctrlock); + if((*inringing > 0)&& ast_test_flag(&fup->flags[0], SIP_INC_RINGING)) { + (*inringing)--; + ast_clear_flag(&fup->flags[0], SIP_INC_RINGING); + } else if (*inringing < 0) { + ctrproblem=TRUE; + ctrdebug=*inringing; + *inringing = 0; + } + ast_mutex_unlock(&callctrlock); + } + if(ctrproblem) { + ast_debug(2, "Bug13668: inringing %i corrected to 0 @2\n", ctrdebug); + ctrproblem=FALSE; } + /* Decrement onhold count if applicable */ + ast_mutex_lock(&callctrlock); if (ast_test_flag(&fup->flags[1], SIP_PAGE2_CALL_ONHOLD) && global_notifyhold) { ast_clear_flag(&fup->flags[1], SIP_PAGE2_CALL_ONHOLD); + ast_mutex_unlock(&callctrlock); sip_peer_hold(fup, FALSE); + } else { + ast_mutex_unlock(&callctrlock); } if (sipdebug) ast_debug(2, "Call %s %s '%s' removed from call limit %d\n", outgoing ? "to" : "from", "peer", name, *call_limit); @@ -4955,30 +4990,102 @@ return -1; } } + ctrproblem=FALSE; if (inringing && (event == INC_CALL_RINGING)) { - if (!ast_test_flag(&fup->flags[0], SIP_INC_RINGING)) { - ast_atomic_fetchadd_int(inringing, +1); + ast_mutex_lock(&callctrlock); + if ((*inringing >= 0)&& !ast_test_flag(&fup->flags[0], SIP_INC_RINGING)) { + (*inringing)++; ast_set_flag(&fup->flags[0], SIP_INC_RINGING); + } else if (*inringing < 0) { + ctrproblem=TRUE; + ctrdebug=*inringing; + *inringing = 1; + } + ast_mutex_unlock(&callctrlock); + if(ctrproblem) { + ast_debug(2, "Bug13668: inringing %i corrected to 1 @3\n", ctrdebug); + ctrproblem=FALSE; } } /* Continue */ - ast_atomic_fetchadd_int(inuse, +1); - ast_set_flag(&fup->flags[0], SIP_INC_COUNT); + if(inuse) { + ast_mutex_lock(&callctrlock); + if((*inuse >= 0) && !ast_test_flag(&fup->flags[0], SIP_INC_COUNT)) { + (*inuse)++; + ast_set_flag(&fup->flags[0], SIP_INC_COUNT); + } else { + ctrproblem=TRUE; + ctrdebug=*inuse; + *inuse = 1; + } + ast_mutex_unlock(&callctrlock); + } + if(ctrproblem) { + ast_debug(2, "Bug13668: inuse %i corrected to 1 @4\n", ctrdebug); + ctrproblem=FALSE; + } if (sipdebug) { ast_debug(2, "Call %s %s '%s' is %d out of %d\n", outgoing ? "to" : "from", "peer", name, *inuse, *call_limit); } break; case DEC_CALL_RINGING: - if (inringing && *inringing > 0 && ast_test_flag(&fup->flags[0], SIP_INC_RINGING)) { - ast_atomic_fetchadd_int(inringing, -1); - ast_clear_flag(&fup->flags[0], SIP_INC_RINGING); + ctrproblem=FALSE; + if (inringing ) { + ast_mutex_lock(&callctrlock); + if((*inringing > 0) && ast_test_flag(&fup->flags[0], SIP_INC_RINGING)) { + (*inringing)--; + ast_clear_flag(&fup->flags[0], SIP_INC_RINGING); + } else if (*inringing < 0) { + ctrproblem=TRUE; + ctrdebug=*inringing; + *inringing = 0; + } + ast_mutex_unlock(&callctrlock); + } + if(ctrproblem) { + ast_debug(2, "Bug13668: inringing %i corrected to 0 @5\n", ctrdebug); + ctrproblem=FALSE; } break; default: ast_log(LOG_ERROR, "update_call_counter(%s, %d) called with no event!\n", name, event); } + /* **********************************************/ + /* remember murphy! */ + /* to be removed if tests are successful */ + ctrproblem=FALSE; + if (inringing ) { + ast_mutex_lock(&callctrlock); + if (*inringing < 0) { + ctrproblem=TRUE; + ctrdebug=*inringing; + *inringing = 0; + } + ast_mutex_unlock(&callctrlock); + } + if(ctrproblem) { + ast_debug(2, "Bug13668: inringing %i corrected to 0 @6\n", ctrdebug); + ctrproblem=FALSE; + } + if (inuse) { + ast_mutex_lock(&callctrlock); + if (*inuse < 0) { + ctrproblem=TRUE; + ctrdebug=*inuse; + *inuse = 0; + } + ast_mutex_unlock(&callctrlock); + } + if(ctrproblem) { + ast_debug(2, "Bug13668: inuse %i corrected to 0 @7\n", ctrdebug); + ctrproblem=FALSE; + } + /* end of removable code */ + /* ********************************************/ + + if (p) { ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", p->name); unref_peer(p, "update_call_counter: unref_peer from call counter");