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:
- Unix (demo, development)
- VxWorks (production)
EK includes the following Kermit Protocol features:
- Long packets
- Sliding windows with Go-Back-to-N error recovery
- Repeat-count compression
- Control-character prefixing and unprefixing
- 8th-bit prefixing (for transferring 8-bit data on 7-bit links) (= parity)
- Attribute packets (type, size, and date)
- Sending and receiving single or multiple files.
- Automatic per-file text/binary mode switching.
- All three block check types (6- and 12-bit checksum, 16-bit CRC).
- Status reports (protocol state, file name, size, timestamp, bytes so far).
- Transfer cancellation by either party.
The following Kermit Protocol features are not implemented:
- Sliding windows with selective repeat.
- Character sets
- Locking shifts
- Client/server
- Timeouts
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:
- If desired, open the communications device, if any.
- If desired, put the communications device, if any, into "packet mode".
- Initialize the kermit struct with desired operating parameters.
- Call kermit(K_INIT, ...) to have Kermit initialize itself.
- If sending files, call kermit(K_SEND) to start the transfer.
Then in a loop, it:
- Gets a buffer and reads an incoming packet into it.
- Checks for user interruption.
- Calls kermit(K_RUN, ...) to do the next step in the protocol.
- Does whatever else it wants (e.g. runs other tasks).
- Quits or continues the loop based on the kermit() return code.
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:
- The current protocol state;
- The current filename;
- The file's size, if known, or -1;
- The file's timestamp, if known;
- The number of bytes transferred so far.
When done, the control program:
- Restores and (if desired) closes the communications device.
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)
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:
- Using the regular ACK/NAK protocol allows the control program to regain
control after every packet. This lets it multitask, put up a graphical
file-transfer display, whatever. Streaming or sliding windows could put
the control program out of business for long periods of time.
- Streaming or true sliding windows would make the interface between the
control program and the kermit() module much more complicated, and in
fact, would push a lot of protocol details into the control program's
space, where they don't belong.
- Streaming can be used only on reliable connections (such as TCP/IP) but
devices with embedded communications generally use serial ports.
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.
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:
- No global variables (except for debugging) or buffers.
- No initializing of arrays by compiler.
- Just for safety, no initializing automatic scalars either.
- No library or system calls, no #include <...>.
- All communications i/o is done by functions defined in separate modules.
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.
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.
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:
- Add a new Makefile entry for your target, or write your own build
procedure.
- Create a platform.h file for your platform. This can include any
desired #include's or definitions, and it can also be used to override certain
definitions in kermit.h:
#define NODEBUG to build without debugging code.
#define HAVE_UCHAR if UCHAR is already defined or
typedef'd to unisgned char.
#define HAVE_ULONG if ULONG is already defined or
typedef'd to unisgned long.
#define IBUFLEN to be the desired size for the file input buffer.
#define OBUFLEN to be the desired size for the file output buffer.
#define FN_MAX to be the maximum length for a filename.
#define P_PKTLEN to override the default maximum packet length.
#define P_WSLOTS to override the default maximum window slots.
- Replace the sample main.c with your own control program. Use the
same header files and calling conventions as in the sample.
- Copy unixio.c to xxxio.c (name of your choice),
edit it to work on your platform using exactly the same calling conventions,
and adjust your build procedure to link with your new xxxio
module instead of unixio. Note that the fill input and output
buffers (i_buf[] and o_buf[]) must be defined in your
xxxio routine.
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.
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