home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1993 May / SIMTEL_0593.ISO / msdos / fido / ftsc_all.z43 / FSC-0010.TXT < prev    next >
Text File  |  1987-12-01  |  11KB  |  398 lines

  1. FSC-0010
  2.  
  3. RESYNC, a sealink protocol enhancement by Henk Wevers  2/0
  4. ==========================================================
  5.  
  6.  
  7. What is resync (recovarable sealink)
  8. ------------------------------------
  9.  
  10. Resync is a protocol enhancement on Sealink by Sea corporation
  11. that allows the protocol to pickup broken transfers were it was
  12. interrupted. The coding overhead is very minor because almost all
  13. routines needed are already part of most sealink implementations.
  14.  
  15. As a sideeffect transmissions of exact duplicate files (from whatever
  16. source) will only result in the two programs exchanging EOT and thus
  17. saving a lot of transfertime and costs.
  18.  
  19. The protocol
  20. -------------
  21.  
  22. The capability of doing ackless sealink
  23. is signalled by the SENDER by having
  24. byte  41 (1 based) in block 0 of a sealink file transfer being <> 0. 
  25. Recovery is signalled in the sameway by byte 42 <> 0.
  26.  
  27. Recoverable sealink starts off like normal (unrecoverable sealink).
  28. After the receiver has received block zero without errors the
  29. receiver checks for a duplicate filename in its incoming file
  30. directory. When a match is found the time and datestamp are checked
  31. and when they match the resync procedure is started otherwise`
  32. the transfer goes on like normal.
  33.  
  34. Recovery procedure:
  35.  
  36. RECEIVER
  37. --------
  38.  
  39. The receiver sends the following block to the
  40. sender:
  41.  
  42. <sync> <blocknumber> <eot> <crclow> <crchigh>
  43.  
  44. sync = $22
  45. blocknumber: ascii , number of block to resume with, 1 based
  46. eot = $03
  47. crc as usual
  48.  
  49. The reason this form is choosen is that it is the same block as used
  50. for passing the filename in sealink based filerequests so the code
  51. was already there.
  52.  
  53. now the receiver waits ontil the line dies (looks for a 1 sec pause)
  54. then sends $05 and waits for ACK or NAK from the sender. If nak is
  55. received the recovery procedure is restarted . After a given number
  56. of failed tries the session is aborted.
  57.  
  58. After an ACK the receiver 'seeks' at the given
  59. block and resumes sealink transfer.
  60.  
  61.  
  62. SENDER
  63. ------
  64.  
  65. The sender has the capability to recognize returning ACK, NAK and
  66. SYNC. When a SYNC is received the sender stops all output, purges its
  67. outputbuffers and tries to get the resyncinfo.
  68. (some smart programming to allow an unintended sync caused by
  69. linenoise may make the protocol more stable. You may also test for
  70. ack/nack directly after the SYNC because the ascvii blocknumer
  71. garantees that a received ack/nak probably means a spurious sync. ).
  72. As soon as the blocknumber is received the sender acks and resume
  73. the sealink transfer at the given block.
  74.  
  75. NOTES
  76. ------
  77.  
  78. This only works if the receiver closes a partly recived file
  79. properly, gives it the right name and sets the right time/date.
  80. In the current dutchie 2.80 implementation it also
  81. only works for files, not for mailpackets, but that is only a
  82. question of implementation and choise.
  83.  
  84. IMPLEMENTATION
  85. ---------------
  86.  
  87. Currently only dutchie 2.80 implements this enhancement. testing
  88. has shown that the protocol is very stable and works well.
  89. Some code in turbo pascal follows to help those who want to
  90. implement it.
  91.  
  92. 1. The code used for transferring the wanted restart blocknumber
  93.    to the sender. In real implementations this code will be shared 
  94.    by the filerequest stuff.
  95.  
  96.   function resyncok(blknum:integer):boolean;
  97.  
  98. Var
  99.  blockstring : string[5];
  100.  tries,
  101.  ch,
  102.  n            : Integer;
  103.  
  104. Begin
  105.   str(blknum,blockstring);
  106.   tries := 0;
  107.   repeat
  108.     tries := tries +1;
  109.     if ((not Comm_Carrier(Comport)) or keyescape or ( tries >=8)) then
  110.     begin
  111.       If not Comm_Carrier(Comport) then Logit(3,1,'Lost Carrier') else
  112.       If (tries>=8) then Logit(3,1,'Too much errors') else
  113.       Logit(3,1,'Keyboard <esc>');
  114.       dumerr := fileerr;
  115.       resyncok := false;
  116.       exit;
  117.     end;
  118.     Comm_purge_in(ComPort);
  119.     ClearCrC;
  120.     comm_transmit(comport,22);
  121.     For n:= 1 to length(blockstring) do
  122.     Begin
  123.       Comm_transmit(Comport,Ord(blockstring[n]));
  124.       UpdatCrc(ord(blockstring[n]));
  125.     End;
  126.     UpdatCrc(0);
  127.     UpdatCrc(0);
  128.     Comm_Transmit(Comport,$03);
  129.     Comm_Transmit(ComPort,Lo(CrcAccum));
  130.     Comm_Transmit(ComPort,Hi(CrcAccum));
  131.     Comm_purge_in(comport);
  132.     {wait for a 1 sec pause}
  133.     {Wait until line dies}
  134.     Repeat
  135.       Ch := timed_read(ComPort, 10);
  136.     Until (Ch = $FFFF);
  137.     comm_transmit(comport,05);
  138.     ch := timed_read(Comport,20);
  139.   until (ch=ACK);
  140.   resyncok := true;
  141. end;
  142.  
  143.  
  144. 2. part of sender ack/nack logic to handshake
  145.    above code
  146.  
  147. function getsyncblock(var c:integer):Boolean;
  148. var t1 : real;
  149.     n,
  150.     Crclo,
  151.     CrcHi,
  152.     pl,
  153.     code,
  154.     ch : integer;
  155.     temp1,
  156.     temp : string64;
  157.     label 100;
  158.  
  159.  
  160. begin
  161.   ReqName := '';
  162.   getsyncblock := false;
  163.   t1 := timerset(50);
  164.   repeat
  165.     ch := timed_read(comport,0);
  166.     if ((ch > $1F) and (ch <$7F)) then ReqName := ReqName + Chr(ch);
  167.     if ((ch = ack) or (ch = nak)) then
  168.     begin
  169.       c:= ch;
  170.       goto 100;
  171.     end;
  172.     if not comm_carrier(Comport) then goto 100;
  173.   until ((ch = $03) or timeup(t1));
  174.   CrcLo := Timed_Read(Comport,10);
  175.   CrcHi := Timed_Read(Comport,10);
  176.   ClearCrc;
  177.   For n := 1 to length(ReqName) do UpdatCrc(ord(reqName[n]));
  178.   UpdatCrc(0);
  179.   UpdatCrc(0);
  180.   {now wait for enquiry (must be within 5 secs)}
  181.   t1 := timerset(50);
  182.   repeat
  183.     ch := timed_read(comport,50);
  184.   until ((ch = $05) or timeup(t1));
  185.  
  186.   If ((Lo(CrcAccum) = CrcLo) and (Hi(CrcAccum) = CrcHi)) then
  187.   Begin
  188.     val(reqname,outblk,pl);
  189.     Comm_transmit(Comport,ACK);
  190.     getsyncblock :=true;
  191.   end
  192.   else
  193.     begin
  194.     fixwindow;    
  195.     Writeln('           Bad Checksum');
  196.     Comm_transmit(comport,Nak);
  197.     end;
  198. 100:
  199. end;
  200.  
  201.  
  202.  
  203.  
  204.   Procedure AckChk;
  205.  
  206.     {  The Various ACK/NAK states are:
  207.     0:   Ground state, ACK or NAK expected
  208.     1:   ACK received
  209.     2:   NAK received
  210.     3:   ACK, bloknumber received
  211.     4:   NAK, bloknumber received
  212.     }
  213.  
  214.   Var
  215.     c : Integer;
  216.     label 100;
  217.  
  218.   Begin
  219.  
  220.     ackrep := false;
  221.     c := timed_read(ComPort,0);
  222.     While c <> $FFFF Do
  223.     Begin
  224.       If ((Ackst = 3) Or (Ackst = 4)) Then
  225.       Begin
  226.         Slide := 1;
  227.         If (Rawblk = (c Xor $FF)) Then
  228.         Begin
  229.           Rawblk := Outblk-((Outblk-Rawblk) And $FF);
  230.           If ((Rawblk >= 0) And (Rawblk <= Outblk) And (Rawblk > (Outblk-128))) Then
  231.           Begin
  232.             If (Ackst = 3) Then  {advance for an ACK}
  233.             Begin
  234.               If (Ackblk <= Rawblk) Then Ackblk := Rawblk;
  235.               Slide := SeaWindow;
  236.               ackseen := ackseen + 1;
  237.               if (ackless and (ackseen > 10)) then
  238.               begin
  239.                 ackless := false;
  240.                 fixwindow;
  241.                 writeln(#13,'- Overdrive disengaged                  ');
  242.               end;
  243.               fixwindow;
  244.               Write(#13, '  ACK ', Rawblk:5, ' == ')
  245.             End
  246.             Else
  247.             Begin
  248.               If (Rawblk < 0) Then Outblk := 0 Else Outblk := Rawblk;
  249.               If numnak < 4 then slide := seawindow else slide := 1;
  250.               fixwindow;
  251.               Write(#13, '  NAK ', Rawblk:5, ' == ');
  252.             End;
  253.             Ackrep := true;
  254.           End;
  255.         End;
  256.         Ackst := 5;
  257.       End;
  258.  
  259.         If ((Ackst = 1) Or (Ackst = 2)) Then
  260.         Begin
  261.           Rawblk := c;
  262.           Ackst := Ackst+2
  263.         End;
  264.  
  265.         If (Not(Slide = SeaWindow) Or (Ackst = 0)) Then
  266.         Begin
  267.           If (c = syn) then
  268.           begin
  269.             Write(#13, '  Resync received                          ',#13);
  270.             if not getsyncblock(c) then
  271.             begin
  272.                if ((c = ack) or (c=nak)) then goto 100;
  273.                numnak := 255;
  274.                 exit;
  275.             end;
  276.             ackblk := outblk-1;
  277.             beginblk := outblk-1;
  278.           end;  
  279. 100:
  280.           If (c = Ack) Then
  281.           Begin
  282.             If (Not(Slide = SeaWindow)) Then
  283.             Begin
  284.               Ackblk := Ackblk+1;
  285.               fixwindow;
  286.               Write(#13, '  ACK ', Ackblk:5, ' -- ');
  287.               ackrep := true;
  288.             End;
  289.             Ackst := 1;
  290.             NumNak := 0;
  291.           End
  292.           Else
  293.           Begin
  294.             If ((c = Crc) Or (c = Nak)) Then
  295.             Begin
  296.               If (Chktec > 1) Then
  297.               Begin
  298.                 If (c = Nak) Then Chktec := 0 Else Chktec := 1;
  299.                 If (Modem Or Modem7) Then Ackblk := 0;
  300.               End;
  301.               Comm_purge_out(Comport);
  302.               TimeWait(6);
  303.               If Not(Slide = SeaWindow) Then
  304.               Begin
  305.                 Outblk := Ackblk+1;
  306.                 fixwindow;
  307.                 Write(#13, '  NAK ', Ackblk+1:5, ' -- ');
  308.                 Ackrep := true;
  309.               End;
  310.               Ackst := 2;
  311.               NumNak := NumNak+1;
  312.               If BlkSnt > 0 Then Toterr := Toterr+1;
  313.             End;
  314.           End;
  315.         End;
  316.  
  317.         If (Ackst = 5) Then Ackst := 0;
  318.         c := timed_read(ComPort,0);
  319.       End;
  320.   End;
  321.  
  322.  
  323. 3. part of receiver logic
  324. ----------------------------
  325.  
  326. {we come here after successfully receiving block zero}
  327.  
  328.    If Sealink then
  329.    begin
  330.      Timestring := Seatime((((Buffer[8]*256.0)+Buffer[7])*256.0+Buffer[6])*256.0+Buffer[5]);
  331.      ackless := false;
  332.       If (Buffer[41]  <> 0) then
  333.      begin
  334.        writeln('- Overdrive engaged');
  335.        ackless := true;
  336.      end;
  337.      If (Buffer[42]  <> 0) then
  338.      begin
  339.        writeln('- Recovery enabled');
  340.        recovers := true;
  341.      end;  
  342.    end;
  343.    Assign(Afile, FileDir+filenm);
  344.    Reset(Afile);
  345.    If IOResult = 0 Then
  346.    Begin
  347.      if sealink and recovers then
  348.      begin
  349.       {find date/time}
  350.        code := FindFirst(Filedir+filenm);
  351.        If code = 0 Then
  352.        begin
  353.          {we have a duplicate ?}
  354.          If file_name = filenm then
  355.          begin
  356.            {check timestamp}
  357.            tstring[0] := #4;
  358.            tstring[1] := Chr(dir.time[1]);
  359.            tstring[2] := Chr(dir.time[2]);
  360.            tstring[3] := Chr(dir.date[1]);
  361.            tstring[4] := Chr(dir.date[2]);
  362.            if tstring  = timestring then
  363.            begin
  364.              Blknum :=Trunc(file_size/128)+1;
  365.              startblk := blknum-1;
  366.              Str(blknum,blkstring);
  367.              LogIt(3,1, 'Resynced from '+blkstring);
  368.              if resyncok(blknum) then
  369.              begin
  370.                resyncflag := true;
  371.                longseek(afile,(blknum-1)*128);
  372.                truncate(afile);
  373.              end
  374.              else
  375.              begin
  376.                sealinkrx := false;
  377.                goto 150;
  378.              end;
  379.            end;
  380.          end;
  381.        end;
  382.      end;
  383.      if not resyncflag then
  384.      begin
  385.        if not overwrite then
  386.        begin
  387.          filenm[1] := '$';
  388.          LogIt(3,1, 'Renamed to '+filenm);
  389.        end
  390.        else Logit(3,1,'Overwrote old file !');
  391.      end;
  392.    End;
  393.  
  394.  
  395. PLEASE COMPARE THESE TO THE ORIGINAL SEA DOCUMENTS ON SEALINK
  396. (IN C)
  397.  
  398.