Improved TSB85 tests, which now check call clearing.

FAX now differentiates properly between <page result code> and <image> <page resuly code> when deciding how to retry.
This commit is contained in:
Steve Underwood 2014-06-20 00:24:10 +08:00
parent d886cc12fa
commit b780371943
9 changed files with 759 additions and 195 deletions

View File

@ -33,6 +33,7 @@
modem CDATA #IMPLIED
tag CDATA #IMPLIED
value CDATA #IMPLIED
timein CDATA #IMPLIED
timeout CDATA #IMPLIED
crc_error CDATA #IMPLIED
pattern CDATA #IMPLIED

View File

@ -91,6 +91,9 @@
<step dir="T" type="PREAMBLE" modem="V.21"/>
<step dir="T" type="HDLC" tag="DCN" value="FF C8 5F"/>
<step dir="T" type="POSTAMBLE"/>
<step dir="T" type="CLEAR"/>
<step dir="R" type="CLEAR" timein="0" timeout="100"/>
<step type="STATUS" value="RX_DCNDATA"/>
</test>
<test name="V17-12000-V29-9600">
<!-- Tester calls, trying to provoke a crash seen in some versions of spandsp, when
@ -183,6 +186,9 @@
<step dir="T" type="PREAMBLE" modem="V.21"/>
<step dir="T" type="HDLC" tag="DCN" value="FF C8 5F"/>
<step dir="T" type="POSTAMBLE"/>
<step dir="T" type="CLEAR"/>
<step dir="R" type="CLEAR" timein="0" timeout="100"/>
<step type="STATUS" value="OK"/>
</test>
<test name="Phase-D-collision">
<!-- DUT calls tester and sends 1 IMPRESS and 1 WHITE page. The MCF after the first
@ -224,6 +230,8 @@
<step dir="T" type="POSTAMBLE"/>
<step dir="R" type="HDLC" modem="V.21" tag="DCN+" value="FF C8 DF"/>
<step dir="R" type="CLEAR" timein="800" timeout="1200"/>
<step type="STATUS" value="OK"/>
</test>
</test-group>
</fax-tests>

File diff suppressed because it is too large Load Diff

View File

@ -181,6 +181,10 @@ struct t30_state_s
/*! \brief True if the short training sequence should be used. */
bool short_train;
/*! \brief True if an image carrier appears to have been received, even if it did not successfully
train. */
bool image_carrier_attempted;
/*! \brief A count of the number of bits in the trainability test. This counts down to zero when
sending TCF, and counts up when receiving it. */
int tcf_test_bits;
@ -293,6 +297,8 @@ struct t30_state_s
partial pages still to come. */
bool ecm_at_page_end;
/*! \brief The last result for a received non-ECM page - T30_MPS, T30_RTP, or T30_RTN. */
int last_rx_page_result;
/*! \brief The transmission step queued to follow the one in progress. */
int next_tx_step;
/*! \brief The FCF for the next receive step. */
@ -310,11 +316,6 @@ struct t30_state_s
/*! \brief The current completion status. */
int current_status;
/*! \brief The number of RTP events */
int rtp_events;
/*! \brief The number of RTN events */
int rtn_events;
/*! \brief the FCF2 field of the last PPS message we received. */
uint8_t last_pps_fcf2;
/*! \brief True if all frames of the current received ECM block are now OK */
@ -323,6 +324,11 @@ struct t30_state_s
deciding whether to continue error correction when PPRs keep repeating. */
int ecm_progress;
/*! \brief The number of RTP events */
int rtp_events;
/*! \brief The number of RTN events */
int rtn_events;
/*! \brief Error and flow logging control */
logging_state_t logging;
};

View File

@ -173,9 +173,7 @@ enum
T30_STATE_I,
T30_STATE_II,
T30_STATE_II_Q,
T30_STATE_III_Q_MCF,
T30_STATE_III_Q_RTP,
T30_STATE_III_Q_RTN,
T30_STATE_III_Q,
T30_STATE_IV,
T30_STATE_IV_PPS_NULL,
T30_STATE_IV_PPS_Q,
@ -210,9 +208,7 @@ static const char *state_names[] =
"I",
"II",
"II_Q",
"III_Q_MCF",
"III_Q_RTP",
"III_Q_RTN",
"III_Q",
"IV",
"IV_PPS_NULL",
"IV_PPS_Q",
@ -3600,7 +3596,7 @@ static void process_state_f_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int
state, it looks like either:
- we didn't see the image data carrier properly, or
- they didn't see our T30_CFR, and are repeating the DCS/TCF sequence.
- they didn't see out T30_MCF, and are repeating the end of page message. */
- they didn't see our T30_MCF, T30_RTP or T30_RTN and are repeating the end of page message. */
fcf = msg[2] & 0xFE;
switch (fcf)
{
@ -3616,13 +3612,22 @@ static void process_state_f_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int
}
/* Fall through */
case T30_MPS:
/* Treat this as a bad quality page. */
if (s->phase_d_handler)
s->phase_d_handler(s->phase_d_user_data, fcf);
s->next_rx_step = fcf;
queue_phase(s, T30_PHASE_D_TX);
set_state(s, T30_STATE_III_Q_RTN);
send_simple_frame(s, T30_RTN);
if (s->image_carrier_attempted)
{
/* Treat this as a bad quality page. */
if (s->phase_d_handler)
s->phase_d_handler(s->phase_d_user_data, fcf);
s->next_rx_step = fcf;
s->last_rx_page_result = T30_RTN;
queue_phase(s, T30_PHASE_D_TX);
set_state(s, T30_STATE_III_Q);
send_simple_frame(s, s->last_rx_page_result);
}
else
{
/* This appears to be a retry, because the far end didn't see our last response */
repeat_last_command(s);
}
break;
case T30_PRI_EOM:
if (s->remote_interrupts_allowed)
@ -3631,14 +3636,23 @@ static void process_state_f_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int
/* Fall through */
case T30_EOM:
case T30_EOS:
/* Treat this as a bad quality page. */
if (s->phase_d_handler)
s->phase_d_handler(s->phase_d_user_data, fcf);
s->next_rx_step = fcf;
/* Return to phase B */
queue_phase(s, T30_PHASE_B_TX);
set_state(s, T30_STATE_III_Q_RTN);
send_simple_frame(s, T30_RTN);
if (s->image_carrier_attempted)
{
/* Treat this as a bad quality page. */
if (s->phase_d_handler)
s->phase_d_handler(s->phase_d_user_data, fcf);
s->next_rx_step = fcf;
s->last_rx_page_result = T30_RTN;
/* Return to phase B */
queue_phase(s, T30_PHASE_B_TX);
set_state(s, T30_STATE_III_Q);
send_simple_frame(s, s->last_rx_page_result);
}
else
{
/* This appears to be a retry, because the far end didn't see our last response */
repeat_last_command(s);
}
break;
case T30_PRI_EOP:
if (s->remote_interrupts_allowed)
@ -3646,13 +3660,22 @@ static void process_state_f_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int
}
/* Fall through */
case T30_EOP:
/* Treat this as a bad quality page. */
if (s->phase_d_handler)
s->phase_d_handler(s->phase_d_user_data, fcf);
s->next_rx_step = fcf;
queue_phase(s, T30_PHASE_D_TX);
set_state(s, T30_STATE_III_Q_RTN);
send_simple_frame(s, T30_RTN);
if (s->image_carrier_attempted)
{
/* Treat this as a bad quality page. */
if (s->phase_d_handler)
s->phase_d_handler(s->phase_d_user_data, fcf);
s->next_rx_step = fcf;
s->last_rx_page_result = T30_RTN;
queue_phase(s, T30_PHASE_D_TX);
set_state(s, T30_STATE_III_Q);
send_simple_frame(s, s->last_rx_page_result);
}
else
{
/* This appears to be a retry, because the far end didn't see our last response */
repeat_last_command(s);
}
break;
case T30_DCN:
t30_set_status(s, T30_ERR_RX_DCNDATA);
@ -3705,18 +3728,18 @@ static void assess_copy_quality(t30_state_t *s, uint8_t fcf)
{
case T30_COPY_QUALITY_PERFECT:
case T30_COPY_QUALITY_GOOD:
set_state(s, T30_STATE_III_Q_MCF);
send_simple_frame(s, T30_MCF);
s->last_rx_page_result = T30_MCF;
break;
case T30_COPY_QUALITY_POOR:
set_state(s, T30_STATE_III_Q_RTP);
send_simple_frame(s, T30_RTP);
s->last_rx_page_result = T30_RTP;
break;
case T30_COPY_QUALITY_BAD:
set_state(s, T30_STATE_III_Q_RTN);
send_simple_frame(s, T30_RTN);
default:
s->last_rx_page_result = T30_RTN;
break;
}
set_state(s, T30_STATE_III_Q);
send_simple_frame(s, s->last_rx_page_result);
}
/*- End of function --------------------------------------------------------*/
@ -3761,6 +3784,10 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg,
queue_phase(s, T30_PHASE_D_TX);
assess_copy_quality(s, fcf);
break;
case T30_DCS:
span_log(&s->logging, SPAN_LOG_FLOW, "DCS received after CFR\n");
process_rx_dcs(s, msg, len);
break;
case T30_DCN:
t30_set_status(s, T30_ERR_RX_DCNFAX);
terminate_call(s);
@ -3823,6 +3850,7 @@ static void process_state_f_doc_and_post_doc_ecm(t30_state_t *s, const uint8_t *
case T30_EOM:
case T30_EOS:
case T30_MPS:
s->image_carrier_attempted = false;
s->next_rx_step = fcf2;
queue_phase(s, T30_PHASE_D_TX);
set_state(s, T30_STATE_F_DOC_ECM);
@ -3837,6 +3865,7 @@ static void process_state_f_doc_and_post_doc_ecm(t30_state_t *s, const uint8_t *
process_rx_pps(s, msg, len);
break;
case T30_CTC:
s->image_carrier_attempted = false;
/* T.30 says we change back to long training here */
s->short_train = false;
queue_phase(s, T30_PHASE_D_TX);
@ -4270,7 +4299,7 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len)
}
/*- End of function --------------------------------------------------------*/
static void process_state_iii_q_mcf(t30_state_t *s, const uint8_t *msg, int len)
static void process_state_iii_q(t30_state_t *s, const uint8_t *msg, int len)
{
uint8_t fcf;
@ -4283,8 +4312,8 @@ static void process_state_iii_q_mcf(t30_state_t *s, const uint8_t *msg, int len)
case T30_MPS:
/* Looks like they didn't see our signal. Repeat it */
queue_phase(s, T30_PHASE_D_TX);
set_state(s, T30_STATE_III_Q_MCF);
send_simple_frame(s, T30_MCF);
set_state(s, T30_STATE_III_Q);
send_simple_frame(s, s->last_rx_page_result);
break;
case T30_DIS:
if (msg[2] == T30_DTC)
@ -4297,78 +4326,8 @@ static void process_state_iii_q_mcf(t30_state_t *s, const uint8_t *msg, int len)
process_rx_fnv(s, msg, len);
break;
case T30_DCN:
terminate_call(s);
break;
default:
/* We don't know what to do with this. */
unexpected_final_frame(s, msg, len);
break;
}
}
/*- End of function --------------------------------------------------------*/
static void process_state_iii_q_rtp(t30_state_t *s, const uint8_t *msg, int len)
{
uint8_t fcf;
fcf = msg[2] & 0xFE;
switch (fcf)
{
case T30_EOP:
case T30_EOM:
case T30_EOS:
case T30_MPS:
/* Looks like they didn't see our signal. Repeat it */
queue_phase(s, T30_PHASE_D_TX);
set_state(s, T30_STATE_III_Q_RTP);
send_simple_frame(s, T30_RTP);
break;
case T30_DIS:
if (msg[2] == T30_DTC)
process_rx_dis_dtc(s, msg, len);
break;
case T30_CRP:
repeat_last_command(s);
break;
case T30_FNV:
process_rx_fnv(s, msg, len);
break;
default:
/* We don't know what to do with this. */
unexpected_final_frame(s, msg, len);
break;
}
}
/*- End of function --------------------------------------------------------*/
static void process_state_iii_q_rtn(t30_state_t *s, const uint8_t *msg, int len)
{
uint8_t fcf;
fcf = msg[2] & 0xFE;
switch (fcf)
{
case T30_EOP:
case T30_EOM:
case T30_EOS:
case T30_MPS:
/* Looks like they didn't see our signal. Repeat it */
queue_phase(s, T30_PHASE_D_TX);
set_state(s, T30_STATE_III_Q_RTN);
send_simple_frame(s, T30_RTN);
break;
case T30_DIS:
if (msg[2] == T30_DTC)
process_rx_dis_dtc(s, msg, len);
break;
case T30_CRP:
repeat_last_command(s);
break;
case T30_FNV:
process_rx_fnv(s, msg, len);
break;
case T30_DCN:
t30_set_status(s, T30_ERR_RX_DCNNORTN);
if (s->last_rx_page_result == T30_RTN)
t30_set_status(s, T30_ERR_RX_DCNNORTN);
terminate_call(s);
break;
default:
@ -5090,14 +5049,8 @@ static void process_rx_control_msg(t30_state_t *s, const uint8_t *msg, int len)
case T30_STATE_II_Q:
process_state_ii_q(s, msg, len);
break;
case T30_STATE_III_Q_MCF:
process_state_iii_q_mcf(s, msg, len);
break;
case T30_STATE_III_Q_RTP:
process_state_iii_q_rtp(s, msg, len);
break;
case T30_STATE_III_Q_RTN:
process_state_iii_q_rtn(s, msg, len);
case T30_STATE_III_Q:
process_state_iii_q(s, msg, len);
break;
case T30_STATE_IV:
process_state_iv(s, msg, len);
@ -5315,17 +5268,10 @@ static void repeat_last_command(t30_state_t *s)
queue_phase(s, T30_PHASE_B_TX);
send_dis_or_dtc_sequence(s, true);
break;
case T30_STATE_III_Q_MCF:
case T30_STATE_F_DOC_NON_ECM:
case T30_STATE_III_Q:
queue_phase(s, T30_PHASE_D_TX);
send_simple_frame(s, T30_MCF);
break;
case T30_STATE_III_Q_RTP:
queue_phase(s, T30_PHASE_D_TX);
send_simple_frame(s, T30_RTP);
break;
case T30_STATE_III_Q_RTN:
queue_phase(s, T30_PHASE_D_TX);
send_simple_frame(s, T30_RTN);
send_simple_frame(s, s->last_rx_page_result);
break;
case T30_STATE_II_Q:
queue_phase(s, T30_PHASE_D_TX);
@ -5526,9 +5472,7 @@ static void timer_t2_expired(t30_state_t *s)
span_log(&s->logging, SPAN_LOG_FLOW, "T2 expired in phase %s, state %s\n", phase_names[s->phase], state_names[s->state]);
switch (s->state)
{
case T30_STATE_III_Q_MCF:
case T30_STATE_III_Q_RTP:
case T30_STATE_III_Q_RTN:
case T30_STATE_III_Q:
case T30_STATE_F_POST_RCP_PPR:
case T30_STATE_F_POST_RCP_MCF:
switch (s->next_rx_step)
@ -5738,6 +5682,7 @@ static void t30_non_ecm_rx_status(void *user_data, int status)
switch (status)
{
case SIG_STATUS_TRAINING_IN_PROGRESS:
s->image_carrier_attempted = true;
break;
case SIG_STATUS_TRAINING_FAILED:
s->rx_trained = false;
@ -6205,6 +6150,8 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status)
case T30_STATE_F_CFR:
if (send_cfr_sequence(s, false))
{
s->image_carrier_attempted = false;
s->last_rx_page_result = -1;
if (s->error_correcting_mode)
{
set_state(s, T30_STATE_F_DOC_ECM);
@ -6231,9 +6178,8 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status)
timer_t2_start(s);
}
break;
case T30_STATE_III_Q_MCF:
case T30_STATE_III_Q_RTP:
case T30_STATE_III_Q_RTN:
case T30_STATE_F_DOC_NON_ECM:
case T30_STATE_III_Q:
case T30_STATE_F_POST_RCP_PPR:
case T30_STATE_F_POST_RCP_MCF:
if (s->step == 0)
@ -6248,6 +6194,7 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status)
case T30_PRI_MPS:
case T30_MPS:
/* We should now start to get another page */
s->image_carrier_attempted = false;
if (s->error_correcting_mode)
{
set_state(s, T30_STATE_F_DOC_ECM);
@ -6264,8 +6211,8 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status)
case T30_EOM:
case T30_EOS:
/* See if we get something back, before moving to phase B. */
timer_t2_start(s);
set_phase(s, T30_PHASE_D_RX);
timer_t2_start(s);
break;
case T30_PRI_EOP:
case T30_EOP:

View File

@ -264,32 +264,39 @@ static void parse_tone_set(super_tone_rx_descriptor_t *desc, xmlDocPtr doc, xmlN
static void get_tone_set(super_tone_rx_descriptor_t *desc, const char *tone_file, const char *set_id)
{
xmlParserCtxtPtr ctxt;
xmlDocPtr doc;
xmlNsPtr ns;
xmlNodePtr cur;
#if 1
xmlValidCtxt valid;
#endif
xmlChar *x;
ns = NULL;
xmlKeepBlanksDefault(0);
xmlCleanupParser();
if ((doc = xmlParseFile(tone_file)) == NULL)
if ((ctxt = xmlNewParserCtxt()) == NULL)
{
fprintf(stderr, "No document\n");
fprintf(stderr, "Failed to allocate parser context\n");
printf("Test failed\n");
exit(2);
}
/*endif*/
xmlXIncludeProcess(doc);
#if 1
if (!xmlValidateDocument(&valid, doc))
/* parse the file, activating the DTD validation option */
if ((doc = xmlCtxtReadFile(ctxt, tone_file, NULL, XML_PARSE_XINCLUDE | XML_PARSE_DTDVALID)) == NULL)
{
fprintf(stderr, "Invalid document\n");
fprintf(stderr, "Failed to read the XML document\n");
printf("Test failed\n");
exit(2);
}
/*endif*/
#endif
if (ctxt->valid == 0)
{
fprintf(stderr, "Failed to validate the XML document\n");
xmlFreeDoc(doc);
xmlFreeParserCtxt(ctxt);
printf("Test failed\n");
exit(2);
}
xmlFreeParserCtxt(ctxt);
/* Check the document is of the right kind */
if ((cur = xmlDocGetRootElement(doc)) == NULL)
{

View File

@ -203,33 +203,39 @@ static void parse_tone_set(xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur)
static void get_tone_set(const char *tone_file, const char *set_id)
{
xmlParserCtxtPtr ctxt;
xmlDocPtr doc;
xmlNsPtr ns;
xmlNodePtr cur;
#if 0
xmlValidCtxt valid;
#endif
xmlChar *x;
ns = NULL;
xmlKeepBlanksDefault(0);
xmlCleanupParser();
doc = xmlParseFile(tone_file);
if (doc == NULL)
if ((ctxt = xmlNewParserCtxt()) == NULL)
{
fprintf(stderr, "No document\n");
fprintf(stderr, "Failed to allocate parser context\n");
printf("Test failed\n");
exit(2);
}
/*endif*/
xmlXIncludeProcess(doc);
#if 0
if (!xmlValidateDocument(&valid, doc))
/* parse the file, activating the DTD validation option */
if ((doc = xmlCtxtReadFile(ctxt, tone_file, NULL, XML_PARSE_XINCLUDE | XML_PARSE_DTDVALID)) == NULL)
{
fprintf(stderr, "Invalid document\n");
fprintf(stderr, "Failed to read the XML document\n");
printf("Test failed\n");
exit(2);
}
/*endif*/
#endif
if (ctxt->valid == 0)
{
fprintf(stderr, "Failed to validate the XML document\n");
xmlFreeDoc(doc);
xmlFreeParserCtxt(ctxt);
printf("Test failed\n");
exit(2);
}
xmlFreeParserCtxt(ctxt);
/* Check the document is of the right kind */
if ((cur = xmlDocGetRootElement(doc)) == NULL)
{

View File

@ -92,9 +92,86 @@ t30_exchanged_info_t expected_rx_info;
char next_tx_file[1000];
static int timein_x = -1;
static int timeout_x = -1;
static int next_step(faxtester_state_t *s);
static bool test_for_call_drop = false;
static bool test_for_call_clear = false;
static int call_clear_timer = 0;
static bool far_end_cleared_call = false;
struct
{
const char *tag;
int code;
} t30_status[] =
{
{"OK", T30_ERR_OK},
{"CEDTONE", T30_ERR_CEDTONE},
{"T0_EXPIRED", T30_ERR_T0_EXPIRED},
{"T1_EXPIRED", T30_ERR_T1_EXPIRED},
{"T3_EXPIRED", T30_ERR_T3_EXPIRED},
{"HDLC_CARRIER", T30_ERR_HDLC_CARRIER},
{"CANNOT_TRAIN", T30_ERR_CANNOT_TRAIN},
{"OPER_INT_FAIL", T30_ERR_OPER_INT_FAIL},
{"INCOMPATIBLE", T30_ERR_INCOMPATIBLE},
{"RX_INCAPABLE", T30_ERR_RX_INCAPABLE},
{"TX_INCAPABLE", T30_ERR_TX_INCAPABLE},
{"NORESSUPPORT", T30_ERR_NORESSUPPORT},
{"NOSIZESUPPORT", T30_ERR_NOSIZESUPPORT},
{"UNEXPECTED", T30_ERR_UNEXPECTED},
{"TX_BADDCS", T30_ERR_TX_BADDCS},
{"TX_BADPG", T30_ERR_TX_BADPG},
{"TX_ECMPHD", T30_ERR_TX_ECMPHD},
{"TX_GOTDCN", T30_ERR_TX_GOTDCN},
{"TX_INVALRSP", T30_ERR_TX_INVALRSP},
{"TX_NODIS", T30_ERR_TX_NODIS},
{"TX_PHBDEAD", T30_ERR_TX_PHBDEAD},
{"TX_PHDDEAD", T30_ERR_TX_PHDDEAD},
{"TX_T5EXP", T30_ERR_TX_T5EXP},
{"RX_ECMPHD", T30_ERR_RX_ECMPHD},
{"RX_GOTDCS", T30_ERR_RX_GOTDCS},
{"RX_INVALCMD", T30_ERR_RX_INVALCMD},
{"RX_NOCARRIER", T30_ERR_RX_NOCARRIER},
{"RX_NOEOL", T30_ERR_RX_NOEOL},
{"RX_NOFAX", T30_ERR_RX_NOFAX},
{"RX_T2EXPDCN", T30_ERR_RX_T2EXPDCN},
{"RX_T2EXPD", T30_ERR_RX_T2EXPD},
{"RX_T2EXPFAX", T30_ERR_RX_T2EXPFAX},
{"RX_T2EXPMPS", T30_ERR_RX_T2EXPMPS},
{"RX_T2EXPRR", T30_ERR_RX_T2EXPRR},
{"RX_T2EXP", T30_ERR_RX_T2EXP},
{"RX_DCNWHY", T30_ERR_RX_DCNWHY},
{"RX_DCNDATA", T30_ERR_RX_DCNDATA},
{"RX_DCNFAX", T30_ERR_RX_DCNFAX},
{"RX_DCNPHD", T30_ERR_RX_DCNPHD},
{"RX_DCNRRD", T30_ERR_RX_DCNRRD},
{"RX_DCNNORTN", T30_ERR_RX_DCNNORTN},
{"FILEERROR", T30_ERR_FILEERROR},
{"NOPAGE", T30_ERR_NOPAGE},
{"BADTIFF", T30_ERR_BADTIFF},
{"BADPAGE", T30_ERR_BADPAGE},
{"BADTAG", T30_ERR_BADTAG},
{"BADTIFFHDR", T30_ERR_BADTIFFHDR},
{"NOMEM", T30_ERR_NOMEM},
{"RETRYDCN", T30_ERR_RETRYDCN},
{"CALLDROPPED", T30_ERR_CALLDROPPED},
{"NOPOLL", T30_ERR_NOPOLL},
{"IDENT_UNACCEPTABLE", T30_ERR_IDENT_UNACCEPTABLE},
{"SUB_UNACCEPTABLE", T30_ERR_SUB_UNACCEPTABLE},
{"SEP_UNACCEPTABLE", T30_ERR_SEP_UNACCEPTABLE},
{"PSA_UNACCEPTABLE", T30_ERR_PSA_UNACCEPTABLE},
{"SID_UNACCEPTABLE", T30_ERR_SID_UNACCEPTABLE},
{"PWD_UNACCEPTABLE", T30_ERR_PWD_UNACCEPTABLE},
{"TSA_UNACCEPTABLE", T30_ERR_TSA_UNACCEPTABLE},
{"IRA_UNACCEPTABLE", T30_ERR_IRA_UNACCEPTABLE},
{"CIA_UNACCEPTABLE", T30_ERR_CIA_UNACCEPTABLE},
{"ISP_UNACCEPTABLE", T30_ERR_ISP_UNACCEPTABLE},
{"CSA_UNACCEPTABLE", T30_ERR_CSA_UNACCEPTABLE},
{NULL, -1}
};
static int phase_b_handler(void *user_data, int result)
{
@ -622,6 +699,7 @@ static int next_step(faxtester_state_t *s)
xmlChar *bad_rows;
xmlChar *crc_error;
xmlChar *pattern;
xmlChar *timein;
xmlChar *timeout;
xmlChar *min_bits;
xmlChar *frame_size;
@ -638,12 +716,12 @@ static int next_step(faxtester_state_t *s)
int ecm_frame_size;
int ecm_block;
int compression_type;
int timer;
int len;
t4_tx_state_t t4_tx_state;
t30_state_t *t30;
t30_stats_t t30_stats;
test_for_call_drop = false;
test_for_call_clear = false;
if (s->cur == NULL)
{
if (!s->final_delayed)
@ -677,6 +755,7 @@ static int next_step(faxtester_state_t *s)
bad_rows = xmlGetProp(s->cur, (const xmlChar *) "bad_rows");
crc_error = xmlGetProp(s->cur, (const xmlChar *) "crc_error");
pattern = xmlGetProp(s->cur, (const xmlChar *) "pattern");
timein = xmlGetProp(s->cur, (const xmlChar *) "timein");
timeout = xmlGetProp(s->cur, (const xmlChar *) "timeout");
min_bits = xmlGetProp(s->cur, (const xmlChar *) "min_bits");
frame_size = xmlGetProp(s->cur, (const xmlChar *) "frame_size");
@ -687,26 +766,31 @@ static int next_step(faxtester_state_t *s)
span_log(&s->logging,
SPAN_LOG_FLOW,
"Dir - %s, type - %s, modem - %s, value - %s, timeout - %s, tag - %s\n",
"Dir - %s, type - %s, modem - %s, value - %s, timein - %s, timeout - %s, tag - %s\n",
(dir) ? (const char *) dir : "",
(type) ? (const char *) type : "",
(modem) ? (const char *) modem : "",
(value) ? (const char *) value : "",
(timein) ? (const char *) timein : "",
(timeout) ? (const char *) timeout : "",
(tag) ? (const char *) tag : "");
if (type == NULL)
return 1;
if (timeout)
timer = atoi((const char *) timeout);
if (timein)
timein_x = atoi((const char *) timein);
else
timer = -1;
timein_x = -1;
if (timeout)
timeout_x = atoi((const char *) timeout);
else
timeout_x = -1;
if (dir && strcasecmp((const char *) dir, "R") == 0)
{
/* Receive always has a timeout applied. */
if (timer < 0)
timer = 7000;
faxtester_set_timeout(s, timer);
if (timeout_x < 0)
timeout_x = 7000;
faxtester_set_timeout(s, timeout_x);
if (modem)
{
hdlc = (strcasecmp((const char *) type, "PREAMBLE") == 0);
@ -801,10 +885,11 @@ static int next_step(faxtester_state_t *s)
{
faxtest_set_rx_silence(s);
}
else if (strcasecmp((const char *) type, "DROPCALL") == 0)
else if (strcasecmp((const char *) type, "CLEAR") == 0)
{
span_log(&s->logging, SPAN_LOG_FLOW, "Far end should drop the call\n");
test_for_call_drop = true;
test_for_call_clear = true;
call_clear_timer = 0;
}
else
{
@ -814,7 +899,7 @@ static int next_step(faxtester_state_t *s)
}
else
{
faxtester_set_timeout(s, timer);
faxtester_set_timeout(s, timeout_x);
if (modem)
{
hdlc = (strcasecmp((const char *) type, "PREAMBLE") == 0);
@ -1117,9 +1202,35 @@ static int next_step(faxtester_state_t *s)
span_log(&s->logging, SPAN_LOG_FLOW, "ECM image is %d bytes (min row bits %d)\n", len, min_row_bits);
faxtester_set_ecm_image_buffer(s, image, len, ecm_block, ecm_frame_size, i);
}
else if (strcasecmp((const char *) type, "DROPCALL") == 0)
else if (strcasecmp((const char *) type, "CLEAR") == 0)
{
span_log(&s->logging, SPAN_LOG_FLOW, "Time to drop the call\n");
t30 = fax_get_t30_state(fax);
t30_terminate(t30);
return 0;
}
else if (strcasecmp((const char *) type, "STATUS") == 0)
{
if (value)
{
for (i = 0; t30_status[i].code >= 0; i++)
{
if (strcmp(t30_status[i].tag, (const char *) value) == 0)
break;
}
if (t30_status[i].code >= 0)
delay = t30_status[i].code;
else
delay = atoi((const char *) value);
t30 = fax_get_t30_state(fax);
t30_get_transfer_statistics(t30, &t30_stats);
span_log(&s->logging, SPAN_LOG_FLOW, "Expect status %d. Got %d\n", delay, t30_stats.current_status);
if (delay != t30_stats.current_status)
{
printf("Test failed\n");
exit(2);
}
}
return 0;
}
else
@ -1211,12 +1322,23 @@ static void exchange(faxtester_state_t *s)
/*endif*/
}
/*endif*/
if (test_for_call_drop)
if (test_for_call_clear && !far_end_cleared_call)
{
call_clear_timer += len;
if (!t30_call_active(fax_get_t30_state(fax)))
{
printf("Call dropped\n");
//break;
span_log(&s->logging, SPAN_LOG_FLOW, "Far end cleared after %dms (limits %dms to %dms)\n", call_clear_timer/8, timein_x, timeout_x);
if (call_clear_timer/8 < timein_x || call_clear_timer/8 > timeout_x)
{
printf("Test failed\n");
exit(2);
}
span_log(&s->logging, SPAN_LOG_FLOW, "Clear time OK\n");
far_end_cleared_call = true;
test_for_call_clear = false;
while (next_step(s) == 0)
;
/*endwhile*/
}
/*endif*/
}
@ -1297,29 +1419,37 @@ static int parse_test_group(faxtester_state_t *s, xmlDocPtr doc, xmlNsPtr ns, xm
static int get_test_set(faxtester_state_t *s, const char *test_file, const char *test)
{
xmlParserCtxtPtr ctxt;
xmlDocPtr doc;
xmlNsPtr ns;
xmlNodePtr cur;
xmlValidCtxt valid;
ns = NULL;
xmlKeepBlanksDefault(0);
xmlCleanupParser();
if ((doc = xmlParseFile(test_file)) == NULL)
if ((ctxt = xmlNewParserCtxt()) == NULL)
{
fprintf(stderr, "No document\n");
fprintf(stderr, "Failed to allocate parser context\n");
printf("Test failed\n");
exit(2);
}
/*endif*/
xmlXIncludeProcess(doc);
if (!xmlValidateDocument(&valid, doc))
/* parse the file, activating the DTD validation option */
if ((doc = xmlCtxtReadFile(ctxt, test_file, NULL, XML_PARSE_XINCLUDE | XML_PARSE_DTDVALID)) == NULL)
{
fprintf(stderr, "Invalid document\n");
fprintf(stderr, "Failed to read the XML document\n");
printf("Test failed\n");
exit(2);
}
/*endif*/
if (ctxt->valid == 0)
{
fprintf(stderr, "Failed to validate the XML document\n");
xmlFreeDoc(doc);
xmlFreeParserCtxt(ctxt);
printf("Test failed\n");
exit(2);
}
xmlFreeParserCtxt(ctxt);
/* Check the document is of the right kind */
if ((cur = xmlDocGetRootElement(doc)) == NULL)

View File

@ -38,8 +38,7 @@ done
#MRGN16 fails because we don't adequately distinguish between receiving a
#bad image signal and receiving none at all.
#for TEST in MRGN09 MRGN10 MRGN11 MRGN12 MRGN13 MRGN14 MRGN15 MRGN16 MRGN17
for TEST in MRGN09 MRGN10 MRGN11 MRGN12 MRGN13 MRGN15 MRGN17
for TEST in MRGN09 MRGN10 MRGN11 MRGN12 MRGN13 MRGN14 MRGN15 MRGN16 MRGN17
do
run_tsb85_test
done
@ -58,8 +57,7 @@ done
# MRGX05 is failing because we don't distinguish MPS immediately after MCF from MPS after
# a corrupt image signal.
#for TEST in MRGX01 MRGX02 MRGX03 MRGX04 MRGX05 MRGX06 MRGX07 MRGX08
for TEST in MRGX01 MRGX02 MRGX04 MRGX06 MRGX07 MRGX08
for TEST in MRGX01 MRGX02 MRGX03 MRGX04 MRGX05 MRGX06 MRGX07 MRGX08
do
run_tsb85_test
done