-<!-- $Id: odr.xml,v 1.3 2001-07-20 21:34:36 adam Exp $ -->
- <chapter><title id="odr">The ODR Module</title>
+<!-- $Id: odr.xml,v 1.11 2003-11-19 21:17:26 adam Exp $ -->
+ <chapter id="odr"><title>The ODR Module</title>
- <sect1><title>Introduction</title>
+ <sect1 id="odr.introduction"><title>Introduction</title>
<para>
&odr; is the BER-encoding/decoding subsystem of &yaz;. Care as been taken
<para>
If you are only interested in writing a Z39.50 implementation based on
the PDUs that are already provided with &yaz;, you only need to concern
- yourself with the section on managing ODR streams (section
- <link linkend="odr-use">Using ODR</link>). Only if you need to
+ yourself with the section on managing ODR streams
+ (<xref linkend="odr.use"/>). Only if you need to
implement ASN.1 beyond that which has been provided, should you
worry about the second half of the documentation
(section <link linkend="odr-prog">Programming with ODR</link>).
</para>
<para>
- This is important, so we'll repeat it for emphasis: <emphasis>You do not
- need to read section <link linkend="odr-prog">Programming with ODR</link> to
- implement Z39.50 with &yaz;.</emphasis>
+ This is important, so we'll repeat it for emphasis: <emphasis>You do
+ not need to read section <link linkend="odr-prog">Programming with
+ ODR</link> to implement Z39.50 with &yaz;.</emphasis>
</para>
<para>
</para>
</sect1>
- <sect1><title id="odr-use">Using ODR</title>
+ <sect1 id="odr.use"><title>Using ODR</title>
<sect2><title>ODR Streams</title>
<para>
The memory subsystem of &odr; is fairly efficient at allocating and
releasing little bits of memory. Rather than managing the individual,
- small bits of space, the system maintains a freelist of larger chunks
+ small bits of space, the system maintains a free-list of larger chunks
of memory, which are handed out in small bits. This scheme is
generally known as a <emphasis>nibble memory</emphasis> system.
- It is very useful for maintaing short-lived constructions such
+ It is very useful for maintaining short-lived constructions such
as protocol PDUs.
</para>
The integer pointed to by len is set to the length of the encoded
data, and a pointer to that data is returned. <literal>*size</literal>
is set to the size of the buffer (unless <literal>size</literal> is null,
- signalling that you are not interested in the size). The next call to
+ signaling that you are not interested in the size). The next call to
a primitive function using the same &odr; stream will overwrite the
data, unless a different buffer has been supplied using the call
</para>
</para>
<para>
- It is important to realise that the ODR stream will not release this
+ It is important to realize that the ODR stream will not release this
memory when you call <function>odr_reset()</function>: It will
merely update its internal pointers to prepare for the encoding of a
new data value.
be released <emphasis>only</emphasis> if the <literal>can_grow</literal>
parameter to <function>odr_setbuf()</function> was nonzero. The
<literal>can_grow</literal> parameter, in other words, is a way of
- signalling who is to own the buffer, you or the ODR stream. If you never call
+ signaling who is to own the buffer, you or the ODR stream. If you never call
<function>odr_setbuf()</function> on your encoding stream, which is
typically the case, the buffer allocated by the stream will belong to
the stream by default.
data you wish to decode (eg, <function>odr_integer()</function> odr
<function>z_APDU()</function>).
</para>
-
- <para>
- Examples of encoding/decoding functions:
- </para>
-
- <synopsis>
- int odr_integer(ODR o, int **p, int optional, const char *name);
-
- int z_APDU(ODR o, Z_APDU **p, int optional, const char *name);
- </synopsis>
+
+ <example><title>Encoding and decoding functions</title>
+ <synopsis>
+ int odr_integer(ODR o, int **p, int optional, const char *name);
+
+ int z_APDU(ODR o, Z_APDU **p, int optional, const char *name);
+ </synopsis>
+ </example>
<para>
If the data is absent (or doesn't match the tag corresponding to
last call to <function>odr_reset()</function> will be released.
</para>
- <para>
- The use of the double indirection can be a little confusing at first
- (its purpose will become clear later on, hopefully),
- so an example is in order. We'll encode an integer value, and
- immediately decode it again using a different stream. A useless, but
- informative operation.
- </para>
-
- <programlisting>
-
+ <example><title>Encoding and decoding of an integer</title>
+ <para>
+ The use of the double indirection can be a little confusing at first
+ (its purpose will become clear later on, hopefully),
+ so an example is in order. We'll encode an integer value, and
+ immediately decode it again using a different stream. A useless, but
+ informative operation.
+ </para>
+ <programlisting><![CDATA[
void do_nothing_useful(int value)
{
ODR encode, decode;
odr_destroy(encode);
odr_destroy(decode);
}
- </programlisting>
-
- <para>
- This looks like a lot of work, offhand. In practice, the &odr; streams
- will typically be allocated once, in the beginning of your program
- (or at the beginning of a new network session), and the encoding
- and decoding will only take place in a few, isolated places in your
- program, so the overhead is quite manageable.
- </para>
-
+]]>
+ </programlisting>
+ <para>
+ This looks like a lot of work, offhand. In practice, the &odr; streams
+ will typically be allocated once, in the beginning of your program
+ (or at the beginning of a new network session), and the encoding
+ and decoding will only take place in a few, isolated places in your
+ program, so the overhead is quite manageable.
+ </para>
+ </example>
+
</sect2>
<sect2><title>Diagnostics</title>
</sect2>
</sect1>
- <sect1><title id="odr-prog">Programming with ODR</title>
+ <sect1 id="odr.programming"><title id="odr-prog">Programming with ODR</title>
<para>
The API of &odr; is designed to reflect the structure of ASN.1, rather
other external forms.
</para>
+ <tip>
+ <para>
+ There is an ASN.1 tutorial available at
+ <ulink url="http://asn1.elibel.tm.fr/en/introduction/">this site</ulink>.
+ This site also has standards for ASN.1 (X.680) and BER (X.690)
+ <ulink url="http://asn1.elibel.tm.fr/en/standards/">online</ulink>.
+ </para>
+ </tip>
+
<para>
- The interface is based loosely on that of the Sun Microsystems XDR routines.
+ The ODR interface is based loosely on that of the Sun Microsystems
+ XDR routines.
Specifically, each function which corresponds to an ASN.1 primitive
type has a dual function. Depending on the settings of the ODR
stream which is supplied as a parameter, the function may be used
either to encode or decode data. The functions that can be built
- using these primitive functions, to represent more complex datatypes, share
- this quality. The result is that you only have to enter the definition
- for a type once - and you have the functionality of encoding, decoding
- (and pretty-printing) all in one unit. The resulting C source code is
- quite compact, and is a pretty straightforward representation of the
- source ASN.1 specification. Although no ASN.1 compiler is supplied
- with &odr; at this time, it shouldn't be too difficult to write one, or
- perhaps even to adapt an existing compiler to output &odr; routines
- (not surprisingly, writing encoders/decoders using &odr; turns out
- to be boring work).
+ using these primitive functions, to represent more complex data types,
+ share this quality. The result is that you only have to enter the
+ definition for a type once - and you have the functionality of encoding,
+ decoding (and pretty-printing) all in one unit.
+ The resulting C source code is quite compact, and is a pretty
+ straightforward representation of the source ASN.1 specification.
</para>
-
+
<para>
In many cases, the model of the XDR functions works quite well in this
role.
In others, it is less elegant. Most of the hassle comes from the optional
- SEQUENCE memebers which don't exist in XDR.
+ SEQUENCE members which don't exist in XDR.
</para>
<sect2><title>The Primitive ASN.1 Types</title>
</para>
<synopsis>
-int odr_integer(ODR o, int **p, int optional, const char *name);
+ int odr_integer(ODR o, int **p, int optional, const char *name);
</synopsis>
<para>
(we don't allow values that can't be contained in a C integer.)
</para>
-
+
<para>
This form is typical of the primitive &odr; functions. They are named
after the type of data that they encode or decode. They take an &odr;
</synopsis>
<para>
- The functions are modelled after the manipulation functions that
+ The functions are modeled after the manipulation functions that
accompany the <literal>fd_set</literal> type used by the
<function>select(2)</function> call.
<literal>ODR_MASK_ZERO</literal> should always be called first on a
</synopsis>
<para>
- The C OID represenation is simply an array of integers, terminated by
+ The C OID representation is simply an array of integers, terminated by
the value -1 (the <literal>Odr_oid</literal> type is synonymous with
the <literal>int</literal> type).
We suggest that you use the OID database module (see section
<para>
The function <function>myInt()</function> can then be used like any of
the primitive functions provided by &odr;. Note that the behavior of
- <function>odr_explicit()</function>
- and <function>odr_implicit()</function> macros
+ <function>odr_explicit_tag()</function>
+ and <function>odr_implicit_tag()</function> macros
act exactly the same as the functions they are applied to - they
respond to error conditions, etc, in the same manner - they
simply have three extra parameters. The class parameter may
Note the 1 in the call to <function>odr_bool()</function>, to mark
that the sequence member is optional.
If either of the member types had been tagged, the macros
- <function>odr_implicit()</function> or <function>odr_explicit()</function>
+ <function>odr_implicit_tag()</function> or
+ <function>odr_explicit_tag()</function>
could have been used.
The new function can be used exactly like the standard functions provided
with &odr;. It will encode, decode or pretty-print a data value of the
You could, of course, name your structures, types, and functions any way
you please - as long as you're consistent, and your code is easily readable.
<literal>odr_ok</literal> is just that - a predicate that returns the
- state of the stream. It is used to ensure that the behaviour of the new
+ state of the stream. It is used to ensure that the behavior of the new
type is compatible with the interface of the primitive types.
</para>
<para>
which overrides the tag of the type immediately following it. The
- macro <function>odr_implicit()</function> works by calling
+ macro <function>odr_implicit_tag()</function> works by calling
<function>odr_implicit_settag()</function> immediately
before calling the function pointer argument.
Your type function could look like this:
Notice that the interface here gets kind of nasty. The reason is
simple: Explicitly tagged, constructed types are fairly rare in
the protocols that we care about, so the
- aesthetic annoyance (not to mention the dangers of a cluttered
+ esthetic annoyance (not to mention the dangers of a cluttered
interface) is less than the time that would be required to develop a
better interface. Nevertheless, it is far from satisfying, and it's a
point that will be worked on in the future. One option for you would
- be to simply apply the <function>odr_explicit()</function> macro to
+ be to simply apply the <function>odr_explicit_tag()</function> macro to
the first function, and not
have to worry about <function>odr_constructed_*</function> yourself.
Incidentally, as you might have guessed, the
<sect2><title>SEQUENCE OF</title>
<para>
- To handle sequences (arrays) of a apecific type, the function
+ To handle sequences (arrays) of a specific type, the function
</para>
<synopsis>
</para>
<para>
- The ASN.1 specifictions naturally requires that each member of a
+ The ASN.1 specifications naturally requires that each member of a
CHOICE have a distinct tag, so they can be told apart on decoding.
Sometimes it can be useful to define a CHOICE that has multiple types
that share the same tag. You'll need some other mechanism, perhaps
</sect2>
</sect1>
- <sect1><title>Debugging</title>
+ <sect1 id="odr.debugging"><title>Debugging</title>
<para>
The protocol modules are suffering somewhat from a lack of diagnostic
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document: "yaz.xml"
- sgml-local-catalogs: "../../docbook/docbook.cat"
+ sgml-local-catalogs: nil
sgml-namecase-general:t
End:
-->