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 transparently performs 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, void **data, Tcl_Interp
*interp, int mode)
Arguments: We provide
below the parameters' default interpretation. For the
other cases, please refer to the description of the mode
parameter below.
- (in) inBuf: Points to the start of the
input buffer. It is assumed that the filter
consumes the entire input. If it is not possible
to generate filtered output for all the input
data, part of it can be buffered
internally. The responsability of freeing
the buffer always pertains to the DP code, and not to the
filter.
- (in) inLength: The length of the input
buffer.
- (out) outBuf: Whenever the filter will
generate output, the address of the buffer must
be stored in *outbuf.
The parameter is ignored by the DP code when *outLength is
set to 0. Unless the value of mode is DP_FILTER_GET, it is
the responsability of the DP code to manage the
buffer. When mode is DP_FILTER_GET,
it is the responsability of the filter function
to manage the buffer.
- (out) outLength: The length of the
output buffer. If there is no output, *outLength
must be set to 0.
- (in) data:
If filter functions need persistent state
associated with the streams they filter, they can
store a pointer to these structures in *data. Before
the first call to the filter function, the
plug-in channel code initializes *data with NULL. The filter
function has full responsability in managing the
memory zone pointed to by *data. In particular,
the filter should free all the allocated space
when the value of the mode parameter is DP_FILTER_CLOSE.
- (in) interp:
Pointer to the tcl interpreter in which the
filter channel was created. It can be used to
create filters that evaluate arbitrary tcl
expressions (see, for example. the tclfilter
function below).
- (in) mode: This parameter specifies how
the other arguments must be interpreted. Unless
specified otherwise, the default interpretation
of the other parameters must be used.
- DP_FILTER_NORMAL: The mode
parameter will have this value when the -buffering
option of the filter channel has been set
to line
or full.
- DP_FILTER_FLUSH: The filter is encouraged
to generate output, even if this would
not normally be the case. The filter can
ignore this argument and behave like mode
was DP_FILTER_NORMAL. The mode
parameter will have this value when the -buffering
option of the filter channel has been set
to none.
- DP_FILTER_EOF:
This value of the parameter
signals that no more data will be
received from the subordinated
channel. At this point, the
filter function must generate all
the output it can, and free all
its internal buffers.
- DP_FILTER_CLOSE: This value of
the parameter signals that the filter
channel is about to be closed, and this
is the last call to the filter function.
The filter must deallocate all its
internal data structures, and generate
all the output it can.
- 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
function can use the string to set its
internal variables. For example, this
mechanism could be used to set a
different pgp key for each channel.
- DP_FILTER_GET: All parameters
are ignored, except for outBuf. The
filter function must store in *outBuf
the address of a null-terminated string
that describes its internal state. The
string is read only once by DP, immediately
after the filter returns. This is the
only case when the filter function has to
manage the memory zone whose address was
stored in *outbuf; which is done to avoid
unnecessary reconstructions of the state
string.
Return value: If no error is detected, the return
value must be zero. A non-zero return value signals an
error, if needed, POSIX
error codes can be used to indicate the type of the
error.
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 plug-in
filters are provided (unless specified otherwise, the
filters have no internal parameters):
- identity: Used as default value for a filter
function that was not defined explicitly.
Property: identity(X) = X.
- plug1to2: The input string is filtered by
replacing each character of the string with two
copies of itself. Example:
Plug1to2("abc") = "aabbcc".
- plug2to1: The input string is filtered by
selecting the characters that have even indices.
Example: Plug2to1("abcdef") =
"ace".
- xor: An arbitrary, non-empty 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
nonnegative integer in base 10; the integer is
padded to the left with non-significant zeroes.
Normally a packet is the amount of data that is
written to (read from) the underlying channel at
one time. (Note: If the amount of data is bigger
than the capacity of Tcl's internal buffers
(usually 4k), spurious packets will be
generated.) 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. Example: uuencode("abc") =
"begin 740 uufilter\n$86C"O\\\n\n
\nend\n" ('\n' stands for line feed, and
'\\'stands for backslash).
- uudecode: Same functionality as Unix uudecode.
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 takes two arguments, and is
assumed to consume the whole input (and
buffer it, if necessary). The first
argument is the (possibly zero-length)
input string, The second argument can
only have the values "normal",
"flush", "close",
"eof" and corresponds to the
mode parameter
above. The output value is a (possibly
zero-length) string that represents the
first use. Arguments: the name of the tcl
procedure must be set up before the first
use.
- hexout: Given a string of even length containing
the characters 0..9, a..f, A..F this filter
translates it into a sequence of bytes whose
hexadecimal representation is the given string.
Example: hexout("00Ff") will generate
two bytes, the first one having all bits set to
zero, the second one having all bites set to 1.
- hexin: Has the opposite effect to hexout.
Filters as Independent Channels
When some peculiar requirement or Tcl's idiosyncracies make it
inconvenient or impossible to implement some filters using
plug-in 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 plug-in 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. Note: do not confuse the
identity (standalone) filter channel with the identity filter
function.
packoff: This filter identifies packets generated by the
packon plug-in 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.
hexin(hexout(X)) = X
hexout(hexin(X)) = X
hexin(hexout(X)) != hexout(hexin(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
The subordinated channel and the input and output filter
functions of a filter channel can not 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. 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. A plug-in filter channel will always be both readable
and writeable, but the real behavior will depend on the
characteristics of the internal buffering of filter functions,
and on the behavior of the subordinated channel.
Note: though tcl itself can not handle binary data, the
plug-in filters can. Care must be taken to set the -translation option to binary for the
appropriate channels.
Composition of Filters
Both plug-in 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.