KERMIT PROTOCOL MANUAL KERMIT PROTOCOL MANUAL KERMIT PROTOCOL MANUAL ________ _______ _ Protocol Version 3 1 Frank da Cruz, Bill Catchings Columbia University Center for Computing Activities New York, New York 10027 29 April 1983 Copyright (C) 1981,1982,1983 Trustees of Columbia University in the City of New York __________ __ _______ __ ___ __________ __ ___________ __ ____ __ Permission is granted to any individual or institution to copy or _______________ 1 Present address: Lehman Bros, Kuhn & Loeb, NYC 1 ___ ____ ________ ___ ___ ________ _________ __ __ ______ ___ use this document and the programs described in it, except for __________ __________ ________ explicitly commercial purposes. - 2 - Preface to the Protocol Manual Preface to the Protocol Manual Preface to the Protocol Manual In the second edition, the Kermit manual contained everything -- user's guide, protocol description, appendices describing the operation of various microcom- puters, etc. Due to the proliferation of Kermit implementations, and to the growing number of users who aren't interested in the protocol, the manual has been split in two -- a Users Guide and a Protocol Manual. This is the Protocol Manual. It is intended for use by those who wish to produce a new implemen- tation of Kermit. Readers are assumed to be thoroughly familiar with the Ker- mit Users Guide. In splitting the manual into two parts, some new material was added to each part. This part has a new state table, descriptions of some of the features new to version 2 of the protocol (8-bit quoting, server functions). A minor bug was fixed in the KERMIT.C listing. Version 3 differs from version 2 by al- lowing for optional checksum types and data compression. The version 3 manual also clarifies some minor points that were left unstated in the version 2 manual, and the KERMIT.C listing has been replaced by one for an actual produc- tion UNIX KERMIT. Before attempting to write a new Kermit program, be sure to check with the au- thors to make sure that no one else is working on the same thing, and that you have the latest information. To avoid confusion, the Columbia University DEC-20 implementation of KERMIT should be considered the definitive implementation of the protocol. The true test of any new Kermit is whether it can talk to Columbia DEC-20 Kermit. KERMIT is distributed from Columbia University on magnetic tape. Complete or- dering instructions are in the Kermit Users Guide. KERMIT Distribution Columbia University Center for Computing Activities 7th Floor, Watson Laboratory 612 West 115th Street New York, NY 10025 No warranty of the software nor of the accuracy of the documentation surround- ing it is expressed or implied, and neither the authors nor Columbia University acknowledge any liability resulting from program or documentation errors. - 3 - CHAPTER 1 CHAPTER 1 CHAPTER 1 THE KERMIT PROTOCOL THE KERMIT PROTOCOL THE KERMIT PROTOCOL This manual describes the KERMIT protocol. It is assumed that you understand the purpose and operation of the Kermit file transfer facility, described in ______ _____ _____ the Kermit Users Guide. 1.1. Background 1.1. Background 1.1. Background The KERMIT file transfer protocol is intended for use in an environment where there is a diverse mixture of computers of all types -- micros, workstations, laboratory computers, timesharing systems. All these systems need have in com- mon is the ability to communicate in ASCII over ordinary serial telecommunica- tion lines. KERMIT makes no assumptions about the speed, flow control, or duplex of the systems involved. Various protocols for transferring files over TTY lines already existed when KERMIT was developed. Unlike many of its predecessors, KERMIT is not truly full duplex or "asynchronous"; in order to accommodate itself to half-duplex systems (and to the DEC-20, with its "Achilles Heel" front end), it does not "stack" packets and it does not send long packets; it normally waits for a reply to each packet it sends. Thus transfer rates cannot be achieved that are as high as those for truly asynchronous full duplex protocols. Nevertheless, KERMIT runs at 50-80% efficiency (user bits / baud rate). Its half duplex mode of communication allows it to be implemented on computers with either full or half duplex terminal communications, and in fact it presently runs on IBM mainframes (half duplex), UNIX systems (full duplex, but line-oriented ), and on character-oriented full duplex systems (TOPS-20, most micros). The primary design goals of KERMIT are reliability, portability, simplicity, and file transparency (for textual files). Efficiency has been sacrificed to some extent for portability (especially to work for half duplex systems) and for simplicity. Complex approaches (like multiprocessing/scheduling schemes, multiplexed physical links, multichannel logical links, etc) were were avoided so that the KERMIT specification can be easily implemented on any computer, and that the person who works from the specification has some chance of understand- ing it. The procedure for running KERMIT tends to be complicated because it is intended for individual, rather than system, use. Host servers, embedded signon procedures, etc, are not required so that use of KERMIT will be relatively uniform between any two systems, and any ordinary user can establish a connec- tion. Actually, version 2 of the protocol simplifies the "user interface" a great deal by allowing a server or "slave" mode of operation -- the server is not a permanent feature of the host, but is cranked up by the user as needed. But once running on the user's line, the server simplifies things a great deal. In the following sections, we define some terminology, discuss some minimal re- quirements for host systems, describe the packet format and the protocol. A state table for the protocol is given, and a listing is provided of an actual working implementation of the Kermit "Kernel" in the C language. - 4 - 1.2. Overview 1.2. Overview 1.2. Overview The KERMIT protocol is specifically designed for character-oriented transmis- sion over serial telecommunication lines. The design allows for the restric- tions and peculiarities of the medium and the requirements of diverse operating systems -- buffering, duplex, parity, character set, file organization, etc. The service provided is minimal -- no attempt is made at an "integrated" link between two systems. KERMIT provides terminal connection and file transfer, period. File transfer is accomplished by sending packets back and forth; the sender sends file names, file contents, and control information; the receiver acknowledges (positively or negatively) each packet. The packets have a layered design, in keeping with the ANSI and ISO philosophy, with the outermost fields used by the data link layer to verify data integrity, the next by the session layer to verify continuity, and the data itself at the highest level to perform any transformations that may be necessary. 1.3. Definitions 1.3. Definitions 1.3. Definitions _______ _____ All numbers in the following text are expressed in octal (base 8) notation un- less otherwise specified. _____ _________ __________ ASCII_character_mnemonics: NUL Null, idle, ASCII character 0. SOH Start-of-header, ASCII character 1. SP Space, blank, ASCII 40. CR Carriage return, ASCII 15. LF Linefeed, ASCII 12. CRLF A carriage-return linefeed sequence. DEL Delete, rubout, ASCII 177. _______ _________ A control__character is considered to be any ASCII character in the range 0 through 37, or the DEL character (177). _________ _____ _________ A printable_ASCII_character is considered to be any character in the range 40 (SP) through 176 (tilde). _________ Several functions are useful in the description of the protocol and in the program example. The machine that Kermit runs on need operate only on integer data, so these are functions that operate upon the numeric value of single AS- CII characters. _ char(x) = x+40 Transforms the integer x, which is assumed to lie in the range 0 to 136, into a printable ASCII character; 0 becomes SP, 1 be- comes "!", etc. unchar(x) = x-40 _ Transforms the character x, which is assumed to be in the printable range (SP through tilde), into an integer in the range 0 to 136. - 5 - ctl(x) = x XOR 100 Maps between control characters and their printable represen- 2 _ tations, preserving the high-order bit . If x is a control character, then x = ctl(ctl(x)) that is, the same function is used to controllify and uncon- trollify. The argument is assumed to be a true control charac- ter (0 to 37), or the result of applying CTL to a true control character (i.e. 100 to 137). The transformation is the ex- pected one, viz. ^A becomes A and vice versa. ___ ACK stands for "Acknowledge", a packet that acknowledges receipt of another packet. Not to be confused with the ASCII character ACK. ___ NAK stands for "Negative Acknowledge". A packet that says a packet was received in bad condition (e.g. bad checksum), the wrong packet was received, or an expected packet was never received. Not to be confused with the ASCII character NAK. 1.4. Host System Requirements 1.4. Host System Requirements 1.4. Host System Requirements In order to run on as many different systems as possible, KERMIT makes the fol- lowing assumptions: 1. All printable ASCII characters are acceptable as input to the host and will not be transformed in any way. 2. A single nonprintable ASCII character can be used for synchroniza- tion. The character is normally Control-A (SOH, ASCII 1), but can be redefined. 3. If a host requires a line terminator for terminal input, that ter- minator must be a single ASCII character, presumably a control character such as CR or LF. 4. When using a job's controlling terminal for file transfer, the sys- tem must allow the KERMIT program to set the terminal to half duplex, infinite width (no "wraparound" or CRLF insertion by the operating system), and no translation of incoming or outgoing characters (for instance, raising lowercase letters to uppercase, _______________ 2 The high order bit is normally the parity bit, but Kermit uses this bit as data in order to do 8-bit transmission for binary files when the systems permit. - 6 - transforming control characters to printable sequences, etc). In short, the terminal must be put in "raw" mode, and, hopefully, res- tored afterwards to normal operation. 5. The host's terminal input buffer is at least long enough to receive the longest ACK packet (the ACK to the send-initiate packet can be 10 or 12 characters long). 6. If a host requires padding, the padding character is in the range ASCII 0-37 or ASCII 177. 7. Both communicating hosts are capable of 8-bit terminal i/o if Kermit is to transfer binary files. The last item may be circumvented for those hosts which insist upon having a parity bit; version 2 of Kermit provides a new 8-bit quoting mechanism, which is described later. ___ KERMIT does not assume: 1. Anything about baud rate. 2. That the host can do XON/XOFF or any other kind of flow control. This kind of flow control can be initiated behind Kermit's back by commands to the host computers. If the hosts support any kind of flow control, then it should be used if possible, since it will cut down on retransmission due to buffering problems. 3. That the host is capable of full duplex operation. Any mixture of half and full duplex hosts is supported. 1.5. Data Representation 1.5. Data Representation 1.5. Data Representation For transmission between unlike systems, files must be assigned to either of _________ ______ two catagories: printable or binary. A printable file is defined to be one that will make sense on the foreign system -- a document, program source, tex- tual data, etc. A binary file is one that will (and probably can) not make sense on the foreign system -- an executable program, numbers stored in inter- nal format, etc. When binary files are transmitted to an unlike system, it is important only that they can be brought back to the original system (or one like it) intact; no special conversions are necessary during transmission. But for printable files to be transferred in a useful fashion, there must be a standard way to represent them during transmission. KERMIT's standard is simple: ASCII characters, with "logical records" (lines) delimited by CRLFs. All characters are transmitted and interpreted in 7- or 8-bit ASCII. If any conversion is necessary to or from ASCII it is the responsibility of the non- ASCII host do so. It is assumed that the computers implementing this protocol can transmit and receive the printable ASCII characters between 040 and 176 (octal), i.e. space through tilde, without translation. Similarly, it is the responsibility of systems that do not store printable files as sequences of - 7 - lines delimited by CRLFs to perform the necessary conversions upon input and output. For instance, IBM mainframes might strip trailing blanks on output and add them back on input; UNIX would prepend a CR to its normal record ter- minator, LF, upon output and discard it upon input. Since computers can't be expected to distinguish a printable file from a binary file -- especially one originating from an unlike system -- the user will generally have to give a command to Kermit to tell it whether to perform these conversions. Any ASCII control characters (0-37 octal) and DEL (177 octal) are preceded by a special quote character and mapped to characters in the printable range on transmission and unquoted and unmapped upon receipt. This is to prevent un- predicatable actions that can occur when the remote host receives raw control characters (for instance, it might interpret them as flow control signals). For binary files, eight bit character transmission is permissible as long as the two Kermit programs involved can control the value of the parity bit. In that case, the 8th bit of a transmitted character will match that of the original data byte, after control-quoting has been done. When one or both sides cannot control the parity bit, a special prefix character may be prepended, as described below. Data compression is also allowed. A special prefix character will denote that the following character is a repeat count, and the next character is the one to be repeated. These prefix characters can be combined in various ways; for instance a control _ character with its 8th bit set may be repeated n times, the repeat prefix may be quoted as a data character, etc. See the appendix for a listing of the ASCII alphabet, with EBCDIC equivalents. 1.6. Packet Format 1.6. Packet Format 1.6. Packet Format The KERMIT protocol is built around exchange of packets of the following for- mat: _____ or where all fields consist of ASCII characters, and: ____ mark Is a synchronization character to mark the beginning of the packet. In standard KERMIT, this is SOH (Control-A, ASCII 1), but may be redefined. _____ count The number of ASCII characters within the packet that follow this - 8 - field, in other words the packet length minus two. Since this number is transformed to a single character via the char function, packet character counts of 0 to 94 (decimal) are permitted, and 96 (decimal) is the maximum total packet length. Does not include end of line or padding characters, which are outside the packet and are strictly for the benefit of the operating system. ___ seq The packet sequence number, modulo 100, ranging from 0 to 77 (octal). Sequence numbers "wrap around" to 0 after each group of 64 (decimal) packets. ____ type The packet type, a single ASCII character, one of the following: D Data packet Y Acknowledge (ACK) N Negative acknowledge (NAK) S Send initiate B Break transmission F File header Z End of file (EOF) E Error The following are new packet types for version 2 of the protocol. Not all of them have been implemented, and some may never be at all, but their use should be reserved. These packet types have been added to allow for a "Kermit Server", which receives all its commands from the other Kermit, rather than directly from the user. R Receive Initiate. Ask the server to send the specified file(s). C Host Command. The data field contains a string to be executed as a command by the host. G Generic Kermit Command. Single character in data field (possibly followed by operands, shown in {braces}, optional fields in [brackets]) specifies the command: I Login {user~password~account} C Connect, Change working directory {directory[~password]} L Logout, Bye F Finish (Shut down the server, but don't logout). D Directory [{filespec}] U Disk Usage Query E Erase (delete) {filespec} T Type {filespec} S Submit for batch processing {filespec~options} P Print {filespec~options} W Who's logged in? (Finger) [{user ID}] M Send a Message {user or line ID} H Help Q Server Status Query Note that tilde ("~") is chosen to delimit fields when a command takes more than one operand, on the assumption that tildes are not - 9 - found in user IDs, passwords, directory names, or account desig- nators on systems that might support Kermit servers. X Text header. Allows transfer of text to the other Kermit's screen in response to a generic or host command. This works just like file transfer except that the destination "device" is the screen rather than a file. ____ data The "contents" of the packet, if any contents are required in the given type of packet, interpreted according to the packet type. Nonprintable ASCII characters (and possibly 8-bit and/or repeated characters) are quoted with prefix characters and suitably transformed. Quoted or prefixed sequences may not be broken across packets. Logical records in printable files are delimited with quoted CRLFs. Any quote charac- ters are included in the count. _____ check A block check on the characters in the packet between, but not includ- ing, the mark and the checksum itself, taken modulo 100 (octal). The check for each packet is computed by both hosts, and must agree if a packet is to be accepted. There are presently 3 types of checks (bit 0 is the least significant): ________ 1. Single-character arithmetic sum (REQUIRED); only six bits of the arithmetic sum are included. In order that all the bits of each character contribute to this quantity, the bits 6 and 7 of the final value are added to the quantity formed by _ bits 0-5. Thus if s is the arithmetic sum of the ASCII characters, then chksum = (s + ((s AND 300)/100)) AND 77 The final result is transformed by CHAR. This is the default block check, and all Kermits must be capable of per- forming it. 2. Two-character arithmetic sum (optional). Bits 6-11 form the first character (via CHAR), bits 0-5 form the second (also via CHAR). 3. Three-character 16-bit CRC-CCITT (optional). The 16-bit CRC 16 12 5 _ _ _ formed from the generating polynomial X +X +X +1 is par- celled into three printable characters, via CHAR: bits 12-15 in the first, 6-11 in the second, and 0-5 in the third. This option will be described in greater detail should it ever actually be implemented. The single-character checksum has proven quite adequate in practice. The other options can be used only if both sides agree to do so. Any line terminator that may be required by the host may be appended to the packet; this is carriage return (ASCII 15) by default. Line terminators are - 10 - not considered part of the packet, and are not accounted for in the count or checksum. Terminators are not necessary to the protocol, and are invisible to it, as are any characters that may appear between packets. If a host cannot do single character input from a TTY line, then a terminator will be required for that host. The terminator can be specified in the initial connection protocol. The contents of the data field for each type of packet may vary depending upon the state of the transmission. For instance, the acknowledgement to a send-in- itiate packet contains various parameters (timing and buffer-size information, etc.), whereas when in file-receiving state, the acknowledgment packet contains no data. 1.7. Smart and Dumb Kermits 1.7. Smart and Dumb Kermits 1.7. Smart and Dumb Kermits A "smart" Kermit is one that is capable of timing out; a "dumb" Kermit is one that cannot. A timeout feature is desirable so that Kermit won't wait forever for expected data to arrive. While timing out lets you detect when the remote system or program crashes, the most important use of timeouts is to prevent deadlocks, such as might happen when all or part of a packet is lost in trans- mission (leaving the receiving Kermit waiting for the packet that never ar- rived, and the sending Kermit for the ACK that is never sent). In any conversation between two Kermits, one smart Kermit is sufficient to prevent deadlocks. Two smart Kermits also work reliably together. Two dumb Kermits, however, must be watched carefully. The local Kermit should keep some sort of running confirmation on the screen, so that the user can detect when transmission stops. For instance, microcomputer Kermits keep the current packet number on the screen, so that the user can watch it changing. Some provision should be made in a dumb Kermit for manual intervention; for in- stance, if input appears at the keyboard while waiting for a packet, then send a NAK for the expected packet or resend the current one. Shared systems which can become sluggish when heavily used should adjust their own timeout intervals on a per-packet basis, based on the system load, so that file transfers won't fail simply because the system was too slow. 1.8. Local and Remote Kermits 1.8. Local and Remote Kermits 1.8. Local and Remote Kermits "Local" refers to the host that has control of the user's terminal; "remote" refers to the other host. "Sending" refers to the host that is sending a file; "receiving" refers the host receiving a file. If the local Kermit is sending, the remote Kermit is receiving. And vice versa. A microcomputer is always in control of the screen, so it can always be con- sidered local. An implementation of Kermit for a multi-terminal system must be able to determine whether it is in control of the terminal or not. In general, if it is sending packets to its controlling terminal (primary output, stdout, TTY:, KB:, or whatever) then it is a remote Kermit; if it is sending packets to an assigned terminal or device (e.g. as specified by the SET LINE command), it is a local Kermit and it should update the screen. - 11 - At initialization, a Kermit program should determine whether it is local or remote and set a flag that can be used later to determine how it updates the screen, handles errors, etc. 1.9. User and Server Kermits 1.9. User and Server Kermits 1.9. User and Server Kermits ______ ______ A Kermit Server is always a remote Kermit, a "slave". Unlike ordinary inter- active Kermits, it does not have a "user interface"; it gets all its commands from another Kermit. Most Kermits are not capable of acting as servers, but when a server is available, it is desirable that all implementations of Kermit know how to talk to it. The server is a concept new to version 2 of the Kermit protocol and differs from earlier Kermits by the addition of several new packet types (Receive Init, Generic Command, Host Command). Kermits that want to talk to servers should implement handling for these new packet types. Old Kermits can still send files to servers, but they have no way to ask a server to send files, and no way to shut down a remote server (other than connecting to it and killing it with some host function like ^C). Note that between transactions, when the server has no tasks pending, it sends out periodic NAKs to prevent a deadlock in case a command was sent to it but was lost. These NAKs can pile up in the local "user" Kermit's input buffer (if it has one), so the user Kermit should be prepared to clear its input buffer before sending a command to a server. 1.10. Initial Connection Protocol 1.10. Initial Connection Protocol 1.10. Initial Connection Protocol The user starts the remote Kermit first via a virtual terminal connection, and then escapes back to the local host and starts or continues the local Kermit. The receiving Kermit waits for a send-init packet from the sending Kermit. It doesn't matter whether the sending Kermit is started before or after the receiving Kermit (if before, the send-init packet will be retransmitted periodically until the receiving Kermit acknowledges it). The data field in the send-init packet is optional; trailing fields can be omitted to accept default values. <8-bit-quote> where: ______ 1. bufsiz The sending Kermit's maximum buffer size. If none specified, the default value of 96 (decimal) is assumed. The receiving Kermit should send packets no longer than this length. ______ 2. timout The number of seconds after which the sending Kermit wishes to be timed out if no packets have been successfully received by the receiving Ker- mit, provided the receiving Kermit is capable of timeouts. If none specified, the receiving Kermit's default is accepted. The normal - 12 - value is in the 5-15 second range. A value of 0 means "don't time me out". This value is taken as a guideline rather than an absolute, and may be adjusted on a per-packet basis by timesharing systems depending upon system load. ____ 3. npad The number of padding characters the sending Kermit needs preceding each packet. Some systems may require padding; for instance, some half duplex systems may need some time to "turn the line around". If none specified, or a value of 0 (ASCII NUL) is specified, no padding is done and the contents of the next field is ignored. ___ 4. pad The character the sending Kermit wants used for padding. Normally NUL (ASCII 0), but some IBM systems want DEL (ASCII 177). If npad is non- zero but pad is omitted, 0 will be used as a padding character. ___ 5. eol The desired line terminator for incoming packets. Only a single con- trol character, transformed by CHAR (not CTL!), is permitted in this field. Hosts cannot specify printable terminators or multi-character terminator sequences. If none specified, carriage return (CR, ASCII 15) is used. _____ 6. quote The printable ASCII character the sending Kermit will use when quoting control characters, in the range 41-76 or 140-176. If none specified, "#" is used. This character is taken literally. ___________ 7. 8-Bit-Quote Specify quoting mechanism for 8-bit quantities. A quoting mechanism is necessary when sending binary files to hosts which prevent use of the 8th bit for data. When elected, the quoting mechanism will be used by ____ both hosts, and the quote character must be in the range 41-76 or 140-176, but different from the control-quoting character. This field is interpreted as follows: Y I agree to 8-bit quoting if you request it. N I will not do 8-bit quoting. & (or any other character in the range 41-76 or 140-176 besides Y and N) I want to do 8-bit quoting using this character (it will be done if the other Kermit puts a Y in this field). The recommended 8th-bit quoting prefix character is "&". ________ ____ Anything Else: 8-bit quoting will not be done. _______ 8. chktype The type of block check. The only values presently allowed in this field are "1", "2", and "3", though future implementations may allow others. These values specify the single- and double-character arith- metic checksums, or the three-character CRC, described above. If any- thing other than "1" or "2", or if this field is omitted, "1" will be used. The sender requests the desired type of checksum in this field; if the receiver replies with the same type in its ACK then the re- quested type will be used, otherwise the single-character arithmetic checksum must be used ("1"). Both sides, of course, must use the same - 13 - checksum type. ______ 9. repeat The prefix character to be used to indicate a repeated character. This can be any printable character other than blank (which denotes no repeat count prefix), but "~" is recommended. Both sides must agree (as they must for the block check type), or else repeat counts will not be done. Groups of 4 identical characters or more may be transmitted more efficiently using a repeat count, though an individual implemen- tation may wish to set a higher threshhold. ________ ______ 10-11. Reserved Fields Sites who wish to add their own parameters to the initial connection negotiation must start at field 12 (decimal). Any intervening fields may be left blank (that is, they may contain the space character). The receiving Kermit responds with an ACK ("Y") packet containing the same in- formation as it applies to itself. From that point, both Kermits are "configured" to communicate with each other. In the case of 8-bit quoting, one side must specify the character to be used, and the other must agree with a "Y" in the same field, but the order in which this occurs does not matter. Similarly for checksums -- if one side requests 2 character checksums and the other side responds with a "1" or with nothing at all, then single-character checksums will be done, since not all implementations can be expected to do 2- character checksums or CRCs. And for repeat counts; if the repeat field of the send-init and the ACK do not agree, repeat processing will not be done. All send-init fields are optional. The data field may be left totally empty. Similarly, intervening fields may be defaulted by setting them to blank. Ker- mit implementations should know what to do in these cases, namely apply ap- propriate defaults. The defaults should be: bufsiz: system dependent npad, pad: 0, no padding. eol: CR (carriage return) quote: the character "#" 8-bit-quote: none, don't do 8-bit quoting chktype: "1", single-character checksum repeat: No repeat count processing Note that there are no prolonged negotiations during this initial connection protocol -- there is one send-init and one ACK in reply. Everything must be settled in this exchange. The very first send-init may not get through if the sending Kermit makes wrong assumptions about the receiving host. For instance, the receiving host may re- - 14 - quire some padding or a special end of line character in order to read the send-init packet. For this reason, there should be SET command parameters to allow the user to specify whatever may be necessary to get the first packet through. When Kermit is running as a server, it is possible for the user side to send a rcv-init packet to it, telling it to fetch some files. Since we can't assume that the two Kermits are running on like systems, the local (user) Kermit must parse the file specification as a character string and let the server to check ___ __ it. If the server likes the filespec, it sends a send-init packet -- not an _______________ acknowledgement! -- to the user, and then behaves as described above. The server may also recognize some kinds of "bureaucratic" packets (containing com- mands to type a file, provide a directory listing, access a directory, etc). In fact, it will sit and listen for packets forever, until it gets one that tells it to shut itself down. 1.11. Prefix Quoting 1.11. Prefix Quoting 1.11. Prefix Quoting Quoting is used for control characters, and may also be used for 8-bit quan- tities or repeat counts. When more than one type of quoting is in effect, a single character can be preceded by more than one quote character. A receiver will never do any kind of quoting, since quoting can only occur in the data field, and the receiver only send ACKs and NAKs with empty or special data fields. Repeat count processing can only be requested by the sender, and will only be used by the sender if the receiver agrees. 8th-bit quoting is a spe- cial case, since it is normally not desirable to use it because it increases both processing and transmission overhead. However, since it is the only mechanism for binary file transfer available to those systems that usurp the parity bit, a receiver must be able to request the sender to do 8th-bit quot- ing, since most senders will not normally do it by default. The following table should clarify Kermit's quoting mechanism: Quoted With _________ ______________ ______ _____ Character Representation Repeat_Count A A ~(A ["(" is ASCII 40 - 32 = 6] ^A #A ~(#A 'A &A ~(&A '^A &#A ~(&#A # ## ~(## '# &## ~(&## & #& ~(#& '& &#& ~(&#& ~ #~ ~(#~ '~ &#~ ~(&#~ A represents any printable character, ^A represents any control character, 'x represents any character with the 8th bit set. The # character is used for control-character quoting, and the & character for 8-bit quoting. The repeat count must always precede any other prefix character. The repeat count is taken literally (after transformation by UNCHAR); for instance "#" and "&" im- - 15 - mediately following a "~" denote repeat counts, not control characters or 8-bit characters. The quote character "#" is most closely bound to the data charac- ter, followed by the 8-bit prefix, followed by the repeat count; in other words, the order should be: repeat prefix and count, 8-bit quote, control ___ quote, the data character itself. To illustrate, note that &#& is not equiv- alent to #&&. And finally, note that: _______ _________ ____ ___ __ ______ ______ _______ Quoting sequences must not be broken across packets. 1.12. The KERMIT Protocol 1.12. The KERMIT Protocol 1.12. The KERMIT Protocol ___________ The protocol is defined over a transaction. A transaction consists of the suc- cessful or unsuccessful transfer of one or more files. An initial connection is made for each transaction, and the connection is broken at the end of a transaction. The machine sending the file(s) transmits a send-initiate packet. Upon ack- nowledgement, a file header packet (containing the file name as data) is sent, followed by as many data packets as necessary to transmit the file. The file is followed by an end of file packet. The sending machine waits for an ack- nowledgment of each packet from the receiving machine. When all the files are transmitted, an end of transmission packet is sent. If a host times out wait- ing for an acknowledgement, it tries to retransmit the unacknowledged packet several times. If a host times out waiting for some other kind of packet, it can send either a NAK packet for the expected packet or another ACK for the last packet it got. If any packet is garbled or lost in transmission (the lat- ter is detected when the sequence number increases by more than 1, modulo 100, the former by a bad checksum), the host that received it sends a NAK for the garbled or missing packet. The prodecure is the same when a Kermit server is involved, except that user may send a receive-initiate packet, which merely requests the server to send back a send-initiate packet, followed by the files requested. A few heuristics are useful: 1. A NAK for the current packet is equivalent to an ACK for the pre- vious packet. This covers the common situation in which a packet is successfully received, and then ACK'd, but the ACK is lost. The ACKing side then times out waiting for the next packet and NAKs it. _ _ The side that receives a NAK for packet n+1 while waiting for an ACK _ _ _ for packet n simply sends packet n+1. _ 2. If packet n arrives more than once, simply ACK it and discard it. This can happen when the first ACK was lost. Resending the ACK is necessary and sufficient -- don't write the packet out to the file, because it's already there! 3. When opening a connection, discard the contents of the line's input buffer before reading or sending the first packet. This is espe- - 16 - cially important if the other side is either in receive mode, or ac- ting as a server, in which case it has been sending out periodic NAKs for your expected SEND-INIT or command packet. If you don't do this, you may find that there are sufficient NAKs to prevent the transfer -- you send a SEND-INIT, read the response, which is an old NAK, so you send another SEND-INIT, read the next old NAK, and so forth, up to the retransmission limit, and give up before getting to the ACKs that are waiting in line behind all the old NAKs. If the number of NAKs is below the cutoff, then each packet may be trans- mitted multiply. 4. Similarly, after reading a packet (successfully or not), you should clear the input buffer. There should be nothing there for you anyway, since the other side must normally wait for you to send your packet in response. Failure to clear the buffer could result in propogation of the repetition of a packet caused by stacked-up NAKs. 1.13. KERMIT Protocol State Table 1.13. KERMIT Protocol State Table 1.13. KERMIT Protocol State Table The KERMIT protocol consists of a set of states, and rules for what to do when changing from one state to another. State changes normally occur based on the type of packets that are sent or received, or errors that may occur. Packets always go back and forth; the sender of a file always sends data packets of some kind (init, header, data) and the receiver always returns ACK or NAK pack- ets. "Smart" Kermits can time out while waiting for a packet. Timeouts have been omitted from the following state table for simplicity, but the action is the same as if the expected packet had been received in bad condition -- it is NAK'd. A local Kermit can print error messages on its own screen. If an error occurs in the remote Kermit, an error message cannot simply be printed at the "terminal" because it will come to the local Kermit in the packet data stream, and will be discarded because it's not a valid packet. Therefore, remote Ker- mits should handle error conditions by sending Error packets containing the text of the error message, and then taking appropriate action, such as breaking transmission with a Break packet. Error conditions generally arise in low level routines which are outside the scope of the state table -- for instance, trying to write onto a full or write-protected disk. Kermit servers always return to "start" state after an error. Here's the state table for version 2 of Kermit; it differs from version 1 only by the addition of the "super state" (which is different for "user" and "server" Kermits). Version 1 always starts out in state S or R. Note that upon entering a given state, a certain kind of packet is either being sent or is expected to arrive -- this is shown on top of the description of that state. As a result of the action, various events may take place; these are shown in the EVENT column. For each event, an appropriate ACTION is taken, and the protocol enters a NEW STATE. - 17 - _____ _____ ______ ___ _____ STATE EVENT ACTION NEW_STATE _____ _____ -- SUPER STATE -- ____ ____ ____ ____ User_Mode_________________________________________________ start Want to send (none) S Want to rcv Send rcv-init R ______ ____ ______ ____ Server_Mode_______________________________________________ start Get send-init (none) R Get rcv-init Find file to send S Can't find file, give error start Get "G" cmd ACK, Execute generic command start Get "C" cmd ACK, Execute host command start (other) Report error start ____ ______ -- SEND STATES -- ____ ____ ____ ______ ____ _________ ______ Send_Send-Init_Packet_____________________________________ S Get NAK,bad ACK (None) S Get good ACK Set remote's parms, open file SF (Other) (None) A ____ ____ ______ ______ ____ ___________ ______ Send_File-Header_Packet___________________________________ SF Get NAK,bad ACK (None) SF Get good ACK Get bufferful of file data SD (Other) (None) A ____ ____ ____ ______ ____ _________ ______ Send_File-Data_Packet_____________________________________ SD Get NAK,bad ACK (None) SD Get good ACK Get bufferful of file data SD (End of file) (None) SZ (Other) (None) A ____ ___ ______ ____ ___ ______ Send_EOF_Packet___________________________________________ SZ Get NAK,bad ACK (None) SZ Get good ACK Get next file to send SF (No more files) (None) SB (Other) (None) A ____ _____ ___ ______ ____ _____ _____ ______ Send_Break_(EOT)_Packet___________________________________ SB Get NAK,bad ACK (None) SB Get good ACK (None) C (Other) (None) A _______ ______ -- RECEIVE STATES -- - 18 - ____ ___ ____ ____ ______ ____ ___ _________ ______ Wait_for_Send-Init_Packet_________________________________ R Get Send-Init ACK w/local parms RF (Other) (None) A ____ ___ ____ ______ ______ ____ ___ ___________ ______ Wait_for_File-Header_Packet_______________________________ RF Get Send-Init ACK w/local parms (previous ACK was lost) RF Get Send-EOF ACK (prev ACK lost) RF Get Break ACK C Get File-Header Open file, ACK RD (Other) (None) A ____ ___ ____ ____ ______ ____ ___ _________ ______ Wait_for_File-Data_Packet_________________________________ RD Get previous packet(D,F) ACK it again RD Get EOF ACK it, close the file RF Get good data Write to file, ACK RD (Other) (None) A ______ ______ __ _______ ___ _________ -- STATES COMMON TO SENDING AND RECEIVING -- C (Send Complete) start A ("Abort") start 1.14. Low-Level Considerations 1.14. Low-Level Considerations 1.14. Low-Level Considerations The preceding state table shows the packet level protocol. When writing a new Kermit, you still must worry about building the packets and getting them in and out of your machine. This work is best done by low level routines with names like "send-packet", "receive-packet", "get-character", "send-character", etc. The packet-level routines -- which do quoting, build checksums, etc -- would be fairly standard in any implementation of Kermit. Low level i/o routines, however, must be customized for each machine or operating system. Some operat- ing systems make i/o very easy, while others require you to pay a lot of atten- tion to small details. The C program in the next section is an example where the operating system (UNIX in this case) does all the work; you send and receive characters simply by using system READ and WRITE functions. A few general low-level considerations are worth mentioning: End of Line If your host does not require a record terminator for terminal input -- that is, if it can "wake up" on every character -- then you don't have to worry about line terminators on in- coming packets; you can just skip over everything between the end of a packet and the beginning of the next one. On the other hand, you must supply whatever terminator the other host requires (it tells you what that is in its send-init packet, or in its acknowledgement to yours). - 19 - Padding Some hosts may require padding, a sequence of "idle characters" (typically NUL or DEL). You have to worry about sending them. You don't have to worry about them on input though, since they come between packets, and will probably have been eaten by some other process or interface anyway (or else why would you need them?). Timeout When doing input on the serial port, it is desirable to get an interrupt to wake you up after a certain amount of time if nothing comes in. Or, if you have a port status register, you can have a loop that looks at it a certain number of times be- fore giving up. Or, you can check both the port and the keyboard each time through the loop, which allows wakeup from hung protocol when the user gives typein. Quoting Once characters have been successfully received, quoted control characters, prefixed 8-bit bytes, or repeat-count sequences must be fixed. Similarly, the quoting transformations must be done when filling a packet, before sending it out or computing the block check. Parity Character-level routines must know how to handle the parity bit. This is normally controlled by the settings of some flags that say whether incoming characters have data or parity in the 8th bit, and whether the 8th bit must be used for parity on outgoing characters, and if so, what kind of parity. Handshake When dealing with record-oriented or half duplex systems, you may have to worry about line turnaround. Again, the user nor- mally sets a special flag, which should be checked before send- ing a packet. For instance, when communicating with an IBM host, a packet cannot be sent until you have an XON. Local file i/o In addition to port i/o, each Kermit must know how to do i/o to its own file structure. The DEC-20 has to worry about whether the file is to be opened in 8-bit or 7-bit mode, and should make sure not to try to send certain kinds of files (directories, archived files, RMS files, etc). IBM VM/CMS Ker- mit must worry about LRECL, BLKSIZE, RECFM, and so on. Micros must worry about ^Zs at end of file, and funny files created by word processing software. Most systems have to worry about conflicts arising when an incoming file has the same name as an existing file. Terminal emulation When doing terminal emulation (although this is outside the protocol), Kermit must worry about whether to echo characters locally or to let the host do it; it must do whatever must be done with parity bits in both directions; it must interpret screen control codes; it must watch out for the escape charac- ter. - 20 - Here, for instance, is more or less what a micro has to do to send a packet (which is already built, with all quoting done): 1. Loop thru all chars in packet, building checksum. 2. Add eol if required. 3. Padding? Yes, send n pad chars. 4. Sending to IBM? Yes, wait for XON. 5. Timed out? Whoops, give up. 6. Send each character. To send a character: 1. Get port status. 2. Ready? No, repeat previous step. 3. Set parity bit appropriately. 4. Output the character. Getting a character: 1. Get port status. 2. If no character, then check console. 3. If nothing either place, back to step 1. 4. Got char from port. Doing parity? Yes, turn it off. 5. Dispatch appropriately. - 21 - CHAPTER 2 CHAPTER 2 CHAPTER 2 THE KERMIT PROGRAM THE KERMIT PROGRAM THE KERMIT PROGRAM What follows is a listing of a real production version of KERMIT, written in the C language, that runs under the UNIX operating system. This program imple- ments version 1 of the protocol, and even that not entirely (for instance, er- ror packets are not sent or processed). Only the most rudimentary command par- ______ _____ _____ ser is provided; the Kermit Users Guide shows the commands that more advanced Kermits have. It must be emphasized that this is a bare minimum implementation of Kermit. Anyone writing a new Kermit from scratch is encouraged to look at the source for one of the more advanced implementations -- Kermit-20, Kermit-80, Kermit-86 -- as a model. Although you may not understand the language they're written in, there are profuse comments that can be useful. /* * K e r m i t File Transfer Utility * * UNIX Kermit, Columbia University, 1981, 1982, 1983 * Bill Catchings, Bob Cattani, Chris Maio, Frank da Cruz * * usage: kermit [csr][dlbe line baud escapechar] [f1 f2 ...] * * where c=connect, s=send [files], r=receive, d=debug, * l=tty line, b=baud rate, e=escape char (decimal ascii code). * For "host" mode Kermit, format is either "kermit r" to * receive files, or "kermit s f1 f2 ..." to send f1 .. fn. * */ #include /* Standard UNIX definitions */ #include #include #include /* Conditional Compilation: 0 means don't compile it, nonzero means do */ #define UNIX 0 /* Conditional compilation for UNIX */ #define TOPS_20 1 /* Conditional compilation for TOPS-20 */ #define VAX_VMS 0 /* Ditto for VAX/VMS */ #define IBM_UTS 0 /* Ditto for Amdahl UTS on IBM systems */ /* Symbol Definitions */ - 22 - #define MAXPACK 94 /* Maximum packet size */ #define SOH 1 /* Start of header */ #define SP 32 /* ASCII space */ #define CR 015 /* ASCII Carriage Return */ #define DEL 127 /* Delete (rubout) */ #define CTRLD 4 #define BRKCHR CTRLD /* Default escape character for CONNECT */ #define MAXTRY 5 /* Times to retry a packet */ #define MYQUOTE '#' /* Quote character I will use */ #define MYPAD 0 /* Number of padding characters I will need */ #define MYPCHAR 0 /* Padding character I need */ #define MYEOL '\n' /* End-Of-Line character I need */ #define MYTIME 5 /* Seconds after which I should be timed out */ #define MAXTIM 20 /* Maximum timeout interval */ #define MINTIM 2 /* Minumum timeout interval */ #define TRUE -1 /* Boolean constants */ #define FALSE 0 /* Global Variables */ int size, /* Size of present data */ n, /* Message number */ rpsiz, /* Maximum receive packet size */ spsiz, /* Maximum send packet size */ pad, /* How much padding to send */ timint, /* Timeout for foreign host on sends */ numtry, /* Times this packet retried */ oldtry, /* Times previous packet retried */ fd, /* File pointer of file to read/write */ remfd, /* File pointer of the host's tty */ image, /* -1 means 8-bit mode */ remspd, /* Speed of this tty */ host, /* -1 means we're a host-mode kermit */ debug; /* -1 means debugging */ char state, /* Present state of the automaton */ padchar, /* Padding character to send */ eol, /* End-Of-Line character to send */ escchr, /* Connect command escape character */ quote, /* Quote character in incoming data */ **filelist, /* List of files to be sent */ *filnam, /* Current file name */ recpkt[MAXPACK], /* Receive packet buffer */ packet[MAXPACK]; /* Packet buffer */ - 23 - struct sgttyb rawmode, /* Host tty "raw" mode */ cookedmode, /* Host tty "normal" mode */ remttymode; /* Assigned tty line "raw" mode */ jmp_buf env; /* Environment ptr for timeout longjump */ /* * m a i n * * Main routine - parse command and options, set up the * tty lines, and dispatch to the appropriate routine. */ main(argc,argv) int argc; /* Character pointer for */ char **argv; /* command line arguments */ { char *remtty,*cp; /* tty for CONNECT, char pointer */ int speed, cflg, rflg, sflg; /* speed of assigned tty, */ /* flags for CONNECT, RECEIVE, SEND */ if (argc < 2) usage(); /* Make sure there's a command line. */ cp = *++argv; argv++; argc -= 2; /* Set up pointers to args */ /* Initialize this side's SEND-INIT parameters */ eol = CR; /* EOL for outgoing packets */ quote = MYQUOTE; /* Standard control-quote char "#" */ pad = 0; /* No padding */ padchar = NULL; /* Use null if any padding wanted */ speed = cflg = sflg = rflg = 0; /* Turn off all parse flags */ remtty = 0; /* Default is host (remote) mode */ image = UNIX; /* Default to 8-bit mode for UNIX, */ /* 7-bit CRLF mode for others */ escchr = BRKCHR; /* Default escape character */ - 24 - while ((*cp) != NULL) /* Get a character from the cmd line */ switch (*cp++) /* Based on what the character is, */ { /* do one of the folloing */ case '-': break; /* Ignore dash (UNIX style) */ case 'c': cflg++; break; /* C = CONNECT command */ case 's': sflg++; break; /* S = SEND command */ case 'r': rflg++; break; /* R = RECEIVE command */ case 'e': if (argc--) /* E = specify escape char */ escchr = atoi(*argv++); /* as ascii decimal number */ else usage(); if (debug) fprintf(stderr,"escape char is ascii %d\n",escchr); break; case 'l': if (argc--) /* L = specify tty line to use */ remtty = *argv++; else usage(); if (debug) fprintf(stderr,"line %s\n",remtty); break; #if UNIX /* This part only for UNIX systems */ case 'b': if (argc--) speed = atoi(*argv++); /* Set baud rate */ else usage(); if (debug) fprintf(stderr,"speed %d\n",speed); break; case 'i': image = TRUE; break; /* Image (8-bit) mode */ #endif /* UNIX */ case 'd': debug = TRUE; break; /* Debug mode */ } /* Done parsing */ if ((cflg+sflg+rflg) != 1) usage(); /* Only one command allowed */ remfd = 0; /* Start out as a host (remote) */ host = TRUE; if (remtty) /* If another tty was specified, */ { remfd = open(remtty,2); /* open it */ if (remfd < 0) /* check for failure */ { fprintf(stderr,"Kermit: cannot open %s\n",remtty); exit(-1); /* Failed, quit. */ } host = FALSE; /* Opened OK, flag local (not host) */ } /* Put the tty(s) into the correct modes */ - 25 - gtty(0,&cookedmode); /* Save current mode for later */ gtty(0,&rawmode); rawmode.sg_flags |= (RAW|TANDEM); rawmode.sg_flags &= ~(ECHO|CRMOD); gtty(remfd,&remttymode); /* If local kermit, get mode of */ /* assigned tty */ remttymode.sg_flags |= (RAW|TANDEM); remttymode.sg_flags &= ~(ECHO|CRMOD); #if UNIX /* Speed changing for UNIX only */ if (speed) /* User specified a speed? */ { switch(speed) /* Get internal system code */ { case 110: speed = B110; break; case 150: speed = B150; break; case 300: speed = B300; break; case 1200: speed = B1200; break; case 2400: speed = B2400; break; case 4800: speed = B4800; break; case 9600: speed = B9600; break; default: fprintf(stderr,"bad line speed\n"); } remttymode.sg_ispeed = speed; remttymode.sg_ospeed = speed; } #endif /* UNIX */ if (remfd) stty(remfd,&remttymode); /* Put asg'd tty in raw mode */ /* All set up, now execute the command that was given. */ if (cflg) connect(); /* CONNECT command */ if (sflg) /* SEND command */ { if (argc--) filnam = *argv++; /* Get file to send */ else usage(); filelist = argv; if (host) stty(0,&rawmode); /* Put tty in raw mode if remote */ if (sendsw() == FALSE) /* Send the file(s) */ printf("Send failed.\n"); /* Report failure */ else /* or */ printf("OK\n"); /* success */ if (host) stty(0,&cookedmode); /* Restore tty */ } - 26 - if (rflg) /* RECEIVE command */ { if (host) stty(0,&rawmode); /* Put tty in raw mode if remote */ if (recsw() == FALSE) /* Receive the file */ printf("Receive failed.\n"); /* Report failure */ else /* or */ printf("OK\n"); /* success */ if (host) stty(0,&cookedmode); /* Restore tty */ } } usage() /* Give message if user makes */ { /* a mistake in the command */ fprintf(stderr, "usage: kermit [csr][di][lbe] [line] [baud] [esc char] [f1 f2 ...]\n"); exit(); } /* * s e n d s w * * Sendsw is the state table switcher for sending * files. It loops until either it finishes, or * an error is encountered. The routines called by * sendsw are responsible for changing the state. * */ sendsw() { char sinit(),sfile(),seof(),sdata(),sbreak(); state = 'S'; /* Send initiate is the start state */ n = 0; /* Initialize message number */ numtry = 0; /* Say no tries yet */ while(TRUE) /* Do this as long as necessary */ { switch(state) { case 'D': state = sdata(); break; /* Data-Send state */ case 'F': state = sfile(); break; /* File-Send */ case 'Z': state = seof(); break; /* End-of-File */ case 'S': state = sinit(); break; /* Send-Init */ case 'B': state = sbreak(); break; /* Break-Send */ case 'C': return (TRUE); /* Complete */ case 'A': return (FALSE); /* "Abort" */ default: return (FALSE); /* Unknown, fail */ } } } - 27 - /* * s i n i t * * Send Initiate: Send my parameters, get other side's back. */ char sinit() { int num, len; /* Packet number, length */ if (debug) fprintf(stderr,"sinit\n"); if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */ spar(packet); /* Fill up with init info */ if (debug) fprintf(stderr,"n = %d\n",n); #if UNIX if (host) /* Clear any pending input */ ioctl(); /* like stacked-up NAKs */ else ioctl(remfd,TIOCFLUSH,0); #endif /* UNIX */ spack('S',n,6,packet); /* Send an S packet */ switch(rpack(&len,&num,recpkt)) /* What was the reply? */ { case 'N': return(state); /* NAK */ case 'Y': /* ACK */ if (n != num) return(state); /* If wrong ACK, stay in S state */ rpar(recpkt); /* Get other side's init info */ if (eol == 0) eol = '\n'; /* Check and set defaults */ if (quote == 0) quote = '#'; /* Control-prefix quote */ numtry = 0; /* Reset try counter */ n = (n+1)%64; /* Bump packet count */ if (debug) fprintf(stderr,"Opening %s\n",filnam); fd = open(filnam,0); /* Open the file to be sent */ if (fd < 0) return('A'); /* if bad file descriptor, give up */ if (!host) printf("Sending %s\n",filnam); return('F'); /* OK, switch state to F */ case FALSE: return(state); /* Receive failure, stay in S state */ default: return('A'); /* Anythig else, just "abort" */ } } /* * s f i l e * * Send File Header. */ - 28 - char sfile() { int num, len; /* Packet number, length */ if (debug) fprintf(stderr,"sfile\n"); if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */ for (len=0; filnam[len] != '\0'; len++); /* Add up the length */ #if UNIX /* Don't know why this is here */ len++; /* Add 1 */ #endif /* But leaves an extra null */ spack('F',n,len,filnam); /* Send an F packet */ switch(rpack(&len,&num,recpkt)) /* What was the reply? */ { case 'N': /* NAK, just stay in this state, */ if (n != (num=(--num<0)?63:num)) /* unless NAK for next packet, */ return(state); /* which is just like an ACK */ /* for this packet, fall thru to... */ case 'Y': /* ACK */ if (n != num) return(state); /* If wrong ACK, stay in F state */ numtry = 0; /* Reset try counter */ n = (n+1)%64; /* Bump packet count */ size = bufill(packet); /* Get first data from file */ return('D'); /* Switch state to D */ case FALSE: return(state); /* Receive failure, stay in F state */ default: return('A'); /* Something esle, just "abort" */ } } /* * s d a t a * * Send File Data */ char sdata() { int num, len; /* Packet number, length */ if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */ spack('D',n,size,packet); /* Send a D packet */ - 29 - switch(rpack(&len,&num,recpkt)) /* What was the reply? */ { case 'N': /* NAK, just stay in this state, */ if (n != (num=(--num<0)?63:num)) /* unless NAK for next packet, */ return(state); /* which is just like an ACK */ /* for this packet, fall thru to... */ case 'Y': /* ACK */ if (n != num) return(state); /* If wrong ACK, fail */ numtry = 0; /* Reset try counter */ n = (n+1)%64; /* Bump packet count */ if ((size = bufill(packet)) == EOF) /* Get data from file */ return('Z'); /* If EOF set state to that */ return('D'); /* Got data, stay in state D */ case FALSE: return(state); /* Receive failure, stay in D */ default: return('A'); /* Anything else, "abort" */ } } /* * s e o f * * Send End-Of-File. */ char seof() { int num, len; /* Packet number, length */ if (debug) fprintf(stderr,"seof\n"); if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */ spack('Z',n,0,packet); /* Send a 'Z' packet */ if (debug) fprintf(stderr,"seof1 "); switch(rpack(&len,&num,recpkt)) /* What was the reply? */ { case 'N': /* NAK, fail */ if (n != (num=(--num<0)?63:num)) /* ...unless for previous packet, */ return(state); /* in which case, fall thru to ... */ case 'Y': /* ACK */ if (debug) fprintf(stderr,"seof2 "); if (n != num) return(state); /* If wrong ACK, hold out */ numtry = 0; /* Reset try counter */ n = (n+1)%64; /* and bump packet count */ if (debug) fprintf(stderr,"closing %s, ",filnam); close(fd); /* Close the input file */ if (debug) fprintf(stderr,"ok, getting next file\n"); if (gnxtfl() == FALSE) /* No more files go? */ return('B'); /* if not, break, EOT, all done */ if (debug) fprintf(stderr,"new file is %s\n",filnam); return('F'); /* More files, switch state to F */ - 30 - case FALSE: return(state); /* Receive failure, stay in state Z */ default: return('A'); /* Something else, "abort" */ } } /* * s b r e a k * * Send Break (EOT) */ char sbreak() { int num, len; /* Packet number, length */ if (debug) fprintf(stderr,"sbreak\n"); if (numtry++ > MAXTRY) return('A'); /* If too many tries "abort" */ spack('B',n,0,packet); /* Send a B packet */ switch (rpack(&len,&num,recpkt)) /* What was the reply? */ { case 'N': /* NAK, fail */ if (n != (num=(--num<0)?63:num)) /* ...unless for previous packet, */ return(state); /* in which case, fall thru to ... */ case 'Y': /* ACK */ if (n != num) return(state); /* If wrong ACK, fail */ numtry = 0; /* Reset try counter */ n = (n+1)%64; /* and bump packet count */ return('C'); /* switch state to Complete */ case FALSE: return(state); /* Receive failure, stay in state B */ default: return ('A'); /* Other, "abort" */ } } /* * r e c s w * * This is the state table switcher for receiving files. */ recsw() { char rinit(),rdata(),rfile(); /* Use these procedures */ state = 'R'; /* Receive is the start state */ n = 0; /* Initialize message number */ numtry = 0; /* Say no tries yet */ - 31 - while(TRUE) switch(state) /* Do until done */ { case 'D': state = rdata(); break; /* Data receive state */ case 'F': state = rfile(); break; /* File receive state */ case 'R': state = rinit(); break; /* Send initiate state */ case 'C': return(TRUE); /* Complete state */ case 'A': return(FALSE); /* "Abort" state */ } } /* * r i n i t * * Receive Initialization */ char rinit() { int len, num; /* Packet length, number */ if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */ switch(rpack(&len,&num,packet)) /* Get a packet */ { case 'S': /* Send-Init */ rpar(packet); /* Get the other side's init data */ spar(packet); /* Fill up packet with my init info */ spack('Y',n,6,packet); /* ACK with my parameters */ oldtry = numtry; /* Save old try count */ numtry = 0; /* Start a new counter */ n = (n+1)%64; /* Bump packet number, mod 64 */ return('F'); /* Enter File-Send state */ case FALSE: return (state); /* Didn't get a packet, keep waiting */ default: return('A'); /* Some other packet type, "abort" */ } } /* * r f i l e * * Receive File Header */ char rfile() { int num, len; /* Packet number, length */ - 32 - if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */ switch(rpack(&len,&num,packet)) /* Get a packet */ { case 'S': /* Send-Init, maybe our ACK lost */ if (oldtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */ if (num == ((n==0)?63:n-1)) /* Previous packet, mod 64? */ { /* Yes, ACK it again */ spar(packet); /* with our Send-Init parameters */ spack('Y',num,6,packet); /* ... */ numtry = 0; /* Reset try counter */ return(state); /* Stay in this state */ } else return('A'); /* Not previous packet, "abort" */ case 'Z': /* End-Of-File */ if (oldtry++ > MAXTRY) return('A'); if (num == ((n==0)?63:n-1)) /* Previous packet, mod 64? */ { /* Yes, ACK it again. */ spack('Y',num,0,0); numtry = 0; return(state); /* Stay in this state */ } else return('A'); /* Not previous packet, "abort" */ case 'F': /* File Header, */ if (num != n) return('A'); /* which is what we really want */ /* The packet number must be right */ if (!getfil(packet)) /* Try to open a new file */ { fprintf(stderr,"Could not create %s\n"); /* Give up if can't */ return('A'); } else /* OK, give message */ if (!host) printf("Receiving %s\n",packet); spack('Y',n,0,0); /* Acknowledge the file header */ oldtry = numtry; /* Reset try counters */ numtry = 0; /* ... */ n = (n+1)%64; /* Bump packet number, mod 64 */ return('D'); /* Switch to Data state */ case 'B': /* Break transmission (EOT) */ if (num != n) return ('A'); /* Need right packet number here */ spack('Y',n,0,0); /* Say OK */ return('C'); /* Go to complete state */ case FALSE: return(state); /* Couldn't get packet, keep trying */ default: return ('A'); /* Some other packet, "abort" */ } } - 33 - /* * r d a t a * * Receive Data */ char rdata() { int num, len; /* Packet number, length */ if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */ switch(rpack(&len,&num,packet)) /* Get packet */ { case 'D': /* Got Data packet */ if (num != n) /* Right packet? */ { /* No */ if (oldtry++ > MAXTRY) return('A'); /* If too many tries, give up */ if (num == ((n==0)?63:n-1)) /* Else check packet number */ { /* Previous packet again? */ spack('Y',num,6,packet); /* Yes, re-ACK it */ numtry = 0; /* Reset try counter */ return(state); /* Stay in D, don't write out data! */ } else return('A'); /* sorry wrong number */ } /* Got data with right packet number */ bufemp(packet,fd,len); /* Write the data to the file */ spack('Y',n,0,0); /* Acknowledge the packet */ oldtry = numtry; /* Reset the try counters */ numtry = 0; /* ... */ n = (n+1)%64; /* Bump packet number, mod 64 */ return('D'); /* Remain in data state */ case 'F': /* Got a File Header */ if (oldtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */ if (num == ((n==0)?63:n-1)) /* Else check packet number */ { /* It was the previous one */ spack('Y',num,0,0); /* ACK it again */ numtry = 0; /* Reset try counter */ return(state); /* Stay in Data state */ } else return('A'); /* Not previous packet, "abort" */ case 'Z': /* End-Of-File */ if (num != n) return('A'); /* Must have right packet number */ spack('Y',n,0,0); /* OK, ACK it. */ close(fd); /* Close the file */ n = (n+1)%64; /* Bump packet number */ return('F'); /* Go back to Receive File state */ - 34 - case FALSE: return(state); /* No packet came, keep waiting */ default: return('A'); /* Some other packet, "abort" */ } } /* * c o n n e c t * * Establish a virtual terminal connection with the remote host, over an * assigned tty line. * */ connect() { int parent; /* Fork handle */ char c = NULL, r = '\r'; if (host) /* If in host mode, nothing to connect to */ { fprintf(stderr,"Kermit: nothing to connect to\n"); return; } parent = fork(); /* Start fork to get typeout from remote host */ if (parent) /* Parent passes typein to remote host */ { printf("Kermit: connected.\r\n"); /* Give message */ stty(0,&rawmode); /* Put tty in raw mode */ read(0,&c,1); /* Get a character */ while (c != escchr) /* Check for escape character */ { /* Not it */ write(remfd,&c,1); /* Write the character on screen */ c = NULL; /* Nullify it */ read(0,&c,1); /* Get next character */ } /* Until escape character typed */ kill(parent,9); /* Done, get rid of fork */ stty(0,&cookedmode); /* Restore tty mode */ printf("\nKermit: disconnected.\n"); /* Give message */ return; /* Done */ } else /* Child does the reading from the remote host */ { while(1) /* Do this forever */ { read(remfd,&c,1); write(1,&c,1); } } } - 35 - /* * KERMIT utilities. */ clkint() /* Timer interrupt handler */ { longjmp(env,TRUE); /* Tell rpack to give up */ } /* tochar converts a control character to a printable one by adding a space */ char tochar(ch) char ch; { return(ch + ' '); /* make sure not a control char */ } /* unchar undoes tochar */ char unchar(ch) char ch; { return(ch - ' '); /* restore char */ } /* * ctl turns a control character into a printable character by toggling the * control bit (ie. ^A becomes A and A becomes ^A). */ char ctl(ch) char ch; { return(ch ^ 64); /* toggle the control bit */ } /* * s p a c k * * Send a Packet */ - 36 - spack(type,num,len,data) char type, *data; int num, len; { int i; /* Character loop counter */ char chksum, buffer[100]; /* Checksum, packet buffer */ register char *bufp; /* Buffer pointer */ bufp = buffer; /* Set up buffer pointer */ for (i=1; i<=pad; i++) write(remfd,&padchar,1); /* Issue any padding */ *bufp++ = SOH; /* Packet marker, ASCII 1 (SOH) */ chksum = tochar(len+3); /* Initialize the checksum */ *bufp++ = tochar(len+3); /* Send the character count */ chksum = chksum + tochar(num); /* Init checksum */ *bufp++ = tochar(num); /* Packet number */ chksum = chksum + type; /* Accumulate checksum */ *bufp++ = type; /* Packet type */ for (i=0; i MAXTIM) || (timint < MINTIM)) timint = MYTIME; alarm(timint); - 37 - if (host) /* Clear any pending input, */ ioctl(); /* like stacked-up ACKs */ else ioctl(remfd,TIOCFLUSH,0); #endif /* UNIX */ while (t != SOH) read(remfd,&t,1); /* Wait for packet header */ done = FALSE; /* Got SOH, init loop */ while (!done) /* Loop to get a packet */ { read(remfd,&t,1); /* Get character */ if (!image) t &= 0177; /* Handle parity */ if (t == SOH) continue; /* Resynchronize if SOH */ chksum = t; /* Start the checksum */ *len = unchar(t)-3; /* Character count */ read(remfd,&t,1); /* Get character */ if (!image) t &= 0177; /* Handle parity */ if (t == SOH) continue; /* Resynchronize if SOH */ chksum = chksum + t; /* Accumulate checksum */ *num = unchar(t); /* Packet number */ read(remfd,&t,1); /* Get character */ if (!image) t &= 0177; /* Handle parity */ if (t == SOH) continue; /* Resynchronize if SOH */ chksum = chksum + t; /* Accumulate checksum */ type = t; /* Packet type */ for (i=0; i<*len; i++) /* The data itself, if any */ { /* Loop for character count */ read(remfd,&t,1); /* Get character */ if (!image) t &= 0177; /* Handle parity */ if (t == SOH) continue; /* Resynch if SOH */ chksum = chksum + t; /* Accumulate checksum */ data[i] = t; /* Put it in the data buffer */ } data[*len] = 0; /* Mark the end of the data */ read(remfd,&t,1); /* Get last character (checksum) */ if (!image) t &= 0177; /* Handle parity */ if (t == SOH) continue; /* Resynchronize if SOH */ done = TRUE; /* Got checksum, done */ } #if UNIX alarm(0); /* Disable the timer interrupt */ #endif chksum = (chksum + (chksum & 192) / 64) & 63; /* Fold bits 7,8 into chksum */ if (chksum != unchar(t)) return(FALSE); /* Check the checksum, fail if bad */ - 38 - return(type); /* All OK, return packet type */ } /* * b u f i l l * * Get a bufferful of data from the file that's being sent. * Only control-quoting is done; 8-bit & repeat count prefixes are * not handled. */ bufill(buffer) char buffer[]; /* Buffer */ { int i; /* Loop index */ char t,t7; i = 0; /* Init data buffer pointer */ while(read(fd,&t,1) > 0) /* Get the next character */ { if (image) /* In 8-bit mode? */ { t7 = t & 0177; /* Yes, look at low-order 7 bits */ if (t7 < SP || t7==DEL || t7==quote) /* Control character? */ { /* Yes, */ buffer[i++] = quote; /* quote this character */ if (t7 != quote) t = ctl(t); /* and uncontrollify */ } } else /* Else, ASCII text mode */ { t &= 0177; /* Strip off the parity bit */ if (t < SP || t == DEL || t == quote) /* Control character? */ { /* Yes */ if (t=='\n') /* If newline, squeeze CR in first */ { buffer[i++] = quote; buffer[i++] = ctl('\r'); } buffer[i++] = quote; /* Insert quote */ if (t != quote) t=ctl(t); /* Uncontrollified the character */ } } buffer[i++] = t; /* Deposit the character itself */ if (i >= spsiz-8) return(i); /* Check length */ } if (i==0) return(EOF); /* Wind up here only on EOF */ return(i); /* Handle partial buffer */ } - 39 - /* * b u f e m p * * Get data from an incoming packet into a file. */ bufemp(buffer,fd,len) char buffer[]; /* Buffer */ int fd, len; /* File pointer, length */ { int i; /* Counter */ char t; /* Character holder */ for (i=0; i 0); /* Return false if file won't open */ } /* * g n x t f l * * Get next file in a file group */ - 40 - gnxtfl() { if (debug) fprintf(stderr, "gnxtfl\n"); filnam = *(filelist++); if (filnam == 0) return FALSE; /* If no more, fail */ else return TRUE; /* else succeed */ } /* * s p a r * * Fill the data array with my send-init parameters * */ spar(data) char data[]; { data[0] = tochar(MAXPACK); /* Biggest packet I can receive */ data[1] = tochar(MYTIME); /* When I want to be timed out */ data[2] = tochar(MYPAD); /* How much padding I need */ data[3] = ctl(MYPCHAR); /* Padding character I want */ data[4] = tochar(MYEOL); /* End-Of-Line character I want */ data[5] = MYQUOTE; /* Control-Quote character I send */ } /* r p a r * * Get the other host's send-init parameters * */ rpar(data) char data[]; { spsiz = unchar(data[0]); /* Maximum send packet size */ timint = unchar(data[1]); /* When I should time out */ pad = unchar(data[2]); /* Number of pads to send */ padchar = ctl(data[3]); /* Padding character to send */ eol = unchar(data[4]); /* EOL character I must send */ quote = data[5]; /* Incoming data quote character */ } - 41 - I. THE ASCII CHARACTER SET I. THE ASCII CHARACTER SET I. THE ASCII CHARACTER SET _____ ____ _____ __________ ASCII_Code_(ANSI_X3.4-1968) There are 128 characters in the ASCII (American national Standard Code for In- formation Interchange) "alphabet". The characters are listed in order of ASCII value; the columns are labeled as follows: Bit Even parity bit for ASCII character. ASCII Dec Decimal (base 10) representation. ASCII Oct Octal (base 8) representation. ASCII Hex Hexadecimal (base 16) representation. EBCDIC Hex EBCDIC hexadecimal equivalent for Kermit translate tables. Char Name or graphical representation of character. Remark Description of character. The first group consists of nonprintable 'control' characters: - 42 - .....ASCII.... EBCDIC ___ ___ ___ ___ ___ ____ _______ Bit Dec Oct Hex Hex Char Remarks 0 000 000 00 00 NUL ^@, Null, Idle 1 001 001 01 01 SOH ^A, Start of heading 1 002 002 02 02 STX ^B, Start of text 0 003 003 03 03 ETX ^C, End of text 1 004 004 04 37 EOT ^D, End of transmission 0 005 005 05 2D ENQ ^E, Enquiry 0 006 006 06 2E ACK ^F, Acknowledge 1 007 007 07 2F BEL ^G, Bell, beep, or fleep 1 008 010 08 16 BS ^H, Backspace 0 009 011 09 05 HT ^I, Horizontal tab 0 010 012 0A 25 LF ^J, Line feed 1 011 013 0B 0B VT ^K, Vertical tab 0 012 014 0C 0C FF ^L, Form feed (top of page) 1 013 015 0D 0D CR ^M, Carriage return 1 014 016 0E 0E SO ^N, Shift out 0 015 017 0F 0F SI ^O, Shift in 1 016 020 10 10 DLE ^P, Data link escape 0 017 021 11 11 DC1 ^Q, Device control 1, XON 0 018 022 12 12 DC2 ^R, Device control 2 1 019 023 13 13 DC3 ^S, Device control 3, XOFF 0 020 024 14 3C DC4 ^T, Device control 4 1 021 025 15 3D NAK ^U, Negative acknowledge 1 022 026 16 32 SYN ^V, Synchronous idle 0 023 027 17 26 ETB ^W, End of transmission block 0 024 030 18 18 CAN ^X, Cancel 1 025 031 19 19 EM ^Y, End of medium 1 026 032 1A 3F SUB ^Z, Substitute 0 027 033 1B 27 ESC ^[, Escape, prefix, altmode 1 028 034 1C 1C FS ^\, File separator 0 029 035 1D 1D GS ^], Group separator 0 030 036 1E 1E RS ^^, Record separator 1 031 037 1F 1F US ^_, Unit separator The last four are usually associated with the control version of backslash, right square bracket, uparrow (or circumflex), and underscore, respectively, but some terminals do not transmit these control characters. The following characters are printable: - 43 - First, some punctuation characters. .....ASCII.... EBCDIC ___ ___ ___ ___ ___ ____ _______ Bit Dec Oct Hex Hex Char Remarks 1 032 040 20 40 SP Space, blank 0 033 041 21 5A ! Exclamation mark 0 034 042 22 7F " Doublequote 1 035 043 23 7B # Number sign, pound sign 0 036 044 24 5B $ Dollar sign 1 037 045 25 6C % Percent sign 1 038 046 26 50 & Ampersand 0 039 047 27 7D ' Apostrophe, accent acute 0 040 050 28 4D ( Left parenthesis 1 041 051 29 5D ) Right parenthesis 1 042 052 2A 5C * Asterisk, star 0 043 053 2B 4E + Plus sign 1 044 054 2C 6B , Comma 0 045 055 2D 60 - Dash, hyphen, minus sign 0 046 056 2E 4B . Period, dot 1 047 057 2F 61 / Slash Numeric characters: .....ASCII.... EBCDIC ___ ___ ___ ___ ___ ____ _______ Bit Dec Oct Hex Hex Char Remarks 0 048 060 30 F0 0 Zero 1 049 061 31 F1 1 One 1 050 062 32 F2 2 Two 0 051 063 33 F3 3 Three 1 052 064 34 F4 4 Four 0 053 065 35 F5 5 Five 0 054 066 36 F6 6 Six 1 055 067 37 F7 7 Seven 1 056 070 38 F8 8 Eight 0 057 071 39 F9 9 Nine More punctuation characters: .....ASCII.... EBCDIC ___ ___ ___ ___ ___ ____ _______ Bit Dec Oct Hex Hex Char Remarks 0 058 072 3A 7A : Colon 1 059 073 3B 5E ; Semicolon 0 060 074 3C 4C < Left angle bracket 1 061 075 3D 7E = Equal sign 1 062 076 3E 6E > Right angle bracket 0 063 077 3F 6F ? Question mark 1 064 100 40 7C @ "At" sign - 44 - Upper-case alphabetic characters (letters): .....ASCII.... EBCDIC ___ ___ ___ ___ ___ ____ _______ Bit Dec Oct Hex Hex Char Remarks 0 065 101 41 C1 A 0 066 102 42 C2 B 1 067 103 43 C3 C 0 068 104 44 C4 D 1 069 105 45 C5 E 1 070 106 46 C6 F 0 071 107 47 C7 G 0 072 110 48 C8 H 1 073 111 49 C9 I 1 074 112 4A D1 J 0 075 113 4B D2 K 1 076 114 4C D3 L 0 077 115 4D D4 M 0 078 116 4E D5 N 1 079 117 4F D6 O 0 080 120 50 D7 P 1 081 121 51 D8 Q 1 082 122 52 D9 R 0 083 123 53 E2 S 1 084 124 54 E3 T 0 085 125 55 E4 U 0 086 126 56 E5 V 1 087 127 57 E6 W 1 088 130 58 E7 X 0 089 131 59 E8 Y 0 090 132 5A E9 Z More punctuation characters: .....ASCII.... EBCDIC ___ ___ ___ ___ ___ ____ _______ Bit Dec Oct Hex Hex Char Remarks 1 091 133 5B AD [ Left square bracket 0 092 134 5C E0 \ Backslash 1 093 135 5D BD ] Right square bracket 1 094 136 5E 5F ^ Circumflex, up arrow 0 095 137 5F 6D _ Underscore, left arrow 0 096 140 60 79 ` Accent grave - 45 - Lower-case alphabetic characters (letters): .....ASCII.... EBCDIC ___ ___ ___ ___ ___ ____ _______ Bit Dec Oct Hex Hex Char Remarks 1 097 141 61 81 a 1 098 142 62 82 b 0 099 143 63 83 c 1 100 144 64 84 d 0 101 145 65 85 e 0 102 146 66 86 f 1 103 147 67 87 g 1 104 150 68 88 h 0 105 151 69 89 i 0 106 152 6A 91 j 1 107 153 6B 92 k 0 108 154 6C 93 l 1 109 155 6D 94 m 1 110 156 6E 95 n 0 111 157 6F 96 o 1 112 160 70 97 p 0 113 161 71 98 q 0 114 162 72 99 r 1 115 163 73 A2 s 0 116 164 74 A3 t 1 117 165 75 A4 u 1 118 166 76 A5 v 0 119 167 77 A6 w 0 120 170 78 A7 x 1 121 171 79 A8 y 1 122 172 7A A9 z More punctuation characters: .....ASCII.... EBCDIC ___ ___ ___ ___ ___ ____ _______ Bit Dec Oct Hex Hex Char Remarks 0 123 173 7B C0 { Left brace (curly bracket) 1 124 174 7C 4F | Vertical bar 0 125 175 7D D0 } Right brace (curly bracket) 0 126 176 7E 7E ~ Tilde Finally, one more nonprintable character: 0 127 177 7F 07 DEL Delete, rubout - 46 - INDEX INDEX INDEX Records 6 8-Bit-Quote 12 Remote 5, 10 Repeat Count 13 ACK 5, 6 Reserved Fields 13 ASCII 5, 6, 41 Server 8, 11, 14 Baud 6 SET 14 Binary Files 6 Smart 10 Char(x) 4 Timeout 10, 16 Checksum 9, 12 Control Characters 7, 42 Unchar(x) 4 Ctl(x) 4 XON/XOFF 6, 42 Deadlock 10 Dumb 10 Duplex 6 EBCDIC 41 End-Of-Line (EOL) 5, 9, 12 Full Duplex 6 Half Duplex 6, 12 Initial Connection Protocol 11 KERMIT 3 Kermit Server 8, 11 Line 10 Line Terminator (see End-Of-Line) Local 10 Logical Records 6 Microcomputer 10 NAK 5 Octal 4 Packet 7 Padding 6, 12 Parity 6, 42 Printable Files 6 Program, Kermit 21 Protocol 3 Quote 12 - i - Table of Contents Table of Contents Table of Contents 1. The KERMIT Protocol 1. The KERMIT Protocol 1. The KERMIT Protocol 3 1.1. Background 3 1.2. Overview 4 1.3. Definitions 4 1.4. Host System Requirements 5 1.5. Data Representation 6 1.6. Packet Format 7 1.7. Smart and Dumb Kermits 10 1.8. Local and Remote Kermits 10 1.9. User and Server Kermits 11 1.10. Initial Connection Protocol 11 1.11. Prefix Quoting 14 1.12. The KERMIT Protocol 15 1.13. KERMIT Protocol State Table 16 1.14. Low-Level Considerations 18 2. The KERMIT Program 2. The KERMIT Program 2. The KERMIT Program 21 I. The ASCII Character Set I. The ASCII Character Set I. The ASCII Character Set 41 Index Index Index 46