1 % file: .../doc/c-lib.tex
3 % $Header: /cvs/Darwin/Security/SecuritySNACCRuntime/doc/c-lib.tex,v 1.1.1.1 2001/05/18 23:14:10 mb Exp $
5 % Revision 1.1.1.1 2001/05/18 23:14:10 mb
6 % Move from private repository to open source repository
8 % Revision 1.1.1.1 1999/03/16 18:05:52 aram
9 % Originals from SMIME Free Library.
11 % Revision 1.1 1997/01/01 22:47:34 rj
15 \chapter{\label{lib-C-chapter
}C ASN
.1 Library
}
16 \section{\label{libover-C-section
}Overview
}
18 Each 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,
20 decode, free and print routines for the given type. This chapter
21 contains a description of each library type and its routines.
22 This library is also referred to as the runtime library.
24 After installing Snacc, you should test the library types to make sure
25 that they are encoding and decoding properly. Use the
26 {\ufn \dots/c-examples/test-lib/
} example to check them.
28 In addition to other errors, most decoding routines will
report an
29 error if they attempt to read past the end of the data. Be aware that
30 some buffer types do not support this type of checking. This is
31 explained more in the buffer management section.
33 \section{\label{tag-C-section
}Tags
}
35 Snacc's tag representation was motivated by several things.
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.
42 The first requirement meant that tags had to be integer types (for the
43 {\C switch
} statement). The representation of the tag within the integer
44 was set by the second requirement.
46 The best way to decode cheaply is minimize the transformation between
47 the encoded and decoded (internal) format. So the four (can be set-up
48 for two) bytes of the long integer are used to hold the encoded tag,
49 starting with the first octet of the tag in the most significant byte
50 of the integer and the rest (if any) following. Any unused (always
51 trailing) bytes in the integer are zero. This limits the
52 representable tag code to less than $
2^
{21}$ but for reasonable ASN
.1
53 specifications this should not be a problem.
55 To meet the third requirement the decoded tag representation was
56 bypassed entirely by using macros (
{\C BEncTag1()
} etc.) that
57 write the encoded tag octet(s) to the buffer. The writing of an
58 encoded tag octet involves bit shifting, bitwise ands and bitwise ors
59 with constant values; most optimizing C compilers can compute these at
60 compile time. This simplifies encoding a tag to writing some constant
61 byte value(s) to the buffer.
63 The following excerpt from
{\ufn \dots/c-lib/inc/asn-tag.h
} shows some
67 typedef unsigned long int AsnTag;
69 #define MAKE_TAG_ID( class, form, code) ...
70 #define TAG_IS_CONS( tag) ...
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) ...
78 AsnTag BDecTag (BUF_TYPE b, AsnLen *bytesDecoded, ENV_TYPE env);
82 The generated decode routines use the
{\C BDecTag
} to decode a tag
83 from the buffer. The returned tag value is either used in an
84 {\C if
} expression or as the argument to
{\C switch
} statements.
85 The
{\C MAKE
\_TAG\_ID} macro is used to make a tag for comparison to
86 the one returned by
{\C BDecTag
}. The
{\C MAKE
\_TAG\_ID} is used is
87 {\C switch
} statement case labels and in
{\C if
} statements.
89 Most of the time tags are only compared for equality, however, the
90 OCTET STRING and BIT STRING decoders check the constructed bit in the
91 tag using the
{\C TAG
\_IS\_CONS} macro.
93 The
{\C BEncTag
} macros are quite fragile because they return the
94 encoded length of the tag; they cannot be treated as a single
95 statement. This requires careful use of braces when using them in
96 your own code in places such as the sole statement in an
{\C if
}
97 statement. This ugliness is caused by the difficulty in returning
98 values from multi-line macros (macros are used for performance here
99 since encoding tags can be a significant part of BER encoding).
101 The
{\C BDecTag
} routine will
report an error via
{\C longjmp
} if
102 the encoded tag is longer than can be held in the
{\C AsnTag
} type
103 or if it read past the end of the data when decoding the tag.
105 \section{\label{len-C-section
}Lengths
}
107 Decoded lengths are represented by unsigned long integers, with the
108 maximum value indicating indefinite length.
110 Snacc users can choose between using only indefinite or only definite
111 lengths when encoding constructed values' lengths when compiling the
112 generated code. Of course, the generated decoders can handle both
113 forms. Define the
{\C USE
\_INDEF\_LEN} symbol when compiling the
114 generated code if you want to use indefinite lengths when encoding
115 constructed values. Primitive values are always encoded with definite
116 lengths as required by the standard; this is necessary to avoid
117 confusion between a value's content and the End-Of-Contents marker.
119 There is no loss of performance when using definite lengths with snacc
120 encoders. This is due the ``backwards'' encoding as described in
121 Section~
\ref{encode-gen-C-section
}. The schemes used by other compilers'
122 encoders to handle definite lengths may hurt performance.
124 Most of the routines in the following code are obvious except for
125 {\C BEncDefLenTo127()
}. This is used instead of
{\C BEncDefLen
}
126 in the generated code when the compiler knows the value being encoded
127 will not be over
127 octets long. Values such as BOOLEANs,
128 INTEGERs, and REALs are assumed to be shorter than
127 octets
129 (constraints on the decoded representation of INTEGERs and REALs make
133 typedef unsigned long int AsnLen;
135 /* max unsigned value - used for internal rep of indef len */
136 #define INDEFINITE_LEN ~
0L
139 #define BEncEocIfNec( b) BEncEoc (b)
140 #define BEncConsLen(b, len)
2 + BEncIndefLen (b)
142 #define BEncEocIfNec( b)
143 #define BEncConsLen( b, len) BEncDefLen (b, len)
146 #define BEncIndefLen( b) ...
147 #define BEncDefLenTo127( b, len) ...
148 AsnLen BEncDefLen (BUF_TYPE b, AsnLen len);
149 AsnLen BDecLen (BUF_TYPE b, AsnLen *bytesDecoded, ENV_TYPE env);
151 #define BEncEoc( b) ...
152 #define BDEC_2ND_EOC_OCTET( b, bytesDecoded, env) ...
153 void BDecEoc (BUF_TYPE b, AsnLen *bytesDecoded, ENV_TYPE env);
157 The
{\C BDecLen
} routine will
report an error via
{\C longjmp
} if
158 it attempts to read past the end of the data or the decoded length is
159 too large to be held in the
{\C AsnLen
} representation.
160 {\C BDecEoc
} will
report an error if it attempts to read past the
161 end of the data or one of the EOC (End-Of-Contents) octets is
164 \section{\label{bool-C-section
}BOOLEAN
}
166 The BOOLEAN type is represented by an
{\C unsigned char
}. It has
167 the following routines for manipulating it.
170 typedef unsigned char AsnBool;
172 AsnLen BEncAsnBool (BUF_TYPE b, AsnBool *data);
173 void BDecAsnBool (BUF_TYPE b, AsnBool *result, AsnLen *bytesDecoded,
176 AsnLen BEncAsnBoolContent (BUF_TYPE b, AsnBool *data);
177 void BDecAsnBoolContent (BUF_TYPE b, AsnTag tag, AsnLen len,
178 AsnBool *result, AsnLen *bytesDecoded,
181 #define FreeAsnBool( v)
182 void PrintAsnBool (FILE *f, AsnBool *b, unsigned short int indent);
186 As discussed in Sections
\ref{encode-gen-C-section
} and
\ref{decode-gen-C-section
},
187 {\C BEncAsnBool
} and
{\C BDecAsnBool
} encode/decode the UNIVERSAL
188 tag, length and content of the given BOOLEAN value. The
\linebreak {\C BEncAsnBoolContent
} and
{\C BDecAsnBoolContent
} routine only
189 encode/decode the content of the given BOOLEAN value.
191 The
{\C FreeAsnBool
} routine does nothing since the BOOLEAN type
192 does not contain pointers to data; the free routine generator does not
193 have to check which types need freeing and simply calls the type's
194 free routine. It also allows the user to modify the types and their
195 free routines without changing the free routine generator. However,
196 the ANY and ANY DEFINED BY type hash table initialization routine
197 generator does need to know which types have empty free routines
198 because the hash entries contain pointers to the free functions (NULL
199 is used for the empty free functions like
{\C FreeAsnBool
}). The
200 INTEGER, NULL, REAL and ENUMERATED types have empty free routines for
203 {\C BDecAsnBool
} will
report an error if the tag is not
204 UNIVERSAL-PRIM-
1.
{\C BDecAsnBoolContent
} will
report an error if it
205 decodes 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.
208 \section{\label{int-C-section
}INTEGER
}
210 The INTEGER type is represented by a
32 bit integer type,
{\C AsnInt
}.
211 The 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.
212 If you are using INTEGER types that are only positive (via subtyping or
213 protocol definition) you may want to use the
{\C UAsnInt
} and
214 associated routines that use the unsigned int for a larger positive value range.
218 typedef unsigned int UAsnInt;
220 AsnLen BEncAsnInt (BUF_TYPE b, AsnInt *data);
221 void BDecAsnInt (BUF_TYPE b, AsnInt *result, AsnLen *bytesDecoded,
224 AsnLen BEncAsnIntContent (BUF_TYPE b, AsnInt *data);
225 void BDecAsnIntContent (BUF_TYPE b, AsnTag tag, AsnLen elmtLen,
226 AsnInt *result, AsnLen *bytesDecoded,
229 #define FreeAsnInt( v)
230 void PrintAsnInt (FILE *f, AsnInt *v, unsigned short int indent);
232 AsnLen BEncUAsnInt (BUF_TYPE b, UAsnInt *data);
233 void BDecUAsnInt (BUF_TYPE b, UAsnInt *result, AsnLen *bytesDecoded,
236 AsnLen BEncUAsnIntContent (BUF_TYPE b, UAsnInt *data);
237 void BDecUAsnIntContent (BUF_TYPE b, AsnTag tagId, AsnLen len,
238 UAsnInt *result, AsnLen *bytesDecoded,
241 #define FreeUAsnInt( v)
242 void PrintUAsnInt (FILE *f, UAsnInt *v, unsigned short int indent);
246 {\C BDecAsnInt
} will
report an error if the tag is not
247 UNIVERSAL-PRIM-
2.
{\C BDecAsnIntContent
} will
report an error if it
248 decodes past the end of the data or the integer value is too large for
251 \section{\label{null-C-section
}NULL
}
253 The NULL type is represented by the
{\C AsnNull
} type. Its content
254 is always empty and hence its encoded length always is zero.
257 typedef char AsnNull;
259 AsnLen BEncAsnNull (BUF_TYPE b, AsnNull *data);
260 void BDecAsnNull (BUF_TYPE b, AsnNull *result, AsnLen *bytesDecoded,
263 /* 'return' length of encoded NULL value,
0 */
264 #define BEncAsnNullContent(b, data)
0
265 void BDecAsnNullContent (BUF_TYPE b, AsnTag tag, AsnLen len,
266 AsnNull *result, AsnLen *bytesDecoded,
269 #define FreeAsnNull( v)
270 void PrintAsnNull (FILE *f, AsnNull * b, unsigned short int indent);
274 \section{\label{real-C-section
}REAL
}
276 The REAL type is represented by
{\C AsnReal
}, a double. This type's
277 representation can depend on the compiler or system you are using so
278 several different encoding routines are provided.
279 Even so, you may need to modify the code.
281 If 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}
283 and
{\C MINUS
\_INFINITY} values.
285 There are three encode routines included and they can be selected by
286 defining one of
{\C IEEE
\_REAL\_FMT},
{\C IEEE
\_REAL\_LIB} or nothing.
287 Defining
{\C IEEE
\_REAL\_FMT} uses the encode routine that assumes the
288 double representation is the standard IEEE double
\cite{68881}.
289 Defining
{\C IEEE
\_REAL\_LIB} uses the encode routine that assumes the
290 IEEE functions library (isinf, scalbn, signbit etc.\ ) is available.
291 If neither are defined, the default encode routine uses
{\C frexp
}.
293 There is only one content decoding routine and it builds the value
294 through multiplication and the
{\C pow
} routine (requires the math
295 library). The content decoding routine only supports the binary
296 encoding of a REAL, not the decimal encoding.
300 typedef double AsnReal;
302 extern AsnReal PLUS_INFINITY;
303 extern AsnReal MINUS_INFINITY;
305 void InitAsnInfinity();
306 AsnLen BEncAsnReal (BUF_TYPE b, AsnReal *data);
307 void BDecAsnReal (BUF_TYPE b, AsnReal *result, AsnLen *bytesDecoded,
310 AsnLen BEncAsnRealContent (BUF_TYPE b, AsnReal *data);
311 void BDecAsnRealContent (BUF_TYPE b, AsnTag tag, AsnLen len,
312 AsnReal *result, AsnLen *bytesDecoded,
316 #define FreeAsnReal( v)
317 void PrintAsnReal (FILE *f, AsnReal *b, unsigned short int indent);
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.
325 \section{\label{bits-C-section
}BIT STRING
}
327 The BIT STRING type is represented by the
{\C AsnBits
} structure. It
328 contains a pointer to the bits and integer that holds the length
329 in bits of the BIT STRING\@.
331 In addition to the standard encode, decode, print and free routines,
332 there are some other utility routines.
{\C AsnBitsEquiv
} returns
333 TRUE if the given BIT STRINGs are identical. The
{\C SetAsnBit
},
334 {\C ClrAsnBit
} and
{\C GetAsnBit
} are routines for writing and
335 reading a BIT STRING value.
337 You may notice that the AsnBits type does not have any means of
338 handling linked pieces of BIT STRINGs. Some ASN
.1 tools use lists of
339 structures like
{\C AsnBits
} to represent BIT STRINGs. This is done
340 because, as you should be aware, BIT STRINGs can be encoded in a
341 nested, constructed fashion. The snacc BIT STRING decoder attempts to
342 save you the hassle of dealing with fragments of BIT STRINGs by
343 concatenating them in the decoding step. Every BIT STRING value
344 returned by the decoder will have contiguous bits.
346 Some people contend that fragmented BIT STRINGs are necessary to
347 support systems that lack enough memory to hold the entire value.
348 Snacc encodes value ``backwards'' so the entire value must be encoded
349 before it can be sent, thus you must have enough memory to hold the
350 whole encoded value. If the fragmented representation is useful to
351 your protocol implementation for other reasons, it should be fairly
352 simple to modify the BIT STRING routines. Remember, no significance
353 should be placed on where constructed BIT STRING values are fragmented.
355 Snacc uses a table to hold pointers to the BIT STRING fragments in the
356 buffer while it is decoding them. Once the whole BIT STRING value has
357 been decoded, a block of memory that is large enough to hold the
358 entire BIT STRING is allocated and the fragments are copied into it.
359 The table initially can hold pointers to
128 fragments. If more table
360 entries are needed the stack will grow via
{\C realloc
} (with
361 associated performance loss) and will not shrink after growing. If
362 you wish to modify this behaviour, change the
363 {\ufn \dots/c-lib/inc/str-stk.h
} file.
365 The
{\C FreeAsnBits
} routine will free memory referenced by the
370 typedef struct AsnBits
376 extern char numToHexCharTblG
[];
377 #define TO_HEX( fourBits) (numToHexCharTblG
[(fourBits) &
0x0f])
378 #define ASNBITS_PRESENT( abits) ((abits)->bits != NULL)
380 AsnLen BEncAsnBits (BUF_TYPE b, AsnBits *data);
381 void BDecAsnBits (BUF_TYPE b, AsnBits *result, AsnLen *bytesDecoded,
384 AsnLen BEncAsnBitsContent (BUF_TYPE b, AsnBits *bits);
385 void BDecAsnBitsContent (BUF_TYPE b, AsnLen len, AsnTag tagId,
386 AsnBits *result, AsnLen *bytesDecoded,
389 void FreeAsnBits (AsnBits *v);
390 void PrintAsnBits (FILE *f, AsnBits *b, unsigned short int indent);
392 int AsnBitsEquiv (AsnBits *b1, AsnBits *b2);
393 void SetAsnBit (AsnBits *b1, unsigned long int bit);
394 void ClrAsnBit (AsnBits *b1, unsigned long int bit);
395 int GetAsnBit (AsnBits *b1, unsigned long int bit);
399 {\C BDecAsnBits
} will
report an error if the tag is not UNIVERSAL-CONS-
3 or UNIVERSAL-PRIM-
3.
400 When 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.
401 If the decoder attempts to read past the end of the data an error will be reported.
404 \section{\label{octets-C-section
}OCTET STRING
}
405 The OCTET STRING type is represented by the
{\C AsnOcts
} structure.
406 It contains a pointer to the octets and an integer that holds the length in octets of the OCTET STRING\@.
408 As with BIT STRINGs, OCTET STRINGs can have constructed values. These
409 are handled in the same way as the constructed BIT STRING values. The
410 decoded representation of an OCTET STRING is always contiguous.
412 The
{\C FreeAsnOcts
} routine will free the memory referenced by the
413 {\C octs
} pointer. The
{\C AsnOctsEquiv
} routine will return TRUE
414 if the given OCTET STRINGs are identical.
418 typedef struct AsnOcts
420 unsigned long int octetLen;
424 #define ASNOCTS_PRESENT( aocts) ((aocts)->octs != NULL)
426 AsnLen BEncAsnOcts (BUF_TYPE b, AsnOcts *data);
428 void BDecAsnOcts (BUF_TYPE b, AsnOcts *result, AsnLen *bytesDecoded,
431 AsnLen BEncAsnOctsContent (BUF_TYPE b, AsnOcts *octs);
432 void BDecAsnOctsContent (BUF_TYPE b, AsnLen len, AsnTag tagId,
433 AsnOcts *result, AsnLen *bytesDecoded,
436 void FreeAsnOcts (AsnOcts *o);
437 void PrintAsnOcts (FILE *f, AsnOcts *o, unsigned short int indent);
439 int AsnOctsEquiv (AsnOcts *o1, AsnOcts *o2);
443 {\C BDecAsnOcts
} will
report an error if the tag is not
444 UNIVERSAL-CONS-
4 or UNIVERSAL-PRIM-
4. When decoding constructed OCTET
445 STRING BER values, an error will be reported if an internal component
446 does not have the UNIVERSAL-
4 tag. If the decoder attempts to read
447 past the end of the data an error will be reported.
450 \section{\label{oid-C-section
}OBJECT IDENTIFIER
}
452 In snacc, OBJECT IDENTIFIERs are kept in their encoded form to improve
453 performance. The
{\C AsnOid
} type is defined as
{\C AsnOcts
}, as
454 it holds the octets of the encoded OBJECT IDENTIFIER\@. It seems that
455 the most common operation with OBJECT IDENTIFIERs is to compare for
456 equality, for which the encoded representation (which is canonical)
459 There is a linked OBJECT IDENTIFIER representation called
{\C OID
}
460 and routines to convert it to and from the
{\C AsnOid
} format, but it
461 should not be used if performance is an issue.
463 Since 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
}
466 encoding and decoding routines cannot be used because the OBJECT
467 IDENTIFIER has a different tag and cannot be encoded in a constructed
470 An OBJECT IDENTIFIER must have a minimum of two arc numbers but the
471 decoding routines do not check this.
475 typedef AsnOcts AsnOid;
477 #define ASNOID_PRESENT( aoid) ASNOCTS_PRESENT (aoid)
479 AsnLen BEncAsnOid (BUF_TYPE b, AsnOid *data);
480 void BDecAsnOid (BUF_TYPE b, AsnOid *result, AsnLen *bytesDecoded,
483 #define BEncAsnOidContent(b, oid) BEncAsnOctsContent(b, oid)
484 void BDecAsnOidContent (BUF_TYPE b, AsnTag tag, AsnLen len,
485 AsnOid *result, AsnLen *bytesDecoded,
488 #define FreeAsnOid FreeAsnOcts
489 void PrintAsnOid (FILE *f, AsnOid *b, unsigned short int indent);
491 #define AsnOidsEquiv( o1, o2) AsnOctsEquiv (o1, o2)
496 \section{\label{list-C-section
}SET OF and SEQUENCE OF
}
498 The SET OF and SEQUENCE OF type are represented by the
{\C AsnList
}
499 structure. An
{\C AsnList
} consists of a head object that has
500 pointers to the first, current and last nodes and the current number
501 of nodes in the list. Each list node has a pointer to its next and
502 previous list member and the node's data. The first list node's
503 previous pointer is always NULL and the last list node's next pointer
506 Each SET OF or SEQUENCE OF type is defined as an
{\C AsnList
}, so the
507 element type information (kept via a
{\C void~*
}) is not kept,
508 therefore, the
{\C AsnList
} type is not type safe.
510 The
{\C AsnList
} is a doubly linked list to simplify ``backwards''
511 encoding. The reverse link allows the list to be traversed in reverse
512 so the components can be encoded from last to first.
514 Initially, the lists were designed to allow the list element itself to
515 be contained in the list node (hence the
{\C elmtSize
} parameter to
516 the AsnListNew() routine). The design eventually changed such that
517 every list element was reference by pointer from the list node.
519 A small problem with the
{\C AsnListNew
} routine is the memory
520 allocation. Since it is used by the decoding routines to allocate new
521 lists, 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
523 desirable when building values to be transmitted. You may need to
524 provide another AsnListNew routine that uses a different allocation
525 scheme to solve this.
529 typedef struct AsnListNode
531 struct AsnListNode *prev;
532 struct AsnListNode *next;
533 void *data; /* this must be the last field of this structure */
536 typedef struct AsnList
541 int count; /* number of elements in list */
542 int dataSize; /* space required in each node for the data */
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) ...
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)
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))
563 void AsnListRemove (AsnList *l);
564 void *AsnListAdd (AsnList *l);
565 void *AsnListInsert (AsnList *list);
566 void AsnListInit (AsnList *list, int dataSize);
567 AsnList *AsnListNew (int elmtSize);
568 void *AsnListPrev (AsnList *);
569 void *AsnListNext (AsnList *);
570 void *AsnListLast (AsnList *);
571 void *AsnListFirst (AsnList *);
572 void *AsnListPrepend (AsnList *);
573 void *AsnListAppend (AsnList *);
574 void *AsnListCurr (AsnList *);
575 int AsnListCount (AsnList *);
576 AsnList *AsnListConcat (AsnList *, AsnList *);
580 There are a number of macros for dealing with the list type, the
581 most important being the list traversal macros. The
582 {\C FOR
\_EACH\_LIST\_ELMT} macro acts like a ``for'' statment that
583 traverses forward through the list. The first parameter should be a
584 pointer to the list element type that will be used to hold the current list
585 element for each iteration of the ``for'' loop. The second parameter is
586 the list of elements that you wish to traverse.
588 The
{\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
590 the list to the front. The
{\C FOR
\_REST\_LIST\_ELMT} macro is
591 similar to the other two but it does not reset the
{\C curr
} pointer
592 in the
{\C AsnList
} type. This has the effect of iterating from the
593 current element to the end of the list. Look in the generated code
594 for a better indication of how to use these macros. The other macros
595 are straight forward.
598 \section{\label{any-C-section
}ANY and ANY DEFINED BY
}
601 The ANY and ANY DEFINED BY type are classically the most irritating
602 ASN
.1 types for compiler writers. They rely on mechanisms outside of
603 ASN
.1 to specify what types they contain. The
1992 ASN
.1 standard has
604 rectified this by adding much stronger typing semantics and eliminating
607 The ANY DEFINED BY type can be handled automatically by
{\em snacc
} if
608 the SNMP OBJECT-TYPE
\cite{snmp
} macro is used to specify the
609 identifier value to type mappings. The identifier can be an INTEGER
610 or OBJECT IDENTIFIER\@. Handling ANY types properly will require
611 modifications to the generated code since there is no identifier
612 associated with the type.
614 The general approach used by
{\em snacc
} to handle ANY DEFINED BY
615 types is to lookup the identifier value in a hash table for the
616 identified type. The hash table entry contains information about the
617 type such as the routines to use for encoding and decoding.
619 Two hash tables are used, one for INTEGER to type mappings and the
620 other for OBJECT IDENTIFIER to type mappings.
{\em Snacc
} generates
621 an
{\tt InitAny
} routine for each module that uses the OBJECT-TYPE
622 macro. This routine adds entries to the hash table(s). The
{\tt
623 InitAny
} routine(s) is called once before any encoding or decoding is
627 The hash tables are constructed such that an INTEGER or OBJECT
628 IDENTIFIER value will hash to an entry that contains:
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
}
638 The referenced encode and decode routines are PDU oriented in that
639 they encode the type's tag(s) and length(s) as well as the type's
642 {\em Snacc
} builds an
{\tt enum
} called
{\tt AnyId
} that enumerates
643 each mapping defined by the OBJECT-TYPE macros. The name of the value
644 associated with each macro is used as part of the enumerated
645 identifier. The
{\tt anyId
} in the hash table holds the identified
646 type's
{\tt AnyId enum
} value. The
{\tt anyId
} is handy for making
647 decisions based on the received identifier, without comparing OBJECT
648 IDENTIFIERs. If the identifiers are INTEGERs then the
{\tt anyId
} is
651 With ANY DEFINED BY types, it is important to have the identifier
652 decoded before the ANY DEFINED BY type is decoded. Hence, an ANY
653 DEFINED BY type should not be declared before its identifier in a SET
654 since SETs are un-ordered. An ANY DEFINED BY type should not be
655 declared after its identifier in a SEQUENCE\@.
{\em Snacc
} will print a
656 warning if either of these situations occur.
658 The hash tables may be useful to plain ANY types which do not have an
659 identifier field like the ANY DEFINED BY types; the OBJECT-TYPE macro
660 can be used to define the mappings and the
{\tt SetAnyTypeByInt
} or
661 {\tt SetAnyTypeByOid
} routine can be called with the appropriate
662 identifier value before encoding or decoding an ANY value. The
663 compiler will insert calls to these routines where necessary with some
664 of the arguments left as ``???''. There will usually be a ``
{\tt /*
665 ANY -- Fix me! */
}'' comment before code that needs to be modified to
666 correctly handle the ANY type. The code generated from an ASN
.1
667 module that uses the ANY type will not compile without modifications.
669 OPTIONAL ANYs and ANY DEFINED BY types that have not been tagged are a
670 special problem for
{\em snacc
}. Unless they are the last element of a SET
671 or SEQUENCE, the generated code will need to be modified.
{\em Snacc
} will
672 print a warning message when it encounters one of these cases.
674 To illustrate how ANY DEFINED BY values are handled, we present
675 typical encoding and decoding scenarios. Each ANY or ANY DEFINED BY
676 type is represented in C by the
{\tt AsnAny
} type which contains only
677 a
{\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.
680 When encoding, before the ANY DEFINED BY value is encoded,
{\tt
681 SetAnyTypeByOid
} or
{\tt SetAnyTypeByInt
} (depending on the type of
682 the 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.
684 Then to encode the ANY DEFINED BY value, the encode routine pointed to
685 from the hash table entry is called with the
{\tt value
} {\tt void *
}
686 from the
{\tt AsnAny
} value. The
{\tt value
} {\tt void *
} in the
{\tt
687 AsnAny
} should point to a value of the correct type for the given
688 identifier, 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
690 value's type is the same as indicated by the identifier.
692 For decoding, the identifier must be decoded prior to the ANY DEFINED
693 BY value otherwise the identifier will contain an uninitialized value.
694 Before the ANY or ANY DEFINED BY value is decoded,
{\tt
695 SetAnyTypeByOid
} or
{\tt SetAnyTypeByInt
} (depending on the type of
696 the identifier) is called to set the
{\tt AsnAny
} value's
{\tt ai
}
697 pointer to the proper hash table entry. Then a block of memory of the
698 size indicated in the hash table entry is allocated, and its pointer
699 stored in the
{\tt AsnAny
} value's
{\tt void *
} entry. Then the decode
700 routine pointed to from the hash table entry is called with the newly
701 allocated block as its value pointer parameter. The decode routine
702 fills in the value assuming it is of the correct type. Simple!
704 There is a problem with
{\em snacc
}'s method for handling ANY DEFINED
705 BY types for specifications that have two or more ANY DEFINED BY types
706 that share some identifier values. Since only two hash tables are
707 used and they are referenced using the identifier value as a key,
708 duplicate identifiers will cause unresolvable hash collisions.
710 Here is some of the
{\C AsnAny
} related code from the header file. It
711 should help you understand the way things are done a bit better. Look
712 in the
{\ufn hash.c
} and
{\ufn hash.h
} files as well.
716 *
1 hash table for integer keys
717 *
1 hash table for oid keys
719 extern Table *anyOidHashTblG;
720 extern Table *anyIntHashTblG;
722 typedef
(*EncodeFcn) (BUF_TYPE b, void *value);
723 typedef void (*DecodeFcn) (BUF_TYPE b, void *value,
724 AsnLen *bytesDecoded, ENV_TYPE env);
725 typedef void (*FreeFcn) (void *v);
726 typedef void (*PrintFcn) (FILE *f, void *v);
729 * this is put into the hash table with the
730 * int or oid as the key
732 typedef struct AnyInfo
734 int anyId; /* will be a value from the AnyId enum */
735 AsnOid oid; /* will be zero len/null if intId is valid */
737 unsigned int size; /* size of the C data type (ie as ret'd by sizeof) */
744 typedef struct AsnAny
746 AnyInfo *ai; /* point to entry in hash tbl that has routine ptrs */
747 void *value; /* points to the value */
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
755 #define GetAsnAnyId( a) (((a)->ai)? (a)->ai->anyId: -1)
758 * used before encoding or decoding a type so the proper
759 * encode or decode routine is used.
761 void SetAnyTypeByInt (AsnAny *v, AsnInt id);
762 void SetAnyTypeByOid (AsnAny *v, AsnOid *id);
766 * used to initialize the hash table(s)
768 void InstallAnyByInt (int anyId, AsnInt intId,
769 unsigned int size, EncodeFcn encode,
770 DecodeFcn decode, FreeFcn free, PrintFcn print);
772 void InstallAnyByOid (int anyId, AsnOid *oid, unsigned int size,
773 EncodeFcn encode, DecodeFcn decode, FreeFcn free,
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.
782 void FreeAsnAny (AsnAny *v);
783 AsnLen BEncAsnAny (BUF_TYPE b, AsnAny *v);
784 void BerDecAsnAny (BUF_TYPE b, AsnAny *result, AsnLen *bytesDecoded,
786 void PrintAsnAny (FILE *f, AsnAny *v, unsigned short indent);
789 /* AnyDefinedBy is the same as AsnAny */
790 typedef AsnAny AsnAnyDefinedBy;
791 #define FreeAsnAnyDefinedBy FreeAsnAny
792 #define BEncAsnAnyDefinedBy BEncAsnAny
793 #define BDecAsnAnyDefinedBy BDecAsnAny
794 #define PrintAsnAnyDefinedBy PrintAsnAny
799 \section{\label{lib-buf-section}Buffer Management}
801 Encoding and decoding performance is heavily affected by the cost of
802 writing to and reading from buffers, thus, efficient buffer management
803 is necessary. Flexibility is also important to allow integration of
804 the generated encoders and decoders into existing environments. To
805 provide both of these features, the calls to the buffer routines are
806 actually macros that can be configured as you want (see
807 {\ufn \dots/c-lib/inc/asn-config.h}). Virtually all buffer calls will
808 be made from the encode/decode library routines. So macros used in
809 the generated code will make buffer calls.
811 If your environment uses a single, simple buffer type, the buffer
812 routine macros can be defined as the macros for your simple buffer type.
813 This results in the buffer type being bound at compile time, with no
814 function call overhead from the encode or decode routines. This also
815 means that the runtime library only works for that buffer type.
817 If multiple buffer formats must be supported at runtime, the buffer
818 macros can be defined like the ISODE buffer calls, where a buffer type
819 contains pointers to the buffer routines and data of the current
820 buffer type. This approach will hurt performance since each buffer
821 operation will be an indirect function call. I have implemented
822 buffers like this for the table tools (performace is already hosed so
823 slower buffer routines are a drop in the bucket). See the type tables
824 section for their description.
826 The backwards encoding technique requires special buffer primitives
827 that write from the end of the buffer towards the front. This
828 requirement will make it impossible to define buffer primitives that
829 write directly to stream oriented objects such as TCP connections. In
830 cases 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''
834 Nine buffer primitives are required by the runtime library's encode
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);}
848 These buffer operations are described in the next subsections. The
849 {\C ExpBuf}, {\C SBuf} and {\C MinBuf} buffer formats that come
850 with the Snacc distribution and how to configure the buffer operations
851 are discussed following that.
853 \subsection{\label{buf-read-c-section}Buffer Reading Routine Semantics}
855 The buffer reading routines are called by the decoder routines. The
856 following is the list of necessary buffer reading routines and their
857 semantics. Be sure to setup the buffer in reading mode before
858 calling any of these routines. The means of putting a buffer in
859 reading mode depends on the buffer type.
862 unsigned char BufGetByte (BUF_TYPE b);
864 Returns the next byte from the buffer and advances the current pointer
865 such that a subsequent buffer read returns the following byte(s).
866 This will set the read error flag if an attempt to read past the end
870 unsigned char BufPeekByte (BUF_TYPE b);
872 Returns the next byte from the buffer without advancing the current
876 char *BufGetSeg (BUF_TYPE b, unsigned long int *lenPtr);
878 Returns a pointer to the next bytes from the buffer and advances the
879 current pointer. {\C *lenPtr} should contain the number of bytes to
880 read. If the buffer has a least {\C *lenPtr} contiguous bytes
881 remaining to be read before calling {\C BufGetSeg}, a pointer to
882 them will be returned and {\C *lenPtr} will be unchanged. If there
883 are less than {\C *lenPtr} contiguous bytes remaining in the buffer
884 before 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
886 referenced by the returned pointer. The current pointer will be
887 advanced by the value returned in {\C *lenPtr} (this may advance to the
888 next buffer segment if any). Note that the read error flag is not set
889 if {\C *lenPtr} is greater than the remaining number of unread
893 unsigned long int BufCopy (char *dst, BUF_TYPE b, unsigned long int len)
895 Copies the next {\C len} bytes from the buffer into the {\C dst char~*}
896 and advances the current pointer appropriately. Returns the
897 number of bytes actually copied. The number of bytes copied will be
898 less than requested only if the end of data is reached, in which case
899 the read error flag is set.
903 void BufSkip (BUF_TYPE b, unsigned long int len);
905 Advances the buffer's current pointer by {\C len} bytes. This will set the
906 read error flag if less than {\C len} unread bytes remain in the
907 buffer before the call to {\C BufSkip}.
910 int BufReadError (BUF_TYPE b);
912 Returns non-zero if a read error occurred for the given buffer.
913 Read errors occur if one of the buffer reading routines attempted to
914 read past the end of the buffer's data.
916 \subsection{\label{buf-write-c-section}Buffer Writing Routine Semantics}
918 Encoding routines call the buffer writing routines. Here is a list of
919 the buffer writing routine and their semantics. Before calling the
920 writing routines, you should make sure the buffer is setup for
921 writing in reverse mode. The means of doing this depends on the
925 void BufPutByteRvs (BUF_TYPE b, unsigned char byte);
927 Writes the given byte to the beginning of the data in the given
928 buffer. The newly written byte becomes part of the buffer's data such
929 that subsequent writes place bytes before the newly written byte. If
930 a buffer write error occurs, subsequent writes do nothing.
933 void BufPutSegRvs (BUF_TYPE b, char *data, unsigned long int len);
935 Prepends the given bytes, {\C data}, of length {\C len} to the
936 beginning of the data in the given buffer {\C b}. The {\C data}
937 bytes are written such that the first byte in {\C data} becomes the
938 first byte of the buffer's data, followed by the rest. (This means the
939 bytes in {\C data} are not reversed, they are simply prepended as a
940 unit to the buffer's original data). If a buffer write error occurs,
941 subsequent writes do nothing.
944 int BufWriteError (BUF_TYPE b);
946 Returns non-zero if a write error occurred for the given buffer.
947 Write errors occur if the buffer runs out of space for data or cannot
948 allocate another data block (depends on the buffer type).
950 \subsection{Buffer Configuration}
952 The runtime library's encode and decode routines as well as the
953 generated code access the buffers via the nine buffer macros
954 described in the last two sections. These macros can be defined to
955 call simple macros for speed or to call functions. Note that the
956 buffer configuration is bound at the time the library and generated
959 The following is from {\ufn \dots/include/asn-config.h} and shows how to
960 configure 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
963 their {\C ExpBuf} equivalents in a similar way.
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)
979 If 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
981 file, sets the {\C BUF\_TYPE} type, and defines the nine buffer
982 routines ({\C BufGetByte} etc.) to call your buffer routines. Your
983 buffer routines should have the semantics and prototypes described in
984 the last two sections (Sections \ref{buf-read-c-section} and~\ref{buf-write-c-section}).
986 \subsection{ExpBuf Buffers}
988 The {\C ExpBuf} buffers are a doubly linked series of buffers that
989 can be expanded when encoding by adding new buffers as necessary.
990 Each {\C ExpBuf} consists of two blocks of memory, one for the
991 control and linking information and the other for the data; when
992 refering to an {\C ExpBuf} both parts are included. {\C ExpBuf} is
993 short for ``Expanding Buffer''. Look in {\ufn \dots/c-lib/exp-buf.c}
994 for 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
996 introduction on how to use {\C ExpBufs}.
998 {\C ExpBufs} are fairly general and useful when a reasonable upper
999 bound can not be put on the size of the encoded values that will be
1000 encountered by the protocol. The flexibility of these buffer routines
1001 will hurt the performance as many of the {\C ExpBuf} calls are not
1002 macros and new buffers may need to be allocated during encoding.
1004 For encoding you need to write into the {\C ExpBufs}. Start with a
1005 single ExpBuf (or the last one in a list of ExpBufs from a previous
1006 encoding). Make sure this ExpBuf has been reset is ``Write Reverse''
1007 mode (use {\C ExpBufResetInWriteRvsMode}). This clears the write
1008 error flag (and sets the read error flag in case you try a read) and
1009 resets the data start and data end pointers such that the buffer is
1010 empty and ready for writing from the end towards the front.
1012 During encoding, if an {\C ExpBuf}'s data part fills up, a new
1013 {\C ExpBuf} before (since writing is reversed) the current buffer is
1014 needed. If the {\C prev} pointer in the current buffer is non-NULL,
1015 the previous buffer is reset for writing and becomes the current
1016 buffer. If the {\C prev} pointer in the current buffer si NULL, a new
1017 buffer is allocated, its pointer is placed in {\C prev} and it
1018 becomes the current buffer. The notion of current buffer is handled
1019 by the parameter to the encoding and decoding routines. The buffer
1020 parameter is an {\C ExpBuf~**} and it always holds the current
1021 {\C ExpBuf~*} (current buffer).
1023 When encoding is finished and the encoded value has been transmitted,
1024 you have two options. You can free the entire buffer list or you can
1025 keep them around and re-use them for the next encoding. Freeing the
1026 buffers after each encoding may be quite slow. If you re-use the
1027 buffers, the buffer list will grow to the size of the largest encoding
1028 and stay there. You can easily implement other management schemes.
1029 By 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
1031 environment better. If buffer allocation fails during a write, the
1032 writeError flag will be set and subsequent writes will do nothing.
1034 For decoding you will want to put the encoded data into the
1035 {\C ExpBuf} format. For example, if your encoded value is
1036 contiguous in a single block of memory, you could use
1037 {\C ExpBufInstallDataInBuf} to attach your data to a single ExpBuf.
1038 Once your data is in the ExpBuf format, you should call
1039 {\C ExpBufResetInReadMode} on the first buffer in the list (if more
1040 than one). Then you can pass it to the desired decode routine.
1042 If a decode routine attempts to read past the end of a buffer (usually
1043 due to an erroneous encoding), the readError flag will be set for the
1044 current {\C ExpBuf} in the list. This error will typically cause
1045 the decoding routine that called the buffer read routine to call
1048 The {\C BUF\_TYPE} is defined as {\C ExpBuf~**} so that the buffer
1049 parameter {\C b} can be set to the next active {\C ExpBuf} by the
1050 buffer routines. This saves having a head of the list type structure
1051 that keeps track of the first, last and current buffers (the
1052 indirectness of this approach would hurt performance).
1054 There are many routines for administrating the {\C ExpBufs} if you
1055 want to treat them like an abstract data type. Sometimes it may be
1056 easier to skip the utility routines and modify the fields directly.
1058 The following routines are the required nine buffer routines. Compile
1059 the library and the generated code with the {\C USE\_EXP\_BUF} symbol
1060 defined to map buffer routines that the generated and library code
1061 calls to the {\C ExpBuf} routines (see
1062 {\ufn \dots/c-lib/inc/asn-config.h}). These {\C ExpBuf} routines
1063 adhere to the buffer routine prototypes and semantics defined in
1064 Sections \ref{buf-read-c-section} and~\ref{buf-write-c-section}.
1067 void ExpBufSkip (ExpBuf **, unsigned long len);
1068 int ExpBufCopy (char *dst, ExpBuf **b, unsigned long len);
1069 unsigned char ExpBufPeekByte (ExpBuf **b);
1070 char *ExpBufGetSeg (ExpBuf **b, unsigned long *len);
1071 void ExpBufPutSegRvs (ExpBuf **b, char *data, unsigned long len);
1072 unsigned char ExpBufGetByte (ExpBuf **b);
1073 void ExpBufPutByteRvs (ExpBuf **b, unsigned char byte);
1075 #define ExpBufReadError( b) ((*b)->readError)
1076 #define ExpBufWriteError( b) ((*b)->writeError)
1080 The following {\C ExpBuf} routines are also provided. Their
1081 descriptions can be found in the code.
1083 void ExpBufInit (unsigned long dataBlkSize);
1084 void ExpBufInstallDataInBuf (ExpBuf *b, char *data, unsigned long int len);
1086 void ExpBufResetInReadMode (ExpBuf *b);
1087 void ExpBufResetInWriteRvsMode (ExpBuf *b);
1089 ExpBuf *ExpBufAllocBufAndData();
1090 void ExpBufFreeBufAndData (ExpBuf *b);
1091 void ExpBufFreeBufAndDataList (ExpBuf *b);
1093 ExpBuf *ExpBufNext (ExpBuf *b);
1094 ExpBuf *ExpBufPrev (ExpBuf *b);
1095 ExpBuf *ExpBufListLastBuf (ExpBuf *b);
1096 ExpBuf *ExpBufListFirstBuf (ExpBuf *b);
1098 int ExpBufAtEod (ExpBuf *b);
1099 int ExpBufFull (ExpBuf *b);
1100 int ExpBufHasNoData (ExpBuf *b);
1102 char *ExpBufDataPtr (ExpBuf *b);
1103 unsigned long ExpBufDataSize (ExpBuf *b);
1104 unsigned long ExpBufDataBlkSize (ExpBuf *b);
1107 \subsection{SBuf Buffers}
1109 The {\C SBuf}s are simple buffers of a fixed size, much like an
1110 {\C ExpBuf} that cannot expand. If you attempt to write
1111 past the end of the buffer, the writeError flag will be set and the
1112 encoding will fail. If you attempt to read past the end of a buffer
1113 the readError flag will be set and the decoding will fail.
1115 The {\C SBuf}s are useful if you can put a reasonable upper bound on
1116 the size of the encodings you will be dealing with. The buffer
1117 operations are much simpler because the data is contiguous. In fact,
1118 all of the {\C SBuf} buffer operations are implemented by macros.
1120 Look in {\ufn \dots/c-examples/simple/sbuf-ex.c} for a quick
1121 introduction to using {\C SBuf}s in your code. The following
1122 operations are defined for the {\C SBuf} buffers.
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) ...
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) ...
1147 Snacc is configured to use {\C SBuf}s by default. The symbols that
1148 will affect the buffer configuration during compilation of the
1149 libraries and generated code are {\C USE\_EXP\_BUF} and
1152 \subsection{MinBuf Buffers}
1154 The {\C MinBuf}s provide maximum performance but should only be used under
1155 restricted conditions (to avoid segmentation faults etc.). No checks are
1156 made to determine whether a decoder is reading past the end of the
1157 buffer or if an encoder is writing ``past'' the beginning of the data
1158 block (remember, snacc encoders write backwards).
1160 A {\C MinBuf} is just a {\C char~**}; the referenced {\C char~*} points
1161 to the next byte to be read or the last byte that was written. The
1162 read routine advances the {\C char~*} and the write reverse routines
1163 move the {\C char~*} backwards.
1165 When you start encoding, the {\C MinBuf} {\C char~**} should be a
1166 pointer to a pointer to the byte AFTER the last valid byte in your
1167 buffer. For example the following C fragment would work:
1173 minBuf = blk + 128; /* start writing a end of block */
1174 BEncPersonnelRecord (&minBuf, pr);
1177 The {\C MinBuf}s should only be used during encoding if the size of
1178 the {\C MinBuf}'s buffer is guaranteed to be large enough to hold
1179 the encoded value. Otherwise, the encoder will blindly continue
1180 writing into whatever lies after the {\C MinBuf}'s buffer.
1182 When you start decoding, the {\C MinBuf} value should be a pointer
1183 to a pointer to the first byte of the BER value to be decoded. Look
1184 in {\ufn \dots/c-examples/simple/minbuf-ex.c} for a real example.
1186 The {\C MinBuf}s should only be used for decoding when the value
1187 being decoded is certain to contain no encoding errors. Otherwise, for
1188 encodings that are incomplete or contain length errors, the decoder may
1189 attempt to read the memory that follows the {\C MinBuf}s. If you are
1190 lucky, the decoder will return an error with the {\C longjmp}
1191 mechanism. If your system has memory protection and you are unlucky
1192 this may abort your program. If you are really unlucky, the data
1193 following the {\C MinBuf} may fool the decoder into thinking that it
1194 is valid and you receive a wrong PDU with no error indication. This
1195 risky technique has been used successfully in some systems where the
1196 encodings are not guaranteed to be correct.
1198 To configure the generated code to use the {\C MinBuf}s, compile it
1199 with the {\C USE\_MIN\_BUF} symbol defined.
1201 \subsection{Hybrid Buffer Solutions}
1203 The decoding routines only call the buffer reading routines and the
1204 encoding routines only call the buffer writing routines. You may wish
1205 to choose a different buffer format for the encoding and decoding to
1206 gain performance. For instance, if you can be sure that the size of
1207 outgoing encodings is less than a certain upper bound, but don't want
1208 to risk segmentation faults when decoding incoming values, you could
1209 use {\C MinBuf}s for the the buffer writing (encoding) operations
1210 and {\C SBuf}s or {\C ExpBuf}s for the buffer reading (decoding)
1213 In this case you will need to massage the generated code to achieve
1214 the desired results.
1216 \section{\label{lib-mem-C-section}Dynamic Memory Management}
1218 Like buffer management, efficient memory management is very important
1219 for efficient decoders. As a decoder decodes a value, it allocates
1220 memory to hold the internal representation of the value.
1222 The runtime librarys and the generated decode routines allocate memory
1223 using the\linebreak {\C Asn1Alloc} routine. The runtime librarys
1224 and the generated free routines free memory using the {\C Asn1Free}
1225 routine. The decoding routines also use {\C CheckAsn1Alloc} to make
1226 sure that each allocation succeeded. These memory routines are defined
1228 {\ufn asn-config.h} and have the prototypes:
1230 void *Asn1Alloc (unsigned long int size);
1231 void Asn1Free (void *ptr);
1232 int CheckAsn1Alloc (void *ptr, ENV_TYPE env);
1235 The decoders assume that {\C Asn1Alloc} returns a \emph{zeroed} block
1236 of memory. This saves explicit initialization of OPTIONAL elements with
1237 NULL in the generated decoders. It wouldn't be too hard to modify the
1238 compiler to produce decoders that initialized OPTIONAL elements
1241 The generated free routines hierarchically free all a value's
1242 memory using a depth first algorithm. If you use the Nibble Memory
1243 scheme, you will not need the generated free routines.
1245 By default, snacc uses a ``Nibble Memory'' scheme to provide efficient
1246 memory management. Nibble Memory works by allocating a large block of
1247 memory for allocating from. When the decoded value has been
1248 processed, you can free the entire value by calling a routine that
1249 simply resets a few pointers. There is no need to traverse the entire
1250 value freeing a piece at a time. The following is from
1251 {\ufn nibble-alloc.h}.
1253 void InitNibbleMem (unsigned long int initialSize,
1254 unsigned long int incrementSize);
1255 void *NibbleAlloc (unsigned long int size);
1256 void ResetNibbleMem();
1257 void ShutdownNibbleMem();
1260 You must explicitly initialize the Nibble Memory with the
1261 {\C InitNibbleMem} routine before using a decoder. You must specify
1262 the initial size of the nibble block and the size that it should grow
1263 by. If you attempt to allocate a block that is larger that the
1264 initial nibble block or its grow size, a new block of the correct size
1265 will be allocated. Note that the ``growth'' occurs by linking
1266 separate blocks, not by the potentially slow alternative,
1269 When you have processed the decoded value you can free it by calling
1270 {\C ResetNibbleMem}. This resets a couple pointers and frees any
1271 extra blocks that were allocated to handle values larger than the
1272 initial block size. The original memory block is zeroed
1273 using {\C memset} so that all allocations will return zeroed values.
1274 This is necessary to support the implicit initialization of OPTIONAL
1275 elements to NULL\@. The zeroing is done in this routine instead of
1276 {\C NibbleAlloc} under the assumption that zeroing one large block
1277 is more efficient than zeroing pieces of it as they are allocated.
1279 When you no longer need the Nibble Memory, you can release it by
1280 using\linebreak {\C ShutDownNibbleMem}. This frees all of the
1281 memory associated with Nibble Memory, both the control data and the
1282 block(s) used for allocation.
1284 There are some problems with this memory management scheme. Currently
1285 the Nibble Memory control information is kept track of via a global
1286 variable that holds a pointer to the control information. This can
1287 present a problem if separate Nibble Memory contexts are needed, for
1288 example, one to hold one value that will be kept after decoding and
1289 another to hold a decoded value that will soon be discarded.
1291 The problem of separate contexts could be solved by adding another
1292 layer that would use identifiers for different memory contexts. This
1293 would require you to set the context using its identifier before
1294 calling a decoding routine and to pass the context identifier to the
1295 {\C ResetNibbleMem} routine.
1297 Another problem has to do with building the values to be encoded.
1298 There is no restriction on what allocator you use to build internal
1299 values. However, it is convenient to use the {\C AsnListNew}
1300 routine 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
1303 aware of this if {\C Asn1Alloc} is not what you are using to
1304 allocate the rest of the value. This could be fixed with a different
1305 interface to the {\C AsnListNew} routine.
1307 It is possible to change the memory management system without too much
1308 difficulty. For example if you are not too worried about performance
1309 and want to use {\C malloc} and {\C free}, you could change the
1310 {\ufn asn-config.h} file as follows:
1313 #define Asn1Alloc( size) calloc (1, size)
1314 #define Asn1Free( ptr) free (ptr)
1315 #define CheckAsn1Alloc( ptr, env)\
1319 If you use {\C malloc} based allocators such as {\C calloc}, you
1320 must use the generated free routines to free your values. Note that
1321 this example used {\C calloc} instead of {\C malloc} because
1322 {\C calloc} {\em zeroes} each allocated block of memory, as required
1326 \section{\label{lib-err-C-section}Error Management}
1328 The decoding routines use {\C longjmp} to handle any errors they
1329 encounter in the value being decoded. {\C longjmp} works by rolling
1330 back the stack to where the {\C setjmp} call was made. Every decode
1331 routine takes a {\C jmp\_buf env} parameter (initialized by the
1332 {\C setjmp} call) that tells the {\C longjmp} routine how to
1333 restore the processor to the correct state. {\C longjmp} makes the
1334 error management much simpler since the decoding routines do not have
1335 to pass back error codes or check ones from other decoding routines.
1337 Before a PDU can be decoded, the {\C jmp\_buf env} parameter to the
1338 decoding routine must be initialized using the {\C setjmp} routine.
1339 This should be done immediately and only once before calling the
1340 decoding routine. This parameter will be passed down to any other
1341 decoding routines called within a decoding routine. The following code
1342 fragment from {\ufn \dots/c-examples/simple/exbuf-ex.c} shows how to
1343 use {\C setjmp} before decoding.
1347 if ((val = setjmp (env)) == 0)
1348 BDecPersonnelRecord (&buf, &pr, &decodedLen, env);
1352 fprintf (stderr, "ERROR - Decode routines returned %d\n", val);
1357 The code that will signal an error typically looks like:
1360 if (mandatoryElmtCount1 != 2)
1362 Asn1Error ("BDecChildInformationContent: ERROR - non-optional elmt missing from SET.\n");
1363 longjmp (env, -108);
1369 Most {\C longjmp} calls are preceded by a call to {\C Asn1Error}
1370 which takes a single {\C char~*} string as a parameter. The library
1371 routines and the generated code try to use meaningful messages as the
1372 parameter. {\C Asn1Error} is defined in {\ufn \dots/c-lib/inc/asn-config.h} and
1373 currently just prints the given string to {\C stderr}. You may wish
1374 to make it do nothing, which may shrink the size of your binary
1375 because all of the error strings will be gone. {\C Asn1Warning} is
1376 similar but is not used by the library or generated code anymore.
1378 The encoding routines do no error checking except for buffer
1379 overflows. Hence, they do not use the {\C longjmp} mechanism and
1380 instead require you to check the status of the buffer after encoding
1381 (use {\C BufWriteError()}). If you are not building your values
1382 properly, for example having random pointers for uninitialized
1383 OPTIONAL elements, the encode routines will fail, possibly