Security-54.1.9.tar.gz
[apple/security.git] / SecuritySNACCRuntime / doc / c-lib.tex
CommitLineData
bac41a7b
A
1% file: .../doc/c-lib.tex
2
a66d0d4a 3% $Header: /cvs/root/Security/SecuritySNACCRuntime/doc/Attic/c-lib.tex,v 1.1.1.1 2001/05/18 23:14:10 mb Exp $
bac41a7b
A
4% $Log: c-lib.tex,v $
5% Revision 1.1.1.1 2001/05/18 23:14:10 mb
6% Move from private repository to open source repository
7%
8% Revision 1.1.1.1 1999/03/16 18:05:52 aram
9% Originals from SMIME Free Library.
10%
11% Revision 1.1 1997/01/01 22:47:34 rj
12% first check-in
13%
14
15\chapter{\label{lib-C-chapter}C ASN.1 Library}
16\section{\label{libover-C-section}Overview}
17
18Each library type has a file in the {\ufn \dots/c-lib/src/} and
19{\ufn \dots/c-lib/inc/} directories. Each source file contains the encode,
20decode, free and print routines for the given type. This chapter
21contains a description of each library type and its routines.
22This library is also referred to as the runtime library.
23
24After installing Snacc, you should test the library types to make sure
25that they are encoding and decoding properly. Use the
26{\ufn \dots/c-examples/test-lib/} example to check them.
27
28In addition to other errors, most decoding routines will report an
29error if they attempt to read past the end of the data. Be aware that
30some buffer types do not support this type of checking. This is
31explained more in the buffer management section.
32
33\section{\label{tag-C-section}Tags}
34
35Snacc's tag representation was motivated by several things.
36\begin{enumerate}
37\item the tags must be easy to compare for equality in {\C if} and {\C switch} statements to make tag-based decisions cheap.
38\item a tag must be cheap to decode.
39\item a tag must be cheap to encode.
40\end{enumerate}
41
42The first requirement meant that tags had to be integer types (for the
43{\C switch} statement). The representation of the tag within the integer
44was set by the second requirement.
45
46The best way to decode cheaply is minimize the transformation between
47the encoded and decoded (internal) format. So the four (can be set-up
48for two) bytes of the long integer are used to hold the encoded tag,
49starting with the first octet of the tag in the most significant byte
50of the integer and the rest (if any) following. Any unused (always
51trailing) bytes in the integer are zero. This limits the
52representable tag code to less than $2^{21}$ but for reasonable ASN.1
53specifications this should not be a problem.
54
55To meet the third requirement the decoded tag representation was
56bypassed entirely by using macros ({\C BEncTag1()} etc.) that
57write the encoded tag octet(s) to the buffer. The writing of an
58encoded tag octet involves bit shifting, bitwise ands and bitwise ors
59with constant values; most optimizing C compilers can compute these at
60compile time. This simplifies encoding a tag to writing some constant
61byte value(s) to the buffer.
62
63The following excerpt from {\ufn \dots/c-lib/inc/asn-tag.h} shows some
64of the tag routines.
65\begin{small}
66\begin{verbatim}
67typedef unsigned long int AsnTag;
68
69#define MAKE_TAG_ID( class, form, code) ...
70#define TAG_IS_CONS( tag) ...
71
72#define BEncTag1( b, class, form, code) ...
73#define BEncTag2( b, class, form, code) ...
74#define BEncTag3( b, class, form, code) ...
75#define BEncTag4( b, class, form, code) ...
76#define BEncTag5( b, class, form, code) ...
77
78AsnTag BDecTag (BUF_TYPE b, AsnLen *bytesDecoded, ENV_TYPE env);
79\end{verbatim}
80\end{small}
81
82The generated decode routines use the {\C BDecTag} to decode a tag
83from the buffer. The returned tag value is either used in an
84{\C if} expression or as the argument to {\C switch} statements.
85The {\C MAKE\_TAG\_ID} macro is used to make a tag for comparison to
86the one returned by {\C BDecTag}. The {\C MAKE\_TAG\_ID} is used is
87{\C switch} statement case labels and in {\C if} statements.
88
89Most of the time tags are only compared for equality, however, the
90OCTET STRING and BIT STRING decoders check the constructed bit in the
91tag using the {\C TAG\_IS\_CONS} macro.
92
93The {\C BEncTag} macros are quite fragile because they return the
94encoded length of the tag; they cannot be treated as a single
95statement. This requires careful use of braces when using them in
96your own code in places such as the sole statement in an {\C if}
97statement. This ugliness is caused by the difficulty in returning
98values from multi-line macros (macros are used for performance here
99since encoding tags can be a significant part of BER encoding).
100
101The {\C BDecTag} routine will report an error via {\C longjmp} if
102the encoded tag is longer than can be held in the {\C AsnTag} type
103or if it read past the end of the data when decoding the tag.
104
105\section{\label{len-C-section}Lengths}
106
107Decoded lengths are represented by unsigned long integers, with the
108maximum value indicating indefinite length.
109
110Snacc users can choose between using only indefinite or only definite
111lengths when encoding constructed values' lengths when compiling the
112generated code. Of course, the generated decoders can handle both
113forms. Define the {\C USE\_INDEF\_LEN} symbol when compiling the
114generated code if you want to use indefinite lengths when encoding
115constructed values. Primitive values are always encoded with definite
116lengths as required by the standard; this is necessary to avoid
117confusion between a value's content and the End-Of-Contents marker.
118
119There is no loss of performance when using definite lengths with snacc
120encoders. This is due the ``backwards'' encoding as described in
121Section~\ref{encode-gen-C-section}. The schemes used by other compilers'
122encoders to handle definite lengths may hurt performance.
123
124Most of the routines in the following code are obvious except for
125{\C BEncDefLenTo127()}. This is used instead of {\C BEncDefLen}
126in the generated code when the compiler knows the value being encoded
127will not be over 127 octets long. Values such as BOOLEANs,
128INTEGERs, and REALs are assumed to be shorter than 127 octets
129(constraints on the decoded representation of INTEGERs and REALs make
130this valid).
131\begin{small}
132\begin{verbatim}
133typedef unsigned long int AsnLen;
134
135/* max unsigned value - used for internal rep of indef len */
136#define INDEFINITE_LEN ~0L
137
138#ifdef USE_INDEF_LEN
139#define BEncEocIfNec( b) BEncEoc (b)
140#define BEncConsLen(b, len) 2 + BEncIndefLen (b)
141#else
142#define BEncEocIfNec( b)
143#define BEncConsLen( b, len) BEncDefLen (b, len)
144#endif
145
146#define BEncIndefLen( b) ...
147#define BEncDefLenTo127( b, len) ...
148AsnLen BEncDefLen (BUF_TYPE b, AsnLen len);
149AsnLen BDecLen (BUF_TYPE b, AsnLen *bytesDecoded, ENV_TYPE env);
150
151#define BEncEoc( b) ...
152#define BDEC_2ND_EOC_OCTET( b, bytesDecoded, env) ...
153void BDecEoc (BUF_TYPE b, AsnLen *bytesDecoded, ENV_TYPE env);
154\end{verbatim}
155\end{small}
156
157The {\C BDecLen} routine will report an error via {\C longjmp} if
158it attempts to read past the end of the data or the decoded length is
159too large to be held in the {\C AsnLen} representation.
160{\C BDecEoc} will report an error if it attempts to read past the
161end of the data or one of the EOC (End-Of-Contents) octets is
162non-zero.
163
164\section{\label{bool-C-section}BOOLEAN}
165
166The BOOLEAN type is represented by an {\C unsigned char}. It has
167the following routines for manipulating it.
168\begin{small}
169\begin{verbatim}
170typedef unsigned char AsnBool;
171
172AsnLen BEncAsnBool (BUF_TYPE b, AsnBool *data);
173void BDecAsnBool (BUF_TYPE b, AsnBool *result, AsnLen *bytesDecoded,
174 ENV_TYPE env);
175
176AsnLen BEncAsnBoolContent (BUF_TYPE b, AsnBool *data);
177void BDecAsnBoolContent (BUF_TYPE b, AsnTag tag, AsnLen len,
178 AsnBool *result, AsnLen *bytesDecoded,
179 ENV_TYPE env);
180
181#define FreeAsnBool( v)
182void PrintAsnBool (FILE *f, AsnBool *b, unsigned short int indent);
183\end{verbatim}
184\end{small}
185
186As discussed in Sections \ref{encode-gen-C-section} and \ref{decode-gen-C-section},
187{\C BEncAsnBool} and {\C BDecAsnBool} encode/decode the UNIVERSAL
188tag, length and content of the given BOOLEAN value. The\linebreak {\C BEncAsnBoolContent} and {\C BDecAsnBoolContent} routine only
189encode/decode the content of the given BOOLEAN value.
190
191The {\C FreeAsnBool} routine does nothing since the BOOLEAN type
192does not contain pointers to data; the free routine generator does not
193have to check which types need freeing and simply calls the type's
194free routine. It also allows the user to modify the types and their
195free routines without changing the free routine generator. However,
196the ANY and ANY DEFINED BY type hash table initialization routine
197generator does need to know which types have empty free routines
198because the hash entries contain pointers to the free functions (NULL
199is used for the empty free functions like {\C FreeAsnBool}). The
200INTEGER, NULL, REAL and ENUMERATED types have empty free routines for
201the same reason.
202
203{\C BDecAsnBool} will report an error if the tag is not
204UNIVERSAL-PRIM-1. {\C BDecAsnBoolContent} will report an error if it
205decodes past the end of the data or the length of the encoded value
206(given by the {\C len} parameter) is not exactly one octet.
207
208\section{\label{int-C-section}INTEGER}
209
210The INTEGER type is represented by a 32 bit integer type, {\C AsnInt}.
211The C integer type chosen depends on the machine and compiler and may be {\C int}, {\C long} or {\C short}, whatever is 32 bits in size.
212If you are using INTEGER types that are only positive (via subtyping or
213protocol definition) you may want to use the {\C UAsnInt} and
214associated routines that use the unsigned int for a larger positive value range.
215\begin{small}
216\begin{verbatim}
217typedef int AsnInt;
218typedef unsigned int UAsnInt;
219
220AsnLen BEncAsnInt (BUF_TYPE b, AsnInt *data);
221void BDecAsnInt (BUF_TYPE b, AsnInt *result, AsnLen *bytesDecoded,
222 ENV_TYPE env);
223
224AsnLen BEncAsnIntContent (BUF_TYPE b, AsnInt *data);
225void BDecAsnIntContent (BUF_TYPE b, AsnTag tag, AsnLen elmtLen,
226 AsnInt *result, AsnLen *bytesDecoded,
227 ENV_TYPE env);
228
229#define FreeAsnInt( v)
230void PrintAsnInt (FILE *f, AsnInt *v, unsigned short int indent);
231
232AsnLen BEncUAsnInt (BUF_TYPE b, UAsnInt *data);
233void BDecUAsnInt (BUF_TYPE b, UAsnInt *result, AsnLen *bytesDecoded,
234 ENV_TYPE env);
235
236AsnLen BEncUAsnIntContent (BUF_TYPE b, UAsnInt *data);
237void BDecUAsnIntContent (BUF_TYPE b, AsnTag tagId, AsnLen len,
238 UAsnInt *result, AsnLen *bytesDecoded,
239 ENV_TYPE env);
240
241#define FreeUAsnInt( v)
242void PrintUAsnInt (FILE *f, UAsnInt *v, unsigned short int indent);
243\end{verbatim}
244\end{small}
245
246{\C BDecAsnInt} will report an error if the tag is not
247UNIVERSAL-PRIM-2. {\C BDecAsnIntContent} will report an error if it
248decodes past the end of the data or the integer value is too large for
249an {\C AsnInt}.
250
251\section{\label{null-C-section}NULL}
252
253The NULL type is represented by the {\C AsnNull} type. Its content
254is always empty and hence its encoded length always is zero.
255\begin{small}
256\begin{verbatim}
257typedef char AsnNull;
258
259AsnLen BEncAsnNull (BUF_TYPE b, AsnNull *data);
260void BDecAsnNull (BUF_TYPE b, AsnNull *result, AsnLen *bytesDecoded,
261 ENV_TYPE env);
262
263/* 'return' length of encoded NULL value, 0 */
264#define BEncAsnNullContent(b, data) 0
265void BDecAsnNullContent (BUF_TYPE b, AsnTag tag, AsnLen len,
266 AsnNull *result, AsnLen *bytesDecoded,
267 ENV_TYPE env);
268
269#define FreeAsnNull( v)
270void PrintAsnNull (FILE *f, AsnNull * b, unsigned short int indent);
271\end{verbatim}
272\end{small}
273
274\section{\label{real-C-section}REAL}
275
276The REAL type is represented by {\C AsnReal}, a double. This type's
277representation can depend on the compiler or system you are using so
278several different encoding routines are provided.
279Even so, you may need to modify the code.
280
281If you are using the REAL type in your ASN.1 modules, you should call the
282{\C InitAsnInfinity()} routine to setup the {\C PLUS\_INFINITY}
283and {\C MINUS\_INFINITY} values.
284
285There are three encode routines included and they can be selected by
286defining one of {\C IEEE\_REAL\_FMT}, {\C IEEE\_REAL\_LIB} or nothing.
287Defining {\C IEEE\_REAL\_FMT} uses the encode routine that assumes the
288double representation is the standard IEEE double \cite{68881}.
289Defining {\C IEEE\_REAL\_LIB} uses the encode routine that assumes the
290IEEE functions library (isinf, scalbn, signbit etc.\ ) is available.
291If neither are defined, the default encode routine uses {\C frexp}.
292
293There is only one content decoding routine and it builds the value
294through multiplication and the {\C pow} routine (requires the math
295library). The content decoding routine only supports the binary
296encoding of a REAL, not the decimal encoding.
297
298\begin{small}
299\begin{verbatim}
300typedef double AsnReal;
301
302extern AsnReal PLUS_INFINITY;
303extern AsnReal MINUS_INFINITY;
304
305void InitAsnInfinity();
306AsnLen BEncAsnReal (BUF_TYPE b, AsnReal *data);
307void BDecAsnReal (BUF_TYPE b, AsnReal *result, AsnLen *bytesDecoded,
308 ENV_TYPE env);
309
310AsnLen BEncAsnRealContent (BUF_TYPE b, AsnReal *data);
311void BDecAsnRealContent (BUF_TYPE b, AsnTag tag, AsnLen len,
312 AsnReal *result, AsnLen *bytesDecoded,
313 ENV_TYPE env);
314
315/* do nothing */
316#define FreeAsnReal( v)
317void PrintAsnReal (FILE *f, AsnReal *b, unsigned short int indent);
318\end{verbatim}
319\end{small}
320
321{\C BDecAsnReal} will report an error if the value's tag is not UNIVERSAL-PRIM-9.
322{\C BDecAsnRealContent} will report an error if the base is not supported or the decimal type REAL encoding is received.
323
324
325\section{\label{bits-C-section}BIT STRING}
326
327The BIT STRING type is represented by the {\C AsnBits} structure. It
328contains a pointer to the bits and integer that holds the length
329in bits of the BIT STRING\@.
330
331In addition to the standard encode, decode, print and free routines,
332there are some other utility routines. {\C AsnBitsEquiv} returns
333TRUE if the given BIT STRINGs are identical. The {\C SetAsnBit},
334{\C ClrAsnBit} and {\C GetAsnBit} are routines for writing and
335reading a BIT STRING value.
336
337You may notice that the AsnBits type does not have any means of
338handling linked pieces of BIT STRINGs. Some ASN.1 tools use lists of
339structures like {\C AsnBits} to represent BIT STRINGs. This is done
340because, as you should be aware, BIT STRINGs can be encoded in a
341nested, constructed fashion. The snacc BIT STRING decoder attempts to
342save you the hassle of dealing with fragments of BIT STRINGs by
343concatenating them in the decoding step. Every BIT STRING value
344returned by the decoder will have contiguous bits.
345
346Some people contend that fragmented BIT STRINGs are necessary to
347support systems that lack enough memory to hold the entire value.
348Snacc encodes value ``backwards'' so the entire value must be encoded
349before it can be sent, thus you must have enough memory to hold the
350whole encoded value. If the fragmented representation is useful to
351your protocol implementation for other reasons, it should be fairly
352simple to modify the BIT STRING routines. Remember, no significance
353should be placed on where constructed BIT STRING values are fragmented.
354
355Snacc uses a table to hold pointers to the BIT STRING fragments in the
356buffer while it is decoding them. Once the whole BIT STRING value has
357been decoded, a block of memory that is large enough to hold the
358entire BIT STRING is allocated and the fragments are copied into it.
359The table initially can hold pointers to 128 fragments. If more table
360entries are needed the stack will grow via {\C realloc} (with
361associated performance loss) and will not shrink after growing. If
362you wish to modify this behaviour, change the
363{\ufn \dots/c-lib/inc/str-stk.h} file.
364
365The {\C FreeAsnBits} routine will free memory referenced by the
366{\C bits} pointer.
367
368\begin{small}
369\begin{verbatim}
370typedef struct AsnBits
371{
372 int bitLen;
373 char *bits;
374} AsnBits;
375
376extern char numToHexCharTblG[];
377#define TO_HEX( fourBits) (numToHexCharTblG[(fourBits) & 0x0f])
378#define ASNBITS_PRESENT( abits) ((abits)->bits != NULL)
379
380AsnLen BEncAsnBits (BUF_TYPE b, AsnBits *data);
381void BDecAsnBits (BUF_TYPE b, AsnBits *result, AsnLen *bytesDecoded,
382 ENV_TYPE env);
383
384AsnLen BEncAsnBitsContent (BUF_TYPE b, AsnBits *bits);
385void BDecAsnBitsContent (BUF_TYPE b, AsnLen len, AsnTag tagId,
386 AsnBits *result, AsnLen *bytesDecoded,
387 ENV_TYPE env);
388
389void FreeAsnBits (AsnBits *v);
390void PrintAsnBits (FILE *f, AsnBits *b, unsigned short int indent);
391
392int AsnBitsEquiv (AsnBits *b1, AsnBits *b2);
393void SetAsnBit (AsnBits *b1, unsigned long int bit);
394void ClrAsnBit (AsnBits *b1, unsigned long int bit);
395int GetAsnBit (AsnBits *b1, unsigned long int bit);
396\end{verbatim}
397\end{small}
398
399{\C BDecAsnBits} will report an error if the tag is not UNIVERSAL-CONS-3 or UNIVERSAL-PRIM-3.
400When decoding constructed BIT STRING BER values, an error will be reported if a component other than the last one has non-zero unused bits in its last octet or an internal component does not have the UNIVERSAL-3 tag.
401If the decoder attempts to read past the end of the data an error will be reported.
402
403
404\section{\label{octets-C-section}OCTET STRING}
405The OCTET STRING type is represented by the {\C AsnOcts} structure.
406It contains a pointer to the octets and an integer that holds the length in octets of the OCTET STRING\@.
407
408As with BIT STRINGs, OCTET STRINGs can have constructed values. These
409are handled in the same way as the constructed BIT STRING values. The
410decoded representation of an OCTET STRING is always contiguous.
411
412The {\C FreeAsnOcts} routine will free the memory referenced by the
413{\C octs} pointer. The {\C AsnOctsEquiv} routine will return TRUE
414if the given OCTET STRINGs are identical.
415
416\begin{small}
417\begin{verbatim}
418typedef struct AsnOcts
419{
420 unsigned long int octetLen;
421 char *octs;
422} AsnOcts;
423
424#define ASNOCTS_PRESENT( aocts) ((aocts)->octs != NULL)
425
426AsnLen BEncAsnOcts (BUF_TYPE b, AsnOcts *data);
427
428void BDecAsnOcts (BUF_TYPE b, AsnOcts *result, AsnLen *bytesDecoded,
429 ENV_TYPE env);
430
431AsnLen BEncAsnOctsContent (BUF_TYPE b, AsnOcts *octs);
432void BDecAsnOctsContent (BUF_TYPE b, AsnLen len, AsnTag tagId,
433 AsnOcts *result, AsnLen *bytesDecoded,
434 ENV_TYPE env);
435
436void FreeAsnOcts (AsnOcts *o);
437void PrintAsnOcts (FILE *f, AsnOcts *o, unsigned short int indent);
438
439int AsnOctsEquiv (AsnOcts *o1, AsnOcts *o2);
440\end{verbatim}
441\end{small}
442
443{\C BDecAsnOcts} will report an error if the tag is not
444UNIVERSAL-CONS-4 or UNIVERSAL-PRIM-4. When decoding constructed OCTET
445STRING BER values, an error will be reported if an internal component
446does not have the UNIVERSAL-4 tag. If the decoder attempts to read
447past the end of the data an error will be reported.
448
449
450\section{\label{oid-C-section}OBJECT IDENTIFIER}
451
452In snacc, OBJECT IDENTIFIERs are kept in their encoded form to improve
453performance. The {\C AsnOid} type is defined as {\C AsnOcts}, as
454it holds the octets of the encoded OBJECT IDENTIFIER\@. It seems that
455the most common operation with OBJECT IDENTIFIERs is to compare for
456equality, for which the encoded representation (which is canonical)
457works well.
458
459There is a linked OBJECT IDENTIFIER representation called {\C OID}
460and routines to convert it to and from the {\C AsnOid} format, but it
461should not be used if performance is an issue.
462
463Since the OBJECT IDENTIFIERs are represented {\C AsnOcts}, the
464{\C AsnOcts} content encoding routine can be used for the
465{\C AsnOid} content encoding routine. The other {\C AsnOcts}
466encoding and decoding routines cannot be used because the OBJECT
467IDENTIFIER has a different tag and cannot be encoded in a constructed
468fashion.
469
470An OBJECT IDENTIFIER must have a minimum of two arc numbers but the
471decoding routines do not check this.
472
473\begin{small}
474\begin{verbatim}
475typedef AsnOcts AsnOid;
476
477#define ASNOID_PRESENT( aoid) ASNOCTS_PRESENT (aoid)
478
479AsnLen BEncAsnOid (BUF_TYPE b, AsnOid *data);
480void BDecAsnOid (BUF_TYPE b, AsnOid *result, AsnLen *bytesDecoded,
481 ENV_TYPE env);
482
483#define BEncAsnOidContent(b, oid) BEncAsnOctsContent(b, oid)
484void BDecAsnOidContent (BUF_TYPE b, AsnTag tag, AsnLen len,
485 AsnOid *result, AsnLen *bytesDecoded,
486 ENV_TYPE env);
487
488#define FreeAsnOid FreeAsnOcts
489void PrintAsnOid (FILE *f, AsnOid *b, unsigned short int indent);
490
491#define AsnOidsEquiv( o1, o2) AsnOctsEquiv (o1, o2)
492\end{verbatim}
493\end{small}
494
495
496\section{\label{list-C-section}SET OF and SEQUENCE OF}
497
498The SET OF and SEQUENCE OF type are represented by the {\C AsnList}
499structure. An {\C AsnList} consists of a head object that has
500pointers to the first, current and last nodes and the current number
501of nodes in the list. Each list node has a pointer to its next and
502previous list member and the node's data. The first list node's
503previous pointer is always NULL and the last list node's next pointer
504is always NULL\@.
505
506Each SET OF or SEQUENCE OF type is defined as an {\C AsnList}, so the
507element type information (kept via a {\C void~*}) is not kept,
508therefore, the {\C AsnList} type is not type safe.
509
510The {\C AsnList} is a doubly linked list to simplify ``backwards''
511encoding. The reverse link allows the list to be traversed in reverse
512so the components can be encoded from last to first.
513
514Initially, the lists were designed to allow the list element itself to
515be contained in the list node (hence the {\C elmtSize} parameter to
516the AsnListNew() routine). The design eventually changed such that
517every list element was reference by pointer from the list node.
518
519A small problem with the {\C AsnListNew} routine is the memory
520allocation. Since it is used by the decoding routines to allocate new
521lists, it uses whatever memory management you have setup with the
522{\C Asn1Alloc} macro (see Section~\ref{lib-mem-C-section}). This may not be
523desirable when building values to be transmitted. You may need to
524provide another AsnListNew routine that uses a different allocation
525scheme to solve this.
526
527\begin{small}
528\begin{verbatim}
529typedef struct AsnListNode
530{
531 struct AsnListNode *prev;
532 struct AsnListNode *next;
533 void *data; /* this must be the last field of this structure */
534} AsnListNode;
535
536typedef struct AsnList
537{
538 AsnListNode *first;
539 AsnListNode *last;
540 AsnListNode *curr;
541 int count; /* number of elements in list */
542 int dataSize; /* space required in each node for the data */
543} AsnList;
544
545#define FOR_EACH_LIST_ELMT( elmt, list) ...
546#define FOR_EACH_LIST_ELMT_RVS( elmt, list) ...
547#define FOR_REST_LIST_ELMT( elmt, al) ...
548
549#define CURR_LIST_ELMT( al) (al)->curr->data
550#define NEXT_LIST_ELMT( al) (al)->curr->next->data
551#define PREV_LIST_ELMT( al) (al)->curr->prev->data
552#define LAST_LIST_ELMT( al) (al)->last->data
553#define FIRST_LIST_ELMT( al) (al)->first->data
554#define LIST_EMPTY(al) (( al)->count == 0)
555
556#define CURR_LIST_NODE( al) ((al)->curr)
557#define FIRST_LIST_NODE( al) ((al)->first)
558#define LAST_LIST_NODE( al) ((al)->last)
559#define PREV_LIST_NODE( al) ((al)->curr->prev)
560#define NEXT_LIST_NODE( al) ((al)->curr->next)
561#define SET_CURR_LIST_NODE( al, listNode) ((al)->curr = (listNode))
562
563void AsnListRemove (AsnList *l);
564void *AsnListAdd (AsnList *l);
565void *AsnListInsert (AsnList *list);
566void AsnListInit (AsnList *list, int dataSize);
567AsnList *AsnListNew (int elmtSize);
568void *AsnListPrev (AsnList *);
569void *AsnListNext (AsnList *);
570void *AsnListLast (AsnList *);
571void *AsnListFirst (AsnList *);
572void *AsnListPrepend (AsnList *);
573void *AsnListAppend (AsnList *);
574void *AsnListCurr (AsnList *);
575int AsnListCount (AsnList *);
576AsnList *AsnListConcat (AsnList *, AsnList *);
577\end{verbatim}
578\end{small}
579
580There are a number of macros for dealing with the list type, the
581most important being the list traversal macros. The
582{\C FOR\_EACH\_LIST\_ELMT} macro acts like a ``for'' statment that
583traverses forward through the list. The first parameter should be a
584pointer to the list element type that will be used to hold the current list
585element for each iteration of the ``for'' loop. The second parameter is
586the list of elements that you wish to traverse.
587
588The {\C FOR\_EACH\_LIST\_ELMT\_RVS} macro is identical to the
589{\C FOR\_EACH\_LIST\_ELMT} macro except that is moves from the back of
590the list to the front. The {\C FOR\_REST\_LIST\_ELMT} macro is
591similar to the other two but it does not reset the {\C curr} pointer
592in the {\C AsnList} type. This has the effect of iterating from the
593current element to the end of the list. Look in the generated code
594for a better indication of how to use these macros. The other macros
595are straight forward.
596
597
598\section{\label{any-C-section}ANY and ANY DEFINED BY}
599
600
601The ANY and ANY DEFINED BY type are classically the most irritating
602ASN.1 types for compiler writers. They rely on mechanisms outside of
603ASN.1 to specify what types they contain. The 1992 ASN.1 standard has
604rectified this by adding much stronger typing semantics and eliminating
605macros.
606
607The ANY DEFINED BY type can be handled automatically by {\em snacc} if
608the SNMP OBJECT-TYPE \cite{snmp} macro is used to specify the
609identifier value to type mappings. The identifier can be an INTEGER
610or OBJECT IDENTIFIER\@. Handling ANY types properly will require
611modifications to the generated code since there is no identifier
612associated with the type.
613
614The general approach used by {\em snacc} to handle ANY DEFINED BY
615types is to lookup the identifier value in a hash table for the
616identified type. The hash table entry contains information about the
617type such as the routines to use for encoding and decoding.
618
619Two hash tables are used, one for INTEGER to type mappings and the
620other for OBJECT IDENTIFIER to type mappings. {\em Snacc} generates
621an {\tt InitAny} routine for each module that uses the OBJECT-TYPE
622macro. This routine adds entries to the hash table(s). The {\tt
623InitAny} routine(s) is called once before any encoding or decoding is
624done.
625
626
627The hash tables are constructed such that an INTEGER or OBJECT
628IDENTIFIER value will hash to an entry that contains:
629\begin{itemize}
630\item {the {\tt anyId}}
631\item {the INTEGER or OBJECT IDENTIFIER that maps to it}
632\item {the size in bytes of the identified data type}
633\item {a pointer to the type's PDU encode routine}
634\item {a pointer to the type's PDU decode routine}
635\item {a pointer to the type's print routine}
636\item {a pointer to the type's free routine}
637\end{itemize}
638The referenced encode and decode routines are PDU oriented in that
639they encode the type's tag(s) and length(s) as well as the type's
640content.
641
642{\em Snacc} builds an {\tt enum} called {\tt AnyId} that enumerates
643each mapping defined by the OBJECT-TYPE macros. The name of the value
644associated with each macro is used as part of the enumerated
645identifier. The {\tt anyId} in the hash table holds the identified
646type's {\tt AnyId enum} value. The {\tt anyId} is handy for making
647decisions based on the received identifier, without comparing OBJECT
648IDENTIFIERs. If the identifiers are INTEGERs then the {\tt anyId} is
649less useful.
650
651With ANY DEFINED BY types, it is important to have the identifier
652decoded before the ANY DEFINED BY type is decoded. Hence, an ANY
653DEFINED BY type should not be declared before its identifier in a SET
654since SETs are un-ordered. An ANY DEFINED BY type should not be
655declared after its identifier in a SEQUENCE\@. {\em Snacc} will print a
656warning if either of these situations occur.
657
658The hash tables may be useful to plain ANY types which do not have an
659identifier field like the ANY DEFINED BY types; the OBJECT-TYPE macro
660can be used to define the mappings and the {\tt SetAnyTypeByInt} or
661{\tt SetAnyTypeByOid} routine can be called with the appropriate
662identifier value before encoding or decoding an ANY value. The
663compiler will insert calls to these routines where necessary with some
664of the arguments left as ``???''. There will usually be a ``{\tt /*
665ANY -- Fix me! */}'' comment before code that needs to be modified to
666correctly handle the ANY type. The code generated from an ASN.1
667module that uses the ANY type will not compile without modifications.
668
669OPTIONAL ANYs and ANY DEFINED BY types that have not been tagged are a
670special problem for {\em snacc}. Unless they are the last element of a SET
671or SEQUENCE, the generated code will need to be modified. {\em Snacc} will
672print a warning message when it encounters one of these cases.
673
674To illustrate how ANY DEFINED BY values are handled, we present
675typical encoding and decoding scenarios. Each ANY or ANY DEFINED BY
676type is represented in C by the {\tt AsnAny} type which contains only
677a {\tt void *} named {\tt value} to hold a pointer to the value and a
678{\tt AnyInfo *} named {\tt ai} which points to a hash table entry.
679
680When encoding, before the ANY DEFINED BY value is encoded, {\tt
681SetAnyTypeByOid} or {\tt SetAnyTypeByInt} (depending on the type of
682the identifier) is called with the current identifier value to set the
683{\tt AsnAny} value's {\tt ai} pointer to the proper hash table entry.
684Then to encode the ANY DEFINED BY value, the encode routine pointed to
685from the hash table entry is called with the {\tt value} {\tt void *}
686from the {\tt AsnAny} value. The {\tt value} {\tt void *} in the {\tt
687AsnAny} should point to a value of the correct type for the given
688identifier, if the user set it up correctly. Note that setting the
689{\tt void *} value is not type safe; one must make sure that the
690value's type is the same as indicated by the identifier.
691
692For decoding, the identifier must be decoded prior to the ANY DEFINED
693BY value otherwise the identifier will contain an uninitialized value.
694Before the ANY or ANY DEFINED BY value is decoded, {\tt
695SetAnyTypeByOid} or {\tt SetAnyTypeByInt} (depending on the type of
696the identifier) is called to set the {\tt AsnAny} value's {\tt ai}
697pointer to the proper hash table entry. Then a block of memory of the
698size indicated in the hash table entry is allocated, and its pointer
699stored in the {\tt AsnAny} value's {\tt void *} entry. Then the decode
700routine pointed to from the hash table entry is called with the newly
701allocated block as its value pointer parameter. The decode routine
702fills in the value assuming it is of the correct type. Simple!
703
704There is a problem with {\em snacc}'s method for handling ANY DEFINED
705BY types for specifications that have two or more ANY DEFINED BY types
706that share some identifier values. Since only two hash tables are
707used and they are referenced using the identifier value as a key,
708duplicate identifiers will cause unresolvable hash collisions.
709
710Here is some of the {\C AsnAny} related code from the header file. It
711should help you understand the way things are done a bit better. Look
712in the {\ufn hash.c} and {\ufn hash.h} files as well.
713\begin{small}
714\begin{verbatim}
715/*
716 * 1 hash table for integer keys
717 * 1 hash table for oid keys
718 */
719extern Table *anyOidHashTblG;
720extern Table *anyIntHashTblG;
721
722typedef (*EncodeFcn) (BUF_TYPE b, void *value);
723typedef void (*DecodeFcn) (BUF_TYPE b, void *value,
724 AsnLen *bytesDecoded, ENV_TYPE env);
725typedef void (*FreeFcn) (void *v);
726typedef void (*PrintFcn) (FILE *f, void *v);
727
728/*
729 * this is put into the hash table with the
730 * int or oid as the key
731 */
732typedef struct AnyInfo
733{
734 int anyId; /* will be a value from the AnyId enum */
735 AsnOid oid; /* will be zero len/null if intId is valid */
736 AsnInt intId;
737 unsigned int size; /* size of the C data type (ie as ret'd by sizeof) */
738 EncodeFcn Encode;
739 DecodeFcn Decode;
740 FreeFcn Free;
741 PrintFcn Print;
742} AnyInfo;
743
744typedef struct AsnAny
745{
746 AnyInfo *ai; /* point to entry in hash tbl that has routine ptrs */
747 void *value; /* points to the value */
748} AsnAny;
749
750/*
751 * Returns anyId value for the given ANY type.
752 * Use this to determine to the type of an ANY after decoding
753 * it. Returns -1 if the ANY info is not available
754 */
755#define GetAsnAnyId( a) (((a)->ai)? (a)->ai->anyId: -1)
756
757/*
758 * used before encoding or decoding a type so the proper
759 * encode or decode routine is used.
760 */
761void SetAnyTypeByInt (AsnAny *v, AsnInt id);
762void SetAnyTypeByOid (AsnAny *v, AsnOid *id);
763
764
765/*
766 * used to initialize the hash table(s)
767 */
768void InstallAnyByInt (int anyId, AsnInt intId,
769 unsigned int size, EncodeFcn encode,
770 DecodeFcn decode, FreeFcn free, PrintFcn print);
771
772void InstallAnyByOid (int anyId, AsnOid *oid, unsigned int size,
773 EncodeFcn encode, DecodeFcn decode, FreeFcn free,
774 PrintFcn print);
775
776/*
777 * Standard enc, dec, free, & print routines.
778 * for the AsnAny type.
779 * These call the routines referenced from the
780 * given value's hash table entry.
781 */
782void FreeAsnAny (AsnAny *v);
783AsnLen BEncAsnAny (BUF_TYPE b, AsnAny *v);
784void BerDecAsnAny (BUF_TYPE b, AsnAny *result, AsnLen *bytesDecoded,
785 ENV_TYPE env);
786void PrintAsnAny (FILE *f, AsnAny *v, unsigned short indent);
787
788
789/* AnyDefinedBy is the same as AsnAny */
790typedef AsnAny AsnAnyDefinedBy;
791#define FreeAsnAnyDefinedBy FreeAsnAny
792#define BEncAsnAnyDefinedBy BEncAsnAny
793#define BDecAsnAnyDefinedBy BDecAsnAny
794#define PrintAsnAnyDefinedBy PrintAsnAny
795\end{verbatim}
796\end{small}
797
798
799\section{\label{lib-buf-section}Buffer Management}
800
801Encoding and decoding performance is heavily affected by the cost of
802writing to and reading from buffers, thus, efficient buffer management
803is necessary. Flexibility is also important to allow integration of
804the generated encoders and decoders into existing environments. To
805provide both of these features, the calls to the buffer routines are
806actually macros that can be configured as you want (see
807{\ufn \dots/c-lib/inc/asn-config.h}). Virtually all buffer calls will
808be made from the encode/decode library routines. So macros used in
809the generated code will make buffer calls.
810
811If your environment uses a single, simple buffer type, the buffer
812routine macros can be defined as the macros for your simple buffer type.
813This results in the buffer type being bound at compile time, with no
814function call overhead from the encode or decode routines. This also
815means that the runtime library only works for that buffer type.
816
817If multiple buffer formats must be supported at runtime, the buffer
818macros can be defined like the ISODE buffer calls, where a buffer type
819contains pointers to the buffer routines and data of the current
820buffer type. This approach will hurt performance since each buffer
821operation will be an indirect function call. I have implemented
822buffers like this for the table tools (performace is already hosed so
823slower buffer routines are a drop in the bucket). See the type tables
824section for their description.
825
826The backwards encoding technique requires special buffer primitives
827that write from the end of the buffer towards the front. This
828requirement will make it impossible to define buffer primitives that
829write directly to stream oriented objects such as TCP connections. In
830cases such as this, you must encode the entire PDU before sending it.
831(Or else extend the back-end of the compiler to produce ``forwards''
832encoders as well).
833
834Nine buffer primitives are required by the runtime library's encode
835and decode routines:
836\begin{itemize}
837\item {\C unsigned char BufGetByte (BUF\_TYPE b);}
838\item {\C unsigned char BufPeekByte (BUF\_TYPE b);}
839\item {\C char *BufGetSeg (BUF\_TYPE b, unsigned long int *lenPtr);}
840\item {\C void BufCopy (char *dst, BUF\_TYPE b, unsigned long int *lenPtr);}
841\item {\C void BufSkip (BUF\_TYPE b, unsigned long int len);}
842\item {\C void BufPutByteRv (BUF\_TYPE b, unsigned char byte);}
843\item {\C void BufPutSegRv (BUF\_TYPE b, char *data, unsigned long int len);}
844\item {\C int BufReadError (BUF\_TYPE b);}
845\item {\C int BufWriteError (BUF\_TYPE b);}
846\end{itemize}
847
848These buffer operations are described in the next subsections. The
849{\C ExpBuf}, {\C SBuf} and {\C MinBuf} buffer formats that come
850with the Snacc distribution and how to configure the buffer operations
851are discussed following that.
852
853\subsection{\label{buf-read-c-section}Buffer Reading Routine Semantics}
854
855The buffer reading routines are called by the decoder routines. The
856following is the list of necessary buffer reading routines and their
857semantics. Be sure to setup the buffer in reading mode before
858calling any of these routines. The means of putting a buffer in
859reading mode depends on the buffer type.
860
861\begin{verbatim}
862unsigned char BufGetByte (BUF_TYPE b);
863\end{verbatim}
864Returns the next byte from the buffer and advances the current pointer
865such that a subsequent buffer read returns the following byte(s).
866This will set the read error flag if an attempt to read past the end
867of the data is made.
868
869\begin{verbatim}
870unsigned char BufPeekByte (BUF_TYPE b);
871\end{verbatim}
872Returns the next byte from the buffer without advancing the current
873pointer.
874
875\begin{verbatim}
876char *BufGetSeg (BUF_TYPE b, unsigned long int *lenPtr);
877\end{verbatim}
878Returns a pointer to the next bytes from the buffer and advances the
879current pointer. {\C *lenPtr} should contain the number of bytes to
880read. If the buffer has a least {\C *lenPtr} contiguous bytes
881remaining to be read before calling {\C BufGetSeg}, a pointer to
882them will be returned and {\C *lenPtr} will be unchanged. If there
883are less than {\C *lenPtr} contiguous bytes remaining in the buffer
884before the call to {\C BufGetSeg}, a pointer to them is returned and
885{\C *lenPtr} is set to the actual number of bytes that are
886referenced by the returned pointer. The current pointer will be
887advanced by the value returned in {\C *lenPtr} (this may advance to the
888next buffer segment if any). Note that the read error flag is not set
889if {\C *lenPtr} is greater than the remaining number of unread
890bytes.
891
892\begin{verbatim}
893unsigned long int BufCopy (char *dst, BUF_TYPE b, unsigned long int len)
894\end{verbatim}
895Copies the next {\C len} bytes from the buffer into the {\C dst char~*}
896and advances the current pointer appropriately. Returns the
897number of bytes actually copied. The number of bytes copied will be
898less than requested only if the end of data is reached, in which case
899the read error flag is set.
900
901
902\begin{verbatim}
903void BufSkip (BUF_TYPE b, unsigned long int len);
904\end{verbatim}
905Advances the buffer's current pointer by {\C len} bytes. This will set the
906read error flag if less than {\C len} unread bytes remain in the
907buffer before the call to {\C BufSkip}.
908
909\begin{verbatim}
910int BufReadError (BUF_TYPE b);
911\end{verbatim}
912Returns non-zero if a read error occurred for the given buffer.
913Read errors occur if one of the buffer reading routines attempted to
914read past the end of the buffer's data.
915
916\subsection{\label{buf-write-c-section}Buffer Writing Routine Semantics}
917
918Encoding routines call the buffer writing routines. Here is a list of
919the buffer writing routine and their semantics. Before calling the
920writing routines, you should make sure the buffer is setup for
921writing in reverse mode. The means of doing this depends on the
922buffer type.
923
924\begin{verbatim}
925void BufPutByteRvs (BUF_TYPE b, unsigned char byte);
926\end{verbatim}
927Writes the given byte to the beginning of the data in the given
928buffer. The newly written byte becomes part of the buffer's data such
929that subsequent writes place bytes before the newly written byte. If
930a buffer write error occurs, subsequent writes do nothing.
931
932\begin{verbatim}
933void BufPutSegRvs (BUF_TYPE b, char *data, unsigned long int len);
934\end{verbatim}
935Prepends the given bytes, {\C data}, of length {\C len} to the
936beginning of the data in the given buffer {\C b}. The {\C data}
937bytes are written such that the first byte in {\C data} becomes the
938first byte of the buffer's data, followed by the rest. (This means the
939bytes in {\C data} are not reversed, they are simply prepended as a
940unit to the buffer's original data). If a buffer write error occurs,
941subsequent writes do nothing.
942
943\begin{verbatim}
944int BufWriteError (BUF_TYPE b);
945\end{verbatim}
946Returns non-zero if a write error occurred for the given buffer.
947Write errors occur if the buffer runs out of space for data or cannot
948allocate another data block (depends on the buffer type).
949
950\subsection{Buffer Configuration}
951
952The runtime library's encode and decode routines as well as the
953generated code access the buffers via the nine buffer macros
954described in the last two sections. These macros can be defined to
955call simple macros for speed or to call functions. Note that the
956buffer configuration is bound at the time the library and generated
957code are compiled.
958
959The following is from {\ufn \dots/include/asn-config.h} and shows how to
960configure the buffer routines. This setup will make all calls to
961{\C BufGetByte} in the library and generated code call your
962{\C ExpBufGetByte} routine; the other buffer routines are mapped to
963their {\C ExpBuf} equivalents in a similar way.
964
965\begin{verbatim}
966#include "exp-buf.h"
967#define BUF_TYPE ExpBuf **
968#define BufGetByte( b) ExpBufGetByte (b)
969#define BufGetSeg( b, lenPtr) ExpBufGetSeg (b, lenPtr)
970#define BufCopy( dst, b, lenPtr) ExpBufCopy (dst, b, lenPtr)
971#define BufSkip( b, len) ExpBufSkip (b, len)
972#define BufPeekByte( b) ExpBufPeekByte (b)
973#define BufPutByteRv( b, byte) ExpBufPutByteRv (b, byte)
974#define BufPutSegRv( b, data, len) ExpBufPutSegRv (b, data, len)
975#define BufReadError( b) ExpBufReadError (b)
976#define BufWriteError( b) ExpBufWriteError (b)
977\end{verbatim}
978
979If you want to use your own buffer type, simply edit the
980{\ufn asn-config.h} file such that it includes your buffer's header
981file, sets the {\C BUF\_TYPE} type, and defines the nine buffer
982routines ({\C BufGetByte} etc.) to call your buffer routines. Your
983buffer routines should have the semantics and prototypes described in
984the last two sections (Sections \ref{buf-read-c-section} and~\ref{buf-write-c-section}).
985
986\subsection{ExpBuf Buffers}
987
988The {\C ExpBuf} buffers are a doubly linked series of buffers that
989can be expanded when encoding by adding new buffers as necessary.
990Each {\C ExpBuf} consists of two blocks of memory, one for the
991control and linking information and the other for the data; when
992refering to an {\C ExpBuf} both parts are included. {\C ExpBuf} is
993short for ``Expanding Buffer''. Look in {\ufn \dots/c-lib/exp-buf.c}
994for an ASCII drawing of the {\C ExpBuf} buffers. Take a look a the
995{\ufn \dots/c-examples/simple/expbuf-ex.c} file for a quick
996introduction on how to use {\C ExpBufs}.
997
998{\C ExpBufs} are fairly general and useful when a reasonable upper
999bound can not be put on the size of the encoded values that will be
1000encountered by the protocol. The flexibility of these buffer routines
1001will hurt the performance as many of the {\C ExpBuf} calls are not
1002macros and new buffers may need to be allocated during encoding.
1003
1004For encoding you need to write into the {\C ExpBufs}. Start with a
1005single ExpBuf (or the last one in a list of ExpBufs from a previous
1006encoding). Make sure this ExpBuf has been reset is ``Write Reverse''
1007mode (use {\C ExpBufResetInWriteRvsMode}). This clears the write
1008error flag (and sets the read error flag in case you try a read) and
1009resets the data start and data end pointers such that the buffer is
1010empty and ready for writing from the end towards the front.
1011
1012During encoding, if an {\C ExpBuf}'s data part fills up, a new
1013{\C ExpBuf} before (since writing is reversed) the current buffer is
1014needed. If the {\C prev} pointer in the current buffer is non-NULL,
1015the previous buffer is reset for writing and becomes the current
1016buffer. If the {\C prev} pointer in the current buffer si NULL, a new
1017buffer is allocated, its pointer is placed in {\C prev} and it
1018becomes the current buffer. The notion of current buffer is handled
1019by the parameter to the encoding and decoding routines. The buffer
1020parameter is an {\C ExpBuf~**} and it always holds the current
1021{\C ExpBuf~*} (current buffer).
1022
1023When encoding is finished and the encoded value has been transmitted,
1024you have two options. You can free the entire buffer list or you can
1025keep them around and re-use them for the next encoding. Freeing the
1026buffers after each encoding may be quite slow. If you re-use the
1027buffers, the buffer list will grow to the size of the largest encoding
1028and stay there. You can easily implement other management schemes.
1029By default the {\C ExpBuf}s (both parts) are allocated and freed with
1030{\C malloc} and {\C free}; you may want to change this to fit your
1031environment better. If buffer allocation fails during a write, the
1032writeError flag will be set and subsequent writes will do nothing.
1033
1034For decoding you will want to put the encoded data into the
1035{\C ExpBuf} format. For example, if your encoded value is
1036contiguous in a single block of memory, you could use
1037{\C ExpBufInstallDataInBuf} to attach your data to a single ExpBuf.
1038Once your data is in the ExpBuf format, you should call
1039{\C ExpBufResetInReadMode} on the first buffer in the list (if more
1040than one). Then you can pass it to the desired decode routine.
1041
1042If a decode routine attempts to read past the end of a buffer (usually
1043due to an erroneous encoding), the readError flag will be set for the
1044current {\C ExpBuf} in the list. This error will typically cause
1045the decoding routine that called the buffer read routine to call
1046{\C longjmp}.
1047
1048The {\C BUF\_TYPE} is defined as {\C ExpBuf~**} so that the buffer
1049parameter {\C b} can be set to the next active {\C ExpBuf} by the
1050buffer routines. This saves having a head of the list type structure
1051that keeps track of the first, last and current buffers (the
1052indirectness of this approach would hurt performance).
1053
1054There are many routines for administrating the {\C ExpBufs} if you
1055want to treat them like an abstract data type. Sometimes it may be
1056easier to skip the utility routines and modify the fields directly.
1057
1058The following routines are the required nine buffer routines. Compile
1059the library and the generated code with the {\C USE\_EXP\_BUF} symbol
1060defined to map buffer routines that the generated and library code
1061calls to the {\C ExpBuf} routines (see
1062{\ufn \dots/c-lib/inc/asn-config.h}). These {\C ExpBuf} routines
1063adhere to the buffer routine prototypes and semantics defined in
1064Sections \ref{buf-read-c-section} and~\ref{buf-write-c-section}.
1065
1066\begin{verbatim}
1067void ExpBufSkip (ExpBuf **, unsigned long len);
1068int ExpBufCopy (char *dst, ExpBuf **b, unsigned long len);
1069unsigned char ExpBufPeekByte (ExpBuf **b);
1070char *ExpBufGetSeg (ExpBuf **b, unsigned long *len);
1071void ExpBufPutSegRvs (ExpBuf **b, char *data, unsigned long len);
1072unsigned char ExpBufGetByte (ExpBuf **b);
1073void ExpBufPutByteRvs (ExpBuf **b, unsigned char byte);
1074
1075#define ExpBufReadError( b) ((*b)->readError)
1076#define ExpBufWriteError( b) ((*b)->writeError)
1077\end{verbatim}
1078
1079
1080The following {\C ExpBuf} routines are also provided. Their
1081descriptions can be found in the code.
1082\begin{verbatim}
1083void ExpBufInit (unsigned long dataBlkSize);
1084void ExpBufInstallDataInBuf (ExpBuf *b, char *data, unsigned long int len);
1085
1086void ExpBufResetInReadMode (ExpBuf *b);
1087void ExpBufResetInWriteRvsMode (ExpBuf *b);
1088
1089ExpBuf *ExpBufAllocBufAndData();
1090void ExpBufFreeBufAndData (ExpBuf *b);
1091void ExpBufFreeBufAndDataList (ExpBuf *b);
1092
1093ExpBuf *ExpBufNext (ExpBuf *b);
1094ExpBuf *ExpBufPrev (ExpBuf *b);
1095ExpBuf *ExpBufListLastBuf (ExpBuf *b);
1096ExpBuf *ExpBufListFirstBuf (ExpBuf *b);
1097
1098int ExpBufAtEod (ExpBuf *b);
1099int ExpBufFull (ExpBuf *b);
1100int ExpBufHasNoData (ExpBuf *b);
1101
1102char *ExpBufDataPtr (ExpBuf *b);
1103unsigned long ExpBufDataSize (ExpBuf *b);
1104unsigned long ExpBufDataBlkSize (ExpBuf *b);
1105\end{verbatim}
1106
1107\subsection{SBuf Buffers}
1108
1109The {\C SBuf}s are simple buffers of a fixed size, much like an
1110{\C ExpBuf} that cannot expand. If you attempt to write
1111past the end of the buffer, the writeError flag will be set and the
1112encoding will fail. If you attempt to read past the end of a buffer
1113the readError flag will be set and the decoding will fail.
1114
1115The {\C SBuf}s are useful if you can put a reasonable upper bound on
1116the size of the encodings you will be dealing with. The buffer
1117operations are much simpler because the data is contiguous. In fact,
1118all of the {\C SBuf} buffer operations are implemented by macros.
1119
1120Look in {\ufn \dots/c-examples/simple/sbuf-ex.c} for a quick
1121introduction to using {\C SBuf}s in your code. The following
1122operations are defined for the {\C SBuf} buffers.
1123\begin{verbatim}
1124/* The nine required buffer operations */
1125#define SBufSkip(b, skipLen) ...
1126#define SBufCopy(dst, b, copyLen) ...
1127#define SBufPeekByte(b) ...
1128#define SBufGetSeg( b, lenPtr) ...
1129#define SBufPutSegRvs(b, seg, segLen) ...
1130#define SBufGetByte(b) ...
1131#define SBufPutByteRvs(b, byte) ...
1132#define SBufReadError(b) ...
1133#define SBufWriteError(b) ...
1134
1135/* other useful buffer operations */
1136#define SBufInit(b, data, dataLen) ...
1137#define SBufResetInReadMode(b) ...
1138#define SBufResetInWriteRvsMode(b) ...
1139#define SBufInstallData(b, data, dataLen) ...
1140#define SBufDataLen(b) ...
1141#define SBufDataPtr(b) ...
1142#define SBufBlkLen(b) ...
1143#define SBufBlkPtr(b) ...
1144#define SBufEod(b) ...
1145\end{verbatim}
1146
1147Snacc is configured to use {\C SBuf}s by default. The symbols that
1148will affect the buffer configuration during compilation of the
1149libraries and generated code are {\C USE\_EXP\_BUF} and
1150{\C USE\_MIN\_BUF}.
1151
1152\subsection{MinBuf Buffers}
1153
1154The {\C MinBuf}s provide maximum performance but should only be used under
1155restricted conditions (to avoid segmentation faults etc.). No checks are
1156made to determine whether a decoder is reading past the end of the
1157buffer or if an encoder is writing ``past'' the beginning of the data
1158block (remember, snacc encoders write backwards).
1159
1160A {\C MinBuf} is just a {\C char~**}; the referenced {\C char~*} points
1161to the next byte to be read or the last byte that was written. The
1162read routine advances the {\C char~*} and the write reverse routines
1163move the {\C char~*} backwards.
1164
1165When you start encoding, the {\C MinBuf} {\C char~**} should be a
1166pointer to a pointer to the byte AFTER the last valid byte in your
1167buffer. For example the following C fragment would work:
1168\begin{verbatim}
1169PersonnelRecord pr;
1170char blk[128];
1171char *minBuf;
1172
1173minBuf = blk + 128; /* start writing a end of block */
1174BEncPersonnelRecord (&minBuf, pr);
1175\end{verbatim}
1176
1177The {\C MinBuf}s should only be used during encoding if the size of
1178the {\C MinBuf}'s buffer is guaranteed to be large enough to hold
1179the encoded value. Otherwise, the encoder will blindly continue
1180writing into whatever lies after the {\C MinBuf}'s buffer.
1181
1182When you start decoding, the {\C MinBuf} value should be a pointer
1183to a pointer to the first byte of the BER value to be decoded. Look
1184in {\ufn \dots/c-examples/simple/minbuf-ex.c} for a real example.
1185
1186The {\C MinBuf}s should only be used for decoding when the value
1187being decoded is certain to contain no encoding errors. Otherwise, for
1188encodings that are incomplete or contain length errors, the decoder may
1189attempt to read the memory that follows the {\C MinBuf}s. If you are
1190lucky, the decoder will return an error with the {\C longjmp}
1191mechanism. If your system has memory protection and you are unlucky
1192this may abort your program. If you are really unlucky, the data
1193following the {\C MinBuf} may fool the decoder into thinking that it
1194is valid and you receive a wrong PDU with no error indication. This
1195risky technique has been used successfully in some systems where the
1196encodings are not guaranteed to be correct.
1197
1198To configure the generated code to use the {\C MinBuf}s, compile it
1199with the {\C USE\_MIN\_BUF} symbol defined.
1200
1201\subsection{Hybrid Buffer Solutions}
1202
1203The decoding routines only call the buffer reading routines and the
1204encoding routines only call the buffer writing routines. You may wish
1205to choose a different buffer format for the encoding and decoding to
1206gain performance. For instance, if you can be sure that the size of
1207outgoing encodings is less than a certain upper bound, but don't want
1208to risk segmentation faults when decoding incoming values, you could
1209use {\C MinBuf}s for the the buffer writing (encoding) operations
1210and {\C SBuf}s or {\C ExpBuf}s for the buffer reading (decoding)
1211operations.
1212
1213In this case you will need to massage the generated code to achieve
1214the desired results.
1215
1216\section{\label{lib-mem-C-section}Dynamic Memory Management}
1217
1218Like buffer management, efficient memory management is very important
1219for efficient decoders. As a decoder decodes a value, it allocates
1220memory to hold the internal representation of the value.
1221
1222The runtime librarys and the generated decode routines allocate memory
1223using the\linebreak {\C Asn1Alloc} routine. The runtime librarys
1224and the generated free routines free memory using the {\C Asn1Free}
1225routine. The decoding routines also use {\C CheckAsn1Alloc} to make
1226sure that each allocation succeeded. These memory routines are defined
1227in the
1228{\ufn asn-config.h} and have the prototypes:
1229\begin{verbatim}
1230void *Asn1Alloc (unsigned long int size);
1231void Asn1Free (void *ptr);
1232int CheckAsn1Alloc (void *ptr, ENV_TYPE env);
1233\end{verbatim}
1234
1235The decoders assume that {\C Asn1Alloc} returns a \emph{zeroed} block
1236of memory. This saves explicit initialization of OPTIONAL elements with
1237NULL in the generated decoders. It wouldn't be too hard to modify the
1238compiler to produce decoders that initialized OPTIONAL elements
1239explicitly.
1240
1241The generated free routines hierarchically free all a value's
1242memory using a depth first algorithm. If you use the Nibble Memory
1243scheme, you will not need the generated free routines.
1244
1245By default, snacc uses a ``Nibble Memory'' scheme to provide efficient
1246memory management. Nibble Memory works by allocating a large block of
1247memory for allocating from. When the decoded value has been
1248processed, you can free the entire value by calling a routine that
1249simply resets a few pointers. There is no need to traverse the entire
1250value freeing a piece at a time. The following is from
1251{\ufn nibble-alloc.h}.
1252\begin{verbatim}
1253void InitNibbleMem (unsigned long int initialSize,
1254 unsigned long int incrementSize);
1255void *NibbleAlloc (unsigned long int size);
1256void ResetNibbleMem();
1257void ShutdownNibbleMem();
1258\end{verbatim}
1259
1260You must explicitly initialize the Nibble Memory with the
1261{\C InitNibbleMem} routine before using a decoder. You must specify
1262the initial size of the nibble block and the size that it should grow
1263by. If you attempt to allocate a block that is larger that the
1264initial nibble block or its grow size, a new block of the correct size
1265will be allocated. Note that the ``growth'' occurs by linking
1266separate blocks, not by the potentially slow alternative,
1267{\C realloc}.
1268
1269When you have processed the decoded value you can free it by calling
1270{\C ResetNibbleMem}. This resets a couple pointers and frees any
1271extra blocks that were allocated to handle values larger than the
1272initial block size. The original memory block is zeroed
1273using {\C memset} so that all allocations will return zeroed values.
1274This is necessary to support the implicit initialization of OPTIONAL
1275elements to NULL\@. The zeroing is done in this routine instead of
1276{\C NibbleAlloc} under the assumption that zeroing one large block
1277is more efficient than zeroing pieces of it as they are allocated.
1278
1279When you no longer need the Nibble Memory, you can release it by
1280using\linebreak {\C ShutDownNibbleMem}. This frees all of the
1281memory associated with Nibble Memory, both the control data and the
1282block(s) used for allocation.
1283
1284There are some problems with this memory management scheme. Currently
1285the Nibble Memory control information is kept track of via a global
1286variable that holds a pointer to the control information. This can
1287present a problem if separate Nibble Memory contexts are needed, for
1288example, one to hold one value that will be kept after decoding and
1289another to hold a decoded value that will soon be discarded.
1290
1291The problem of separate contexts could be solved by adding another
1292layer that would use identifiers for different memory contexts. This
1293would require you to set the context using its identifier before
1294calling a decoding routine and to pass the context identifier to the
1295{\C ResetNibbleMem} routine.
1296
1297Another problem has to do with building the values to be encoded.
1298There is no restriction on what allocator you use to build internal
1299values. However, it is convenient to use the {\C AsnListNew}
1300routine to allocate and initialize a list type. Unfortunately,
1301{\C AsnListNew} is used by the decoding routines so it uses the
1302{\C Asn1Alloc} routine to allocate the new list. You should be
1303aware of this if {\C Asn1Alloc} is not what you are using to
1304allocate the rest of the value. This could be fixed with a different
1305interface to the {\C AsnListNew} routine.
1306
1307It is possible to change the memory management system without too much
1308difficulty. For example if you are not too worried about performance
1309and want to use {\C malloc} and {\C free}, you could change the
1310{\ufn asn-config.h} file as follows:
1311\begin{verbatim}
1312#include "malloc.h"
1313#define Asn1Alloc( size) calloc (1, size)
1314#define Asn1Free( ptr) free (ptr)
1315#define CheckAsn1Alloc( ptr, env)\
1316 if ((ptr) == NULL)\
1317 longjmp (env, -27);
1318\end{verbatim}
1319If you use {\C malloc} based allocators such as {\C calloc}, you
1320must use the generated free routines to free your values. Note that
1321this example used {\C calloc} instead of {\C malloc} because
1322{\C calloc} {\em zeroes} each allocated block of memory, as required
1323by the decoders.
1324
1325
1326\section{\label{lib-err-C-section}Error Management}
1327
1328The decoding routines use {\C longjmp} to handle any errors they
1329encounter in the value being decoded. {\C longjmp} works by rolling
1330back the stack to where the {\C setjmp} call was made. Every decode
1331routine takes a {\C jmp\_buf env} parameter (initialized by the
1332{\C setjmp} call) that tells the {\C longjmp} routine how to
1333restore the processor to the correct state. {\C longjmp} makes the
1334error management much simpler since the decoding routines do not have
1335to pass back error codes or check ones from other decoding routines.
1336
1337Before a PDU can be decoded, the {\C jmp\_buf env} parameter to the
1338decoding routine must be initialized using the {\C setjmp} routine.
1339This should be done immediately and only once before calling the
1340decoding routine. This parameter will be passed down to any other
1341decoding routines called within a decoding routine. The following code
1342fragment from {\ufn \dots/c-examples/simple/exbuf-ex.c} shows how to
1343use {\C setjmp} before decoding.
1344
1345\begin{small}
1346\begin{verbatim}
1347if ((val = setjmp (env)) == 0)
1348 BDecPersonnelRecord (&buf, &pr, &decodedLen, env);
1349else
1350{
1351 decodeErr = TRUE;
1352 fprintf (stderr, "ERROR - Decode routines returned %d\n", val);
1353}
1354\end{verbatim}
1355\end{small}
1356
1357The code that will signal an error typically looks like:
1358\begin{small}
1359\begin{verbatim}
1360if (mandatoryElmtCount1 != 2)
1361{
1362 Asn1Error ("BDecChildInformationContent: ERROR - non-optional elmt missing from SET.\n");
1363 longjmp (env, -108);
1364}
1365\end{verbatim}
1366\end{small}
1367
1368
1369Most {\C longjmp} calls are preceded by a call to {\C Asn1Error}
1370which takes a single {\C char~*} string as a parameter. The library
1371routines and the generated code try to use meaningful messages as the
1372parameter. {\C Asn1Error} is defined in {\ufn \dots/c-lib/inc/asn-config.h} and
1373currently just prints the given string to {\C stderr}. You may wish
1374to make it do nothing, which may shrink the size of your binary
1375because all of the error strings will be gone. {\C Asn1Warning} is
1376similar but is not used by the library or generated code anymore.
1377
1378The encoding routines do no error checking except for buffer
1379overflows. Hence, they do not use the {\C longjmp} mechanism and
1380instead require you to check the status of the buffer after encoding
1381(use {\C BufWriteError()}). If you are not building your values
1382properly, for example having random pointers for uninitialized
1383OPTIONAL elements, the encode routines will fail, possibly
1384catastrophically.