]> git.ipfire.org Git - thirdparty/HylaFAX.git/commitdiff
Bug 533: attempt to handle CTC signals from senders not conforming to spec
authorLee Howard <faxguy@howardsilvan.com>
Tue, 27 Apr 2004 04:43:49 +0000 (04:43 +0000)
committerLee Howard <faxguy@howardsilvan.com>
Tue, 27 Apr 2004 04:43:49 +0000 (04:43 +0000)
faxd/Class1Recv.c++

index 8be26f1fb49e337890ce598708b2e5692724b8f2..36c45048870205d5f1e5a52cecd1700e9599d4f6 100644 (file)
@@ -963,111 +963,150 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                } while (!gotpps && !wasTimeout() && ++recvFrameCount < 20);
                if (gotpps) {
                    tracePPM("RECV recv", ppsframe.getFCF());
-                   if (ppsframe.getLength() > 5) {
+                   if (ppsframe.getFCF() == FCF_PPS) {
                        // sender may violate T.30-A.4.3 and send another signal (i.e. DCN)
                        tracePPM("RECV recv", ppsframe.getFCF2());
                    }
-                   if (ppsframe.getFCF() == FCF_PPS) {
-                       // PPS is the only valid signal, Figure A.8/T.30
-                       u_int fc = frameRev[ppsframe[6]] + 1;
-                       if (fc == 256 && !dataseen) fc = 0;    // distinguish between 0 and 256
-                       if (fcount < fc) fcount = fc;
-                       protoTrace("RECV received %u frames of block %u of page %u", \
-                           fc, frameRev[ppsframe[5]]+1, frameRev[ppsframe[4]]+1);
-                       blockgood = true;
-                       if (fc > 0) {   // assume that 0 frames means that sender is done
-                           for (u_int i = 0; i <= (fcount - 1); i++) {
-                               u_int pprpos, pprval;
-                               for (pprpos = 0, pprval = i; pprval >= 8; pprval -= 8) pprpos++;
-                               if (ppr[pprpos] & frameRev[1 << pprval]) blockgood = false;
-                           }
-                       }
+                   switch (ppsframe.getFCF()) {
+                       /*
+                        * PPS is the only valid signal, Figure A.8/T.30; however, some
+                        * senders don't handle T.30 A.1.3 ("When PPR is received four
+                        * times for the same block...") properly (possibly because T.30
+                        * A.4.1 isn't clear about the "per-block" requirement), and so
+                        * it is possible for us to get CTC or EOR here (if the modem
+                        * quickly reported NO CARRIER when we went looking for the
+                        * non-existent high-speed carrier and the sender is persistent).
+                        */
+                       case FCF_PPS:
+                           {
+                               u_int fc = frameRev[ppsframe[6]] + 1;
+                               if (fc == 256 && !dataseen) fc = 0;             // distinguish between 0 and 256
+                               if (fcount < fc) fcount = fc;
+                               protoTrace("RECV received %u frames of block %u of page %u", \
+                                   fc, frameRev[ppsframe[5]]+1, frameRev[ppsframe[4]]+1);
+                               blockgood = true;
+                               if (fc > 0) {   // assume that 0 frames means that sender is done
+                                   for (u_int i = 0; i <= (fcount - 1); i++) {
+                                       u_int pprpos, pprval;
+                                       for (pprpos = 0, pprval = i; pprval >= 8; pprval -= 8) pprpos++;
+                                       if (ppr[pprpos] & frameRev[1 << pprval]) blockgood = false;
+                                   }
+                               }
 
-                       // requisite pause before sending response (PPR/MCF)
-                       if (!useV34 && !atCmd(conf.class1SwitchingCmd, AT_OK)) {
-                           emsg = "Failure to receive silence.";
-                           if (conf.saveUnconfirmedPages && pagedataseen) {
-                               protoTrace("RECV keeping unconfirmed page");
-                               writeECMData(tif, block, (fcount * frameSize), params, (seq |= 2));
-                               prevPage = true;
+                               // requisite pause before sending response (PPR/MCF)
+                               if (!useV34 && !atCmd(conf.class1SwitchingCmd, AT_OK)) {
+                                   emsg = "Failure to receive silence.";
+                                   if (conf.saveUnconfirmedPages && pagedataseen) {
+                                       protoTrace("RECV keeping unconfirmed page");
+                                       writeECMData(tif, block, (fcount * frameSize), params, (seq |= 2));
+                                       prevPage = true;
+                                   }
+                                   free(block);
+                                   return (false);
+                               }
                            }
-                           free(block);
-                           return (false);
-                       }
-                       if (! blockgood) {
-                           // inform the remote that one or more frames were invalid
+                           /* ... pass through ... */
+                       case FCF_CTC:
+                       case FCF_EOR:
+                           if (! blockgood &&
+                                (ppsframe.getFCF() == FCF_CTC || ppsframe.getFCF() == FCF_EOR) &&
+                                (!useV34 || !conf.class1PersistentECM)) {      // only if we can make use of the signal
+                               signalRcvd = ppsframe.getFCF();
+                               pprcnt = 4;
+                           }
+                           if (! blockgood) {
+                               if (signalRcvd == 0) {
+                                   // inform the remote that one or more frames were invalid
 
-                           if (!useV34) atCmd(thCmd, AT_CONNECT);
-                           startTimeout(3000);
-                           sendFrame(FCF_PPR, fxStr(ppr, 32));
-                           stopTimeout("sending PPR frame");
-                           tracePPR("RECV send", FCF_PPR);
+                                   if (!useV34) atCmd(thCmd, AT_CONNECT);
+                                   startTimeout(3000);
+                                   sendFrame(FCF_PPR, fxStr(ppr, 32));
+                                   stopTimeout("sending PPR frame");
+                                   tracePPR("RECV send", FCF_PPR);
 
-                           pprcnt++;
-                           if (pprcnt == 4 && (!useV34 || !conf.class1PersistentECM)) {
-                               // expect sender to send CTC/EOR after every fourth PPR, not just the fourth
-                               protoTrace("RECV sent fourth PPR");
-                               pprcnt = 0;
-                               HDLCFrame rtnframe(conf.class1FrameOverhead);
-                               if (recvFrame(rtnframe, conf.t2Timer)) {
-                               tracePPM("RECV recv", rtnframe.getFCF());
-                                   u_int dcs;                  // possible bits 1-16 of DCS in FIF
-                                   switch (rtnframe.getFCF()) {
-                                       case FCF_CTC:
-                                           if (useV34) {
-                                               // T.30 F.3.4.5 Note 1 does not permit CTC in V.34-fax
-                                               emsg = "Received invalid CTC signal in V.34-Fax.";
-                                               if (conf.saveUnconfirmedPages && pagedataseen) {
-                                                   protoTrace("RECV keeping unconfirmed page");
-                                                   writeECMData(tif, block, (fcount * frameSize), params, (seq |= 2));
-                                                   prevPage = true;
+                                   pprcnt++;
+                               }
+                               if (pprcnt == 4 && (!useV34 || !conf.class1PersistentECM)) {
+                                   HDLCFrame rtnframe(conf.class1FrameOverhead);
+                                   if (signalRcvd == 0) {
+                                       // expect sender to send CTC/EOR after every fourth PPR, not just the fourth
+                                       protoTrace("RECV sent fourth PPR");
+                                   } else {
+                                       // we already got the signal
+                                       rtnframe = ppsframe;
+                                   }
+                                   pprcnt = 0;
+                                   if (signalRcvd != 0 || recvFrame(rtnframe, conf.t2Timer)) {
+                                       if (signalRcvd == 0) tracePPM("RECV recv", rtnframe.getFCF());
+                                       else signalRcvd = 0;            // reset it, we're in-sync now
+                                       u_int dcs;                      // possible bits 1-16 of DCS in FIF
+                                       switch (rtnframe.getFCF()) {
+                                           case FCF_CTC:
+                                               if (useV34) {
+                                                   // T.30 F.3.4.5 Note 1 does not permit CTC in V.34-fax
+                                                   emsg = "Received invalid CTC signal in V.34-Fax.";
+                                                   if (conf.saveUnconfirmedPages && pagedataseen) {
+                                                       protoTrace("RECV keeping unconfirmed page");
+                                                       writeECMData(tif, block, (fcount * frameSize), params, (seq |= 2));
+                                                       prevPage = true;
+                                                   }
+                                                   free(block);
+                                                   return (false);
                                                }
-                                               free(block);
-                                               return (false);
-                                           }
-                                           // use 16-bit FIF to alter speed, curcap
-                                           dcs = rtnframe[3] | (rtnframe[4]<<8);
-                                           curcap = findSRCapability(dcs&DCS_SIGRATE, recvCaps);
-                                           // requisite pause before sending response (CTR)
-                                           if (!atCmd(conf.class1SwitchingCmd, AT_OK)) {
-                                               emsg = "Failure to receive silence.";
-                                               if (conf.saveUnconfirmedPages && pagedataseen) {
-                                                   protoTrace("RECV keeping unconfirmed page");
-                                                   writeECMData(tif, block, (fcount * frameSize), params, (seq |= 2));
-                                                   prevPage = true;
+                                               // use 16-bit FIF to alter speed, curcap
+                                               dcs = rtnframe[3] | (rtnframe[4]<<8);
+                                               curcap = findSRCapability(dcs&DCS_SIGRATE, recvCaps);
+                                               // requisite pause before sending response (CTR)
+                                               if (!atCmd(conf.class1SwitchingCmd, AT_OK)) {
+                                                   emsg = "Failure to receive silence.";
+                                                   if (conf.saveUnconfirmedPages && pagedataseen) {
+                                                       protoTrace("RECV keeping unconfirmed page");
+                                                       writeECMData(tif, block, (fcount * frameSize), params, (seq |= 2));
+                                                       prevPage = true;
+                                                   }
+                                                   free(block);
+                                                   return (false);
                                                }
-                                               free(block);
-                                               return (false);
-                                           }
-                                           (void) transmitFrame(FCF_CTR|FCF_RCVR);
-                                           tracePPR("RECV send", FCF_CTR);
-                                           break;
-                                       case FCF_EOR:
-                                           tracePPM("RECV recv", rtnframe.getFCF2());
-                                           /*
-                                            * It may be wise to disconnect here if MMR is being
-                                            * used because there will surely be image data loss.
-                                            * However, since the sender knows what the extent of
-                                            * the data loss will be, we'll naively assume that
-                                            * the sender knows what it's doing, and we'll
-                                            * proceed as instructed by it.
-                                            */
-                                           blockgood = true;
-                                           switch (rtnframe.getFCF2()) {
-                                               case 0:
-                                                   // EOR-NULL partial page boundary
-                                                   break;
-                                               case FCF_EOM:
-                                               case FCF_MPS:
-                                               case FCF_EOP:
-                                               case FCF_PRI_EOM:
-                                               case FCF_PRI_MPS:
-                                               case FCF_PRI_EOP:
-                                                   lastblock = true;
-                                                   signalRcvd = rtnframe.getFCF2();
-                                                   break;
-                                               default:
-                                                   emsg = "COMREC invalid response to repeated PPR received";
+                                               (void) transmitFrame(FCF_CTR|FCF_RCVR);
+                                               tracePPR("RECV send", FCF_CTR);
+                                               break;
+                                           case FCF_EOR:
+                                               tracePPM("RECV recv", rtnframe.getFCF2());
+                                               /*
+                                                * It may be wise to disconnect here if MMR is being
+                                                * used because there will surely be image data loss.
+                                                * However, since the sender knows what the extent of
+                                                * the data loss will be, we'll naively assume that
+                                                * the sender knows what it's doing, and we'll
+                                                * proceed as instructed by it.
+                                                */
+                                               blockgood = true;
+                                               switch (rtnframe.getFCF2()) {
+                                                   case 0:
+                                                       // EOR-NULL partial page boundary
+                                                       break;
+                                                   case FCF_EOM:
+                                                   case FCF_MPS:
+                                                   case FCF_EOP:
+                                                   case FCF_PRI_EOM:
+                                                   case FCF_PRI_MPS:
+                                                   case FCF_PRI_EOP:
+                                                       lastblock = true;
+                                                       signalRcvd = rtnframe.getFCF2();
+                                                       break;
+                                                   default:
+                                                       emsg = "COMREC invalid response to repeated PPR received";
+                                                       if (conf.saveUnconfirmedPages && pagedataseen) {
+                                                           protoTrace("RECV keeping unconfirmed page");
+                                                           writeECMData(tif, block, (fcount * frameSize), params, (seq |= 2));
+                                                           prevPage = true;
+                                                       }
+                                                       free(block);
+                                                       return (false);
+                                               }
+                                               // requisite pause before sending response (ERR)
+                                               if (!useV34 && !atCmd(conf.class1SwitchingCmd, AT_OK)) {
+                                                   emsg = "Failure to receive silence.";
                                                    if (conf.saveUnconfirmedPages && pagedataseen) {
                                                        protoTrace("RECV keeping unconfirmed page");
                                                        writeECMData(tif, block, (fcount * frameSize), params, (seq |= 2));
@@ -1075,10 +1114,13 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                                                    }
                                                    free(block);
                                                    return (false);
-                                           }
-                                           // requisite pause before sending response (ERR)
-                                           if (!useV34 && !atCmd(conf.class1SwitchingCmd, AT_OK)) {
-                                               emsg = "Failure to receive silence.";
+                                               }
+                                               (void) transmitFrame(FCF_ERR|FCF_RCVR);
+                                               tracePPR("RECV send", FCF_ERR);
+                                               sentERR = true;
+                                               break;
+                                           default:
+                                               emsg = "COMREC invalid response to repeated PPR received";
                                                if (conf.saveUnconfirmedPages && pagedataseen) {
                                                    protoTrace("RECV keeping unconfirmed page");
                                                    writeECMData(tif, block, (fcount * frameSize), params, (seq |= 2));
@@ -1086,67 +1128,54 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                                                }
                                                free(block);
                                                return (false);
-                                           }
-                                           (void) transmitFrame(FCF_ERR|FCF_RCVR);
-                                           tracePPR("RECV send", FCF_ERR);
-                                           sentERR = true;
-                                           break;
-                                       default:
-                                           emsg = "COMREC invalid response to repeated PPR received";
-                                           if (conf.saveUnconfirmedPages && pagedataseen) {
-                                               protoTrace("RECV keeping unconfirmed page");
-                                               writeECMData(tif, block, (fcount * frameSize), params, (seq |= 2));
-                                               prevPage = true;
-                                           }
-                                           free(block);
-                                           return (false);
-                                   }
-                               } else {
-                                   emsg = "T.30 T2 timeout, expected signal not received";
-                                   if (conf.saveUnconfirmedPages && pagedataseen) {
-                                       protoTrace("RECV keeping unconfirmed page");
-                                       writeECMData(tif, block, (fcount * frameSize), params, (seq |= 2));
-                                       prevPage = true;
+                                       }
+                                   } else {
+                                       emsg = "T.30 T2 timeout, expected signal not received";
+                                       if (conf.saveUnconfirmedPages && pagedataseen) {
+                                           protoTrace("RECV keeping unconfirmed page");
+                                           writeECMData(tif, block, (fcount * frameSize), params, (seq |= 2));
+                                           prevPage = true;
+                                       }
+                                       free(block);
+                                       return (false);
                                    }
-                                   free(block);
-                                   return (false);
                                }
                            }
-                       }
-                       if (signalRcvd == 0) {          // don't overwrite EOR settings
-                           switch (ppsframe.getFCF2()) {
-                               case 0:
-                                   // PPS-NULL partial page boundary
-                                   break;
-                               case FCF_EOM:
-                               case FCF_MPS:
-                               case FCF_EOP:
-                               case FCF_PRI_EOM:
-                               case FCF_PRI_MPS:
-                               case FCF_PRI_EOP:
-                                   lastblock = true;
-                                   signalRcvd = ppsframe.getFCF2();
-                                   break;
-                               default:
-                                   emsg = "COMREC invalid post-page signal received";
-                                   if (conf.saveUnconfirmedPages && pagedataseen) {
-                                       protoTrace("RECV keeping unconfirmed page");
-                                       writeECMData(tif, block, (fcount * frameSize), params, (seq |= 2));
-                                       prevPage = true;
-                                   }
-                                   free(block);
-                                   return (false);
+                           if (signalRcvd == 0) {              // don't overwrite EOR settings
+                               switch (ppsframe.getFCF2()) {
+                                   case 0:
+                                       // PPS-NULL partial page boundary
+                                       break;
+                                   case FCF_EOM:
+                                   case FCF_MPS:
+                                   case FCF_EOP:
+                                   case FCF_PRI_EOM:
+                                   case FCF_PRI_MPS:
+                                   case FCF_PRI_EOP:
+                                       lastblock = true;
+                                       signalRcvd = ppsframe.getFCF2();
+                                       break;
+                                   default:
+                                       emsg = "COMREC invalid post-page signal received";
+                                       if (conf.saveUnconfirmedPages && pagedataseen) {
+                                           protoTrace("RECV keeping unconfirmed page");
+                                           writeECMData(tif, block, (fcount * frameSize), params, (seq |= 2));
+                                           prevPage = true;
+                                       }
+                                       free(block);
+                                       return (false);
+                               }
                            }
-                       }
-                   } else {
-                       emsg = "COMREC invalid response received (expected PPS)";
-                       if (conf.saveUnconfirmedPages && pagedataseen) {
-                           protoTrace("RECV keeping unconfirmed page");
-                           writeECMData(tif, block, (fcount * frameSize), params, (seq |= 2));
-                           prevPage = true;
-                       }
-                       free(block);
-                       return (false);
+                           break;
+                       default:
+                           emsg = "COMREC invalid response received (expected PPS)";
+                           if (conf.saveUnconfirmedPages && pagedataseen) {
+                               protoTrace("RECV keeping unconfirmed page");
+                               writeECMData(tif, block, (fcount * frameSize), params, (seq |= 2));
+                               prevPage = true;
+                           }
+                           free(block);
+                           return (false);
                    }
                } else {
                    emsg = "T.30 T2 timeout, expected signal not received";