Commit | Line | Data |
---|---|---|
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 | ||
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. | |
23 | ||
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. | |
27 | ||
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. | |
32 | ||
33 | \section{\label{tag-C-section}Tags} | |
34 | ||
35 | Snacc'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 | ||
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. | |
45 | ||
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. | |
54 | ||
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. | |
62 | ||
63 | The following excerpt from {\ufn \dots/c-lib/inc/asn-tag.h} shows some | |
64 | of the tag routines. | |
65 | \begin{small} | |
66 | \begin{verbatim} | |
67 | typedef 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 | ||
78 | AsnTag BDecTag (BUF_TYPE b, AsnLen *bytesDecoded, ENV_TYPE env); | |
79 | \end{verbatim} | |
80 | \end{small} | |
81 | ||
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. | |
88 | ||
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. | |
92 | ||
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). | |
100 | ||
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. | |
104 | ||
105 | \section{\label{len-C-section}Lengths} | |
106 | ||
107 | Decoded lengths are represented by unsigned long integers, with the | |
108 | maximum value indicating indefinite length. | |
109 | ||
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. | |
118 | ||
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. | |
123 | ||
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 | |
130 | this valid). | |
131 | \begin{small} | |
132 | \begin{verbatim} | |
133 | typedef 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) ... | |
148 | AsnLen BEncDefLen (BUF_TYPE b, AsnLen len); | |
149 | AsnLen BDecLen (BUF_TYPE b, AsnLen *bytesDecoded, ENV_TYPE env); | |
150 | ||
151 | #define BEncEoc( b) ... | |
152 | #define BDEC_2ND_EOC_OCTET( b, bytesDecoded, env) ... | |
153 | void BDecEoc (BUF_TYPE b, AsnLen *bytesDecoded, ENV_TYPE env); | |
154 | \end{verbatim} | |
155 | \end{small} | |
156 | ||
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 | |
162 | non-zero. | |
163 | ||
164 | \section{\label{bool-C-section}BOOLEAN} | |
165 | ||
166 | The BOOLEAN type is represented by an {\C unsigned char}. It has | |
167 | the following routines for manipulating it. | |
168 | \begin{small} | |
169 | \begin{verbatim} | |
170 | typedef unsigned char AsnBool; | |
171 | ||
172 | AsnLen BEncAsnBool (BUF_TYPE b, AsnBool *data); | |
173 | void BDecAsnBool (BUF_TYPE b, AsnBool *result, AsnLen *bytesDecoded, | |
174 | ENV_TYPE env); | |
175 | ||
176 | AsnLen BEncAsnBoolContent (BUF_TYPE b, AsnBool *data); | |
177 | void BDecAsnBoolContent (BUF_TYPE b, AsnTag tag, AsnLen len, | |
178 | AsnBool *result, AsnLen *bytesDecoded, | |
179 | ENV_TYPE env); | |
180 | ||
181 | #define FreeAsnBool( v) | |
182 | void PrintAsnBool (FILE *f, AsnBool *b, unsigned short int indent); | |
183 | \end{verbatim} | |
184 | \end{small} | |
185 | ||
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. | |
190 | ||
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 | |
201 | the same reason. | |
202 | ||
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. | |
207 | ||
208 | \section{\label{int-C-section}INTEGER} | |
209 | ||
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. | |
215 | \begin{small} | |
216 | \begin{verbatim} | |
217 | typedef int AsnInt; | |
218 | typedef unsigned int UAsnInt; | |
219 | ||
220 | AsnLen BEncAsnInt (BUF_TYPE b, AsnInt *data); | |
221 | void BDecAsnInt (BUF_TYPE b, AsnInt *result, AsnLen *bytesDecoded, | |
222 | ENV_TYPE env); | |
223 | ||
224 | AsnLen BEncAsnIntContent (BUF_TYPE b, AsnInt *data); | |
225 | void BDecAsnIntContent (BUF_TYPE b, AsnTag tag, AsnLen elmtLen, | |
226 | AsnInt *result, AsnLen *bytesDecoded, | |
227 | ENV_TYPE env); | |
228 | ||
229 | #define FreeAsnInt( v) | |
230 | void PrintAsnInt (FILE *f, AsnInt *v, unsigned short int indent); | |
231 | ||
232 | AsnLen BEncUAsnInt (BUF_TYPE b, UAsnInt *data); | |
233 | void BDecUAsnInt (BUF_TYPE b, UAsnInt *result, AsnLen *bytesDecoded, | |
234 | ENV_TYPE env); | |
235 | ||
236 | AsnLen BEncUAsnIntContent (BUF_TYPE b, UAsnInt *data); | |
237 | void BDecUAsnIntContent (BUF_TYPE b, AsnTag tagId, AsnLen len, | |
238 | UAsnInt *result, AsnLen *bytesDecoded, | |
239 | ENV_TYPE env); | |
240 | ||
241 | #define FreeUAsnInt( v) | |
242 | void 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 | |
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 | |
249 | an {\C AsnInt}. | |
250 | ||
251 | \section{\label{null-C-section}NULL} | |
252 | ||
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. | |
255 | \begin{small} | |
256 | \begin{verbatim} | |
257 | typedef char AsnNull; | |
258 | ||
259 | AsnLen BEncAsnNull (BUF_TYPE b, AsnNull *data); | |
260 | void 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 | |
265 | void BDecAsnNullContent (BUF_TYPE b, AsnTag tag, AsnLen len, | |
266 | AsnNull *result, AsnLen *bytesDecoded, | |
267 | ENV_TYPE env); | |
268 | ||
269 | #define FreeAsnNull( v) | |
270 | void PrintAsnNull (FILE *f, AsnNull * b, unsigned short int indent); | |
271 | \end{verbatim} | |
272 | \end{small} | |
273 | ||
274 | \section{\label{real-C-section}REAL} | |
275 | ||
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. | |
280 | ||
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. | |
284 | ||
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}. | |
292 | ||
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. | |
297 | ||
298 | \begin{small} | |
299 | \begin{verbatim} | |
300 | typedef double AsnReal; | |
301 | ||
302 | extern AsnReal PLUS_INFINITY; | |
303 | extern AsnReal MINUS_INFINITY; | |
304 | ||
305 | void InitAsnInfinity(); | |
306 | AsnLen BEncAsnReal (BUF_TYPE b, AsnReal *data); | |
307 | void BDecAsnReal (BUF_TYPE b, AsnReal *result, AsnLen *bytesDecoded, | |
308 | ENV_TYPE env); | |
309 | ||
310 | AsnLen BEncAsnRealContent (BUF_TYPE b, AsnReal *data); | |
311 | void 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) | |
317 | void 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 | ||
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\@. | |
330 | ||
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. | |
336 | ||
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. | |
345 | ||
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. | |
354 | ||
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. | |
364 | ||
365 | The {\C FreeAsnBits} routine will free memory referenced by the | |
366 | {\C bits} pointer. | |
367 | ||
368 | \begin{small} | |
369 | \begin{verbatim} | |
370 | typedef struct AsnBits | |
371 | { | |
372 | int bitLen; | |
373 | char *bits; | |
374 | } AsnBits; | |
375 | ||
376 | extern char numToHexCharTblG[]; | |
377 | #define TO_HEX( fourBits) (numToHexCharTblG[(fourBits) & 0x0f]) | |
378 | #define ASNBITS_PRESENT( abits) ((abits)->bits != NULL) | |
379 | ||
380 | AsnLen BEncAsnBits (BUF_TYPE b, AsnBits *data); | |
381 | void BDecAsnBits (BUF_TYPE b, AsnBits *result, AsnLen *bytesDecoded, | |
382 | ENV_TYPE env); | |
383 | ||
384 | AsnLen BEncAsnBitsContent (BUF_TYPE b, AsnBits *bits); | |
385 | void BDecAsnBitsContent (BUF_TYPE b, AsnLen len, AsnTag tagId, | |
386 | AsnBits *result, AsnLen *bytesDecoded, | |
387 | ENV_TYPE env); | |
388 | ||
389 | void FreeAsnBits (AsnBits *v); | |
390 | void PrintAsnBits (FILE *f, AsnBits *b, unsigned short int indent); | |
391 | ||
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); | |
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. | |
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. | |
402 | ||
403 | ||
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\@. | |
407 | ||
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. | |
411 | ||
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. | |
415 | ||
416 | \begin{small} | |
417 | \begin{verbatim} | |
418 | typedef struct AsnOcts | |
419 | { | |
420 | unsigned long int octetLen; | |
421 | char *octs; | |
422 | } AsnOcts; | |
423 | ||
424 | #define ASNOCTS_PRESENT( aocts) ((aocts)->octs != NULL) | |
425 | ||
426 | AsnLen BEncAsnOcts (BUF_TYPE b, AsnOcts *data); | |
427 | ||
428 | void BDecAsnOcts (BUF_TYPE b, AsnOcts *result, AsnLen *bytesDecoded, | |
429 | ENV_TYPE env); | |
430 | ||
431 | AsnLen BEncAsnOctsContent (BUF_TYPE b, AsnOcts *octs); | |
432 | void BDecAsnOctsContent (BUF_TYPE b, AsnLen len, AsnTag tagId, | |
433 | AsnOcts *result, AsnLen *bytesDecoded, | |
434 | ENV_TYPE env); | |
435 | ||
436 | void FreeAsnOcts (AsnOcts *o); | |
437 | void PrintAsnOcts (FILE *f, AsnOcts *o, unsigned short int indent); | |
438 | ||
439 | int AsnOctsEquiv (AsnOcts *o1, AsnOcts *o2); | |
440 | \end{verbatim} | |
441 | \end{small} | |
442 | ||
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. | |
448 | ||
449 | ||
450 | \section{\label{oid-C-section}OBJECT IDENTIFIER} | |
451 | ||
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) | |
457 | works well. | |
458 | ||
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. | |
462 | ||
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 | |
468 | fashion. | |
469 | ||
470 | An OBJECT IDENTIFIER must have a minimum of two arc numbers but the | |
471 | decoding routines do not check this. | |
472 | ||
473 | \begin{small} | |
474 | \begin{verbatim} | |
475 | typedef AsnOcts AsnOid; | |
476 | ||
477 | #define ASNOID_PRESENT( aoid) ASNOCTS_PRESENT (aoid) | |
478 | ||
479 | AsnLen BEncAsnOid (BUF_TYPE b, AsnOid *data); | |
480 | void BDecAsnOid (BUF_TYPE b, AsnOid *result, AsnLen *bytesDecoded, | |
481 | ENV_TYPE env); | |
482 | ||
483 | #define BEncAsnOidContent(b, oid) BEncAsnOctsContent(b, oid) | |
484 | void BDecAsnOidContent (BUF_TYPE b, AsnTag tag, AsnLen len, | |
485 | AsnOid *result, AsnLen *bytesDecoded, | |
486 | ENV_TYPE env); | |
487 | ||
488 | #define FreeAsnOid FreeAsnOcts | |
489 | void 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 | ||
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 | |
504 | is always NULL\@. | |
505 | ||
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. | |
509 | ||
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. | |
513 | ||
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. | |
518 | ||
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. | |
526 | ||
527 | \begin{small} | |
528 | \begin{verbatim} | |
529 | typedef 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 | ||
536 | typedef 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 | ||
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 *); | |
577 | \end{verbatim} | |
578 | \end{small} | |
579 | ||
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. | |
587 | ||
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. | |
596 | ||
597 | ||
598 | \section{\label{any-C-section}ANY and ANY DEFINED BY} | |
599 | ||
600 | ||
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 | |
605 | macros. | |
606 | ||
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. | |
613 | ||
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. | |
618 | ||
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 | |
624 | done. | |
625 | ||
626 | ||
627 | The hash tables are constructed such that an INTEGER or OBJECT | |
628 | IDENTIFIER 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} | |
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 | |
640 | content. | |
641 | ||
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 | |
649 | less useful. | |
650 | ||
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. | |
657 | ||
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. | |
668 | ||
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. | |
673 | ||
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. | |
679 | ||
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. | |
691 | ||
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! | |
703 | ||
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. | |
709 | ||
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. | |
713 | \begin{small} | |
714 | \begin{verbatim} | |
715 | /* | |
716 | * 1 hash table for integer keys | |
717 | * 1 hash table for oid keys | |
718 | */ | |
719 | extern Table *anyOidHashTblG; | |
720 | extern Table *anyIntHashTblG; | |
721 | ||
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); | |
727 | ||
728 | /* | |
729 | * this is put into the hash table with the | |
730 | * int or oid as the key | |
731 | */ | |
732 | typedef 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 | ||
744 | typedef 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 | */ | |
761 | void SetAnyTypeByInt (AsnAny *v, AsnInt id); | |
762 | void SetAnyTypeByOid (AsnAny *v, AsnOid *id); | |
763 | ||
764 | ||
765 | /* | |
766 | * used to initialize the hash table(s) | |
767 | */ | |
768 | void InstallAnyByInt (int anyId, AsnInt intId, | |
769 | unsigned int size, EncodeFcn encode, | |
770 | DecodeFcn decode, FreeFcn free, PrintFcn print); | |
771 | ||
772 | void 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 | */ | |
782 | void FreeAsnAny (AsnAny *v); | |
783 | AsnLen BEncAsnAny (BUF_TYPE b, AsnAny *v); | |
784 | void BerDecAsnAny (BUF_TYPE b, AsnAny *result, AsnLen *bytesDecoded, | |
785 | ENV_TYPE env); | |
786 | void PrintAsnAny (FILE *f, AsnAny *v, unsigned short indent); | |
787 | ||
788 | ||
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 | |
795 | \end{verbatim} | |
796 | \end{small} | |
797 | ||
798 | ||
799 | \section{\label{lib-buf-section}Buffer Management} | |
800 | ||
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. | |
810 | ||
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. | |
816 | ||
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. | |
825 | ||
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'' | |
832 | encoders as well). | |
833 | ||
834 | Nine buffer primitives are required by the runtime library's encode | |
835 | and 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 | ||
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. | |
852 | ||
853 | \subsection{\label{buf-read-c-section}Buffer Reading Routine Semantics} | |
854 | ||
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. | |
860 | ||
861 | \begin{verbatim} | |
862 | unsigned char BufGetByte (BUF_TYPE b); | |
863 | \end{verbatim} | |
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 | |
867 | of the data is made. | |
868 | ||
869 | \begin{verbatim} | |
870 | unsigned char BufPeekByte (BUF_TYPE b); | |
871 | \end{verbatim} | |
872 | Returns the next byte from the buffer without advancing the current | |
873 | pointer. | |
874 | ||
875 | \begin{verbatim} | |
876 | char *BufGetSeg (BUF_TYPE b, unsigned long int *lenPtr); | |
877 | \end{verbatim} | |
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 | |
890 | bytes. | |
891 | ||
892 | \begin{verbatim} | |
893 | unsigned long int BufCopy (char *dst, BUF_TYPE b, unsigned long int len) | |
894 | \end{verbatim} | |
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. | |
900 | ||
901 | ||
902 | \begin{verbatim} | |
903 | void BufSkip (BUF_TYPE b, unsigned long int len); | |
904 | \end{verbatim} | |
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}. | |
908 | ||
909 | \begin{verbatim} | |
910 | int BufReadError (BUF_TYPE b); | |
911 | \end{verbatim} | |
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. | |
915 | ||
916 | \subsection{\label{buf-write-c-section}Buffer Writing Routine Semantics} | |
917 | ||
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 | |
922 | buffer type. | |
923 | ||
924 | \begin{verbatim} | |
925 | void BufPutByteRvs (BUF_TYPE b, unsigned char byte); | |
926 | \end{verbatim} | |
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. | |
931 | ||
932 | \begin{verbatim} | |
933 | void BufPutSegRvs (BUF_TYPE b, char *data, unsigned long int len); | |
934 | \end{verbatim} | |
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. | |
942 | ||
943 | \begin{verbatim} | |
944 | int BufWriteError (BUF_TYPE b); | |
945 | \end{verbatim} | |
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). | |
949 | ||
950 | \subsection{Buffer Configuration} | |
951 | ||
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 | |
957 | code are compiled. | |
958 | ||
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. | |
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 | ||
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}). | |
985 | ||
986 | \subsection{ExpBuf Buffers} | |
987 | ||
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}. | |
997 | ||
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. | |
1003 | ||
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. | |
1011 | ||
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). | |
1022 | ||
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. | |
1033 | ||
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. | |
1041 | ||
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 | |
1046 | {\C longjmp}. | |
1047 | ||
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). | |
1053 | ||
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. | |
1057 | ||
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}. | |
1065 | ||
1066 | \begin{verbatim} | |
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); | |
1074 | ||
1075 | #define ExpBufReadError( b) ((*b)->readError) | |
1076 | #define ExpBufWriteError( b) ((*b)->writeError) | |
1077 | \end{verbatim} | |
1078 | ||
1079 | ||
1080 | The following {\C ExpBuf} routines are also provided. Their | |
1081 | descriptions can be found in the code. | |
1082 | \begin{verbatim} | |
1083 | void ExpBufInit (unsigned long dataBlkSize); | |
1084 | void ExpBufInstallDataInBuf (ExpBuf *b, char *data, unsigned long int len); | |
1085 | ||
1086 | void ExpBufResetInReadMode (ExpBuf *b); | |
1087 | void ExpBufResetInWriteRvsMode (ExpBuf *b); | |
1088 | ||
1089 | ExpBuf *ExpBufAllocBufAndData(); | |
1090 | void ExpBufFreeBufAndData (ExpBuf *b); | |
1091 | void ExpBufFreeBufAndDataList (ExpBuf *b); | |
1092 | ||
1093 | ExpBuf *ExpBufNext (ExpBuf *b); | |
1094 | ExpBuf *ExpBufPrev (ExpBuf *b); | |
1095 | ExpBuf *ExpBufListLastBuf (ExpBuf *b); | |
1096 | ExpBuf *ExpBufListFirstBuf (ExpBuf *b); | |
1097 | ||
1098 | int ExpBufAtEod (ExpBuf *b); | |
1099 | int ExpBufFull (ExpBuf *b); | |
1100 | int ExpBufHasNoData (ExpBuf *b); | |
1101 | ||
1102 | char *ExpBufDataPtr (ExpBuf *b); | |
1103 | unsigned long ExpBufDataSize (ExpBuf *b); | |
1104 | unsigned long ExpBufDataBlkSize (ExpBuf *b); | |
1105 | \end{verbatim} | |
1106 | ||
1107 | \subsection{SBuf Buffers} | |
1108 | ||
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. | |
1114 | ||
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. | |
1119 | ||
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. | |
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 | ||
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 | |
1150 | {\C USE\_MIN\_BUF}. | |
1151 | ||
1152 | \subsection{MinBuf Buffers} | |
1153 | ||
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). | |
1159 | ||
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. | |
1164 | ||
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: | |
1168 | \begin{verbatim} | |
1169 | PersonnelRecord pr; | |
1170 | char blk[128]; | |
1171 | char *minBuf; | |
1172 | ||
1173 | minBuf = blk + 128; /* start writing a end of block */ | |
1174 | BEncPersonnelRecord (&minBuf, pr); | |
1175 | \end{verbatim} | |
1176 | ||
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. | |
1181 | ||
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. | |
1185 | ||
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. | |
1197 | ||
1198 | To configure the generated code to use the {\C MinBuf}s, compile it | |
1199 | with the {\C USE\_MIN\_BUF} symbol defined. | |
1200 | ||
1201 | \subsection{Hybrid Buffer Solutions} | |
1202 | ||
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) | |
1211 | operations. | |
1212 | ||
1213 | In this case you will need to massage the generated code to achieve | |
1214 | the desired results. | |
1215 | ||
1216 | \section{\label{lib-mem-C-section}Dynamic Memory Management} | |
1217 | ||
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. | |
1221 | ||
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 | |
1227 | in the | |
1228 | {\ufn asn-config.h} and have the prototypes: | |
1229 | \begin{verbatim} | |
1230 | void *Asn1Alloc (unsigned long int size); | |
1231 | void Asn1Free (void *ptr); | |
1232 | int CheckAsn1Alloc (void *ptr, ENV_TYPE env); | |
1233 | \end{verbatim} | |
1234 | ||
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 | |
1239 | explicitly. | |
1240 | ||
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. | |
1244 | ||
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}. | |
1252 | \begin{verbatim} | |
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(); | |
1258 | \end{verbatim} | |
1259 | ||
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, | |
1267 | {\C realloc}. | |
1268 | ||
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. | |
1278 | ||
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. | |
1283 | ||
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. | |
1290 | ||
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. | |
1296 | ||
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. | |
1306 | ||
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: | |
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} | |
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 | |
1323 | by the decoders. | |
1324 | ||
1325 | ||
1326 | \section{\label{lib-err-C-section}Error Management} | |
1327 | ||
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. | |
1336 | ||
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. | |
1344 | ||
1345 | \begin{small} | |
1346 | \begin{verbatim} | |
1347 | if ((val = setjmp (env)) == 0) | |
1348 | BDecPersonnelRecord (&buf, &pr, &decodedLen, env); | |
1349 | else | |
1350 | { | |
1351 | decodeErr = TRUE; | |
1352 | fprintf (stderr, "ERROR - Decode routines returned %d\n", val); | |
1353 | } | |
1354 | \end{verbatim} | |
1355 | \end{small} | |
1356 | ||
1357 | The code that will signal an error typically looks like: | |
1358 | \begin{small} | |
1359 | \begin{verbatim} | |
1360 | if (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 | ||
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. | |
1377 | ||
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 | |
1384 | catastrophically. |