]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
ftmod_libpri: Rework handling of peer-initiated hangup events
authorMatteo Brancaleoni <mbrancaleoni@voismart.it>
Thu, 8 Nov 2012 11:59:22 +0000 (12:59 +0100)
committerStefan Knoblich <stkn@openisdn.net>
Mon, 12 Nov 2012 21:54:27 +0000 (22:54 +0100)
Use peerhangup flag variable to track whether a hangup has been
initiated by the peer or libpri itself (e.g. Layer 2 timeouts).

These changes fix a couple of problems with hangup events not being
handled properly in some situations:

  - Call abort caused by incoming RESTART on a channel in use
  - T309 timeout after L2 loss
  - Improved hangup handling in libpri-side on_hangup() event handler
    and state_advance() (FreeTDM side)

Signed-off-by: Stefan Knoblich <stkn@openisdn.net>
libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c
libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.h
libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c

index 2f1a5ff9ed663f8bde3e4a9df9300ab70c085c43..0e22b0f3506aa0b9328984d960973a2e16b12cbf 100644 (file)
@@ -942,7 +942,7 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan)
                                ftdm_channel_t *chtmp = chan;
 
                                if (call) {
-                                       pri_destroycall(isdn_data->spri.pri, call);
+                                       /* pri call destroy is done by libpri itself (on release_ack) */
                                        chan_priv->call = NULL;
                                }
 
@@ -953,6 +953,9 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan)
                                lpwrap_stop_timer(&isdn_data->spri, &chan_priv->t316);
                                chan_priv->t316_timeout_cnt = 0;
 
+                               /* Unset remote hangup */
+                               chan_priv->peerhangup = 0;
+
                                if (ftdm_channel_close(&chtmp) != FTDM_SUCCESS) {
                                        ftdm_log(FTDM_LOG_WARNING, "-- Failed to close channel %d:%d\n",
                                                ftdm_channel_get_span_id(chan),
@@ -1206,12 +1209,21 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan)
                {
                        if (call) {
                                ftdm_caller_data_t *caller_data = ftdm_channel_get_caller_data(chan);
-
                                pri_hangup(isdn_data->spri.pri, call, caller_data->hangup_cause);
-//                             pri_destroycall(isdn_data->spri.pri, call);
-//                             chan_priv->call = NULL;
+
+                               if (chan_priv->peerhangup) {
+                                       /* Call is inbound and hangup has been initiated by peer */
+                                       if (!ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) {
+                                               ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
+                                       } else if (caller_data->hangup_cause == PRI_CAUSE_NO_USER_RESPONSE) {
+                                               /* Can happen when we have a DL link expire or some timer expired */
+                                               ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
+                                       } else if (caller_data->hangup_cause == PRI_CAUSE_DESTINATION_OUT_OF_ORDER) {
+                                               /* Can happen when we have a DL link expire or some timer expired */
+                                               ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
+                                       }
+                               }
                        }
-                       ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
                }
                break;
 
@@ -1368,6 +1380,7 @@ static int on_hangup(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_even
 {
        ftdm_span_t *span = spri->span;
        ftdm_channel_t *chan = ftdm_span_get_channel(span, pevent->hangup.channel);
+       ftdm_libpri_b_chan_t *chan_priv = chan->call_data;
 
        if (!chan) {
                ftdm_log(FTDM_LOG_CRIT, "-- Hangup on channel %d:%d but it's not in use?\n", ftdm_span_get_id(spri->span), pevent->hangup.channel);
@@ -1386,8 +1399,6 @@ static int on_hangup(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_even
                ftdm_log(FTDM_LOG_DEBUG, "-- Hangup REQ on channel %d:%d\n",
                        ftdm_span_get_id(spri->span), pevent->hangup.channel);
 
-               pri_hangup(spri->pri, pevent->hangup.call, pevent->hangup.cause);
-
                chan->caller_data.hangup_cause = pevent->hangup.cause;
 
                switch (ftdm_channel_get_state(chan)) {
@@ -1400,19 +1411,27 @@ static int on_hangup(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_even
                }
                break;
 
-       case LPWRAP_PRI_EVENT_HANGUP_ACK:       /* */
+       case LPWRAP_PRI_EVENT_HANGUP_ACK:       /* RELEASE_COMPLETE */
                ftdm_log(FTDM_LOG_DEBUG, "-- Hangup ACK on channel %d:%d\n",
                        ftdm_span_get_id(spri->span), pevent->hangup.channel);
 
-               pri_hangup(spri->pri, pevent->hangup.call, pevent->hangup.cause);
-
-               ftdm_set_state(chan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
+               switch (ftdm_channel_get_state(chan)) {
+                       case FTDM_CHANNEL_STATE_RESTART:
+                               /* ACK caused by DL FAILURE in DISC REQ */
+                               ftdm_set_state(chan, FTDM_CHANNEL_STATE_DOWN);
+                               break;
+                       default:
+                               ftdm_set_state(chan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
+                               break;
+               }
                break;
 
        case LPWRAP_PRI_EVENT_HANGUP:   /* "RELEASE/RELEASE_COMPLETE/other" */
                ftdm_log(FTDM_LOG_DEBUG, "-- Hangup on channel %d:%d\n",
                        ftdm_span_get_id(spri->span), pevent->hangup.channel);
 
+               chan_priv->peerhangup = 1;
+
                switch (ftdm_channel_get_state(chan)) {
                case FTDM_CHANNEL_STATE_DIALING:
                case FTDM_CHANNEL_STATE_RINGING:
@@ -1424,9 +1443,19 @@ static int on_hangup(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_even
                        ftdm_set_state(chan, FTDM_CHANNEL_STATE_TERMINATING);
                        break;
                case FTDM_CHANNEL_STATE_HANGUP:
+                       /* this will send "RELEASE_COMPLETE", eventually */
+                       pri_hangup(spri->pri, pevent->hangup.call, chan->caller_data.hangup_cause);
                        chan->caller_data.hangup_cause = pevent->hangup.cause;
                        ftdm_set_state(chan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
                        break;
+               case FTDM_CHANNEL_STATE_RESTART:
+                       /*
+                        * We got an hungup doing a restart, normally beacause link has been lost during
+                        * a call and the T309 timer has expired. So destroy it :) (DL_RELEASE_IND)
+                        */
+                       pri_destroycall(spri->pri, pevent->hangup.call);
+                       ftdm_set_state(chan, FTDM_CHANNEL_STATE_DOWN);
+                       break;
 //             case FTDM_CHANNEL_STATE_TERMINATING:
 //                     ftdm_set_state(chan, FTDM_CHANNEL_STATE_HANGUP);
 //                     break;
index 26db8d315553dadd8953648f6678439481523f54..852f5caaca013ac4c97a7fafe334b3dda9ac55db 100644 (file)
@@ -131,6 +131,7 @@ struct ftdm_libpri_b_chan {
        q931_call *call;                /*!< libpri opaque call handle */
        uint32_t flags;                 /*!< channel flags */
        uint32_t t316_timeout_cnt;      /*!< T316 timeout counter */
+       int peerhangup;                 /*!< hangup requested from libpri (RELEASE/RELEASE_ACK/DL_RELEASE/TIMERS EXPIRY) */
 };
 
 typedef struct ftdm_libpri_b_chan ftdm_libpri_b_chan_t;
index c9f0576951979061c20bc3c12fc996ca2324a772..44518a449639f3d4db1165e2310145b51441df1e 100644 (file)
@@ -169,6 +169,10 @@ int lpwrap_init_pri(struct lpwrap_pri *spri, ftdm_span_t *span, ftdm_channel_t *
 
        if (spri->pri) {
                pri_set_debug(spri->pri, debug);
+#ifdef HAVE_LIBPRI_BRI
+               /* "follow Q.931 Section 5.3.2 call hangup better" */
+               pri_hangup_fix_enable(spri->pri, 1);
+#endif
 #ifdef HAVE_LIBPRI_AOC
                pri_aoc_events_enable(spri->pri, 1);
 #endif