
Notizen zum ZModem-Protokoll
============================


Character-Codierung
-------------------

Escape-Character:
   ZDLE = 0x18 (CAN)

Character-Code-Behandlung:
  - Austausch von c durch ZDLE c^40:
    - Folgende Codes werden beim Senden ersetzt:
         10 11 13 18 90 91 93
    - 0D und 8D werden nur dann ersetzt, wenn 40 oder C0 vorausgeht.
      (wegen der CR-@-CR Escape-Sequence von Telenet).
    - Beim Empfang werden die ZLDE-c^40-Sequenzen fr folgende
      ursprnglichen Codes akzeptiert:
         0..1F 7F 80..9F FF
    - Problem: Die Header-Start-Sequenzen sind gleich codiert wie
      escaped Control-Characters.
  - Die Bytes 11, 13, 91 und 93 werden beim Empfang ignoriert.
    Im Streaming-Mode werden XON/XOFF (11/13) jedoch interpretiert!?
  - Falls die Gegenstation das ESCCTL oder TESCCTL-Capability-Flag
    gesetzt hat, werden beim Empfang alle Control-Chars (0..1F,
    80..9F) ignoriert.



Packet-Headers
--------------

Header-Inhalt:
  - Der Header-Inhalt besteht aus 5 Bytes:
      mit Flags:         Frame-Type F3 F2 F1 F0
      mit Position-Info: Frame-Type P0 P1 P2 P3
  - Die Reihenfolge der Position-Bytes ist Littledian (lo..hi).

Binary Header mit CRC-16:
  - Format: 2A 18 41 hdr-inhalt-bin CRC-16
  - Nachfolgende Data-Subpackets haben CRC-16.

Binary Header mit CRC-32:
  - Format: 2A 18 43 hdr-inhalt-bin CRC-32
  - Nachfolgende Data-Subpackets haben CRC-32.

Hex Header:
  - Format: 2A 2A 18 42 hdr-inhalt-hex CRC-16-hex [0D] 0A [11]
  - Die Hex-Daten mssen mit Kleinbuchstaben formatiert sein!
  - Der Empfnger akzeptiert auch nur LF ohne CR. Bei CR oder
    LF kann das Bit 7 gesetzt sein. (?)
  - Anhngen des XON-Characters:
      - Bei ZFIN nicht (Um Session-Cleanup nicht zu stren).
      - Bei ZACK nicht wenn es als Antwort auf ein ZCRCQ geschickt wird.
        (Um Flow-Control im Streaming-Mode nicht zu stren).
        (RZ sendet nur ein XON bei ZACKs, die als Antwort auf ein
        ZCRCW im File-Daten-Stream geschickt wurden, sonst nicht).
      - Sonst fr alle.
  - Nachfolgende Data-Subpackets haben CRC-16.

Hex/Binary Anwendung:
  - Der File-Receiver sendet immer im Hex-Format.
  - Der File-Sender kann Binary-Format benutzen, falls danach binary
    Data Packets kommen. Er kann aber auch immer Hex-Format benutzen.
    (sz sendet jedoch auch folgende Frames in binary:
    ZSINIT (falls <Zctlesc>=<false>), ZFILE, ZCRC, ZDATA, ZEOF, ZNAK
    (in <getinsync>)). Binkley-ZSEND sendet z.B ZDATA auch immer binary.



Data Subpackets
---------------

- Format der Data-Subpackets: data 18 xx CRC [11] (xx = 68..6A)
- Daten-Blcke knnen bis 1024 Bytes gross sein. Fr tiefere Baudraten
  werden kleinere Blcke verwendet. Die Grsse kann mit der Fehler-
  Hufigkeit variert werden.
  - Fr Fidonet-ZedZap kann die maximum packet size 8192 sein!
- Leere Data-Subpackets sind mglich und knnen gesendet werden um
  Timeouts im File-Receiver zu vermeiden.
  -> Knnen leere Data-Subpackets auch ausserhalb des Data-Streams
     gesendet werden??

- Abschluss von Data-Subpackets:
  ZCRCG: 18 69 CRC weitere-data-Packets
    - Keine Response vom File-Receiver falls CRC-OK. Sonst wird ATTN
      und ZRPOS geschickt.
  ZCRCQ: 18 6A CRC weitere-data-Packets
    - Der File-Receiver antwortet mit ZACK falls CRC-OK, oder ATTN +
      ZRPOS falls Error.
    - ZCRCQ wird fr die Windowing-Size-Limitierung verwendet werden.
    - ZCRCQ darf nicht verwendet werden, falls CANFDX des File-Receivers
      0 ist.
    - Binkley verwendet ZCRCQ nicht, wahrscheinlich um fr Halfduplex-
      Modems optimaler zu sein? (Binkley hat auch keine Window-Kontrolle).
  ZCRCE; 18 68 CRC
    - Markiert End-of-File.
    - Keine Response vom File-Receiver falls CRC-OK, sonst ZRPOS.
    - Falls kein nachfolgendes ZEOF detektiert wird oder beim ZEOF
      festgestellt wird, dass nicht alle Daten empfangen wurden, knnen
      mit ZRPOS wieder Daten angefordert werden.
  ZCRCW: 18 6B CRC 11
    - Der File-Sender wartet auf ZACK oder ZRPOS.
    - Der File-Sender ignoriert ZACKs mit falschem File-Offset.
    - Der File-Sender muss ZCRCW verwenden, falls der File-Receiver
      CANOVIO=0 hat oder <buffer_size> gesetzt hat.
    - ZCRCW wird auch verwendet, wenn der File-Sender zuviele
      Garbage-Characters empfangen hat, oder nach einem ZRPOS innerhalb
      des Streams.
    - SZ und Binkley senden ein XON (11) am Schluss von ZCRCW.



Protocol Transactions
---------------------

- Die Initiative geht normalerweise vom File-Receiver aus.
- Der File-Sender bricht die Session ab (timeout), wenn er
  ca. 60 Sekunden lang keine Headers mehr vom File-Receiver
  erhalten hat (nur wenn er auf eine Response wartet??).

- "Response time" = Timeout von 10 Seconds (default).
  Der File-Receiver wartet so lange auf Antwort vom File-Sender.

- Session-Start vom File-Sender aus:
  - Der File-Sender kann vorher noch "rz"+CR senden.
  R<-S: ZRQINIT
     - Macht der Sender Retries fr ZRQINIT?? -> Wahrscheinlich
       nicht, denn der Receiver macht Retries von ZRINIT.
     - Session-Start-Erkennungssequenz fr Terminal-Sessions (getestet
       mit REXXTERM): "**"18"B00"
  R->S: ZRINIT oder ZCHALLENGE
  ...
- Session-Start vom File-Receiver aus:
  R->S: ZRINIT oder ZCHALLENGE
     - Retries nach "Response Time" (10s) ohne Antwort. Total
       4 Versuche. Nachher Fallback zu YModem.
     - Falls der File-Receiver ein ZRQINIT empfngt, sendet er
       nochmals ein ZRINIT (oder ZCHALLENGE?). (-> Gefahr der
       Message-berlappung beim Vorhandensein von Channel-Delays).
     - Falls der File-Receiver ein ZRINIT empfngt, ist es entweder
       ein Echo (z.B. wenn ein Host im Line-Input-Mode ist), oder
       auf der Gegenseite ist auch ein File-Receiver.
 falls ZCHALLENGE:
  R<-S ZACK (enthlt Random-Number des ZCHALLENGE?)
 falls ZRINIT:
  R<-S (optional): ZSINIT
    R->S: ZACK (Response auf ZSINIT)
  R<-S: ZFILE ... ZCRCW
     (Auf ZFILE wird kein ZACK zurckgeschickt, trotz ZCRCW!)
  R->S: ZRPOS oder ZCRC oder ZSKIP
 falls ZRPOS:
  R<-S: ZDATA + data-subpackets
     - Falls die File-Position im ZDATA-Header nicht stimmt,
       sendet der File-Receiver ein ZRPOS. (-> Gefahr der Message-
       berlappung)
  ...
  R<-S: ZEOF
     - Falls der File-Receiver nicht alle Daten empfangen hat
       (d.h. falls der File-Offset im ZEOF nicht bereinstimmt), wird
       ZEOF ignoriert und ZRPOS geschickt (nur falls noch kein
       ZRPOS unterwegs ist!).
     - ?? Wenn der File-Sender alle Files geschickt hat, sollte er
       Protokoll-Errors ignorieren und nach einem Timeout normal
       zurckkehren. (? -> es ist dann nicht sicher ob das File
       richtig empfangen wurde...)
  R->S: ZRINIT oder ZFERR
  R<-S: ZFIN
  R->S: ZFIN
  R<-S: "OO"
     - Der File-Receiver wartet nur kurz auf die "OO" und
       terminiert sonst auch ohne.

Session-Abort:
  - Empfang von 5 aufeinanderfolgenden ZDLE characters wird als
    Session-Abort interpretiert.
    Gesendet werden 10 ZDLE-Characters, gefolgt von 10 Backspace-
    Characters.
  - Falls der File-Receiver die Session abbrechen will whrend
    Daten im Streaming-Mode kommen, sendet er zuerst die ATTN
    Sequenz.



File-Daten-Transfer
-------------------

- Wenn der File-Sender whrend dem Daten-Senden im Streaming-Mode
  mehr als eine gewisse Anzahl Garbage-Characters empfangen hat,
  sendet er das nchste Daten-Subpacket mit ZCRCW und wartet auf
  eine Response vom File-Receiver.
  Wenn ein 18 oder 2A empfangen wird, stoppt der File-Sender
  sofort und sendet ein leeres ZCRCE-Packet. (ZCRCE wird verwendet
  und nicht ZCRCW, damit der File-Receiver kein extra ZACK oder
  ZRPOS schicken muss). -> Anders implementieren...
- Wenn der File-Sender whrend dem Daten-Senden im Streaming-Mode
  ein ZRPOS empfngt, flusht er die Output-Queue und sendet den
  nchsten Block mit ZCRCW. Dann wird zuerst auf das ZACK gewartet.
  Wenn rz ein ZRPOS geschickt hat, ignoriert es ein ZCRCE (in
  <zgethdr>). Der File-Sender kann also nach dem Queue-Flush ein
  dummy-ZCRCE schicken.
- Wenn der File-Sender mehrmals hintereinander ein ZRPOS erhlt
  ohne ein gltiges ACK, verkrzt er die Block-Size bis auf 32 Bytes.
  -> Die Block-Size muss dynamisch wieder erhht werden.
- Der File-Receiver kann whrend dem Filetransfer ZSKIP schicken
  um den Transfer des Files abzubrechen und die Session aber zu halten.
  Mit ZFIN oder ZABORT wird die Session abgebrochen.



ATTN
----

- Die ATTN-Sequenz wird immer dann vom File-Receiver geschickt,
  wenn der Daten-Stream des File-Senders unterbrochen werden muss.
- Der Default fr die ATTN-Sequenz ist empty.
- Die ATTN-Sequenz wird vom File-Sender mit ZSINIT definiert.
- Break und Pause knnen im ATTN-String mit speziellen Characters
  definiert werden.



Frame-Types
-----------

 0 ZRQINIT  Wird vom File-Sender geschickt um dem File-Receiver die
            Bereitschaft anzuzeigen.
 1 ZRINIT   Wird vom File-Receiver geschickt fr Session-Start.
            Enthlt Capability-Flags und Grsse des RX-Buffers.
            Die RX-Buf-Len spezifiziert die maximale Frame-Size,
            oder ist 0. (Original-rz benutzt 0, ausser fr CP/M).
            -> Siehe "Session-Start vom File-Receiver aus".
 2 ZSINIT   Enthlt File-Sender-Capabilities und ATTN-Sequence.
            (Ein spezielle Feature fr eine Alternate-CAN-Sequence ist
            nicht richtig implementiert in rz/sz).
 3 ZACK     Ack auf ZCRCQ oder ZCRCW: Enthlt File-Offset.
            Ack auf ZCHALLENGE: Enthlt Random-Nummer.
            Ack auf ZSINIT: 0 (?).
            Ack auf ZFREECNT: Enthlt Size of free Disk-Space.
 4 ZFILE    File-Transmission-Request.
            Als Antwort auf ZFILE wird kein ZACK geschickt, obwohl
            die Daten mit ZCRCW abgeschlossen werden!
 5 ZSKIP    Kann vom File-Receiver als Antwort auf ZFILE gesendet
            werden um das File zu ignorieren. Kann auch innerhalb
            eines File-Transfers gesendet werden.
            In der zr-Source wird auch ein ZSKIP behandelt, das
            vom File-Sender an den File-Receiver gesendet wurde.
            Binkley-ZRECEIVE behandelt ZSKIP auch richtig.
            Die Reaktion von rz oder Binkley-ZRECEIVE auf ZSKIP ist
            gleich wie wenn ZEOF empfangen worden wre. Beide schicken
            ein ZRINIT.
 6 ZNAK     Wird als Antwort auf Fehlerhafte (CRC-Errors) oder
            unexpected Frame-Headers geschickt.
            Wird nur fr Diagnostic-Zwecke verwendet (??).
            RZ wiederholt ein ZRPOS wenn ZNAK empfangen wurde.
            (Sonst wird erst nach dem 10-Sec-Timeout wiederholt).
            SZ wiederholt ZFILE nach Empfang eines ZNAK.
 7 ZABORT   Wird vom File-Receiver gesendet um die Session
            abzubrechen (on user request). Der File-Sender
            antwortet mit ZFIN oder ZCOMPL.
            sz schickt jedoch CAN*5 auf ZABORT.
 8 ZFIN     Wird vom File-Sender geschickt um die Session zu beenden,
            oder vom File-Receiver als Antwort auf ein ZFIN vom Sender.
            (ZFIN wird von sz immer im Hex-Mode gschickt).
 9 ZRPOS    Wird vom File-Receiver gesendet zur Anforderung von
            File-Daten (wird auch fr Error-Recovery verwendet).
            Enthlt neue File-Position.
10 ZDATA    Fr File-Daten. Enthlt File-Offset. Ein oder mehrere
            Daten-Subpackets folgen.
11 ZEOF     EOF mit File-Size.
12 ZFERR    Meldet File-i/o-Error. Kann von beiden Seiten geschickt
            werden.
            In der Doku steht, ZFERR sei "protocol equivalent to ZABORT".
            In der rzsz-Source sieht es aber so aus als wrde die
            Session offen gehalten und nur der Filetransfer abgebrochen
            (wie ZSKIP).
            sz schickt nie ZFERR, sondern CAN*5 bei File open/input error.
            In Binkley wird ZFERR nicht verwendet. In Binkley/ZSEND wird
            ZFERR berhaupt nicht erkannt. In <ZS_SendFile> wird sogar
            das ZFILE fr das gleiche File wieder geschickt...
            ==> ZFERR nicht senden!!
            In sz (<getinsync>) wird ZFERR nicht verstanden.
13 ZCRC     Request und Response fr CRC ber File.
            Gibt <maxuint4> zurck falls CRC nicht implementiert.
            Im Request wird die Anzahl Bytes fr CRC oder -1
            bergeben.
            Nicht implementiert in Binkley-ZSEND??
14 ZCHALLENGE Request File-Sender to echo a random number in a ZACK.
15 ZCOMPL   Command completed (fr ZCOMMAND),
16 ZCAN     (intern benutzt in rzsz fr 5-CAN-Abort-Sequence).
17 ZFREECNT Query free Disk-Space.
18 ZCOMMAND Execute Command.
            Nachfolgend kommt ein Data-Subpacket mit ZCRCW, das den
            Command-String enthlt.
            Auf Invalid-Commands wird ein ZCOMPL mit Error-Code
            zurckgeschickt.
            Fr ZCOMMAND muss in ZRQINIT ein Flag gesetzt werden.



Timeouts und Retries
--------------------

Wo werden welche Timeouts verwendet:
  <Rxtimeout>:
    - Main von <sz> setzt <Rxtimeout> auf 600 (60 sec).
    - Main von <rz> setzt <Rxtimeout> auf 100 (10 sec).
    - Wird verwendet in: <zgethdr> und einzel-Char-wait...
    - Wenn <sz> whrend 60 sec kein ZRPOS oder ZACK (auf ZCRCQ/W)
      erhlt, bricht es ab.

Wo macht der File-Sender (sz) Retries:
  ZRQINIT:
    - Fr ZRQINIT wird kein Retry gemacht (ausser wenn ZCOMMAND)
      empfangen wird.
  ZSINIT:
    - Fr ZSINIT macht der File-Sender 19 Retries. Nur wenn ZACK
      empfangen wird (oder CAN*5) wird die Retry-Loop beendet.
  ZFILE:
    - Wird in <zsendfile> geschickt.
    - Wird in <tryz> empfangen.
    - Falls auf ZFILE ein ZRINIT empfangen wird (ist bei Binkley
      der Fall!), macht sz einen Test ob innerhalb von 5 Sekunden ein
      "*" kommt. Falls nicht, wird ZFILE wiederholt.
    - Bei Error oder ZNAK wird ZFILE sofort wiederholt.
  ZCRCQ/W (Nach Data-Subpacket):
    - Wird in <zsendfdata> geschickt.
    - Wenn das TX-Window berschritten wurde (noch keine
      entsprechenden ZACKs eingetroffen sind) wird <getinsync(1)>
      aufgerufen.
    - Nach dem Senden von ZCRCW wird <getinsync(0)> aufgerufen.
    - <getinsync(flag)>:
      - verhaltet sich passiv, ausser dass es bei Errors (und unexpected
        Frames) ZNAK zurckschickt.
      - Bei Timeout wird der Filetransfer abgebrochen.
      - (<getinsync> reagiert auf ZNAK mit ZNAK).
      - Mit flag=0 wartet <getinsync> bis ein ZACK mit dem current
        Offset kommt. Bei flag=1 kehrt es auch bei andern ZACKs zurck.
    -> Kein automatischer Retry.
  ZEOF:
    - Wird am Schluss von <zsendfdata> in der "for (;;)"-Schlaufe
      geschickt.
    - Auf ZACK wird ZEOF wiederholt, falls die File-Position im ZACK
      der EOF-Position entspricht. ??? -> wieso??
      -> Da am Schluss des Files ein ZCRCE geschickt wird (das keine
         ZACK-Response auslst), stimmt die File-Position im ZACK
         normalerweise nicht berein.
  ZFIN (fr File-Sender):
    - Wird in <saybibi> geschickt.
    - Retry wenn etwas anderes als ZFIN oder Session-Abort innerhalb
      des Timeouts empfangen wird (auch bei Error).
  Session-Abort:
    - Kein Retry.

Wo macht der File-Receiver (rz) Retries:



rz/sz-Programmstruktur
----------------------

sz:
main
 wcsend                sendet alle Files
  wcs                  sendet ein File, ffnet das File
   wctxpn              bereitet Path-Name auf
    getnak             findet Protokoll heraus, gibt ok=false zurck
     getzrxinit        gibt OK=0 zurck
      sendzsinit       gibt OK=0 zurck
    zsendfile          sendet ZFILE und wartet auf ZRPOS
     zsendfdata
      getinsync        wird aufgerufen wenn '*' empfangen wurde
      zfilbuf

rz:
main
 wcreceive
  tryz                 schickt <tryzhdrtype>, empfngt ZFILE
  rzfiles
   rzfile
    procheader         verarbeitet ZFILE-Info
    zrdata             empfngt Data-Subpacket
   tryz                -> wie von <rzfiles>

Notizen zu sz:
- In <wctxpn> wird <getnak> nur beim ersten Durchlauf aufgerufen
  (wenn <Zmodem> noch <false> ist.
- Nach dem Empfang von ZSKIP oder ZFERR wird nicht auf ein ZRINIT
  gewartet, bevor das ZFILE fr den nchsten File geschickt wird.
- In der <getinsync> routine wird ZFERR nicht verkraftet (es wird
  ein ZNAK zurckgeschickt). ZSKIP wird jedoch richtig verarbeitet.

Notizen zu rz:
- <tryzhdrtype> kann folgende Werte haben:
    ZRINIT
    ZFERR
    ret-vals von procheader:
       ZFERR
       ZSKIP
- In der Schlaufe von <rzfiles> wird for der iteration <tryz>
  wieder aufgerufen, falls <rzfile> mit ZEOF oder ZSKIP
  zurckkehrte.
- rz sendet nach FSKIP oder ZFERR kein ZRINIT (ausser nach Retry-
  Timeout) sondern wartet sofort auf das nchste ZFILE.



Fragen
------

- Soll XON/XOFF-Handshaking benutzt werden?
  -> Binkley-Source anschauen...
  -> Fr die End-to-End-Flow-Control sollte die Window-Size-Limitierung
     mit ZCRCQ/ZACK verwendet werden.
     -> Nachteil: Die minimale Grsse der i/o-Queues muss bekannt
        sein.
     Fr die Modem-PC-Flow-Control wird RTS/CTS verwendet.
- Mssen fr ZCRCQ die ZACK-Requests aufgestaut werden?
  -> ZACK mssen nicht aufgestaut werden, weil ein ZACK mit
     hherer File-Position die tiefere bersteuert.
  - Knnen mehrere ZCRCQ ausstehend sein?
    -> Ja. Txwspac = Txwindow/4
       Es wird alle <Txwspac> ein ZCRCQ geschickt, aber erst wenn
       die ZACKs mehr als <Txwindow> im Rckstand sind wird gewartet.
       - Ist das sinnvoll, dass <Txwspac> nur ein viertel von
         <Txwindow> ist?
         - Default fr <Txwindow> ist TXBSIZE - 1K.
           <TXBSIZE> ist blicherweise 32K (oder 16K).
           TXBSIZE definiert die Grsse des File-Read-Buffers in sz.
           -> <Txwspac> is blicherweise 8K.
- Wo verwendet sz output-Flush (TCFLSH)?
     - In <zsendfdata> wenn auf ein ZCRCQ nicht ein ZACK kommt.
     ...
