|
|
1.1 root 1:
2:
3:
4:
5:
6:
7: _1. _O_v_e_r_v_i_e_w _o_f _p_e_p_s_y _s_y_s_t_e_m
8:
9: This section describes how the various parts fit
10: together to make the system work. The principle behind
11: pepsy is fairly simple. The ASN.1 is summarised as tables
12: of integers. These tables are read by driver routines which
13: encode or decode data to or from the internal format that
14: ISODE OSI implementation uses. In ISODE specific functions
15: are generated for each ASN.1 type defined in contrast the
16: pepsy merely generates a new table of data which is far far
17: smaller.
18:
19: As there is a great deal of effort invested in the
20: ISODE interface to the encoding/decoding routines pepsy
21: automatically provides macros which map the original func-
22: tions into the appropriate function call of a driver. This
23: allows existing posy using code to switch to the pepsy sys-
24: tem with no changes to the code provided no function
25: pointers are used to the original ISODE functions. Even
26: when there are function pointers used the changes are very
27: simple and take only a few hours to implement.
28:
29: _1._1. _B_r_i_e_f _d_e_s_c_r_i_p_t_i_o_n _o_f _t_h_e _u_s_e _o_f _t_h_e _p_e_p_s_y _s_y_s_t_e_m.
30:
31: _1._1._1. _O_u_t_l_i_n_e _o_f _t_h_e _f_i_l_e_s _p_r_o_d_u_c_e_d _u_n_d_e_r _t_h_e _p_e_p_s_y _s_y_s_-
32: _t_e_m.
33:
34: The pepsy system consists of a program called _p_o_s_y
35: which translates ASN.1 modules into a set of tables, called
36: _p_o_s_y at the moment, and library of driver routines, called
37: _l_i_b_p_e_p_s_y._a. Running this _p_o_s_y program on the ASN.1 file
38: will produce several files. If the name of the ASN.1 module
39: is MODULE the following files are generated:
40:
41: MODULE-types.h
42: which contains C structure definitions. The user of
43: the library provides data as a linked list of these C
44: data structures and expects to receive data back as a
45: similar linked list. These data structures are exactly
46: the same as those produced by the original ISODE _p_o_s_y
47: so that existing software written for the old _p_o_s_y pro-
48: gram needs no change. For details on the C data struc-
49: tures types generated see the documentation of the ori-
50: ginal _p_o_s_y program in volume 4 Chapter 5 of the ISODE
51: manuals.
52:
53: MODULE_tables.c
54: This file contains the tables generated by the new _p_o_s_y
55: program. These tables consist of three parts, the
56: first which contains the summary of ASN.1 types. Each
57: type is summarised as an array of a primitive type,
58: struct pte, for encoding and decoding, and struct ptpe
59: for printing. As implied there is one array for each
60: type for each of encoding, decoding and printing as
61:
62:
63:
64: January 23, 1990
65:
66:
67:
68:
69:
70: - 2 -
71:
72:
73: specified when _p_o_s_y is run. The next part contains up
74: to three tables of pointers to these arrays. Each of
75: the three different types of arrays, encoding, decoding
76: and printing, has its own table of pointers. Finally
77: there is the module type definition which contains con-
78: tains pointers to these tables and some other useful
79: information about the module such as its name. This
80: module type structure, which is typedefed to modtyp, is
81: the only piece of data which is global, all the rest of
82: the data is static and is only addressable via the mod-
83: typ data structure. This provides a kind of object
84: oriented approach to handling the tables. Once you are
85: passed a pointer to an ASN.1's modtyp structure you can
86: encode, decode and print any of its types by calling
87: the appropriate libpepsy.a routine with its type
88: number.
89:
90: MODULE_pre_defs.h
91: This file contains #defines symbol of each of the ASN.1
92: types to its type number, which is used when calling a
93: libpepsy.a routine. Each symbol is _Ztype-nameMODULE
94: where _t_y_p_e-_n_a_m_e is the name of the type with dashes (-)
95: turned into underscores (_) and _M_O_D_U_L_E is the name of
96: the module. For example of the ASN.1 universal type
97: _G_r_a_p_h_i_c_S_t_r_i_n_g would have the #define symbol _ZGra-
98: phicStringUNIV. The __Z is prepended to try to make the
99: symbols unique. This file also contains and extern
100: declaration for the modtyp data for its module.
101:
102: MODULE_defs.h
103: This file contains macros for all the encoding, decod-
104: ing and printing functions that the _p_e_p_y program would
105: have for these ASN.1 types. This allows much of the
106: code that uses the routines generated by running the
107: old _p_o_s_y program and taking its output and running _p_e_p_y
108: on augmented ASN.1 output can be recompiled unchanged.
109: If the code used pointers to these functions it is
110: necessary to change it to pass around the type numbers
111: instead and to call appropriately call a libpepsy.a
112: library routine with the type number. As pointers to
113: the printing routines in ISODE are passed as arguments
114: a #define is provided to turn the argument into the
115: pair of arguments, type number and pointer to modtyp
116: structure, which are needed to allow the diagnostic
117: printing code to work with no change for the current
118: ISODE stack. This file also contains a #include of the
119: _M_O_D_U_L_E__p_r_e__d_e_f_s._h file.
120:
121: As the _M_O_D_U_L_E-_t_y_p_e_s._h file #include's the _M_O_D_U_L_E__d_e_f_s._h
122: file no further #includes need to be added to the files
123: using the encoding/decoding/printing functions. This means
124: that code written to use posy/pepy system may need no change
125: at all and the only effort required is to change the
126: Makefile to use the pepsy system. If there is code changes
127:
128:
129:
130: January 23, 1990
131:
132:
133:
134:
135:
136: - 3 -
137:
138:
139: required it would most likely be because function pointers
140: are used to reference the functions generated by posy. If
141: only the _p_e_p_y system was used, not posy then pepy, with code
142: placed inside action statements then quite a large amount of
143: work may be needed to change over to the new system, depend-
144: ing on how large and complex the _p_e_p_y module is.
145:
146: _1._1._2. _O_u_t_l_i_n_e _o_f _t_h_e _p_e_p_s_y _l_i_b_r_a_r_y.
147:
148: enc.cThis contains the routines that encode data from the C
149: data structures into ISODE's PElement linked list data
150: structure which it uses for all presentation data. The
151: most important function to pepsy users is enc_f which
152: called to encode a particular type. It is passed the
153: type number and a pointer to modtyp structure for that
154: module and then the rest of the arguments which are
155: passed to an encode function generated by _p_o_s_y/_p_e_p_y
156: system. See the documentation in Volume 4, "The Appli-
157: cations Cookbook", Section 6.4 called "Pepy Environ-
158: ment". Most of these latter arguments are ignored,
159: only parm and pe, are used.
160:
161: Contrary to what the ISODE documentation says these
162: ignored parameters are hardly ever used by existing code.
163: We have not found a single case where used for encoding a
164: named type, which is all that the user can reference anyway,
165: so we don't see any problems with ignoring these other
166: parameters. Hopefully one day they can be thrown away
167: entirely, until then they are actually passed the the encod-
168: ing function.
169:
170: The rest of the functions are mostly recursive routines
171: which encode a particular type of table entry. For example
172: SEQUENCE is encoded by en_seq which may call itself or oth-
173: ers to encode the types from which it is built up. The
174: function en_type builds up a simple type and en_obj encodes
175: a new type (object) and so on with other functions. There
176: are a few utility routines in the file such as same which
177: determines whether the value is the same as the default
178: value also.
179:
180: dec.cThis file contains the decoding routines that translate
181: presentation data into C data structures defined in the
182: MODULE-types.h is like _e_n_c._c. It is very much like the
183: file _e_n_c._c except the routines do the reverse tasks The
184: routines are structured in a very similar way. We have
185: dec_f which is called by the user to decode a type and
186: like enc_f takes the same arguments as the decoding
187: functions generated by _p_o_s_y with two additions, the
188: type number and a pointer to the modtyp structure for
189: that module. Likewise the other functions are very
190: much like those of enc.c
191:
192: prnt.cThis file contains the routines that print the
193:
194:
195:
196: January 23, 1990
197:
198:
199:
200:
201:
202: - 4 -
203:
204:
205: presentation data in a format similar to that generated
206: by _p_e_p_y's printing functions. It's main function
207: prnt_f is takes the same arguments as the printing
208: function generated by _p_e_p_y as well as the now familiar
209: type number and modtyp pointer. The functions are
210: modeled on the decoding routines as it has similar job
211: to. The only difference is that instead of storing the
212: decoded data into a C data structure it is nicely
213: printed out.
214:
215: fr.c This file contains code to free the data structures
216: defined in MODULE-types.h. Likewise if the -f flag is
217: given when generating the types file it also includes
218: macros in the types file which replace the freeing
219: functions generated by ISODE's _p_o_s_y. The function that
220: the user calls us fre_obj which takes a pointer to the
221: data structure, its decoding table entry and a pointer
222: to the modtyp structure for the module. The freeing is
223: based on the decoding routines except instead of decod-
224: ing all it does is free each part of the data struc-
225: ture, which might involve recursive calls, then it
226: frees the data structure at the end.
227:
228: util.cThis contains the utility routines used by more than
229: one of the above files. This is mostly diagnostic rou-
230: tines at the moment, more general routines could be
231: included in here. If there is an error at the moment
232: which it can't recover from it just prints out a mes-
233: sage on standard error and calls exit. Not perfect and
234: this is something that will need work.
235:
236: main.cThis contains code to perform a series of tests on the
237: _p_e_p_s_y library which is a useful check to see whether
238: any of the routines has been broken by any changes
239: made. It basically loops through a whole series of
240: test cases. Each test case is encoded from some built
241: in test data and then decoded and checked to see if the
242: data has changed in the transfer. If it is compiled
243: with -_D_P_R_N_T=_1 the encoded data is also printed out to
244: check the printing routines which generates a vast
245: amount of output. Finally the free routines are used
246: to free the allocated data, although it can not
247: directly check the free routines to see if they work,
248: it can be used with a malloc tracing package to check
249: that the routines work.
250:
251: test_table.h
252: This contains the test cases that _m_a_i_n._c program runs.
253: Each entry in the table corresponds to a type. One of
254: the fields is count of how many times that type is to
255: be tested to try out the different possibly data values
256: it might have.
257:
258: pep.h and pepdefs.h
259:
260:
261:
262: January 23, 1990
263:
264:
265:
266:
267:
268: - 5 -
269:
270:
271: These files contain the definition of types used for
272: the tables that drive the encoding/decoding/printing
273: routines. All the constants used in that table are
274: defined here via #defines. The modtyp structure is
275: defined in _p_e_p_d_e_f_s._h.
276:
277: t1.py and t2.py
278: These are test ASN.1 modules that are used by _m_a_i_n._c
279: routines to check the _p_e_p_s_y library. The file _t_1._p_y
280: contains the majority of different types with a few of
281: a different module provided in _t_2._p_y. This allows the
282: testing of the code for handling ASN.1 external refer-
283: ences, i.e. references to types defined in other,
284: external, modules.
285:
286: _1._1._3. _N_e_w _f_i_l_e_s _i_n _t_h_e _p_e_p_y _d_i_r_e_c_t_o_r_y
287:
288: etabs.c, dtabs.c and ptabs.c
289: These files contain the code to generate the
290: encoding/decoding/printing tables. The main routine in
291: _e_t_a_b_s._c is tenc_typ which is called on each ASN.1 type
292: to generate an array of entries which describe how to
293: encode that type. See the details section for more
294: information about how the table entries function.
295: Similarly _d_t_a_b_s._c contains the routine tdec_typ which
296: is called on each type to generate its decoding table
297: entries. Likewise tprnt_typ routine generates the
298: arrays of table entries for the printing tables. This
299: function is in _p_t_a_b_s._c.
300:
301: dfns.cThis file contains miscellaneous string handling rou-
302: tines and hash table routines that don't really belong
303: anywhere else. Some of the routines could be cleaned
304: up in that they tend not to free memory they use.
305:
306: mine.hThis file contains the definitions for the hash
307: table(s) that are used to keep track of the ASN.1
308: types. This could probably be done with out a hash
309: table, should anyone want to clean this up, feel wel-
310: come. The lookup function is in _d_f_n_s._c.
311:
312: pass2.h
313: This file has most of the #defines for the table gen-
314: erating program. Most of the prefixes and suffixes of
315: function names and files names are defined here so,
316: hopefully, the names can be changed by merely changing
317: the definition. This contains most of the important
318: definitions needed by the changes to the _p_o_s_y program
319: needed to generate tables.
320:
321: posy.hThis contains the definition of a symbol which is now
322: needed outside of the the main routine and the yacc
323: file. By putting it here we can include it any file
324: that needs to know it with out putting in any that
325:
326:
327:
328: January 23, 1990
329:
330:
331:
332:
333:
334: - 6 -
335:
336:
337: doesn't need it and with out including all the other
338: definitions that occur in _p_e_p_y._h. The structure and
339: meaning of the tables generated from the ASN.1 grammar
340:
341: Each collection of ASN.1 grammar is called a module.
342: (See ASN.1 ) Each ASN.1 module is completely specified in
343: the program by a single C structure of type modtyp and the
344: data which it references. See the _p_e_p_d_e_f_s._h file in the
345: _p_e_p_s_y directory. For each ASN.1 module there are three
346: tables that are generated fromASN.1 grammar. These initial-
347: ised arrays which we call tables are called the encoding,
348: decoding and printing tables. Each of these tables is
349: referenced through a different pointer of the modtyp struc-
350: ture.
351:
352: Each of these pointers references an array of pointers,
353: one pointer for each ASN.1 type defined in the module. The
354: position of one of these pointers is the unique type number
355: we give to its corresponding type. The pointer references
356: an array of type tpe or ptpe, depending whether it is an
357: entry in the decoding/encoding tables or printing tables
358: respectively. See _p_e_p._h in the _p_e_p_s_y directory. This array
359: actually contains the necessary information to
360: encode/decode/print that ASN.1 type. So given the modtyp
361: structure of an ASN.1 module and its type number you can
362: call a routine to encode, decode or print that type.
363:
364: The rest of this document assumes a good knowledge of
365: ASN.1 notation so go read a copy if you haven't already.
366: From here on I shall mention only tpe and this means tpe in
367: the case of encoding or decoding and ptpe in the case of
368: printing, unless otherwise stated. Each type is represented
369: by an array of tpe (or ptpe for printing). The basic ele-
370: ment consists of four integer fields, the printing table is
371: the same with an addition char pointer field which contains
372: the name corresponding to that entry in the ASN.1 grammar.
373: The first specifies the type of the entry and determines how
374: the rest are interpreted. The possible types are listed in
375: _p_e_p_s_y/_p_e_p._h. Each type is an array which starts with an
376: entry of type PE_START and ends with one of type PE_END.
377: Each primitive type requires one entry to specify it, apart
378: from possible PE_START and PE_END used to specify the start
379: and end of the type. Constructed types are represented by a
380: list of entries terminated by an entry of type PE_END. As
381: ASN.1 types can be nested inside so will the representation
382: in tpe entries be nested. For example the ASN.1 type defin-
383: ition:
384: Example1 ::=
385: SEQUENCE {
386: seq1 SEQUENCE {
387: an-i INTEGER,
388: an-ostring OCTET STRING
389: },
390: a-bool IMPLICIT [0] BOOLEAN
391:
392:
393:
394: January 23, 1990
395:
396:
397:
398:
399:
400: - 7 -
401:
402:
403: }
404: Will generate an encoding array:
405: static tpe et_Example1Test[] = {
406: { PE_START, 0, 0, 0 },
407: { SEQ_START, 0, 16, FL_UNIVERSAL },
408: { SEQ_START, OFFSET(struct type_Test_Example1, seq1), 16, FL_UNIVERSAL },
409: { INTEGER, OFFSET(struct element_Test_0, an__i), 2, FL_UNIVERSAL },
410: { OCTETSTRING, OFFSET(struct element_Test_0, an__ostring), 4, FL_UNIVERSAL },
411: { PE_END, 0, 0, 0 },
412: { BOOLEAN, OFFSET(struct type_Test_Example1, a__bool), 0, FL_CONTEXT },
413: { PE_END, 0, 0, 0 },
414: { PE_END, 0, 0, 0 }
415: };
416:
417:
418: Here the second last PE_END matches and closes off the
419: first SEQ_START. The entries which correspond to the other
420: primative types are pretty obvious, with the INTEGER entry
421: corresponding to the primative INTEGER. For fields that
422: generate data the general interpretation of the other three
423: fields is offset, tag and flags/class fields respectively.
424:
425: offsetThe second field gives the offset in a C data struc-
426: ture needed to reference the data that corresponds to
427: this table entry. Each ASN.1 type has C structure
428: types generated as described in the ISODE manuals,
429: volume 4 "The applications Cookbook" Section 5.2, "POSY
430: Environment". As this offset may have to be determined
431: in a compiler dependent manner a C preprocessor macro
432: is used hide the actual details.
433:
434: tag This is the tag associated with the ASN.1 type for that
435: entry. Notice that in the example the [0] IMPLICIT
436: which changes the tag associated with the BOOLEAN entry
437: actually has the correct tag of 0 in the table. Like-
438: wise SEQUENCE has the correct tag of 16 in its
439: SEQ_START entry and so on for the others.
440:
441: flags/class
442: This contains the ASN.1 class associated with the
443: entry's type. That is UNIVERSAL for all except the
444: BOOLEAN type which is CONTEXT class. This fourth can
445: also contain flags that specify if the type is OPTIONAL
446: or DEFAULT. There is plenty of room here as there is
447: only four possibly classes.
448:
449: Now that you have some idea of how these arrays are
450: arranged for a type definition I will proceed to go through
451: the possible type of entries and describe what they do and
452: how they work. These values are defined in _p_e_p_s_y/_p_e_p._h.
453: Those entries with a value below TYPE_DATA are entries that
454: don't correspond to data to be encoded/decoded and are for
455: other book keeping type purposes.
456:
457:
458:
459:
460: January 23, 1990
461:
462:
463:
464:
465:
466: - 8 -
467:
468:
469: PE_START and PE_END
470: As explained above PE_START starts the beginning of a
471: ASN.1 type's array. It probably isn't necessary but
472: the size of the tables is so small it isn't much of an
473: over head to keep around for cosmetic reasons. The
474: entry type PE_END is necessary to mark the end of some
475: compound type as well as the end of ASN.1 data type.
476:
477: XOBJECT and UCODE
478: These are obsolete types and probably should be
479: removed. They were to allow C code written directly by
480: the user to be incorporated into the encoding/decoding
481: but it was found unnecessary. Prehaps some brave soul
482: would like to use them in an attempt to implement a
483: similar system based on _p_e_p_y which is what we first
484: attempted to do until we found this to be much easier.
485:
486: MALLOCThis field only occurs in the decoding tables. It
487: specifies how much space to malloc out for the current
488: C structure it is just inside of. For instance in the
489: example above the decoding table has the following
490: entry:
491:
492: { MALLOC, 0, sizeof (struct type_Test_Example1), 0 },
493:
494: just after the first SEQ_START entry. It tells it to
495: malloc out a struct type_Test_Example1 structure to
496: hold the data from the sequence when it is decoded.
497:
498: SCTRLThis entry is used in handling the ASN.1 CHOICE type.
499: The C type generated for ASN.1 CHOICE type is a struc-
500: ture with an offset field in it and a union of all the
501: C types present in the CHOICE. Each ASN.1 type in the
502: CHOICE of types has a C type definition generated for
503: it. The union is of all these types, which is quite a
504: logical way to implement a CHOICE type. The offset
505: field specifies which possibility of interpreting the
506: union should be used (which _m_e_m_b_e_r should selected).
507: As such it needs to be read by the encoding routines
508: when encoding the data from the C data structures and
509: to be set by the decoding routines when it is decoding
510: the data into the C data structures. There is one such
511: entry for each CHOICE type to specify where the offset
512: field is.
513:
514: CH_ACTAnother redundant entry type. I think this was also
515: used in code to handle C statements or actions speci-
516: fied by the user. It probably should be removed.
517:
518: OPTL This is used to handle the optionals field that is gen-
519: erated by posy when optional types that are _n_o_t imple-
520: mented by pointers are present in the ASN.1 type. For
521: example if an ASN.1 type has an optional integer field
522: how does the encoding routine determine if the integer
523:
524:
525:
526: January 23, 1990
527:
528:
529:
530:
531:
532: - 9 -
533:
534:
535: is to be present or not? If it was implemented as a
536: pointer it could use a NULL (zero) pointer to mean that
537: the type was not present because NULL is guaranteed to
538: never occur as a legal pointer to a real object. But
539: all the possible values for integer could be legally
540: passed so instead for these types which are not
541: pointers and are optional a bit map is allocated in the
542: structure. Each non pointer optional type a bit from
543: the bit map is allocated.
544:
545: If that bit is set the corresponding type is present
546: and it is not present if the bit is not set. Each bit has a
547: #define generated for it. The bit map is merely an integer
548: field called "optionals" limiting maximum number of such
549: optionals to 32 on Sun machines, 16 on some others. (An
550: array of char as BSD fd_sets would have avoid all such lim-
551: its, not that this limit is expected to be exceeded very
552: often !) Like the SCTRL entry this entry merely serves to
553: specify where this field is so it can be test and set by the
554: encoding and decoding routines respectively.
555:
556: ANY and CONS_ANY
557: The C type corresponding to the entry is a PE pointer.
558: To conform with _p_e_p_y the tag and class of this entry
559: are ignored, which may or may not be the most sensible
560: thing. The CONS_ANY is a redundant symbol which means
561: the same thing but is not used. This should be clean
562: up and removed.
563:
564: INTEGER, BOOLEAN, BITSTRING, OCTETSTRING and OBJID
565: These are just as described in the first article. See
566: the ISODE manual to find out what they are allocated as
567: a C data type to implement them. The offset fields
568: says where to find this data type with in the current
569: structure.
570:
571: SET_START, SETOF_START, SEQ_START and SEQOF_START
572: These compound entries differ from the above in that
573: they group all the following entries together up to the
574: matching PE_END. The entries with OF in them
575: correspond to the ASN.1 types which have OF in them
576: e.g. SET OF. Allowing the OF items to have an arbi-
577: trary number of entries is excessive flexibility, they
578: can only have one type by the ASN.1 grammar rules. The
579: C data type corresponding to them is either a structure
580: if it is the first such type in the array or a pointer
581: to a structure is isn't. This complicates the process-
582: ing of these structures a little but not greatly. The
583: OF types differ one other important way, they may occur
584: zero, one or more times, with no upper bound. To cope
585: with this the C data type is a linked list structure.
586: The pointer to the data structure determines whether or
587: not there is another occurrence of the type, if it is
588: NULL there isn't. Thus each data structure has this
589:
590:
591:
592: January 23, 1990
593:
594:
595:
596:
597:
598: - 10 -
599:
600:
601: pointer to the next occurrence, the offset of this
602: pointer is placed in the PE_END field where it can con-
603: veniently be used to determine whether or not to make
604: another pass through the table entry.
605:
606: OBJECTWhen one type references another it generates an
607: OBJECT entry. This specifies the type number of the
608: type which is present in the 3rd field of the tpe
609: structure, pe_tag. The 2nd field still gives the
610: offset in the C data structure which specifies where
611: the user's data for that type is to be found. Usually
612: this a pointer to the C data structure for that type.
613:
614: T_NULLThis entry means the ASN.1 primative type NULL. It
615: doesn't have any body and consequently has no offset as
616: it cannot carry data directly. Only its absence or
617: presence can mean anything so if it is optional it sets
618: or clears a bit in the bit map as described earlier for
619: OPTL entry.
620:
621: T_OIDThis use to be used for Object Identifiers and now is
622: unused, it should be got rid.
623:
624: OBJIDThis corresponds to the Object Identifier ASN.1 type
625: primitive. It is implemented the same as other prima-
626: tive types like INTEGER and OCTET STRING.
627:
628: ETAG This entry gives the explicit tag of the following
629: entry. The usual fields which define class and tag are
630: the only ones which have meaning in this entry. By
631: concatenating successive ETAG entries it is possibly to
632: build up an limited number explicit tags, although this
633: hasn't been tested yet.
634:
635: IMP_OBJ
636: If a type has an implicit tag usually all we have to do
637: is set its tag and class appropriately in its entry.
638: This works for all but one important case, the refer-
639: ence of another type. This is messy because we can't
640: alter the definition of the type with out wrecking it
641: for the other uses. So what we do for encoding is
642: build the type normally and then afterward it is built
643: change its tag and class to be the values we want.
644: Similarly for decoding we match the tag and class up
645: and then decode the body of the type. We can't use a
646: OBJECT entry for this because among other reasons there
647: 3rd field is already to store the type number. (The
648: forth needs to be free to contain flags such as DEFAULT
649: and OPTIONAL) So a new entry type is used, IMP_OBJ, to
650: hold the tag and class. It must be followed by an
651: OBJECT entry which is used to handle the type as nor-
652: mal, the IMP_OBJ entry gives the tag and class to be
653: used. Like the ETAG entry the IMP_OBJ affects the
654: entry that follows it.
655:
656:
657:
658: January 23, 1990
659:
660:
661:
662:
663:
664: - 11 -
665:
666:
667: EXTOBJ and EXTMOD
668: These handle external type references. This is just
669: like a normal (internal?) type reference except we must
670: now specify which module as well as the type. Simi-
671: larly because there are no more free fields in the
672: OBJECT type we need two entries to hold all the infor-
673: mation we need. The EXTMOD occurs first and holds the
674: type number and the offset into the C data structure
675: and the flags, exactly as for an OBJECT entry. The
676: next entry, which must be an EXTMOD, contains a pointer
677: to the modtyp structure for its module. Like a normal
678: OBJECT entry to handle the case of an implicit tag an
679: IMP_OBJ entry would occur before these two entries
680: which gives the class and tag. Likewise it could have
681: an explicit tag in which the two entries would be pro-
682: ceeded by an ETAG entry.
683:
684: DFLT_F and DFLT_B
685: When a type has a default value, to handle decoding and
686: encoding properly you need to know its value. As there
687: is no space to store the value in most entries we allo-
688: cate a whole entry to specify the value. When encoding
689: it is convenient to have the default occur before the
690: entry it refers to. This allows a single check to han-
691: dle all the default encoding. All it has to do is
692: check whether it is the same as the default value and
693: if so not bother encoding the next type. On the other
694: hand when decoding it is more convenient to have the
695: entry after the one it refers to. In this case we need
696: to determine that it is missing before we use the
697: default value to determine the value to pass to the
698: user. To handle this we have entries of both types.
699: _D_F_L_T__F contains the default value for the following
700: entry (F = Front) and DFLT_B contains that for the
701: entry before it (B = Back). Consequently DFLT_F are
702: only used in the decoding tables and DFLT_B entries are
703: only used in the decoding (and printing tables).
704:
705: S-Types
706: These types are entries for the same ASN.1 type as the
707: entry type formed by removing the starting `S'. The
708: above forms would do to handle ASN.1 but we also have
709: to be compatible with the C data structures generated
710: by _p_o_s_y. The implementors decided to optimise the C
711: data structures generated a little means we have to
712: have all these S type entries. If a type was a single
713: field in most cases they produced a #define which elim-
714: inates the need to have a whole structure just for that
715: type. In all the places where this type is used the
716: field of the C structure is changed from a pointer to
717: field which holds the value directly in the structure.
718: See the ISODE reference given above for more details.
719:
720: We handle this by generating the same tables that would
721:
722:
723:
724: January 23, 1990
725:
726:
727:
728:
729:
730: - 12 -
731:
732:
733: be generated with out the optimisation, except the optimised
734: types the S-type of entries instead of the normal ones. For
735: example an optimised OCTET STRING would have the type field
736: of its entry as SOCTETSTRING instead of OCTETSTRING. The
737: only difference in how S type and its corresponding normal
738: are handle is how they find the C data structure for that
739: entry. That difference is that there is no indirection
740: through pointers.
741:
742: Flags field
743: Besides the encoding the class the pe_flags field also
744: contains a few possible flags. Mainly FL_OPTIONAL
745: which means the ASN.1 type corresponding to this flag
746: is OPTIONAL. Consequently when encoding it has to
747: determine if the type is present in the user data pos-
748: sibly using the bit map as described under the OPTL
749: entry. Likewise when decoding it may have to set a bit
750: in the bit map appropriately. The other flag at the
751: moment is FL_DEFAULT which means the entry corresponds
752: to an ASN.1 DEFAULT type. This bit is still needed as
753: not all types have DFLT_* entries implmented for them
754: at the moment. In particular compound value things
755: like SEQUENCE and SET can't have thier default value
756: specified. This is consistent with ISODE, if fact
757: implementing that may even break existing ISODE code.
758: This last flag FL_IMPLICIT is obsolete and not not used
759: any where.
760:
761:
762: _1._2. _W_a_l_k _t_h_r_o_u_g_h _o_f _p_e_p_s_y _l_i_b_r_a_r_y _r_o_u_t_i_n_e_s.
763:
764: Here we walk through all the pepsy library routines at
765: least briefly. If any new routines are added or a routine
766: changed this documentation is the most likely part that will
767: need changing. First we give some theory as to how the task
768: have have been brocken into routines then describe each
769: function in detail. We assume you are familiar with ISODE's
770: PE data structure manipulation routines. if not they are
771: documented in the ISODE manuals, Volume one, chapter 5,
772: "Encoding of Data-Structures" (It actually covers decoding
773: as well).
774:
775: _1._2._1. _O_v_e_r_v_i_e_w _o_f _p_e_p_s_y _l_i_b_r_a_r_y
776:
777: Each seperate task is put into a different file. So
778: all the encoding stuff is in _e_n_c._c, all the decoding stuff
779: is in _d_e_c._c, printing stuff in _p_r_n_t._c and freeing stuff in
780: _f_r_e._c. Actually it breaks down a little in practice, some
781: of the routines for moving around the tables are used in
782: both _e_n_c._c and _d_e_c._c for example. Probably they should
783: defined in _u_t_i_l._c so that linking one of the files from the
784: library doesn't force linking any other except _u_t_i_l._o.
785:
786: There is a common structure to each of the major files
787:
788:
789:
790: January 23, 1990
791:
792:
793:
794:
795:
796: - 13 -
797:
798:
799: as well. There is a main routine which the user calls to
800: obtain the services provided by that file's routines. As
801: all the files revolve about processing the table entries
802: their structure is based on running through the table
803: entries.
804:
805: We shall call each array of entries a table or an
806: object. There is a routine, usually with a name ending in
807: _obj, which is designed to process an object. For example
808: en_obj is the routine called to generated an encoded object.
809: Then there are routines to call on each compound type such
810: as en_seq for encode a SEQUENCE. Finally all the primitives
811: are handled by a one function that ends in _type. This lets
812: each routine concentrate on handling the features particular
813: to its type and call the appropriate routine to handle each
814: type it finds with in its compound type.
815:
816: Most of these table processing routines have just three
817: arguements: which are called parm, p, mod. The parm is char
818: * or char ** in the encoding and decoding routines respec-
819: tively. This points to the user's C structure that data to
820: be encoded is taken from when encoding. When decoding it is
821: the address of a pointer which is made to point the C struc-
822: ture filled with the decode data. The freeing, which is
823: based on the decoding routines, has a char ** while the
824: printing routines don't look at the user's data and so don't
825: have such a pointer. The p points to the current table
826: entry we are up to processing and the mod arguement points
827: to the modtyp structure for the current module we are pro-
828: cessing.
829:
830: All these processing routines return a PE type, which
831: is defined in ISODE's file _h/_p_s_a_p._h, and to return zero if
832: they have an error, but not always. In fact the error han-
833: dling is needs some work and has not been tested very well.
834: Generally it tries to print out the table entry where some-
835: thing went wrong and the name of the function it was in. It
836: then sometimes does an exit which may not be very pleasent
837: for the user.
838:
839: _1._2._2. _T_h_e _e_n_c_o_d_i_n_g _r_o_u_t_i_n_e_s - _e_n_c._c
840:
841: enc_fThis is the the routine made available to the user for
842: the encoding routines. It is fairly simple as it
843: leaves all the hard things up to other routines. All
844: it does is use the type number and modtyp pointer to
845: get a pointer to the table for encoding that type.
846: Then it calls the table or object encoding routine,
847: en_obj, on that object. It first does a consistency
848: check of making sure the first entry in the table is a
849: PE_start. Note that it returns an integer (OK or
850: NOTOK) instead of a PE pointer. This is to be consi-
851: tent with ISODE functions.
852:
853:
854:
855:
856: January 23, 1990
857:
858:
859:
860:
861:
862: - 14 -
863:
864:
865: en_objWe loop through the entries until we come to the end
866: of the table and then we return the PE we have built up
867: from the user's data which is pointed to by parm. In
868: looping through each entry we call the appropriate rou-
869: tine to encode its data. The default case is handled
870: by calling en_type which takes care of all the primi-
871: tive types.
872:
873: The macro NEXT_TPE sets its arguement to point to the
874: next type in the table, counting compound types as one type.
875: Thus if NEXT_TPE is called on a SET_START it will skip all
876: the entries up to and including the matching PE_END. As
877: many objects consist of one compound type and its components
878: the main loop will only be run through once. Even when the
879: object is not based on a compound type it will then consist
880: of one simple type which is processed by en_type, again
881: probably going through the loop only once. In fact the only
882: way it can go through the loop more than once is to process
883: entries that subsidary to the main type, e.g. ETAG entries
884: and things like that. To double check this is the case
885: there is some code that looks for the processing of more
886: than one data generating entry.
887:
888: Much of that testing could probably be eliminated with
889: no loss. Similarly prehaps the IMP_OBJ and ETAG could be
890: handled by the default action of calling en_type. As these
891: routines have evolved after many changes there are things
892: like that which really need to be looked at closely before
893: trying. The comment /*SUPRESS 288*/ means suppress warning
894: 288 to saber C debugging tool that we use.
895:
896: en_type
897: This is one of the longest functions as it has so many
898: cases to handle. It again is structure as a loop over
899: the types until PE_END but it actually returns as soon
900: as it has encoded the next type. We can now look at
901: the encoding of the primative ASN.1 types in detail.
902:
903: DFLT_FBecause we have arranged that for encoding tables,
904: that we precede the entry with a DFLT_F entry we can
905: neatly handle all the default cases. All we do is
906: check if the parameter passed in the user data, in
907: parm, is the same as the default value specified in the
908: DFLT_F entry. The function same performs this check.
909: If it is the same don't encode anything just return,
910: otherwise continue on and encode it.
911:
912: ETAG To handle explicit tags we merely allocate a PE with
913: the right tag and call en_etype to encode its contents,
914: which are in the following entries. The switch on the
915: pe_ucode field use to make a difference but now it is
916: meaningless and should be cleaned up.
917:
918: SEQ_START, SEQOF_START, SET_START, SETOF_START
919:
920:
921:
922: January 23, 1990
923:
924:
925:
926:
927:
928: - 15 -
929:
930:
931: We merely call the appropriate function handle them.
932: Note one _i_m_p_o_r_t_a_n_t difference in the way they are
933: called here from that in enc_obj, the parm arguement is
934: used as a base to index off and fetch a new pointer to
935: pass the next function. This seemly bizarre action is
936: quite straight forward when seen written as it is nor-
937: mally in C, "parm->offset". Where the field offset is
938: a pointer which has an offset from the start of the
939: structure of p->pe_ucode bytes.
940:
941: This is the magic of how we access all the different
942: fields of the C data structures with the one piece of code.
943: It is also prehaps the most critical dependency of the whole
944: system on the implementation of the C language. As the BGNU
945: C compiler supports this feature then it is compilerable on
946: most machines. But any porters should pay attention to this
947: to ensure that thier compiler is happy generating these
948: offsets and compiling these casts properly.
949:
950: The reason why this is different from the calls in
951: en_obj is that this is not the first compound type in the
952: table. The first and only the first does not have an offset
953: and does not need to be indirected through any pointers.
954: All the compound types inside this type will have as their
955: field a pointer which points to a structure. From here on
956: we shall say _i_n_d_i_r_e_c_t_i_o_n to mean this adding the pe_ucode
957: field to the pointer to the structure and using it to refer-
958: ence a pointer. Whether to use _i_n_d_i_r_e_c_t_i_o_n or not is very
959: important matter that really needs to be understood to
960: understand how the routines are structured.
961:
962: IMP_OBJ
963: Here we have to handle the case where we can encode the
964: object then have to change its tag and class after
965: encoding. At the end of this entry this is done very
966: simply by assigning the right values to the appropriate
967: fields after the object has been built. This means
968: that if the intermeadiate form is altered this piece of
969: code may have to be altered as well. There seems to be
970: no better way of handling this.
971:
972: The complication in handling this field is the handling
973: of all the possible types of object. If it is an external
974: object we have to perform a call to enc_f with all the right
975: arguements where a normal OBJECT, the last else branch,
976: requires a normal call to en_obj. Note the case of SOBJECT
977: is the same as OBJECT _e_x_c_e_p_t _t_h_e_r_e _i_s _n_o _i_n_d_i_r_e_c_t_i_o_n.
978:
979: SOBJECT and OBJECT
980: Here is the code that handles the two cases sperately.
981: It is exactly as in the IMP_OBJ case except seperated
982: out. Note the only difference between the two cases is
983: lack of indirection in the SOBJECT case.
984:
985:
986:
987:
988: January 23, 1990
989:
990:
991:
992:
993:
994: - 16 -
995:
996:
997: CHOICE_START
998: This is exactly as all other compound types, like
999: SEQ_START and OBJECT, we call the appropriate routine
1000: with indirection. From reading the ISODE manuals that
1001: the ASN.1 CHOICE type is handled by a structure of its
1002: own like the other compund types.
1003:
1004: EXTOBJ and SEXTOBJ
1005:
1006:
1007:
1008:
1009:
1010:
1011:
1012:
1013:
1014:
1015:
1016:
1017:
1018:
1019:
1020:
1021:
1022:
1023:
1024:
1025:
1026:
1027:
1028:
1029:
1030:
1031:
1032:
1033:
1034:
1035:
1036:
1037:
1038:
1039:
1040:
1041:
1042:
1043:
1044:
1045:
1046:
1047:
1048:
1049:
1050:
1051:
1052:
1053:
1054: January 23, 1990
1055:
1056:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.