]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
added new boost msg EVENT_CALL_RELEASED to fix race condition on call hangup
authorMoises Silva <moy@sangoma.com>
Thu, 14 Jan 2010 05:23:40 +0000 (05:23 +0000)
committerMoises Silva <moy@sangoma.com>
Thu, 14 Jan 2010 05:23:40 +0000 (05:23 +0000)
git-svn-id: http://svn.openzap.org/svn/openzap/branches/sangoma_boost@960 a93c3328-9c30-0410-af19-c9cd2b2d52af

libs/freetdm/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c
libs/freetdm/src/ozmod/ozmod_sangoma_boost/sangoma_boost_client.c
libs/freetdm/src/ozmod/ozmod_sangoma_boost/sigboost.h
libs/freetdm/src/zap_io.c

index 4d8581f8069585735c04a6cd37083025d3c76571..cc85b0bfee259ebf6fadf5ba26a3409c7c78d57a 100644 (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);
@@ -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:
index 9e332d1504fca640d32a655d595c4c6a3473f7a5..ebd27cccac664acc49f74c84559e39cf30b69fdd 100644 (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;
 }
 
index 9e97e9014d977decd189ba2ee1239ba85f8ea9bd..b9cbf110f674216cb0f0f944b736c406d7cde33e 100644 (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*/
index 445fb7094fdadd509bd050c49e9b77ab539ed232..6a39c9fc70ce66d9b2eb6eabb510ac6d6fad4057 100644 (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;
 }