Plug-In Filter Channel
Syntax
dp_connect plugfilter -channel channel_name
-infilter filter_name -outfilter filter_name
Comments
Arguments:
- channel_name is the name of an already existing
channel (the subordinated channel), whose input and/or
output will be filtered. Using filters, an unlimited
number of channels can be composed to form a linear chain
that can transparently perform complex functions (e.g.
sequencing, encrypting/decrypting, transcoding,
etc.).
- filter_name is the name of a registered filter
function (see below). Neither the value for -infilter,
nor for -outfilter is mandatory. If they are missing, the
corresponding filter function will be identity.
- Description of Filter Functions
-
- Prototype: int Filter (char *inBuf, int inLength,
char **outBuf, int *outLength, int mode)
Arguments:
We provide below the "normal" interpretation of
parameters. For the treatment of special cases, please
refer to the mode parameter.
- (in) inBuf: If defined, it points to the
input buffer. It is assumed that the filter
consumes the entire input. If it is not possible
to generate output for all input, part of it can
be buffered internally.
- (in) inLength: The length of the input
buffer.
- (out) outBuf: When the filter generates
output, it allocates an output buffer, and stores
all the available output in it. The address of
the output buffer has to be stored in *outBuf. If
no output is generated (i.e. outLength is 0),
this parameter is not used. Except when
*output contains the internal parameters of the
filter functions (i.e. when mode is DP_FILTER_GET), the
filter function should not manage this space
afterm allocating it. The responsability for
doing so belongs to the plugin channel code. When
mode is DP_FILTER_GET
the string has to be managed by the filter
function; this is done to avoid unnecessary
reconstruction of the parameter string.
- (out) outLength: The filter must store
here the length of the output buffer. If there is
no output, *outLength has to be set to 0.
- (in) data: The filter function can store a
pointer to its local datastructures in *data. The
plugin channel code will initializa *data with NULL. The argument for
infilter will be different from the argument for
the outfilter. The filter function code has the
responsability to manage data referred to by
*data. In particular, the filter should free all
the allocated space when mode is DP_FILTER_CLOSE.
- (in) interp: Pointer to the tcl interpreter in
which the filter was created. It can be used to
create filters that evaluate tcl expressions
(see, for example. the tclfilter function below).
- (int) mode: This parameter can have five
distinct values. They are discussed below:
- DP_FILTER_NORMAL: In this mode
the interpretation of parameters is the
one given above. The filter can either
generate output or not. This mode
corresponds to setting the
"-buffering" argument of the
channel to "full" or
"line".
- DP_FILTER_FLUSH: In this mode
the interpretation of parameters is the
one given above. The filter is encouraged
to generate output, even if this would
not be the case. The filter can ignore
this argument and behave like mode was DP_FILTER_NORMAL.
This mode corresponds to setting the
"-buffering" argument of the
channel to "none".
- DP_FILTER_EOF:
In this mode the interpretation
of parameters is the one given
above. This value of the
parameter signals that the
underlying reached eof, no more
input is expected. It is
important to distinguish this
case when the filter function
buffers data; if the channel is
closed the output that would
generated based on the buffered
data will be lost if the channel
is used for input (see the
uuencode code for an example).
- DP_FILTER_CLOSE: In this mode
the interpretation of parameters is the
one given above. This value of the
parameter signals that the filter channel
is about to be closed, and this is the
last call to the filter. The filter
should deallocate all its internal data
structures, and should generate all the
output it can.
Note: the filter should never try to
deallocate any *outBuf pointer that was
returned to DP. These buffers are managed
and freed at the DP level.
- DP_FILTER_SET: All parameters
are ignored, except for inBuf and
inLength. In this case the input buffer
is a string that is passed "as
is" by Tcl from the "fconfigure
<channel> -[inset | outset]
<string>" command. The filter
should use the string to set its internal
variables. For example, this mechanism
could be used to set a different pgp key
for each channel.
Note: the filter should never try to
deallocate any *outBuf pointer that was
returned to DP. These buffers are managed
and freed at the DP level.
- DP_FILTER_GET: All parameters
are ignored, except for outBuf. The
filter should store in *outBuf the
address of a string that describes its
internal state. The string should end
with a null character ('\0'). If the
string is not static, the filter has to
take care of allocating/freeing it. The
string is used by DP only once,
immediately after the filter returns. In
order for the "fconfigure
<channel>" command to work
with no other arguments, the filter
should return a non-empty string even if
it has no internal state (see the
examples in file
generic/dpFilters.c)
Return value: If no error is detected, the return
value must be zero. A non-zero return value signals an
error. The user should use POSIX error codes to
differentiate the possible error cases.
Before being used, a filter function has to be
registered by calling function Dp_RegisterPlugInFilter.
TCL_OK is returned upon successful completion of
registration.
Prototype: int Dp_RegisterPlugInFilter (Tcl_Interp
interp, Dp_PlugInFilter *newPlugInPtr)
Arguments:
- interp is the pointer to the interpreter
in which the registration wil take place
- newPlugInPtr is a pointer to a filter
function defined as specified above.
Filter functions can also be pre-registered, by adding
them to the array builtInPlugs in file generic/dpChan.c,
and recompiling Tcl-DP. As of now, the following plugin
filters are provided:
- identity: Used as default value for a filter
function that was not defined explicitly. No
internal parameters. Property: identity(X) =
X.
- plug1to2: Given an input string X, this is
filtered by replacing each character of the
string with two copies of itself. No internal
parameters. Example: Plug1to2("abc") =
"aabbcc".
- plug2to1: Given an input string X, this is
filtered by selecting only the characters that
have even indices. No internal arguments.
Example: Plug2to1("abcdef") =
"ace".
- xor: A parameter string has to be provided as an
internal argument before first using the filter.
The input bytes will be xor'd with the bytes in
the parameter, taken in circular order. This
order will be preserved between succesive calls.
The same string must be used for both encoding
and decoding. Example: xor("abc",
"12") = xyz, where x = 'a' ^ '1', y =
'b' ^ '2', z = 'c' ^ '1'.
- packon: Adds a header of 6 bytes to each packet
that is written to or read from the underlying
channel. The header contains a right-aligned
nonnegativeinteger in base 10; it is padded to
the left with non-significantin one step. If
zeroes. A packet is the amount of data that is
written to (read from) the underlying channel
there is more data than itfilter will work both
can fit in one of tcl's buffers (usually 4k),
then one write (read) will be translated into
several packets. Though the formessages. No
internal input and output, it is more likely that
the filter will be used for automatically
attaching the packet length to outgoing (written)
parameters. Example: packon("abc") =
"000003abc".
- uuencode: Same functionality as Unix uuencode;
converts a binary file into a specially formatted
file containg a subset of the ASCII character
set. No internal parameters. Example:
uuencode("abc") = "begin 740
uufilter\n$86C"O\\\n\n \nend\n" ('\n'
stands for linefeed, and '\\'stands for
backslash).
- uudecode: Same functionality as Unix uudecode. No
internal parameters. Example:
uudecode("begin 740
uufilter\n$86C"O\\\n\n \nend\n") =
"abc".
- tclfilter: Allows the user to use any tcl
function to implement a filter. The tcl
filter is assumed to consume the whole
input (and buffer it, if necessary). The
tcl procedure must take two arguments,
the first is the input string (possibly
with length zero), and the second one
indicates the mode. It can have the
values "normal",
"flush", "close",
"eof". The output value is a
string that will be returned as a result
(the output can have length 0).
Arguments: the name of the tcl command
must be setup before the first use.
Filters as Independent Channels
When some peculiar reqquirement or tcl's idiosyncrasies make
it inconvenient or impossible to implement some filters using
plugin channels, one can obtain the desired functionality by
creating a standalone filter channel. We provide two such
examples:
identity: This channel reproduces the functionality of the
identity plugin filter. It is provided as a skeleton that can be
modified to implement more complex filters. This channel does not
accept any non-standard options.
packoff: This type of filter identifies packets generated by
the packon plugin filter (see above) and separates them from the
input stream, returning them separately. Since this operation
makes sense only when reading data, this channel is not writable.
This channel does not accept any non-standard options.
Properties of the Provided In-Built Filter Functions
Plug1to2(Plug2to1(X)) = X.
Plug2to1(Plug1to2(X)) = X.
xor(xor(X,Y),Y) = X.
packon(packoff(X)) = packoff(packon(X)).
uudecode(uuencode(X)) = X.
Order of Operations
When flushing or closing a sequence of channels linked through
filters, one should follow the flow of data.
Example: filter1-->filter2-->TCP_channel
When closing this composite channel the sequence of operations
should be
close $filter1
close $filter2
close $tcp_channel
Configuration of Filter Channels
After being set up, a filter channel does not allow for the
subordinated channel, or the value of input or output filters to
be changed. The peek option is forwarded to the subordinated
channel, but it does not act on the filter channel itself.
There are two options, -inset and -outset, that can be used to
transmit arguments to the input and output filter functions,
respectively. These arguments are designated as the internal
arguments of the filter function. The argument of -inset and
-outset is a string that will be passed to the corresponding
filter function "as is". It is the responsability of
the filter function to interpret the string.
If the user wishes to change an option for the subordinated
channel, this must be done directly.
A filter channel will always be non-blocking. Seek is not
allowed. Also a filter channel will always be readable and
writeable, but the real behavior will depend on the
characteristics of the internal buffering of filter functions,
and on the bahavior of the subordinated channel.
Note: though tcl itself can not handle binary data the plugin
filters can. Care must be taken to set the -translation option to
binary for the appropriate channels.
Composition of Filters
Both plugin and independent channel filters can be composed
with no restrictions.
Examples
- dp_connect plugfilter -channel tcp1 -infilter
plug2to1 -outfilter plug1to2
dp_connect plugfilter -channel email0 -outfilter pgp
-infilter un_pgp
set xout [dp_connect plugfilter -channel file540
-outfilter uuencode
fconfigure $xout -translation binary
set xxout [dp_connect plugfilter -channel $xout
-outfilter xor]
fconfigure $xxout -translation binary -outset "my
secret string goes here"
set xin [dp_connect plugfilter -channel file100 -infilter
tclfilter]
fconfigure $xin -inset MyTclProcedure
dp_connect packoff -channel tcp10
For more details, please refer to the tests/plugin2.test file
in the standard distribution.