fix some error-handling situations, timeouts, hangs, etc.
Changelog for HylaFAX
+* improve some error-handling scenarios (23 Mar 2005)
* improve identification of ECM blocks with zero frames (16 Mar 2005)
* fix potential error in ECM reception frame counting (16 Mar 2005)
-* add CRP usage in receiving when message frames
- are received corrupt (14 Mar 2005)
+* add CRP usage when message frames are received
+ corrupt (14,23 Mar 2005)
* add Class1RMPersistence, better ECM +FCERROR handling (14 Mar 2005)
* small fixes for compilation on AMD-64 (14 Mar 2005)
* fix a few timeouts in faxgetty (11 Mar 2005)
// wait for the control channel to reappear
// should we reset the timeout setting?
waitForDCEChannel(true);
+ gotRTNC = true;
return (false);
break;
default:
* retransmit the frame.
*/
bool
-Class1Modem::recvFrame(HDLCFrame& frame, long ms, u_char docrp)
+Class1Modem::recvFrame(HDLCFrame& frame, u_char dir, long ms, bool readPending)
{
bool gotframe;
u_short crpcnt = 0;
if (useV34) {
do {
- if (crpcnt) tracePPR(docrp & FCF_SNDR ? "SEND send" : "RECV send", FCF_CRP);
+ if (crpcnt) tracePPR(dir == FCF_SNDR ? "SEND send" : "RECV send", FCF_CRP);
frame.reset();
gotframe = recvRawFrame(frame);
- } while (docrp && crpcnt++ < 3 && !gotframe && !wasTimeout() && transmitFrame(docrp));
+ } while (!gotframe && !gotRTNC && !gotEOT && crpcnt++ < 3 && !wasTimeout() && transmitFrame(dir|FCF_CRP));
return (gotframe);
}
startTimeout(ms);
- bool readPending = atCmd(rhCmd, AT_NOTHING, 0);
- if (readPending && waitFor(AT_CONNECT,0)){
+ if (!readPending) readPending = atCmd(rhCmd, AT_NOTHING, 0) && waitFor(AT_CONNECT, 0);
+ if (readPending) {
stopTimeout("waiting for HDLC flags");
if (wasTimeout()){
abortReceive();
}
do {
if (crpcnt) {
- tracePPR(docrp & FCF_SNDR ? "SEND send" : "RECV send", FCF_CRP);
+ tracePPR(dir == FCF_SNDR ? "SEND send" : "RECV send", FCF_CRP);
if (!(atCmd(rhCmd, AT_NOTHING, 0) && waitFor(AT_CONNECT,0))) return (false);
}
frame.reset();
gotframe = recvRawFrame(frame);
- } while (docrp && crpcnt++ < 3 && !gotframe && !wasTimeout() &&
- atCmd(conf.class1SwitchingCmd, AT_OK) && transmitFrame(docrp));
+ } while (!gotframe && crpcnt++ < 3 && !wasTimeout() &&
+ atCmd(conf.class1SwitchingCmd, AT_OK) && transmitFrame(dir|FCF_CRP));
return (gotframe);
}
stopTimeout("waiting for v.21 carrier");
const u_char* bitrev, bool eod);
bool sendClass1ECMData(const u_char* data, u_int cc,
const u_char* bitrev, bool eod, u_int ppmcmd, fxStr& emsg);
- bool recvFrame(HDLCFrame& frame, long ms = 10*1000, u_char docrp = 0);
+ bool recvFrame(HDLCFrame& frame, u_char dir, long ms = 10*1000, bool readPending = false);
bool recvTCF(int br, HDLCFrame&, const u_char* bitrev, long ms);
bool recvRawFrame(HDLCFrame& frame);
bool recvECMFrame(HDLCFrame& frame);
/*
* Wait for a response to be received.
*/
- if (recvFrame(frame, conf.t4Timer)) {
+ if (recvFrame(frame, FCF_RCVR, conf.t4Timer)) {
do {
/*
* Verify a DCS command response and, if
return (true);
} else {
if (lastResponse == AT_FRH3 && waitFor(AT_CONNECT,0)) {
- gotframe = recvRawFrame(frame);
+ gotframe = recvFrame(frame, FCF_RCVR, conf.t4Timer, true);
lastResponse == AT_NOTHING;
}
}
* the full T1 timeout, as specified by the protocol.
*/
t1 = howmany(conf.t1Timer, 1000);
- } while (recvFrame(frame, conf.t2Timer));
+ } while (recvFrame(frame, FCF_RCVR, conf.t2Timer));
}
if (gotEOT) {
emsg = "RSPREC error/got EOT";
processDCSFrame(frame);
break;
}
- } while (frame.moreFrames() && recvFrame(frame, conf.t4Timer));
+ } while (frame.moreFrames() && recvFrame(frame, FCF_RCVR, conf.t4Timer));
return (frame.isOK() && frame.getFCF() == FCF_DCS);
}
} else {
if (rmResponse == AT_FRH3) {
HDLCFrame frame(conf.class1FrameOverhead);
- if (waitFor(AT_CONNECT,0) && recvRawFrame(frame))
+ if (waitFor(AT_CONNECT,0) && recvFrame(frame, FCF_RCVR, conf.t4Timer, true))
signalRcvd = frame.getFCF();
}
}
ppmrcvd = true;
lastPPM = signalRcvd;
} else {
- ppmrcvd = recvFrame(frame, timer, FCF_CRP|FCF_RCVR);
+ ppmrcvd = recvFrame(frame, FCF_RCVR, timer);
if (ppmrcvd) lastPPM = frame.getFCF();
}
/*
if (!messageReceived) messageReceived = !(recvDCSFrames(frame));
if (!messageReceived) messageReceived = !(recvTraining());
if (messageReceived && lastResponse == AT_FRH3 && waitFor(AT_CONNECT,0)) {
- gotframe = recvRawFrame(frame);
+ gotframe = recvFrame(frame, FCF_RCVR, conf.t4Timer, true);
lastResponse = AT_NOTHING;
messageReceived = false;
}
* that we just received, write it to disk.
*/
if (messageReceived) {
- if (!useV34 && !atCmd(conf.class1SwitchingCmd, AT_OK)) {
+ if (!useV34 && emsg == "" && !atCmd(conf.class1SwitchingCmd, AT_OK)) {
emsg = "Failure to receive silence.";
- return (false);
}
/*
* On servers where disk access may be bottlenecked or stressed,
(void) transmitFrame(params.ec != EC_DISABLE ? FCF_RNR : FCF_CRP|FCF_RCVR);
tracePPR("RECV send", params.ec != EC_DISABLE ? FCF_RNR : FCF_CRP);
HDLCFrame rrframe(conf.class1FrameOverhead);
- if (gotresponse = recvFrame(rrframe, conf.t4Timer, FCF_CRP|FCF_RCVR)) {
+ if (gotresponse = recvFrame(rrframe, FCF_RCVR, conf.t4Timer)) {
tracePPM("RECV recv", rrframe.getFCF());
if (params.ec != EC_DISABLE && rrframe.getFCF() != FCF_RR) {
protoTrace("Ignoring invalid response to RNR.");
t2end = 0;
} else {
/*
- * If remote is on hook, then modem responces [+FC]ERROR
- * or NO CARRIER. I only try to prevent looping (V.F.)
+ * We didn't get a message. Try to be resiliant by
+ * looking for the signal again, but prevent infinite
+ * looping with a timer. However, if the modem is on
+ * hook, then modem responds ERROR or NO CARRIER, and
+ * for those cases there is no point in resiliancy.
*/
+ if (lastResponse == AT_NOCARRIER || lastResponse == AT_ERROR) break;
if (t2end) {
if (Sys::now() > t2end)
break;
rtncframe.put(frameRev[ctrlFrameRcvd[i] & 0xFF]);
traceHDLCFrame("-->", rtncframe);
} else
- gotrtncframe = recvFrame(rtncframe, conf.t2Timer, FCF_CRP|FCF_RCVR);
+ gotrtncframe = recvFrame(rtncframe, FCF_RCVR, conf.t2Timer);
} else {
- gotrtncframe = recvRawFrame(rtncframe);
+ gotrtncframe = recvFrame(rtncframe, FCF_RCVR, conf.t2Timer, true);
}
if (gotrtncframe) {
switch (rtncframe.getFCF()) {
HDLCFrame ppsframe(conf.class1FrameOverhead);
u_short recvFrameCount = 0;
do {
- gotpps = recvFrame(ppsframe, conf.t2Timer, FCF_CRP|FCF_RCVR);
- } while (!gotpps && !wasTimeout() && ++recvFrameCount < 20);
+ gotpps = recvFrame(ppsframe, FCF_RCVR, conf.t2Timer);
+ } while (!gotpps && !wasTimeout() && lastResponse != AT_NOCARRIER && ++recvFrameCount < 5);
if (gotpps) {
tracePPM("RECV recv", ppsframe.getFCF());
if (ppsframe.getFCF() == FCF_PPS) {
rtnframe = ppsframe;
}
pprcnt = 0;
- if (signalRcvd != 0 || recvFrame(rtnframe, conf.t2Timer, FCF_CRP|FCF_RCVR)) {
+ if (signalRcvd != 0 || recvFrame(rtnframe, FCF_RCVR, conf.t2Timer)) {
bool gotrtnframe = true;
if (signalRcvd == 0) tracePPM("RECV recv", rtnframe.getFCF());
else signalRcvd = 0; // reset it, we're in-sync now
recvFrameCount = 0;
- while (rtnframe.getFCF() == FCF_PPS && recvFrameCount < 20 && gotrtnframe) {
+ lastResponse = AT_NOTHING;
+ while (rtnframe.getFCF() == FCF_PPS && lastResponse != AT_NOCARRIER && recvFrameCount < 5 && gotrtnframe) {
// we sent PPR, but got PPS again...
if (!useV34 && !atCmd(conf.class1SwitchingCmd, AT_OK)) {
emsg = "Failure to receive silence.";
}
transmitFrame(FCF_PPR, fxStr(ppr, 32));
tracePPR("RECV send", FCF_PPR);
- gotrtnframe = recvFrame(rtnframe, conf.t2Timer, FCF_CRP|FCF_RCVR);
+ gotrtnframe = recvFrame(rtnframe, FCF_RCVR, conf.t2Timer);
recvFrameCount++;
}
u_int dcs; // possible bits 1-16 of DCS in FIF
(void) transmitFrame(FCF_RNR|FCF_RCVR);
tracePPR("RECV send", FCF_RNR);
HDLCFrame rrframe(conf.class1FrameOverhead);
- if (gotresponse = recvFrame(rrframe, conf.t4Timer, FCF_CRP|FCF_RCVR)) {
+ if (gotresponse = recvFrame(rrframe, FCF_RCVR, conf.t4Timer)) {
tracePPM("RECV recv", rrframe.getFCF());
if (params.ec != EC_DISABLE && rrframe.getFCF() != FCF_RR) {
protoTrace("Ignoring invalid response to RNR.");
*/
HDLCFrame frame(conf.class1FrameOverhead);
do {
- if (recvFrame(frame, conf.t2Timer)) {
+ if (recvFrame(frame, FCF_RCVR, conf.t2Timer)) {
switch (frame.getFCF()) {
case FCF_EOP:
(void) transmitFrame(FCF_MCF|FCF_RCVR);
bool framerecvd = false;
if (batched & BATCH_FIRST) // receive carrier raised
- framerecvd = recvRawFrame(frame);
+ framerecvd = recvFrame(frame, FCF_SNDR, conf.t2Timer, true);
else { // receive carrier not raised
// The receiver will allow T2 to elapse intentionally here.
// To keep recvFrame from timing out we double our wait.
- framerecvd = recvFrame(frame, conf.t2Timer * 2);
+ framerecvd = recvFrame(frame, FCF_SNDR, conf.t2Timer * 2);
}
for (;;) {
}
break;
}
- } while (frame.moreFrames() && recvFrame(frame, conf.t2Timer));
+ } while (frame.moreFrames() && recvFrame(frame, FCF_SNDR, conf.t2Timer));
if (frame.isOK()) {
switch (frame.getRawFCF()) {
case FCF_DIS:
*/
if ((unsigned) Sys::now()-start >= t1)
break;
- framerecvd = recvFrame(frame, conf.t2Timer);
+ framerecvd = recvFrame(frame, FCF_SNDR, conf.t2Timer);
}
emsg = "No answer (T.30 T1 timeout)";
protoTrace(emsg);
* FTT, or CFR; and also a premature DCN.
*/
HDLCFrame frame(conf.class1FrameOverhead);
- if (recvFrame(frame, conf.t4Timer)) {
+ if (recvFrame(frame, FCF_SNDR, conf.t4Timer)) {
do {
switch (frame.getFCF()) {
case FCF_NSF:
{ fxStr csi; recvCSI(decodeTSI(csi, frame)); }
break;
}
- } while (frame.moreFrames() && recvFrame(frame, conf.t4Timer));
+ } while (frame.moreFrames() && recvFrame(frame, FCF_SNDR, conf.t4Timer));
}
if (frame.isOK()) {
switch (frame.getFCF()) {
// in those cases waiting T2 for a response will cause the remote to
// hang up. So, using T4 here is imperative so that our second PPS
// message happens before the remote decides to hang up.
- if (gotppr = recvFrame(pprframe, conf.t4Timer)) {
+ if (gotppr = recvFrame(pprframe, FCF_SNDR, conf.t4Timer)) {
tracePPR("SEND recv", pprframe.getFCF());
if (pprframe.getFCF() == FCF_CRP) {
gotppr = false;
stopTimeout("sending RR frame");
tracePPM("SEND send", FCF_RR);
// T.30 states that we must wait no more than T4 between unanswered RR signals.
- if (gotmsg = recvFrame(pprframe, conf.t4Timer)) {
+ if (gotmsg = recvFrame(pprframe, FCF_SNDR, conf.t4Timer)) {
tracePPR("SEND recv", pprframe.getFCF());
if (pprframe.getFCF() == FCF_CRP) {
gotmsg = false;
sendFrame(FCF_CTC|FCF_SNDR, fxStr(ctc, 2));
stopTimeout("sending CTC frame");
tracePPM("SEND send", FCF_CTC);
- if (gotctr = recvFrame(ctrframe, conf.t4Timer)) {
+ if (gotctr = recvFrame(ctrframe, FCF_SNDR, conf.t4Timer)) {
tracePPR("SEND recv", ctrframe.getFCF());
if (ctrframe.getFCF() == FCF_CRP) {
gotctr = false;
stopTimeout("sending EOR frame");
tracePPM("SEND send", FCF_EOR);
tracePPM("SEND send", pps[0]);
- if (goterr = recvFrame(errframe, conf.t2Timer)) {
+ if (goterr = recvFrame(errframe, FCF_SNDR, conf.t2Timer)) {
tracePPR("SEND recv", errframe.getFCF());
if (errframe.getFCF() == FCF_CRP) {
goterr = false;
stopTimeout("sending RR frame");
tracePPM("SEND send", FCF_RR);
// T.30 states that we must wait no more than T4 between unanswered RR signals.
- if (gotmsg = recvFrame(errframe, conf.t2Timer)) {
+ if (gotmsg = recvFrame(errframe, FCF_SNDR, conf.t2Timer)) {
tracePPR("SEND recv", errframe.getFCF());
if (errframe.getFCF() == FCF_CRP) {
gotmsg = false;
{
for (int t = 0; t < 3; t++) {
tracePPM("SEND send", ppm);
- if (transmitFrame(ppm|FCF_SNDR) && recvFrame(mcf, conf.t4Timer))
+ if (transmitFrame(ppm|FCF_SNDR) && recvFrame(mcf, FCF_SNDR, conf.t4Timer))
return (true);
if (abortRequested())
return (false);
while ((c = getModemChar(0)) != EOF && c != '\n')
if (c != '\0' && c != '\r' && cc < bufSize)
rbuf[cc++] = c;
- } while (cc == 0 && c != EOF);
+ } while (!timer.wasTimeout() && cc == 0 && c != EOF);
rbuf[cc] = '\0';
if (ms) stopTimeout("reading line from modem");
if (!timeout)