E - K e r m i t

Compact, Fast, Robust, Portable Kermit File Transfer for Embedding

Version: 1.1
Date: 7 October 2002
This Page Last Updated: Thu Mar 13 16:27:43 2003

[ Announcement ] [ Kermit Project Home ]



EK (Embedded Kermit, E-Kermit) is an implementation of the Kermit file transfer protocol written in ANSI C and designed for embedding in devices or firmware, use in realtime applications, or for construction of DLLs and libraries.

What E-Kermit Does
EK performs just two functions: sending files and receiving files. It is compact, portable, and fully reentrant. On SPARC (RISC), kermit.o is about 25K. On Intel (CISC) it's about 15K.

What E-Kermit Does NOT Do
EK does not include client/server functions; a command or script programming language; character-set conversion; or any form of communications or file input/output. It does not dial modems, it does not make connections, it does not have a built-in TCP/IP stack or interface to an external one. If you need these features, then you need a full Kermit program, such as C-Kermit or Kermit 95.

EK IS NOT FREE OR OPEN-SOURCE SOFTWARE
It must be licensed for use. If you are interested in evaluating it or licensing it, send email to:

kermit@columbia.edu

EK is not an application itself, it's a subroutine to be called from your master application. It is useful only to developers, who must supply the master application or calling environment as well as the file and communications i/o routines. The calling environment must, in turn, make and configure the communications connection if one is required and not already open. Sample calling environments are supplied for:

EK includes the following Kermit Protocol features:

The following Kermit Protocol features are not implemented:


THE CONTROL PROGRAM

EK is designed to work in a cooperative multitasking environment but does not require such an environment. The control program takes care of scheduling. Here's what the control program must (and/or can) do:

Then in a loop, it:

Each time the control program calls the kermit() function, this grants it permission to handle one packet; thus one packet = one time slice. If the control program has nothing else to do, it simply processes packets continously, like a regular Kermit program. While in the data-transfer loop, every kermit() call returns a struct containing:

When done, the control program:

The function codes that the control program may call kermit() with are:

K_INIT   -- Initialize data structures.
K_SEND   -- (Sending only) -- Initiate sending.
K_RUN    -- Run the protocol.
K_STATUS -- Return a status report in the k_response struct.
K_QUIT   -- Quit immediately and silently.
K_ERROR  -- Send Error packet, then quit.

The return codes of the kermit() function are:

X_OK     -- OK, protocol active.
X_DONE   -- OK, protocol complete.
X_ERROR  -- Fatal error.
X_STATUS -- Returning status in response to K_STATUS.

(In fact status is retuned with every call.) Protocol state codes are:

-1       -- Fatal error
 0       -- Receiver (protocol not running)
 1       -- Receiver waiting for S packet
 2       -- Receiver waiting for F or B packet
 3       -- Receiver waiting for A or D packet
 4       -- Receiver waiting for D or Z packet
10       -- Sender (protocol not running)
11       -- Sender sent S packet (start)
12       -- Sender sent F packet (filename)
13       -- Sender sent A packet (attributes)
14       -- Sender sent D packet (data)
15       -- Sender sent Z packet (EOF)
16       -- Sender sent B packet (EOT)


FILE TRANSFER

Because EK is designed primarily for embedding, it does not use streaming or true sliding windows (although much of the sliding windows code is there). This is for the following reasons:

The lack of true sliding windows is compensated by having EK pretend to support them without really doing so. This allows its sending partner to "stream" packets rather than waiting for ACKs after each one, as long as there isn't an error. If there is an error, the recovery strategy is "go back to n" (or perhaps in some cases "error out") rather than "selective repeat".

In any event, since EK is intended primarily for embedding, it is anticipated that round-trip delays won't be a big factor; connections will generally be local, short, relatively fast, and if the connection is effectively flow controlled, error-free. When effective flow control is lacking, the speed and/or packet length and/or window size can be set to a combination of values that maximizes throughput and minimizes data loss.

Should true sliding windows or streaming be required for a particular application, they can be added.


SOURCE CODE

The source files are:

platform.h
Header file for any needed platform-specific #includes or definitions. Required, even if it's empty, because kermit.c includes it.

kermit.h
Header file for all modules. Definition of k_data and k_response structs.

kermit.c
This is the Kermit protocol engine. It is driven entirely by its call data. All state info is saved in the kermit data structure, which is passed by reference from the main module and among all the functions in the kermit module and back again to the main module; thus it should be possible for the same module to transfer multiple files at once on different connections. Furthermore, there are no library references in the kermit module, none at all, not even stdio (except when debugging is enabled), and no /usr/include/* header files are included. Rules for kermit.c:

The single entry point for the kermit.c module is the kermit() function:

int kermit(struct k_data * k, struct k_response * r)

The k structure contains all the operating parameters, variables, state information, and buffers; the r struct keeps the caller informed of the current state of the protocol, filename and file info, and transfer progress (bytes so far).

main.c
Sample control program. In the Unix testbed, this is just the traditional main(), which reads command-line arguments, initializes the protocol, then calls the protocol module in a state-driven loop until its work is done, then cleans up. In the embedded environment, these functions would be integrated into the control program.

unixio.c
I/O functions for Unix. Substite your own module that implements these functions in the target environment and modify your build procedure to link with it. Entry points and calling conventions described below.


THE UNIX VERSION

Development of EK takes place on a conventional Unix platform, such as Solaris, HP-UX, or Linux, in which EK is built as a remote-mode Kermit file transfer program, similar to G-Kermit, and tested against a desktop Kermit such as K95 or C-Kermit. NOTE: The Unix version works over stdin/stdout; the "line" is conditioned in the stupidest possible way (system("stty ...")). This gives variable results; e.g. downloads from EK on Solaris might run at 17Kcps, whereas downloads from Linux on the same net to the same PC might run at 1700Kcps. This is not worth worrying about because EK is not intended for production use on Unix, which already has G-Kermit and C-Kermit for production.

The Unix makefile has the following targets (it's easy to add more):

gcc:   Build with gcc (default).
cc:    Build with cc.
hp:    Build for HP-UX.
gccnd: Build with gcc, no debugging.
gprof: Build with gcc, include profiling.
clean: Remove object and core files.

The makefile creates a Unix executable called "ek" (embedded kermit). The sample main() routine provides a simple command-line interface:

$ ./ek -h
Usage: ./ek options
Options:
 -r           Receive files
 -s files     Send files
 -p [neoms]   Parity: none, even, odd, mark, space
 -b [123]     Block check type: 1, 2, or 3 (default = 3)
 -k           Keep incompletely received files
 -B           Force binary mode
 -T           Force text mode
 -R           Remote mode (vs local)
 -L           Local mode (vs remote)
 -E number    Simulated error rate (0-100)
 -d           Create debug.log
 -h           Help (this message)
$

When sending files, if you don't specify Text or Binary, EK scans each file and chooses text or binary mode based on its contents.

Remote vs Local mode is used only to enable the test for keyboard interruption of file transfer.


PORTING TO A NEW PLATFORM

Version 1.0 of EK was ported to VxWorks by Airvana, Inc, Chelmsford MA. The complete VxWorks EK package is included as an example of a production system by Airvana's permission. To port to a new platform:

Here are a few tips for creating an i/o module:

The device i/o routines are expected to handle communications parameters themselves, including communication line speed, parity, and flow control. In particular, Kermit does not handle parity, but still must be told about it. This is done in the setup by main(). Your readpkt() and tx_data() routines should strip and add parity, respectively, if necessary. On serial connections, maybe the UART can be programmed to do this. The device i/o functions are:

int
devopen(char * device)
Opens the given communications device. Might also be a network host, whatever. Returns 0 on failure, 1 on success.

int
devsettings(char * settings)
This one performs any needed settings for the device, such as speed and flow control for a serial device. Since there's no way to know what the relevant parameters are, this routine just takes a string, which can be in any format, e.g. "9600;8N1" or "speed=57600;flow=rts/cts"; the devsettings routine will have to parse the string. Returns 0 on failure, 1 on success.

int
devrestore(void)
If desired, put device back the way devsettings() found it, e.g. just before closing it.

int
devclose(void)
Closes the communications device.

int
readpkt(UCHAR * buffer, struct k_data * k)
This routine must do exactly what the sample one does: search for the start of packet, then copy all the characters up to (but not including) the end of packet into the packet buffer whose address is given. You'll want to code this as efficiently as possible, using whatever tricks are available to you: nonblocking buffered reads, etc. If you want your Kermit program to time out, this is where you would put the code. NOTE: Timeouts are not necessary, since the changes that ek's Kermit partner can not time out are about 0.

Note the F_CTRLC feature. This is enabled by default. It allows EK to be broken out of packet mode by sending it three consecutive Ctrl-C's. You normally would not need to disable this since, even if the sender is "unprefixing" Ctrl-C, three of them in a row would normally be collapsed into a repeat-count sequence.

int
tx_data(UCHAR * data, int length, short parity)
Here again, you must tack on parity (if it is not being done automatically by the communication device or driver). This routine should be both efficient and robust. It is supposed to transmit the entire data string or else fail. See the unixio.c sample for what I mean by "robust".

The file i/o functions are as follows; of course they can be used for reading or writing anything -- not just files: memory, tape, cards, laser beams, instrument controllers, whatever. It doesn't matter what you call these routines, but the argument list and return type must be as shown; also if you give them different names, you'll have to change the prototypes in kermit.h:

int
openfile(UCHAR * filename, int mode, struct k_date * k)
Opens the named file in the given mode (1 = read, 2 = write, 3 = append). Returns X_OK on success, X_ERROR on failure.

ULONG
fileinfo(UCHAR * filename, UCHAR * buf, int buflen, short * type, short mode)
Gets information about the specified existing local file: size, date, and, if mode == 0, the file type (text or binary). buf and buflen apply to the file's date/time string. Returns X_OK or X_ERROR.

int
readfile(struct k_data *)
Reads a buffer from the input file, and if the transfer is in text mode, converts the record format to standard Kermit Stream CRLF. Returns X_OK or X_ERROR.

int
writefile(struct k_data *, CHAR * buffer, int length)
Writes a buffer to the output file, and if the transfer is in text mode, also converts the standard Kermit Stream CRLF record format to whatever is required locally. Returns X_OK or X_ERROR.

int closefile(struct k_data *, UCHAR code, int mode)
Closes the file. For output files, of course this flushes any pending buffers to the file before closing it; then it checks to see if the sending Kermit canceled the file transfer before it was finished (code == 'D'), in which case it discards the partial file instead of keeping it. The mode indicates whether it's an input or output file, so incompletely received files can be deleted if desired. Returns X_OK or X_ERROR.

The precise calling conventions are shown in the unixio.c file.


DEBUGGING

If EK was built without NODEBUG defined, then if you include the -d option on the command line, ek creates a debug.log file in its current directory. In the production version, you would add -DNODEBUG to the C compiler CFLAGS to eliminate the debugging code. The sizes shown above include debugging. Currently debugging uses C library calls (mainly fprintf()). If this becomes an issue, a set of generic debugging functions can be coded to replace the fprintf()'s.

[ Top ] [ Kermit Home ]


E-Kermit 1.1 / Columbia University / kermit@columbia.edu / 7 Oct 2002