From 200b25e256bd8f2ab901846b4145101833878759 Mon Sep 17 00:00:00 2001 From: Moises Silva <moy@sangoma.com> Date: Thu, 14 Jan 2010 05:23:40 +0000 Subject: [PATCH] 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 --- .../ozmod_sangoma_boost/ozmod_sangoma_boost.c | 64 +++++++++++++++---- .../sangoma_boost_client.c | 15 +++-- .../src/ozmod/ozmod_sangoma_boost/sigboost.h | 13 ++++ libs/freetdm/src/zap_io.c | 33 ++++++---- 4 files changed, 92 insertions(+), 33 deletions(-) diff --git a/libs/freetdm/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c b/libs/freetdm/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c index 4d8581f806..cc85b0bfee 100644 --- a/libs/freetdm/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c +++ b/libs/freetdm/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c @@ -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); @@ -616,10 +616,22 @@ static void handle_call_done(zap_span_t *span, sangomabc_connection_t *mcon, san { zap_channel_t *zchan; 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: diff --git a/libs/freetdm/src/ozmod/ozmod_sangoma_boost/sangoma_boost_client.c b/libs/freetdm/src/ozmod/ozmod_sangoma_boost/sangoma_boost_client.c index 9e332d1504..ebd27cccac 100644 --- a/libs/freetdm/src/ozmod/ozmod_sangoma_boost/sangoma_boost_client.c +++ b/libs/freetdm/src/ozmod/ozmod_sangoma_boost/sangoma_boost_client.c @@ -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; } diff --git a/libs/freetdm/src/ozmod/ozmod_sangoma_boost/sigboost.h b/libs/freetdm/src/ozmod/ozmod_sangoma_boost/sigboost.h index 9e97e9014d..b9cbf110f6 100644 --- a/libs/freetdm/src/ozmod/ozmod_sangoma_boost/sigboost.h +++ b/libs/freetdm/src/ozmod/ozmod_sangoma_boost/sigboost.h @@ -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*/ diff --git a/libs/freetdm/src/zap_io.c b/libs/freetdm/src/zap_io.c index 445fb7094f..6a39c9fc70 100644 --- a/libs/freetdm/src/zap_io.c +++ b/libs/freetdm/src/zap_io.c @@ -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; }