home *** CD-ROM | disk | FTP | other *** search
- The Small Portable Kermit Module (kermitproto.w)
- Stephen Walton
- August 2, 1988
-
- The attached set of routines, which I have christened "kermitproto.w",
- represent several weeks of work. It is intended to be a single,
- self-contained set of Kermit protocol routines suitable for adding to
- a microcomputer terminal emulation program. As such, it does not
- allow the microcomputer to act as a server. It does provide long
- packets, client support, and the optional protocol for a clean
- interrupt.
- The code began its life as the routines in the book _Kermit: A File
- Transfer Protocol_ by Frank da Cruz (Digital Press, 1986). I have kept
- the original style of the book's code, only fixing bugs and adding
- some Lint-related items. I must say here that I don't care all that
- much for the code in the book. The C language provides many more
- elegant constructs for doing what Kermit requires. Far too many
- important flags and result returns are done via global variables. Not
- a single instance of pointers to functions, enums, structs, macros
- beyond very simple string replacement, or abstract data types is to be
- found herein. These should not be used for their own sake, but it
- seems to me that they could make Kermit code much easier to read. An
- ADT called "packet" is an obvious possibility.
- The code communicates to the outside world through both some
- subroutines which the user must provide and a set of global variables
- which control some aspects of the protocol. The variables can safely
- be ignored for the most part; they start out with reasonable default
- values which are modified as the result of Kermit transactions. Only
- 3 must be set by the user interface, and my module declares these as
- extern so your code won't link if you don't.
-
- File Handling Primitives
-
- The module contains file handling primitives written in terms of the
- soon-to-be ANSI standard I/O library. These ought to work on nearly
- all systems, though some (MS-DOS for one) may require some changes to
- distinguish between text and binary files. The ones most likely to
- require local changes are zltor() and zrtol() for converting file
- names back and forth between the local format and the generic Kermit
- format.
-
- Serial Port Primitives
-
- The first set of user-provided routines are for handling the
- serial communications.
-
- int ttol(char *out_string, int n)
-
- Writes the n characters beginning at outstring to the serial port
- using the current settings of flow control, parity, word length, etc.
- Returns the number of characters read from the port or -1 on failure.
-
- int ttinl(char *in_string, int max, int timeout, int eol)
-
- Reads characters from the serial port into in_string. It stops when
- either max characters have been seen or the end-of-read marker eol has
- been seen. If timeout is greater than 0, then the read must be
- completed in no more than timeout seconds. The value returned is the
- number of characters actually read or -1 on error or timeout.
-
- void ttflui(void)
-
- Removes all pending readable characters from the serial port.
-
- Other User-Provided Routines
-
- int gnfile(char *filename, int length)
-
- Copies the next file for Kermit to SEND or GET into the character
- string pointed to by filename, of maximum length length. Returns a
- positive flag if there is a next file, 0 or negative if not.
-
- void sleep(int seconds)
-
- Pause the user's program for the given number of seconds.
-
- Status Routines
-
- These routines are used to report the status of the protocol to
- the user's program for possible display.
-
- void tchar(char c)
-
- Place the character "c" on the user's terminal. c is a . for a
- successful packet transfer and a % for a retry, but c can also be
- anything a remote server might send in response to client commands
- (REMOTE COMMAND, for example).
-
- void tmsg(char *message)
-
- Write the null-terminated string without a carriage return; i.e., if I
- call tmsg("first ") and tmsg("word"), the user should see "first word"
- displayed.
-
- void tmsgl(char *message)
-
- Write tne null-terminated string and start a new line after
- displaying.
-
- Future update plans call for adding code to count packets, file
- bytes, and naks and adding a special call for displaying this type of
- information, similar to the screen() routine in C Kermit 4E(070).
-
- Starting It Up
-
- All Kermit protocol transfers are started by doing whatever startup
- the user's code requires, putting the appropriate start state into the
- extern int start, and calling the routine proto(). Here are the supported
- start states and how they work:
-
- 'v': Receive a file. The protocol module assumes that the remote Kermit
- has been given a SEND command, and passively waits (with timeouts) for the
- file(s) to start arriving. Your Kermit receive subroutine could be as
- simple as:
-
- void kermit_receive(void)
- {
- extern int start;
-
- start = 'v';
- proto();
- }
-
- 's': Send a file. The protocol module calls gnfile() (see above)
- repeatedly, and sends each file requested to the remote. The remote must
- have been given a RECEIVE or a SERVER command first.
-
- 'r': Get file(s). The protocol module calls gnfile() for a list of files
- to request from a remote Kermit server. These can generally include
- wildcards in the remote's syntax, for example *.FOR for all Fortran files
- from an MS/DOS server or *.c for all C files from a Unix server.
-
- 'g': Kermit generic commands. The protocol module sends the string pointed
- to by the extern char *cmarg to the remote as a Kermit generic server
- command. The command string is of the format:
-
- <cmd>[%<string1>...]\0
-
- where <cmd> is a single upper-case letter representing the Kermit generic
- command, and it is followed by one or more optional string arguments. Each
- string is preceded by tochar() of its length. For example, the <cmd> for a
- Kermit BYE (logout) command is L, and it takes no arguments, so the
- simplest possible BYE subroutine would be:
-
- void kermit_bye(void) {
- static char bye_command[] = "L";
- extern char *cmarg;
-
- cmarg = &bye_command[0];
- state = 'g';
- proto();
- }
-
- See the Kermit book for a complete list of the generic commands and the
- arguments required.
-
- 'c': Kermit REMOTE HOST command. cmarg points to a string in the remote's
- command syntax which is to be executed by the remote, with output (if any)
- from that command being returned by the remote server. Here is a simple
- example:
-
- #define tochar(c) ((c) + 32)
-
- void kermit_remote_host(char *remote_command)
- {
- extern char *cmarg;
- char command[90];
-
- state = 'c';
-
- cmarg = command;
- cmarg[0] = tochar(strlen(remote_command));
- strcpy(&cmarg[1], remote_command);
- proto();
- free(cmarg);
- }
-
- Notice that the string pointed to by cmarg must be small enough to fit in a
- single Kermit packet; i.e., 90 characters or less.
-
- External variables
-
- There are several which are of interest to every user program. These
- are, first of all, the flags parity, convert, and text. These are
- simply checked against zero; a non-zero value means that parity is in
- use (that is, the data path is 7 bits wide), that file names are to be
- converted to a generic form, and that files are to be sent or received
- as text, respectively. If they are zero, they indicate an 8-bit wide
- data path, no file name conversion, and binary file transfer. These
- are defined in kermitproto.w but must be declared in the user code;
- that is, the declarations "int parity", "int convert", and "int text"
- must appear somewhere outside of any block.
- The value urpsiz must be declared by the user as well. This is a
- mnemonic for "user requested packet size," and represents the size of
- packets the user wants to request be used. I have written
- kermitproto.w so that if urpsiz is such that long packets are
- required, the code will also request type 3 (CRC) block checks, but
- the equivalent of the SET BLOCK-CHECK 3 must be issued to the remote
- as well.
- The flags cx and cz can be used to abort a file transfer. If cx
- is set upon return from ttinl(), the file currently being transferred
- is skipped, and any partial result from the transfer is deleted. If
- cz is set, then an entire batch transfer is aborted if one is in
- progress. Most Kermit programs understand the protocol used for this
- cancellation. Incidentally, the reason for these flags' names is that
- the book recommends that Control-X be the cancel-file interrupt and
- that Control-Z be the cancel-batch interrupt character.
- Finally, there are all of the variables which control timeouts,
- number of retries, block check type, and so on. These are described
- in the comments at the beginning of the module.
-
- Compiling This
-
- kermitproto.w is a Wart file, and should be passed through the wart
- preprocessor via the command:
- wart kermitproto.w kermitproto.c
- to generate a C file to hand to your local C compiler. wart is
- available (as CKWART.C) from the Kermit archives in the usual way, and
- is sufficiently portable so as to compile on a wide variety of systems
- without modification.
-
- Final Thoughts
-
- 32K is longer than I thought this module would end up when I started.
- I hope it does save someone some work.
-