396 lines
18 KiB
HTML
396 lines
18 KiB
HTML
|
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
||
|
<html>
|
||
|
|
||
|
<head>
|
||
|
<meta http-equiv="Content-Type"
|
||
|
content="text/html; charset=iso-8859-1">
|
||
|
<meta name="Author" content>
|
||
|
<meta name="GENERATOR" content="Microsoft FrontPage 2.0">
|
||
|
<title>Plugin Filter Channel</title>
|
||
|
</head>
|
||
|
|
||
|
<body bgcolor="#C0C0C0" text="#000000" link="#0000EE"
|
||
|
vlink="#551A8B" alink="#FF0000">
|
||
|
|
||
|
<h3>Plug-In Filter Channel</h3>
|
||
|
|
||
|
<p><b>Syntax</b></p>
|
||
|
|
||
|
<p><tt>dp_connect plugfilter -channel </tt><em><tt>channel_name</tt></em><tt>
|
||
|
-infilter </tt><em><tt>filter_name</tt></em><tt> -outfilter </tt><em><tt>filter_name</tt></em></p>
|
||
|
|
||
|
<p><b>Comments</b></p>
|
||
|
|
||
|
<p>Arguments: </p>
|
||
|
|
||
|
<ul>
|
||
|
<li><i>channel_name</i> 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.). </li>
|
||
|
<li><i>filter_name</i> 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 <b>identity</b>.</li>
|
||
|
</ul>
|
||
|
|
||
|
<dl>
|
||
|
<dt><b>Description of Filter Functions</b></dt>
|
||
|
<dt> </dt>
|
||
|
<dd>Prototype: <tt>int Filter (char *inBuf, int inLength,
|
||
|
char **outBuf, int *outLength, void **data, Tcl_Interp
|
||
|
*interp, int mode) </tt><p>Arguments: We provide
|
||
|
below the parameters' default interpretation. For the
|
||
|
other cases, please refer to the description of the mode
|
||
|
parameter below.</p>
|
||
|
<ul>
|
||
|
<li>(in) <tt>inBuf</tt>: 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 <font size="3"
|
||
|
face="Courier New">DP</font> code, and not to the
|
||
|
filter.</li>
|
||
|
<li>(in) <tt>inLength</tt>: The length of the input
|
||
|
buffer. </li>
|
||
|
<li>(out) <tt>outBuf</tt>: Whenever the filter will
|
||
|
generate output, the address of the buffer must
|
||
|
be stored in <font size="2" face="Courier New">*outbuf</font>.
|
||
|
The parameter is ignored by the <font
|
||
|
face="Courier New">DP</font> code when <font
|
||
|
size="2" face="Courier New">*outLength</font> is
|
||
|
set to 0. Unless the value of mode is <font
|
||
|
face="Courier New">DP_FILTER_GET</font>, it is
|
||
|
the responsability of the <font
|
||
|
face="Courier New">DP</font> code to manage the
|
||
|
buffer. When mode is <font face="Courier New">DP_FILTER_GET</font>,
|
||
|
it is the responsability of the filter function
|
||
|
to manage the buffer.</li>
|
||
|
<li>(out) <tt>outLength</tt>: The length of the
|
||
|
output buffer. If there is no output, <font
|
||
|
size="2" face="Courier New">*outLength</font>
|
||
|
must be set to 0.</li>
|
||
|
<li>(in) <font size="2" face="Courier New">data</font>:
|
||
|
If filter functions need persistent state
|
||
|
associated with the streams they filter, they can
|
||
|
store a pointer to these structures in <font
|
||
|
size="2" face="Courier New">*data</font>. Before
|
||
|
the first call to the filter function, the
|
||
|
plug-in channel code initializes <font size="2"
|
||
|
face="Courier New">*data</font> with <font
|
||
|
face="Courier New">NULL</font>. The filter
|
||
|
function has full responsability in managing the
|
||
|
memory zone pointed to by <font size="2"
|
||
|
face="Courier New">*data.</font> In particular,
|
||
|
the filter should free all the allocated space
|
||
|
when the value of the mode parameter is <font
|
||
|
face="Courier New">DP_FILTER_CLOSE.</font></li>
|
||
|
<li>(in) <font size="2" face="Courier New">interp</font>:
|
||
|
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).</li>
|
||
|
<li>(in) <tt>mode</tt>: This parameter specifies how
|
||
|
the other arguments must be interpreted. Unless
|
||
|
specified otherwise, the default interpretation
|
||
|
of the other parameters must be used.</li>
|
||
|
<li><ul>
|
||
|
<li><tt>DP_FILTER_NORMAL</tt>: The <font
|
||
|
size="2" face="Courier New">mode</font>
|
||
|
parameter will have this value when the <font
|
||
|
size="2" face="Courier New">-buffering</font>
|
||
|
option of the filter channel has been set
|
||
|
to <font size="2" face="Courier New">line</font>
|
||
|
or <font size="2" face="Courier New">full</font>.</li>
|
||
|
<li><tt>DP_FILTER_FLUSH</tt>: The filter is <font
|
||
|
size="2" face="Courier New">encouraged</font>
|
||
|
to generate output, even if this would
|
||
|
not normally be the case. The filter can
|
||
|
ignore this argument and behave like <font
|
||
|
size="2" face="Courier New">mode</font>
|
||
|
was <tt>DP_FILTER_NORMAL</tt>. The mode
|
||
|
parameter will have this value when the <font
|
||
|
size="2" face="Courier New">-buffering</font>
|
||
|
option of the filter channel has been set
|
||
|
to <font size="2" face="Courier New">none</font>. </li>
|
||
|
<li><dl>
|
||
|
<dt><font face="Courier New">DP_FILTER_EOF</font>:
|
||
|
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.</dt>
|
||
|
</dl>
|
||
|
</li>
|
||
|
</ul>
|
||
|
<ul>
|
||
|
<li><tt>DP_FILTER_CLOSE</tt>: 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.</li>
|
||
|
<li><tt>DP_FILTER_SET</tt>: All parameters
|
||
|
are ignored, except for <font size="2"
|
||
|
face="Courier New">inBuf</font> and <font
|
||
|
size="2" face="Courier New">inLength</font>.
|
||
|
In this case the input buffer is a string
|
||
|
that is passed "as is" by Tcl
|
||
|
from the <font size="2"
|
||
|
face="Courier New">fconfigure
|
||
|
<channel> -[inset | outset]
|
||
|
<string></font> 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. </li>
|
||
|
<li><tt>DP_FILTER_GET</tt>: All parameters
|
||
|
are ignored, except for <font size="2"
|
||
|
face="Courier New">outBuf</font>. The
|
||
|
filter function must store in <font
|
||
|
size="2" face="Courier New">*outBuf</font>
|
||
|
the address of a null-terminated string
|
||
|
that describes its internal state. The
|
||
|
string is read only once by <font
|
||
|
face="Courier New">DP</font>, 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.</li>
|
||
|
</ul>
|
||
|
</li>
|
||
|
</ul>
|
||
|
<p>Return value: If no error is detected, the return
|
||
|
value must be zero. A non-zero return value signals an
|
||
|
error, if needed, <font size="2" face="Courier New">POSIX</font>
|
||
|
error codes can be used to indicate the type of the
|
||
|
error.</p>
|
||
|
<p>Before being used, a filter function has to be
|
||
|
registered by calling function <tt>Dp_RegisterPlugInFilter</tt>.
|
||
|
<tt>TCL_OK</tt> is returned upon successful completion of
|
||
|
registration. </p>
|
||
|
<p>Prototype: <tt>int Dp_RegisterPlugInFilter (Tcl_Interp
|
||
|
interp, Dp_PlugInFilter *newPlugInPtr) </tt></p>
|
||
|
<p>Arguments: </p>
|
||
|
<ul>
|
||
|
<li><em>interp</em> is the pointer to the interpreter
|
||
|
in which the registration wil take place </li>
|
||
|
<li><em>newPlugInPtr</em> is a pointer to a filter
|
||
|
function defined as specified above. </li>
|
||
|
</ul>
|
||
|
<p>Filter functions can also be pre-registered, by adding
|
||
|
them to the array <b>builtInPlugs</b><i> </i>in file <b>generic/dpChan.c</b>,
|
||
|
and recompiling Tcl-DP. As of now, the following plug-in
|
||
|
filters are provided (unless specified otherwise, the
|
||
|
filters have no internal parameters):</p>
|
||
|
<ul>
|
||
|
<li>identity: Used as default value for a filter
|
||
|
function that was not defined explicitly.
|
||
|
Property: identity(X) = X. </li>
|
||
|
<li>plug1to2: The input string is filtered by
|
||
|
replacing each character of the string with two
|
||
|
copies of itself. Example:
|
||
|
Plug1to2("abc") = "aabbcc".</li>
|
||
|
<li>plug2to1: The input string is filtered by
|
||
|
selecting the characters that have even indices.
|
||
|
Example: Plug2to1("abcdef") =
|
||
|
"ace".</li>
|
||
|
<li>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'.</li>
|
||
|
<li>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".</li>
|
||
|
<li>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).</li>
|
||
|
<li>uudecode: Same functionality as Unix uudecode.
|
||
|
Example: uudecode("begin 740
|
||
|
uufilter\n$86C"O\\\n\n \nend\n") =
|
||
|
"abc".</li>
|
||
|
<li><dl>
|
||
|
<dt>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 <font size="2" face="Courier New">parameter</font>
|
||
|
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.</dt>
|
||
|
</dl>
|
||
|
</li>
|
||
|
<li>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.</li>
|
||
|
<li><dl>
|
||
|
<dt>hexin: Has the opposite effect to hexout.</dt>
|
||
|
</dl>
|
||
|
</li>
|
||
|
</ul>
|
||
|
</dd>
|
||
|
</dl>
|
||
|
|
||
|
<p><b>Filters as Independent Channels</b></p>
|
||
|
|
||
|
<p>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:</p>
|
||
|
|
||
|
<p>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.</p>
|
||
|
|
||
|
<p>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.</p>
|
||
|
|
||
|
<p><b>Properties of the Provided In-Built Filter Functions</b></p>
|
||
|
|
||
|
<p>Plug1to2(Plug2to1(X)) = X. </p>
|
||
|
|
||
|
<p>Plug2to1(Plug1to2(X)) = X. </p>
|
||
|
|
||
|
<p>xor(xor(X,Y),Y) = X.</p>
|
||
|
|
||
|
<p>packon(packoff(X)) = packoff(packon(X)).</p>
|
||
|
|
||
|
<p>uudecode(uuencode(X)) = X.</p>
|
||
|
|
||
|
<p>hexin(hexout(X)) = X</p>
|
||
|
|
||
|
<p>hexout(hexin(X)) = X</p>
|
||
|
|
||
|
<p>hexin(hexout(X)) != hexout(hexin(X))</p>
|
||
|
|
||
|
<p><b>Order of Operations</b></p>
|
||
|
|
||
|
<p>When flushing or closing a sequence of channels linked through
|
||
|
filters, one should follow the flow of data. </p>
|
||
|
|
||
|
<p>Example: filter1-->filter2-->TCP_channel </p>
|
||
|
|
||
|
<p>When closing this composite channel the sequence of operations
|
||
|
should be </p>
|
||
|
|
||
|
<p><tt>close $filter1<br>
|
||
|
close $filter2<br>
|
||
|
close $tcp_channel</tt></p>
|
||
|
|
||
|
<p><b>Configuration of Filter Channels </b></p>
|
||
|
|
||
|
<p>The subordinated channel and the input and output filter
|
||
|
functions of a filter channel can not be changed.</p>
|
||
|
|
||
|
<p>The peek option is forwarded to the subordinated channel, but
|
||
|
it does not act on the filter channel itself. </p>
|
||
|
|
||
|
<p>There are two options, <font size="2" face="Courier New">-inset</font>
|
||
|
and <font size="2" face="Courier New">-outset</font>, that can be
|
||
|
used to transmit arguments to the input and output filter
|
||
|
functions, respectively. The argument of <font size="2"
|
||
|
face="Courier New">-inset</font> and <font size="2"
|
||
|
face="Courier New">-outset</font> 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. </p>
|
||
|
|
||
|
<p>If the user wishes to change an option for the subordinated
|
||
|
channel, this must be done directly. </p>
|
||
|
|
||
|
<p>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. </p>
|
||
|
|
||
|
<p>Note: though tcl itself can not handle binary data, the
|
||
|
plug-in filters can. Care must be taken to set the <font size="2"
|
||
|
face="Courier New">-translation </font>option to binary for the
|
||
|
appropriate channels.</p>
|
||
|
|
||
|
<p><b>Composition of Filters</b></p>
|
||
|
|
||
|
<p>Both plug-in and independent channel filters can be composed
|
||
|
with no restrictions.</p>
|
||
|
|
||
|
<p><b>Examples </b></p>
|
||
|
|
||
|
<dl>
|
||
|
<dt><tt>dp_connect plugfilter -channel tcp1 -infilter
|
||
|
plug2to1 -outfilter plug1to2<br>
|
||
|
<br>
|
||
|
dp_connect plugfilter -channel email0 -outfilter pgp
|
||
|
-infilter un_pgp<br>
|
||
|
<br>
|
||
|
set xout [dp_connect plugfilter -channel file540
|
||
|
-outfilter uuencode<br>
|
||
|
fconfigure $xout -translation binary<br>
|
||
|
set xxout [dp_connect plugfilter -channel $xout
|
||
|
-outfilter xor]<br>
|
||
|
fconfigure $xxout -translation binary -outset "my
|
||
|
secret string goes here"<br>
|
||
|
<br>
|
||
|
set xin [dp_connect plugfilter -channel file100 -infilter
|
||
|
tclfilter]<br>
|
||
|
fconfigure $xin -inset MyTclProcedure<br>
|
||
|
<br>
|
||
|
dp_connect packoff -channel tcp10</tt></dt>
|
||
|
</dl>
|
||
|
|
||
|
<p>For more details, please refer to the tests/plugin2.test file
|
||
|
in the standard distribution.</p>
|
||
|
|
||
|
<p> </p>
|
||
|
</body>
|
||
|
</html>
|
||
|
|