added new boost msg EVENT_CALL_RELEASED to fix race condition on call hangup

git-svn-id: http://svn.openzap.org/svn/openzap/branches/sangoma_boost@960 a93c3328-9c30-0410-af19-c9cd2b2d52af
This commit is contained in:
Moises Silva 2010-01-14 05:23:40 +00:00
parent e9e0edb33f
commit 200b25e256
4 changed files with 92 additions and 33 deletions

View File

@ -451,8 +451,8 @@ static ZIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request)
nack_map[r] = 1;
if (sangoma_boost_data->sigmod) {
sangomabc_exec_command(&sangoma_boost_data->mcon,
(*zchan)->physical_span_id,
(*zchan)->physical_chan_id,
BOOST_SPAN((*zchan)),
BOOST_CHAN((*zchan)),
r,
SIGBOOST_EVENT_CALL_START_NACK,
0);
@ -618,8 +618,20 @@ static void handle_call_done(zap_span_t *span, sangomabc_connection_t *mcon, san
int r = 0;
if ((zchan = find_zchan(span, event, 1))) {
zap_sangoma_boost_data_t *sangoma_boost_data = zchan->span->signal_data;
zap_mutex_lock(zchan->mutex);
if (sangoma_boost_data->sigmod) {
/* not really completely done, but if we ever get an incoming call before moving to HANGUP_COMPLETE
* handle_incoming_call() will take care of moving the state machine to release the channel */
sangomabc_exec_command(&sangoma_boost_data->mcon,
BOOST_SPAN(zchan),
BOOST_CHAN(zchan),
0,
SIGBOOST_EVENT_CALL_RELEASED,
0);
}
if (zchan->state == ZAP_CHANNEL_STATE_DOWN || zchan->state == ZAP_CHANNEL_STATE_HANGUP_COMPLETE) {
goto done;
}
@ -729,6 +741,18 @@ static void handle_call_start_nack(zap_span_t *span, sangomabc_connection_t *mco
#endif
}
static void handle_call_released(zap_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
{
zap_channel_t *zchan;
if ((zchan = find_zchan(span, event, 1))) {
zap_log(ZAP_LOG_DEBUG, "Releasing completely chan s%dc%d\n", event->span, event->chan);
zap_channel_done(zchan);
} else {
zap_log(ZAP_LOG_ERROR, "Odd, We could not find chan: s%dc%d to release the call completely!!\n", event->span, event->chan);
}
}
/**
* \brief Handler for call stop event
* \param span Span where event was fired
@ -773,10 +797,10 @@ static void handle_call_stop(zap_span_t *span, sangomabc_connection_t *mcon, san
if (r) {
return;
}
} /* else we have to do it ourselves.... */
zap_log(ZAP_LOG_WARNING, "We could not find chan: s%dc%d\n", event->span, event->chan);
release_request_id_span_chan(event->span, event->chan);
} else { /* we have to do it ourselves.... */
zap_log(ZAP_LOG_ERROR, "Odd, We could not find chan: s%dc%d\n", event->span, event->chan);
release_request_id_span_chan(event->span, event->chan);
}
}
/**
@ -829,6 +853,9 @@ static void handle_call_start(zap_span_t *span, sangomabc_connection_t *mcon, sa
zap_log(ZAP_LOG_CRIT, "START CANT FIND CHAN %d:%d AT ALL\n", event->span+1,event->chan+1);
goto error;
}
/* this handles race conditions where state handlers are still pending to be executed for finished calls
but an incoming call arrives first, we must complete the channel states and then try again to get the
zap channel */
advance_chan_states(zchan);
if (!(zchan = find_zchan(span, (sangomabc_short_event_t*)event, 0))) {
zap_log(ZAP_LOG_CRIT, "START CANT FIND CHAN %d:%d EVEN AFTER STATE ADVANCE\n", event->span+1,event->chan+1);
@ -996,6 +1023,9 @@ static int parse_sangoma_event(zap_span_t *span, sangomabc_connection_t *mcon, s
case SIGBOOST_EVENT_CALL_STOPPED:
handle_call_stop(span, mcon, event);
break;
case SIGBOOST_EVENT_CALL_RELEASED:
handle_call_released(span, mcon, event);
break;
case SIGBOOST_EVENT_CALL_START_ACK:
handle_call_start_ack(mcon, event);
break;
@ -1070,6 +1100,8 @@ static __inline__ void state_advance(zap_channel_t *zchan)
switch (zchan->state) {
case ZAP_CHANNEL_STATE_DOWN:
{
int call_stopped_ack_sent = 0;
zap_sangoma_boost_data_t *sangoma_boost_data = zchan->span->signal_data;
if (zchan->extra_id) {
zchan->extra_id = 0;
}
@ -1083,24 +1115,32 @@ static __inline__ void state_advance(zap_channel_t *zchan)
if (zchan->call_data && ((uint32_t)(intptr_t)zchan->call_data == SIGBOOST_EVENT_CALL_START_NACK)) {
sangomabc_exec_command(mcon,
zchan->physical_span_id-1,
zchan->physical_chan_id-1,
BOOST_SPAN(zchan),
BOOST_CHAN(zchan),
0,
SIGBOOST_EVENT_CALL_START_NACK_ACK,
0);
} else {
/* we got a call stop msg, time to reply with call stopped ack */
sangomabc_exec_command(mcon,
zchan->physical_span_id-1,
zchan->physical_chan_id-1,
BOOST_SPAN(zchan),
BOOST_CHAN(zchan),
0,
SIGBOOST_EVENT_CALL_STOPPED_ACK,
0);
call_stopped_ack_sent = 1;
}
}
zchan->sflags = 0;
zchan->call_data = NULL;
zap_channel_done(zchan);
if (sangoma_boost_data->sigmod && call_stopped_ack_sent) {
/* we dont want to call zap_channel_done just yet until call released is received */
zap_log(ZAP_LOG_DEBUG, "Waiting for call release confirmation before declaring chan %d:%d as available \n",
zchan->span_id, zchan->chan_id);
} else {
zap_channel_done(zchan);
}
}
break;
case ZAP_CHANNEL_STATE_PROGRESS_MEDIA:

View File

@ -60,6 +60,7 @@ static struct sangomabc_map sangomabc_table[] = {
{SIGBOOST_EVENT_CALL_ANSWERED, "CALL_ANSWERED"},
{SIGBOOST_EVENT_CALL_STOPPED, "CALL_STOPPED"},
{SIGBOOST_EVENT_CALL_STOPPED_ACK, "CALL_STOPPED_ACK"},
{SIGBOOST_EVENT_CALL_RELEASED, "CALL_RELEASED"},
{SIGBOOST_EVENT_SYSTEM_RESTART, "SYSTEM_RESTART"},
{SIGBOOST_EVENT_SYSTEM_RESTART_ACK, "SYSTEM_RESTART_ACK"},
{SIGBOOST_EVENT_HEARTBEAT, "HEARTBEAT"},
@ -457,7 +458,13 @@ int __sangomabc_connection_write(sangomabc_connection_t *mcon, sangomabc_event_t
event->fseqno = mcon->txseq++;
}
event->bseqno = mcon->rxseq;
event->version = SIGBOOST_VERSION;
event->version = SIGBOOST_VERSION;
if (boost_full_event(event->event_id)) {
sangomabc_print_event_call(mcon, event, 0, 1, file, func, line);
} else {
sangomabc_print_event_short(mcon, (sangomabc_short_event_t*)event, 0, 1, file, func, line);
}
if (mcon->sigmod) {
mcon->sigmod->write_msg(mcon->span, event, event_size);
@ -473,12 +480,6 @@ int __sangomabc_connection_write(sangomabc_connection_t *mcon, sangomabc_event_t
zap_assert_return(err == event_size, -1, "Failed to send the boost message completely!");
if (boost_full_event(event->event_id)) {
sangomabc_print_event_call(mcon, event, 0, 1, file, func, line);
} else {
sangomabc_print_event_short(mcon, (sangomabc_short_event_t*)event, 0, 1, file, func, line);
}
return err;
}

View File

@ -28,6 +28,19 @@ enum e_sigboost_event_id_values
SIGBOOST_EVENT_CALL_ANSWERED = 0x84, /*132*/
SIGBOOST_EVENT_CALL_STOPPED = 0x85, /*133*/
SIGBOOST_EVENT_CALL_STOPPED_ACK = 0x86, /*134*/
/* CALL_RELEASED is aimed to fix a race condition that became obvious
* when the boost socket was replaced by direct function calls
* and the channel hunting was moved to openzap, the problem is
* we can get CALL_STOPPED msg and reply with CALL_STOPPED_ACK
* but the signaling module will still (in PRI) send RELEASE and
* wait for RELEASE_COMPLETE from the isdn network before
* marking the channel as available, therefore openzap should
* also not mark the channel as available until CALL_RELEASED
* is received, for socket mode we can continue working as usual
* with CALL_STOPPED being the last step because the hunting is
* done in the signaling module.
* */
SIGBOOST_EVENT_CALL_RELEASED = 0x51, /* 81 */
SIGBOOST_EVENT_SYSTEM_RESTART = 0x87, /*135*/
SIGBOOST_EVENT_SYSTEM_RESTART_ACK = 0x88, /*136*/
SIGBOOST_EVENT_CALL_PROGRESS = 0x50, /*decimal 80*/

View File

@ -1507,22 +1507,24 @@ OZ_DECLARE(zap_status_t) zap_channel_done(zap_channel_t *zchan)
{
assert(zchan != NULL);
zap_mutex_lock(zchan->mutex);
memset(&zchan->caller_data, 0, sizeof(zchan->caller_data));
zap_clear_flag_locked(zchan, ZAP_CHANNEL_INUSE);
zap_clear_flag_locked(zchan, ZAP_CHANNEL_OUTBOUND);
zap_clear_flag_locked(zchan, ZAP_CHANNEL_WINK);
zap_clear_flag_locked(zchan, ZAP_CHANNEL_FLASH);
zap_clear_flag_locked(zchan, ZAP_CHANNEL_STATE_CHANGE);
zap_clear_flag_locked(zchan, ZAP_CHANNEL_HOLD);
zap_clear_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
zap_clear_flag_locked(zchan, ZAP_CHANNEL_RINGING);
zap_clear_flag_locked(zchan, ZAP_CHANNEL_PROGRESS_DETECT);
zap_clear_flag_locked(zchan, ZAP_CHANNEL_CALLERID_DETECT);
zap_clear_flag_locked(zchan, ZAP_CHANNEL_3WAY);
zap_clear_flag_locked(zchan, ZAP_CHANNEL_PROGRESS);
zap_clear_flag_locked(zchan, ZAP_CHANNEL_MEDIA);
zap_clear_flag_locked(zchan, ZAP_CHANNEL_ANSWERED);
zap_clear_flag(zchan, ZAP_CHANNEL_INUSE);
zap_clear_flag(zchan, ZAP_CHANNEL_OUTBOUND);
zap_clear_flag(zchan, ZAP_CHANNEL_WINK);
zap_clear_flag(zchan, ZAP_CHANNEL_FLASH);
zap_clear_flag(zchan, ZAP_CHANNEL_STATE_CHANGE);
zap_clear_flag(zchan, ZAP_CHANNEL_HOLD);
zap_clear_flag(zchan, ZAP_CHANNEL_OFFHOOK);
zap_clear_flag(zchan, ZAP_CHANNEL_RINGING);
zap_clear_flag(zchan, ZAP_CHANNEL_PROGRESS_DETECT);
zap_clear_flag(zchan, ZAP_CHANNEL_CALLERID_DETECT);
zap_clear_flag(zchan, ZAP_CHANNEL_3WAY);
zap_clear_flag(zchan, ZAP_CHANNEL_PROGRESS);
zap_clear_flag(zchan, ZAP_CHANNEL_MEDIA);
zap_clear_flag(zchan, ZAP_CHANNEL_ANSWERED);
zap_mutex_lock(zchan->pre_buffer_mutex);
zap_buffer_destroy(&zchan->pre_buffer);
zchan->pre_buffer_size = 0;
@ -1530,8 +1532,11 @@ OZ_DECLARE(zap_status_t) zap_channel_done(zap_channel_t *zchan)
zchan->init_state = ZAP_CHANNEL_STATE_DOWN;
zchan->state = ZAP_CHANNEL_STATE_DOWN;
zap_log(ZAP_LOG_DEBUG, "channel done %u:%u\n", zchan->span_id, zchan->chan_id);
zap_mutex_unlock(zchan->mutex);
return ZAP_SUCCESS;
}