From c890fbfa2edf04f253027d9f54303bc3c666aa75 Mon Sep 17 00:00:00 2001
From: Steve Underwood <steveu@coppice.org>
Date: Wed, 4 May 2011 20:49:21 +0800
Subject: [PATCH] Changed T.38 terminal handling, so errors from the user's
 packet transmit routine properly filter up the chain, cause termination of
 the FAX session, and are reported to the caller.

---
 libs/spandsp/src/t38_core.c     |  18 ++++-
 libs/spandsp/src/t38_terminal.c | 132 +++++++++++++++++++++++++-------
 2 files changed, 121 insertions(+), 29 deletions(-)

diff --git a/libs/spandsp/src/t38_core.c b/libs/spandsp/src/t38_core.c
index e7ee967e93..55b524af61 100644
--- a/libs/spandsp/src/t38_core.c
+++ b/libs/spandsp/src/t38_core.c
@@ -799,7 +799,11 @@ SPAN_DECLARE(int) t38_core_send_indicator(t38_core_state_t *s, int indicator)
                 return len;
             }
             span_log(&s->logging, SPAN_LOG_FLOW, "Tx %5d: indicator %s\n", s->tx_seq_no, t38_indicator_to_str(indicator));
-            s->tx_packet_handler(s, s->tx_packet_user_data, buf, len, transmissions);
+            if (s->tx_packet_handler(s, s->tx_packet_user_data, buf, len, transmissions) < 0)
+            {
+                span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Tx Packet Handler Failure\n");
+                return -1;
+            }
             s->tx_seq_no = (s->tx_seq_no + 1) & 0xFFFF;
             delay = modem_startup_time[indicator].training;
             if (s->allow_for_tep)
@@ -837,7 +841,11 @@ SPAN_DECLARE(int) t38_core_send_data(t38_core_state_t *s, int data_type, int fie
         span_log(&s->logging, SPAN_LOG_FLOW, "T.38 data len is %d\n", len);
         return len;
     }
-    s->tx_packet_handler(s, s->tx_packet_user_data, buf, len, s->category_control[category]);
+    if (s->tx_packet_handler(s, s->tx_packet_user_data, buf, len, s->category_control[category]) < 0)
+    {
+        span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Tx Packet Handler Failure\n");
+        return -1;
+    }
     s->tx_seq_no = (s->tx_seq_no + 1) & 0xFFFF;
     return 0;
 }
@@ -853,7 +861,11 @@ SPAN_DECLARE(int) t38_core_send_data_multi_field(t38_core_state_t *s, int data_t
         span_log(&s->logging, SPAN_LOG_FLOW, "T.38 data len is %d\n", len);
         return len;
     }
-    s->tx_packet_handler(s, s->tx_packet_user_data, buf, len, s->category_control[category]);
+    if (s->tx_packet_handler(s, s->tx_packet_user_data, buf, len, s->category_control[category]) < 0)
+    {
+        span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Tx Packet Handler Failure\n");
+        return -1;
+    }
     s->tx_seq_no = (s->tx_seq_no + 1) & 0xFFFF;
     return 0;
 }
diff --git a/libs/spandsp/src/t38_terminal.c b/libs/spandsp/src/t38_terminal.c
index c9961f665b..64b30f4805 100644
--- a/libs/spandsp/src/t38_terminal.c
+++ b/libs/spandsp/src/t38_terminal.c
@@ -63,10 +63,18 @@
 #include "spandsp/v17rx.h"
 #include "spandsp/t4_rx.h"
 #include "spandsp/t4_tx.h"
-#if defined(SPANDSP_SUPPORT_T85)
+#if defined(SPANDSP_SUPPORT_T42)  ||  defined(SPANDSP_SUPPORT_T43)  |  defined(SPANDSP_SUPPORT_T85)
 #include "spandsp/t81_t82_arith_coding.h"
+#endif
+#if defined(SPANDSP_SUPPORT_T85)
 #include "spandsp/t85.h"
 #endif
+#if defined(SPANDSP_SUPPORT_T42)
+#include "spandsp/t42.h"
+#endif
+#if defined(SPANDSP_SUPPORT_T43)
+#include "spandsp/t43.h"
+#endif
 #include "spandsp/t4_t6_decode.h"
 #include "spandsp/t4_t6_encode.h"
 #include "spandsp/t30_fcf.h"
@@ -78,10 +86,18 @@
 #include "spandsp/t38_terminal.h"
 
 #include "spandsp/private/logging.h"
-#if defined(SPANDSP_SUPPORT_T85)
+#if defined(SPANDSP_SUPPORT_T42)  ||  defined(SPANDSP_SUPPORT_T43)  |  defined(SPANDSP_SUPPORT_T85)
 #include "spandsp/private/t81_t82_arith_coding.h"
+#endif
+#if defined(SPANDSP_SUPPORT_T85)
 #include "spandsp/private/t85.h"
 #endif
+#if defined(SPANDSP_SUPPORT_T42)
+#include "spandsp/private/t42.h"
+#endif
+#if defined(SPANDSP_SUPPORT_T43)
+#include "spandsp/private/t43.h"
+#endif
 #include "spandsp/private/t4_t6_decode.h"
 #include "spandsp/private/t4_t6_encode.h"
 #include "spandsp/private/t4_rx.h"
@@ -629,7 +645,9 @@ static int set_no_signal(t38_terminal_state_t *s)
 
     if ((s->t38_fe.chunking_modes & T38_CHUNKING_SEND_REGULAR_INDICATORS))
     {
-        t38_core_send_indicator(&s->t38_fe.t38, 0x100 | T38_IND_NO_SIGNAL);
+        if ((delay = t38_core_send_indicator(&s->t38_fe.t38, 0x100 | T38_IND_NO_SIGNAL)) < 0)
+            return delay;
+        /*endif*/
         s->t38_fe.timed_step = T38_TIMED_STEP_NO_SIGNAL;
 #if 0
         if ((s->t38_fe.chunking_modes & T38_CHUNKING_SEND_2S_REGULAR_INDICATORS))
@@ -641,7 +659,9 @@ static int set_no_signal(t38_terminal_state_t *s)
         return s->t38_fe.ms_per_tx_chunk*1000;
     }
     /*endif*/
-    delay = t38_core_send_indicator(&s->t38_fe.t38, T38_IND_NO_SIGNAL);
+    if ((delay = t38_core_send_indicator(&s->t38_fe.t38, T38_IND_NO_SIGNAL)) < 0)
+        return delay;
+    /*endif*/
     s->t38_fe.timed_step = T38_TIMED_STEP_NONE;
     return delay;
 }
@@ -649,7 +669,11 @@ static int set_no_signal(t38_terminal_state_t *s)
 
 static int stream_no_signal(t38_terminal_state_t *s)
 {
-    t38_core_send_indicator(&s->t38_fe.t38, 0x100 | T38_IND_NO_SIGNAL);
+    int delay;
+
+    if ((delay = t38_core_send_indicator(&s->t38_fe.t38, 0x100 | T38_IND_NO_SIGNAL)) < 0)
+        return delay;
+    /*endif*/
 #if 0
     if (s->t38_fe.timeout_tx_samples  &&  s->t38_fe.next_tx_samples >= s->t38_fe.timeout_tx_samples)
         s->t38_fe.timed_step = T38_TIMED_STEP_NONE;
@@ -663,6 +687,7 @@ static int stream_non_ecm(t38_terminal_state_t *s)
 {
     t38_terminal_front_end_state_t *fe;
     uint8_t buf[MAX_OCTETS_PER_UNPACED_CHUNK + 50];
+    int res;
     int delay;
     int len;
 
@@ -674,9 +699,15 @@ static int stream_non_ecm(t38_terminal_state_t *s)
         case T38_TIMED_STEP_NON_ECM_MODEM:
             /* Create a 75ms silence */
             if (fe->t38.current_tx_indicator != T38_IND_NO_SIGNAL)
-                delay = t38_core_send_indicator(&fe->t38, T38_IND_NO_SIGNAL);
+            {
+                if ((delay = t38_core_send_indicator(&fe->t38, T38_IND_NO_SIGNAL)) < 0)
+                    return delay;
+                /*endif*/
+            }
             else
+            {
                 delay = 75000;
+            }
             /*endif*/
             fe->timed_step = T38_TIMED_STEP_NON_ECM_MODEM_2;
 #if 0
@@ -690,7 +721,9 @@ static int stream_non_ecm(t38_terminal_state_t *s)
 #if 0
             if ((s->t38_fe.chunking_modes & T38_CHUNKING_SEND_REGULAR_INDICATORS))
             {
-                delay = t38_core_send_indicator(&fe->t38, 0x100 | fe->next_tx_indicator);
+                if ((delay = t38_core_send_indicator(&fe->t38, 0x100 | fe->next_tx_indicator)) < 0)
+                    return delay;
+                /*endif*/
                 if (fe->next_tx_samples >= fe->timeout_tx_samples)
                     fe->timed_step = T38_TIMED_STEP_NON_ECM_MODEM_3;
                 /*endif*/
@@ -698,7 +731,9 @@ static int stream_non_ecm(t38_terminal_state_t *s)
             }
             /*endif*/
 #endif
-            delay = t38_core_send_indicator(&fe->t38, fe->next_tx_indicator);
+            if ((delay = t38_core_send_indicator(&fe->t38, fe->next_tx_indicator)) < 0)
+                return delay;
+            /*endif*/
             fe->timed_step = T38_TIMED_STEP_NON_ECM_MODEM_3;
             break;
         case T38_TIMED_STEP_NON_ECM_MODEM_3:
@@ -731,7 +766,9 @@ static int stream_non_ecm(t38_terminal_state_t *s)
                 else
                 {
                     /* If we are sending quickly there seems no point in doing any padding */
-                    t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_T4_NON_ECM_SIG_END, buf, len, T38_PACKET_CATEGORY_IMAGE_DATA_END);
+                    if ((res = t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_T4_NON_ECM_SIG_END, buf, len, T38_PACKET_CATEGORY_IMAGE_DATA_END)) < 0)
+                        return res;
+                    /*endif*/
                     fe->timed_step = T38_TIMED_STEP_NON_ECM_MODEM_5;
                     delay = 0;
                     break;
@@ -739,7 +776,9 @@ static int stream_non_ecm(t38_terminal_state_t *s)
                 /*endif*/
             }
             /*endif*/
-            t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_T4_NON_ECM_DATA, buf, len, T38_PACKET_CATEGORY_IMAGE_DATA);
+            if ((res = t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_T4_NON_ECM_DATA, buf, len, T38_PACKET_CATEGORY_IMAGE_DATA)) < 0)
+                return res;
+            /*endif*/
             delay = bits_to_us(s, 8*len);
             break;
         case T38_TIMED_STEP_NON_ECM_MODEM_4:
@@ -750,7 +789,9 @@ static int stream_non_ecm(t38_terminal_state_t *s)
             {
                 len += fe->non_ecm_trailer_bytes;
                 memset(buf, 0, len);
-                t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_T4_NON_ECM_SIG_END, buf, len, T38_PACKET_CATEGORY_IMAGE_DATA_END);
+                if ((res = t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_T4_NON_ECM_SIG_END, buf, len, T38_PACKET_CATEGORY_IMAGE_DATA_END)) < 0)
+                    return res;
+                /*endif*/
                 fe->timed_step = T38_TIMED_STEP_NON_ECM_MODEM_5;
                 /* Allow a bit more time than the data will take to play out, to ensure the far ATA does not
                    cut things short. */
@@ -763,7 +804,9 @@ static int stream_non_ecm(t38_terminal_state_t *s)
             }
             /*endif*/
             memset(buf, 0, len);
-            t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_T4_NON_ECM_DATA, buf, len, T38_PACKET_CATEGORY_IMAGE_DATA);
+            if ((res = t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_T4_NON_ECM_DATA, buf, len, T38_PACKET_CATEGORY_IMAGE_DATA)) < 0)
+                return res;
+            /*endif*/
             delay = bits_to_us(s, 8*len);
             break;
         case T38_TIMED_STEP_NON_ECM_MODEM_5:
@@ -785,6 +828,7 @@ static int stream_hdlc(t38_terminal_state_t *s)
     t38_data_field_t data_fields[2];
     int category;
     int previous;
+    int res;
     int delay;
     int i;
 
@@ -796,9 +840,15 @@ static int stream_hdlc(t38_terminal_state_t *s)
         case T38_TIMED_STEP_HDLC_MODEM:
             /* Create a 75ms silence */
             if (fe->t38.current_tx_indicator != T38_IND_NO_SIGNAL)
-                delay = t38_core_send_indicator(&fe->t38, T38_IND_NO_SIGNAL);
+            {
+                if ((delay = t38_core_send_indicator(&fe->t38, T38_IND_NO_SIGNAL)) < 0)
+                    return delay;
+                /*endif*/
+            }
             else
+            {
                 delay = 75000;
+            }
             /*endif*/
             fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_2;
 #if 0
@@ -814,7 +864,9 @@ static int stream_hdlc(t38_terminal_state_t *s)
 #if 0
             if ((s->t38_fe.chunking_modes & T38_CHUNKING_SEND_REGULAR_INDICATORS))
             {
-                delay = t38_core_send_indicator(&fe->t38, 0x100 | fe->next_tx_indicator);
+                if ((delay = t38_core_send_indicator(&fe->t38, 0x100 | fe->next_tx_indicator)) < 0)
+                    return delay;
+                /*endif*/
                 if (fe->next_tx_samples >= fe->timeout_tx_samples)
                     fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_3;
                 /*endif*/
@@ -822,8 +874,10 @@ static int stream_hdlc(t38_terminal_state_t *s)
             }
             /*endif*/
 #endif
-            delay = t38_core_send_indicator(&fe->t38, fe->next_tx_indicator)
-                  + t38_core_send_flags_delay(&fe->t38, fe->next_tx_indicator);
+            if ((delay = t38_core_send_indicator(&fe->t38, fe->next_tx_indicator)) < 0)
+                return delay;
+            /*endif*/
+            delay += t38_core_send_flags_delay(&fe->t38, fe->next_tx_indicator);
             fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_3;
             break;
         case T38_TIMED_STEP_HDLC_MODEM_3:
@@ -852,7 +906,9 @@ static int stream_hdlc(t38_terminal_state_t *s)
                         data_fields[1].field = NULL;
                         data_fields[1].field_len = 0;
                         category = (s->t38_fe.current_tx_data_type == T38_DATA_V21)  ?  T38_PACKET_CATEGORY_CONTROL_DATA_END  :  T38_PACKET_CATEGORY_IMAGE_DATA_END;
-                        t38_core_send_data_multi_field(&fe->t38, fe->current_tx_data_type, data_fields, 2, category);
+                        if ((res = t38_core_send_data_multi_field(&fe->t38, fe->current_tx_data_type, data_fields, 2, category)) < 0)
+                            return res;
+                        /*endif*/
                         fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_5;
                         /* We add a bit of extra time here, as with some implementations
                            the carrier falling too abruptly causes data loss. */
@@ -868,7 +924,9 @@ static int stream_hdlc(t38_terminal_state_t *s)
                         data_fields[1].field = NULL;
                         data_fields[1].field_len = 0;
                         category = (s->t38_fe.current_tx_data_type == T38_DATA_V21)  ?  T38_PACKET_CATEGORY_CONTROL_DATA  :  T38_PACKET_CATEGORY_IMAGE_DATA;
-                        t38_core_send_data_multi_field(&fe->t38, fe->current_tx_data_type, data_fields, 2, category);
+                        if ((res = t38_core_send_data_multi_field(&fe->t38, fe->current_tx_data_type, data_fields, 2, category)) < 0)
+                            return res;
+                        /*endif*/
                         fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_3;
                         delay = bits_to_us(s, i*8 + fe->hdlc_tx.extra_bits);
                     }
@@ -877,14 +935,18 @@ static int stream_hdlc(t38_terminal_state_t *s)
                 }
                 /*endif*/
                 category = (s->t38_fe.current_tx_data_type == T38_DATA_V21)  ?  T38_PACKET_CATEGORY_CONTROL_DATA  :  T38_PACKET_CATEGORY_IMAGE_DATA;
-                t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_HDLC_DATA, &fe->hdlc_tx.buf[fe->hdlc_tx.ptr], i, category);
+                if ((res = t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_HDLC_DATA, &fe->hdlc_tx.buf[fe->hdlc_tx.ptr], i, category)) < 0)
+                    return res;
+                /*endif*/
                 fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_4;
             }
             else
             {
                 i = fe->octets_per_data_packet;
                 category = (s->t38_fe.current_tx_data_type == T38_DATA_V21)  ?  T38_PACKET_CATEGORY_CONTROL_DATA  :  T38_PACKET_CATEGORY_IMAGE_DATA;
-                t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_HDLC_DATA, &fe->hdlc_tx.buf[fe->hdlc_tx.ptr], i, category);
+                if ((res = t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_HDLC_DATA, &fe->hdlc_tx.buf[fe->hdlc_tx.ptr], i, category)) < 0)
+                    return res;
+                /*endif*/
                 fe->hdlc_tx.ptr += i;
             }
             /*endif*/
@@ -901,7 +963,9 @@ static int stream_hdlc(t38_terminal_state_t *s)
             {
                 /* End of transmission */
                 category = (s->t38_fe.current_tx_data_type == T38_DATA_V21)  ?  T38_PACKET_CATEGORY_CONTROL_DATA_END  :  T38_PACKET_CATEGORY_IMAGE_DATA_END;
-                t38_core_send_data(&fe->t38, previous, T38_FIELD_HDLC_FCS_OK_SIG_END, NULL, 0, category);
+                if ((res = t38_core_send_data(&fe->t38, previous, T38_FIELD_HDLC_FCS_OK_SIG_END, NULL, 0, category)) < 0)
+                    return res;
+                /*endif*/
                 fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_5;
                 /* We add a bit of extra time here, as with some implementations
                    the carrier falling too abruptly causes data loss. */
@@ -922,7 +986,9 @@ static int stream_hdlc(t38_terminal_state_t *s)
             /*endif*/
             /* Finish the current frame off, and prepare for the next one. */
             category = (s->t38_fe.current_tx_data_type == T38_DATA_V21)  ?  T38_PACKET_CATEGORY_CONTROL_DATA  :  T38_PACKET_CATEGORY_IMAGE_DATA;
-            t38_core_send_data(&fe->t38, previous, T38_FIELD_HDLC_FCS_OK, NULL, 0, category);
+            if ((res = t38_core_send_data(&fe->t38, previous, T38_FIELD_HDLC_FCS_OK, NULL, 0, category)) < 0)
+                return res;
+            /*endif*/
             fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_3;
             /* We should now wait enough time for everything to clear through an analogue modem at the far end. */
             delay = bits_to_us(s, fe->hdlc_tx.extra_bits);
@@ -955,14 +1021,18 @@ static int stream_ced(t38_terminal_state_t *s)
                of silence, starting the delay with a no signal indication makes sense.
                We do need a 200ms delay, as that is a specification requirement. */
             fe->timed_step = T38_TIMED_STEP_CED_2;
-            delay = t38_core_send_indicator(&fe->t38, T38_IND_NO_SIGNAL);
+            if ((delay = t38_core_send_indicator(&fe->t38, T38_IND_NO_SIGNAL)) < 0)
+                return delay;
+            /*endif*/
             delay = 200000;
             fe->next_tx_samples = fe->samples;
             break;
         case T38_TIMED_STEP_CED_2:
             /* Initial 200ms delay over. Send the CED indicator */
             fe->timed_step = T38_TIMED_STEP_CED_3;
-            delay = t38_core_send_indicator(&fe->t38, T38_IND_CED);
+            if ((delay = t38_core_send_indicator(&fe->t38, T38_IND_CED)) < 0)
+                return delay;
+            /*endif*/
             fe->current_tx_data_type = T38_DATA_NONE;
             break;
         case T38_TIMED_STEP_CED_3:
@@ -994,7 +1064,9 @@ static int stream_cng(t38_terminal_state_t *s)
                be sending 200ms of silence, according to T.30, starting that delay with
                a no signal indication makes sense. */
             fe->timed_step = T38_TIMED_STEP_CNG_2;
-            delay = t38_core_send_indicator(&fe->t38, T38_IND_NO_SIGNAL);
+            if ((delay = t38_core_send_indicator(&fe->t38, T38_IND_NO_SIGNAL)) < 0)
+                return delay;
+            /*endif*/
             delay = 200000;
             fe->next_tx_samples = fe->samples;
             break;
@@ -1003,7 +1075,9 @@ static int stream_cng(t38_terminal_state_t *s)
                coming the other way interrupts it, or a long timeout controlled by the T.30 engine
                expires. */
             fe->timed_step = T38_TIMED_STEP_NONE;
-            delay = t38_core_send_indicator(&fe->t38, T38_IND_CNG);
+            if ((delay = t38_core_send_indicator(&fe->t38, T38_IND_CNG)) < 0)
+                return delay;
+            /*endif*/
             fe->current_tx_data_type = T38_DATA_NONE;
             return delay;
         }
@@ -1067,6 +1141,12 @@ SPAN_DECLARE(int) t38_terminal_send_timeout(t38_terminal_state_t *s, int samples
         break;
     }
     /*endswitch*/
+    if (delay < 0)
+    {
+        t30_terminate(&s->t30);
+        return TRUE;
+    }
+    /*endif*/
     fe->next_tx_samples += us_to_samples(delay);
     return FALSE;
 }