File: odr.xml

package info (click to toggle)
yaz 3.0.34-2
  • links: PTS, VCS
  • area: main
  • in suites: lenny
  • size: 13,404 kB
  • ctags: 12,108
  • sloc: xml: 116,075; ansic: 52,205; sh: 9,746; tcl: 2,043; makefile: 1,141; yacc: 347
file content (1311 lines) | stat: -rw-r--r-- 44,211 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
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
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
 <chapter id="odr"><title>The ODR Module</title>
  
  <sect1 id="odr.introduction"><title>Introduction</title>

   <para>
     &odr; is the BER-encoding/decoding subsystem of &yaz;. Care as been taken
    to isolate &odr; from the rest of the package - specifically from the
    transport interface. &odr; may be used in any context where basic
    ASN.1/BER representations are used.
   </para>

   <para>
    If you are only interested in writing a Z39.50 implementation based on
    the PDUs that are already provided with &yaz;, you only need to concern
    yourself with the section on managing ODR streams
    (<xref linkend="odr.use"/>). Only if you need to
    implement ASN.1 beyond that which has been provided, should you
    worry about the second half of the documentation
    (<xref linkend="odr.programming"/>).
    If you use one of the higher-level interfaces, you can skip this
    section entirely.
   </para>

   <para>
    This is important, so we'll repeat it for emphasis: <emphasis>You do
     not need to read <xref linkend="odr.programming"/>
     to implement Z39.50 with &yaz;.</emphasis>
   </para>

   <para>
    If you need a part of the protocol that isn't already in &yaz;, you
    should contact the authors before going to work on it yourself: We
    might already be working on it. Conversely, if you implement a useful
    part of the protocol before us, we'd be happy to include it in a
    future release.
   </para>

  </sect1>
  <sect1 id="odr.use"><title>Using ODR</title>

   <sect2 id="odr.streams"><title>ODR Streams</title>

    <para>
     Conceptually, the ODR stream is the source of encoded data in the
     decoding mode; when encoding, it is the receptacle for the encoded
     data. Before you can use an ODR stream it must be allocated. This is
     done with the function
    </para>

    <synopsis>
     ODR odr_createmem(int direction);
    </synopsis>

    <para>
     The <function>odr_createmem()</function> function takes as argument one
     of three manifest constants: <literal>ODR_ENCODE</literal>,
     <literal>ODR_DECODE</literal>, or <literal>ODR_PRINT</literal>.
     An &odr; stream can be in only one mode - it is not possible to change
     its mode once it's selected. Typically, your program will allocate
     at least two ODR streams - one for decoding, and one for encoding.
    </para>

    <para>
     When you're done with the stream, you can use
    </para>

    <synopsis>
     void odr_destroy(ODR o);
    </synopsis>

    <para>
     to release the resources allocated for the stream.
    </para>
   </sect2>

   <sect2 id="odr.memory.management"><title id="memory">Memory Management</title>

    <para>
     Two forms of memory management take place in the &odr; system. The first
     one, which has to do with allocating little bits of memory (sometimes
     quite large bits of memory, actually) when a protocol package is
     decoded, and turned into a complex of interlinked structures. This
     section deals with this system, and how you can use it for your own
     purposes. The next section deals with the memory management which is
     required when encoding data - to make sure that a large enough buffer is
     available to hold the fully encoded PDU.
    </para>

    <para>
     The &odr; module has its own memory management system, which is
     used whenever memory is required. Specifically, it is used to allocate
     space for data when decoding incoming PDUs. You can use the memory
     system for your own purposes, by using the function
    </para>

    <synopsis>
     void *odr_malloc(ODR o, int size);
    </synopsis>

    <para>
     You can't use the normal <function>free(2)</function> routine to free
     memory allocated by this function, and &odr; doesn't provide a parallel
     function. Instead, you can call
    </para>

    <synopsis>
     void odr_reset(ODR o, int size);
    </synopsis>

    <para>
     when you are done with the
     memory: Everything allocated since the last call to
     <function>odr_reset()</function> is released.
     The <function>odr_reset()</function> call is also required to clear
     up an error condition on a stream.
    </para>

    <para>
     The function
    </para>

    <synopsis>
     int odr_total(ODR o);
    </synopsis>

    <para>
     returns the number of bytes allocated on the stream since the last call to
     <function>odr_reset()</function>.
    </para>

    <para>
     The memory subsystem of &odr; is fairly efficient at allocating and
     releasing little bits of memory. Rather than managing the individual,
     small bits of space, the system maintains a free-list of larger chunks
     of memory, which are handed out in small bits. This scheme is
     generally known as a <emphasis>nibble memory</emphasis> system.
     It is very useful for maintaining short-lived constructions such
     as protocol PDUs.
    </para>

    <para>
     If you want to retain a bit of memory beyond the next call to
     <function>odr_reset()</function>, you can use the function
    </para>

    <synopsis>
     ODR_MEM odr_extract_mem(ODR o);
    </synopsis>

    <para>
     This function will give you control of the memory recently allocated
     on the ODR stream. The memory will live (past calls to
     <function>odr_reset()</function>), until you call the function
    </para>

    <synopsis>
     void odr_release_mem(ODR_MEM p);
    </synopsis>

    <para>
     The opaque <literal>ODR_MEM</literal> handle has no other purpose than
     referencing the memory block for you until you want to release it.
    </para>

    <para>
     You can use <function>odr_extract_mem()</function> repeatedly between
     allocating data, to retain individual control of separate chunks of data.
    </para>

   </sect2>
   <sect2 id="odr.encoding.and.decoding"><title>Encoding and Decoding Data</title>

    <para>
     When encoding data, the ODR stream will write the encoded octet string
     in an internal buffer. To retrieve the data, use the function
    </para>

    <synopsis>
     char *odr_getbuf(ODR o, int *len, int *size);
    </synopsis>

    <para>
     The integer pointed to by len is set to the length of the encoded
     data, and a pointer to that data is returned. <literal>*size</literal>
     is set to the size of the buffer (unless <literal>size</literal> is null,
     signaling that you are not interested in the size). The next call to
     a primitive function using the same &odr; stream will overwrite the
     data, unless a different buffer has been supplied using the call
    </para>

    <synopsis>
     void odr_setbuf(ODR o, char *buf, int len, int can_grow);
    </synopsis>

    <para>
     which sets the encoding (or decoding) buffer used by
     <literal>o</literal> to <literal>buf</literal>, using the length
     <literal>len</literal>.
     Before a call to an encoding function, you can use
     <function>odr_setbuf()</function> to provide the stream with an encoding
     buffer of sufficient size (length). The <literal>can_grow</literal>
     parameter tells the encoding &odr; stream whether it is allowed to use
     <function>realloc(2)</function> to increase the size of the buffer when
     necessary. The default condition of a new encoding stream is equivalent
     to the results of calling
    </para>

    <synopsis>
     odr_setbuf(stream, 0, 0, 1);
    </synopsis>

    <para>
     In this case, the stream will allocate and reallocate memory as
     necessary. The stream reallocates memory by repeatedly doubling the
     size of the buffer - the result is that the buffer will typically
     reach its maximum, working size with only a small number of reallocation
     operations. The memory is freed by the stream when the latter is destroyed,
     unless it was assigned by the user with the <literal>can_grow</literal>
     parameter set to zero (in this case, you are expected to retain
     control of the memory yourself).
    </para>

    <para>
     To assume full control of an encoded buffer, you must first call
     <function>odr_getbuf()</function> to fetch the buffer and its length.
     Next, you should call <function>odr_setbuf()</function> to provide a
     different buffer (or a null pointer) to the stream. In the simplest
     case, you will reuse the same buffer over and over again, and you
     will just need to call <function>odr_getbuf()</function> after each
     encoding operation to get the length and address of the buffer.
     Note that the stream may reallocate the buffer during an encoding
     operation, so it is necessary to retrieve the correct address after
     each encoding operation.
    </para>

    <para>
     It is important to realize that the ODR stream will not release this
     memory when you call <function>odr_reset()</function>: It will
     merely update its internal pointers to prepare for the encoding of a
     new data value.
     When the stream is released by the <function>odr_destroy()</function>
     function, the memory given to it by <function>odr_setbuf</function> will
     be released <emphasis>only</emphasis> if the <literal>can_grow</literal>
     parameter to <function>odr_setbuf()</function> was nonzero. The
     <literal>can_grow</literal> parameter, in other words, is a way of
     signaling who is to own the buffer, you or the ODR stream. If you never call
     <function>odr_setbuf()</function> on your encoding stream, which is
     typically the case, the buffer allocated by the stream will belong to
     the stream by default.
    </para>

    <para>
     When you wish to decode data, you should first call
     <function>odr_setbuf()</function>, to tell the decoding stream
     where to find the encoded data, and how long the buffer is
     (the <literal>can_grow</literal> parameter is ignored by a decoding
     stream). After this, you can call the function corresponding to the
     data you wish to decode (eg, <function>odr_integer()</function> odr
     <function>z_APDU()</function>).
    </para>
    
    <example id="example.odr.encoding.and.decoding.functions">
     <title>Encoding and decoding functions</title>
     <synopsis>
      int odr_integer(ODR o, int **p, int optional, const char *name);
      
      int z_APDU(ODR o, Z_APDU **p, int optional, const char *name);
     </synopsis>
    </example>

    <para>
     If the data is absent (or doesn't match the tag corresponding to
     the type), the return value will be either 0 or 1 depending on the
     <literal>optional</literal> flag. If <literal>optional</literal>
     is 0 and the data is absent, an error flag will be raised in the
     stream, and you'll need to call <function>odr_reset()</function> before
     you can use the stream again. If <literal>optional</literal> is
     nonzero, the pointer <emphasis>pointed</emphasis> to/ by
     <literal>p</literal> will be set to the null value, and the function
     will return 1.
     The <literal>name</literal> argument is used to pretty-print the
     tag in question. It may be set to <literal>NULL</literal> if
     pretty-printing is not desired.
    </para>

    <para>
     If the data value is found where it's expected, the pointer
     <emphasis>pointed to</emphasis> by the <literal>p</literal> argument
     will be set to point to the decoded type.
     The space for the type will be allocated and owned by the &odr;
     stream, and it will live until you call
     <function>odr_reset()</function> on the stream. You cannot use
     <function>free(2)</function> to release the memory.
     You can decode several data elements (by repeated calls to
     <function>odr_setbuf()</function> and your decoding function), and
     new memory will be allocated each time. When you do call 
     <function>odr_reset()</function>, everything decoded since the
     last call to <function>odr_reset()</function> will be released.
    </para>

    <example id="example.odr.encoding.of.integer">
     <title>Encoding and decoding of an integer</title>
     <para>
      The use of the double indirection can be a little confusing at first
      (its purpose will become clear later on, hopefully),
      so an example is in order. We'll encode an integer value, and
      immediately decode it again using a different stream. A useless, but
      informative operation.
     </para>
     <programlisting><![CDATA[
void do_nothing_useful(int value)
{
    ODR encode, decode;
    int *valp, *resvalp;
    char *bufferp;
    int len;
     
    /* allocate streams */
    if (!(encode = odr_createmem(ODR_ENCODE)))
        return;
    if (!(decode = odr_createmem(ODR_DECODE)))
        return;

    valp = &amp;value;
    if (odr_integer(encode, &amp;valp, 0, 0) == 0)
    {
        printf("encoding went bad\n");
        return;
    }
    bufferp = odr_getbuf(encode, &amp;len);
    printf("length of encoded data is &percnt;d\n", len);

    /* now let's decode the thing again */
    odr_setbuf(decode, bufferp, len);
    if (odr_integer(decode, &amp;resvalp, 0, 0) == 0)
    {
        printf("decoding went bad\n");
        return;
    }
    printf("the value is &percnt;d\n", *resvalp);

    /* clean up */
    odr_destroy(encode);
    odr_destroy(decode);
}
]]>
     </programlisting>
     <para>
      This looks like a lot of work, offhand. In practice, the &odr; streams
      will typically be allocated once, in the beginning of your program
      (or at the beginning of a new network session), and the encoding
      and decoding will only take place in a few, isolated places in your
      program, so the overhead is quite manageable.
     </para>
    </example>
    
   </sect2>

   <sect2 id="odr.printing"><title>Printing</title>
    <para>
     When an ODR stream is created of type <literal>ODR_PRINT</literal>
     the ODR module will print the contents of a PDU in a readable format.
     By default output is written to the <literal>stderr</literal> stream.
     This behavior can be changed, however, by calling the function
     <synopsis>
      odr_setprint(ODR o, FILE *file);
     </synopsis>
     before encoders or decoders are being invoked.
     It is also possible to direct the output to a buffer (of indeed
     another file), by using the more generic mechanism:
     <synopsis>
      void odr_set_stream(ODR o, void *handle,
                         void (*stream_write)(ODR o, void *handle, int type,
                                              const char *buf, int len),
                         void (*stream_close)(void *handle));
     </synopsis>
     Here the user provides an opaque handle and two handlers,
     <replaceable>stream_write</replaceable> for writing,
     and <replaceable>stream_close</replaceable> which is supposed
     to close/free resources associated with handle. 
     The <replaceable>stream_close</replaceable> handler is optional and
     if NULL for the function is provided, it will not be invoked.
     The <replaceable>stream_write</replaceable> takes the ODR handle
     as parameter, the user defined handle, a type 
     <literal>ODR_OCTETSTRING</literal>, <literal>ODR_VISIBLESTRING</literal>
     which indicates the type of contents is being written.
    </para>
    <para>
     Another utility useful for diagnostics (error handling) or as
     part of the printing facilities is:
     <synopsis>
      const char **odr_get_element_path(ODR o);
     </synopsis>
     which returns a list of current elements that ODR deals with at the 
     moment. For the returned array, say <literal>ar</literal>, 
     <literal>ar[0]</literal> is the top level element,
     <literal>ar[n]</literal> is the last. The last element has the
     property that <literal>ar[n+1] == NULL</literal>.
    </para>
    <example id="example.odr.element.path.record">
     <title>Element Path for record</title>
     <para>
      For a database record part of a PresentResponse the
      array returned by <function>odr_get_element</function>
      is <literal>presentResponse</literal>, <literal>databaseOrSurDiagnostics</literal>, <literal>?</literal>, <literal>record</literal>, <literal>?</literal>, <literal>databaseRecord</literal> . The question mark appears due to 
      unnamed constructions.
     </para>
     </example>
   </sect2>
   <sect2 id="odr.diagnostics"><title>Diagnostics</title>

    <para>
     The encoding/decoding functions all return 0 when an error occurs.
     Until you call <function>odr_reset()</function>, you cannot use the
     stream again, and any function called will immediately return 0.
    </para>

    <para>
     To provide information to the programmer or administrator, the function
    </para>

    <synopsis>
     void odr_perror(ODR o, char *message);
    </synopsis>

    <para>
     is provided, which prints the <literal>message</literal> argument to
     <literal>stderr</literal> along with an error message from the stream.
    </para>

    <para>
     You can also use the function
    </para>

    <synopsis>
     int odr_geterror(ODR o);
    </synopsis>

    <para>
     to get the current error number from the screen. The number will be
     one of these constants:
    </para>

    <table frame="top" id="odr.error.codes">
     <title>ODR Error codes</title>
     <tgroup cols="2">
      <thead>
       <row>
	<entry>code</entry>
	<entry>Description</entry>
       </row>
      </thead>
      <tbody>
       <row>
	<entry>OMEMORY</entry><entry>Memory allocation failed.</entry>
       </row>

       <row>
	<entry>OSYSERR</entry><entry>A system- or library call has failed.
	 The standard diagnostic variable <literal>errno</literal> should be
	 examined to determine the actual error.</entry>
       </row>

       <row>
	<entry>OSPACE</entry><entry>No more space for encoding.
	 This will only occur when the user has explicitly provided a
	 buffer for an encoding stream without allowing the system to
	 allocate more space.</entry>
       </row>

       <row>
	<entry>OREQUIRED</entry><entry>This is a common protocol error; A
	 required data element was missing during encoding or decoding.</entry>
       </row>

       <row>
	<entry>OUNEXPECTED</entry><entry>An unexpected data element was
	 found during decoding.</entry>
       </row>

       <row><entry>OOTHER</entry><entry>Other error. This is typically an
	 indication of misuse of the &odr; system by the programmer, and also
	 that the diagnostic system isn't as good as it should be, yet.</entry>
       </row>
      </tbody>
     </tgroup>
    </table>

    <para>
     The character string array
    </para>

    <synopsis>
     char *odr_errlist[]
    </synopsis>

    <para>
     can be indexed by the error code to obtain a human-readable
     representation of the problem.
    </para>

   </sect2>
   <sect2 id="odr.summary.and.synopsis">
    <title>Summary and Synopsis</title>

    <synopsis>
     #include &lt;odr.h>

     ODR odr_createmem(int direction);

     void odr_destroy(ODR o);

     void odr_reset(ODR o);

     char *odr_getbuf(ODR o, int *len);

     void odr_setbuf(ODR o, char *buf, int len);

     void *odr_malloc(ODR o, int size);

     ODR_MEM odr_extract_mem(ODR o);

     void odr_release_mem(ODR_MEM r);

     int odr_geterror(ODR o);

     void odr_perror(char *message);

     extern char *odr_errlist[];
    </synopsis>

   </sect2>
  </sect1>

  <sect1 id="odr.programming"><title>Programming with ODR</title>

   <para>
    The API of &odr; is designed to reflect the structure of ASN.1, rather
    than BER itself. Future releases may be able to represent data in
    other external forms.
   </para>

   <tip>
    <para>
     There is an ASN.1 tutorial available at
     <ulink url="&url.asn.1.tutorial;">this site</ulink>.
     This site also has standards for ASN.1 (X.680) and BER (X.690) 
     <ulink url="&url.asn.1.standards;">online</ulink>.
    </para>
   </tip>
   
   <para>
    The ODR interface is based loosely on that of the Sun Microsystems
    XDR routines.
    Specifically, each function which corresponds to an ASN.1 primitive
    type has a dual function. Depending on the settings of the ODR
    stream which is supplied as a parameter, the function may be used
    either to encode or decode data. The functions that can be built
    using these primitive functions, to represent more complex data types,
    share this quality. The result is that you only have to enter the
    definition for a type once - and you have the functionality of encoding,
    decoding (and pretty-printing) all in one unit.
    The resulting C source code is quite compact, and is a pretty
    straightforward representation of the source ASN.1 specification. 
   </para>
   
   <para>
    In many cases, the model of the XDR functions works quite well in this
    role.
    In others, it is less elegant. Most of the hassle comes from the optional
    SEQUENCE members which don't exist in XDR.
   </para>

   <sect2 id="odr.primitive.asn1.types">
    <title>The Primitive ASN.1 Types</title>

    <para>
     ASN.1 defines a number of primitive types (many of which correspond
     roughly to primitive types in structured programming languages, such as C).
    </para>

    <sect3 id="odr.integer"><title>INTEGER</title>

     <para>
      The &odr; function for encoding or decoding (or printing) the ASN.1
      INTEGER type looks like this:
     </para>

     <synopsis>
      int odr_integer(ODR o, int **p, int optional, const char *name);
     </synopsis>

     <para>
      (we don't allow values that can't be contained in a C integer.)
     </para>
     
     <para>
      This form is typical of the primitive &odr; functions. They are named
      after the type of data that they encode or decode. They take an &odr;
      stream, an indirect reference to the type in question, and an
      <literal>optional</literal> flag (corresponding to the OPTIONAL keyword
      of ASN.1) as parameters. They all return an integer value of either one
      or zero.
      When you use the primitive functions to construct encoders for complex
      types of your own, you should follow this model as well. This
      ensures that your new types can be reused as elements in yet more
      complex types.
     </para>

     <para>
      The <literal>o</literal> parameter should obviously refer to a properly
      initialized &odr; stream of the right type (encoding/decoding/printing)
      for the operation that you wish to perform.
     </para>

     <para>
      When encoding or printing, the function first looks at
      <literal>* p</literal>. If <literal>* p</literal> (the pointer pointed
      to by <literal>p</literal>) is a null pointer, this is taken to mean that
      the data element is absent. If the <literal>optional</literal> parameter
      is nonzero, the function will return one (signifying success) without
      any further processing. If the <literal>optional</literal> is zero, an
      internal error flag is set in the &odr; stream, and the function will
      return 0. No further operations can be carried out on the stream without
      a call to the function <function>odr_reset()</function>.
     </para>

     <para>
      If <literal>*p</literal> is not a null pointer, it is expected to
      point to an instance of the data type. The data will be subjected to
      the encoding rules, and the result will be placed in the buffer held
      by the &odr; stream.
     </para>

     <para>
      The other ASN.1 primitives have similar functions that operate in
      similar manners:
     </para>
    </sect3>
    <sect3 id="odr.boolean"><title>BOOLEAN</title>

     <synopsis>
int odr_bool(ODR o, bool_t **p, int optional, const char *name);
     </synopsis>

    </sect3>
    <sect3 id="odr.real"><title>REAL</title>

     <para>
      Not defined.
     </para>

    </sect3>
    <sect3 id="odr.null"><title>NULL</title>

     <synopsis>
int odr_null(ODR o, bool_t **p, int optional, const char *name);
     </synopsis>

     <para>
      In this case, the value of **p is not important. If <literal>*p</literal>
      is different from the null pointer, the null value is present, otherwise
      it's absent.
     </para>

    </sect3>
    <sect3 id="odr.octet.string"><title>OCTET STRING</title>

     <synopsis>
typedef struct odr_oct
{
    unsigned char *buf;
    int len;
    int size;
} Odr_oct;

int odr_octetstring(ODR o, Odr_oct **p, int optional,
                    const char *name);
     </synopsis>

     <para>
      The <literal>buf</literal> field should point to the character array
      that holds the octetstring. The <literal>len</literal> field holds the
      actual length, while the <literal>size</literal> field gives the size
      of the allocated array (not of interest to you, in most cases).
      The character array need not be null terminated.
     </para>

     <para>
      To make things a little easier, an alternative is given for string
      types that are not expected to contain embedded NULL characters (eg.
      VisibleString):
     </para>

     <synopsis>
      int odr_cstring(ODR o, char **p, int optional, const char *name);
     </synopsis>

     <para>
      Which encoded or decodes between OCTETSTRING representations and
      null-terminates C strings.
     </para>

     <para>
      Functions are provided for the derived string types, eg:
     </para>

     <synopsis>
int odr_visiblestring(ODR o, char **p, int optional,
                      const char *name);
     </synopsis>

    </sect3>
    <sect3 id="odr.bit.string"><title>BIT STRING</title>

     <synopsis>
int odr_bitstring(ODR o, Odr_bitmask **p, int optional,
                  const char *name);
     </synopsis>

     <para>
      The opaque type <literal>Odr_bitmask</literal> is only suitable for
      holding relatively brief bit strings, eg. for options fields, etc.
      The constant <literal>ODR_BITMASK_SIZE</literal> multiplied by 8
      gives the maximum possible number of bits.
     </para>

     <para>
      A set of macros are provided for manipulating the
      <literal>Odr_bitmask</literal> type:
     </para>

     <synopsis>
void ODR_MASK_ZERO(Odr_bitmask *b);

void ODR_MASK_SET(Odr_bitmask *b, int bitno);

void ODR_MASK_CLEAR(Odr_bitmask *b, int bitno);

int ODR_MASK_GET(Odr_bitmask *b, int bitno);
     </synopsis>

     <para>
      The functions are modeled after the manipulation functions that
      accompany the <literal>fd_set</literal> type used by the
      <function>select(2)</function> call.
      <literal>ODR_MASK_ZERO</literal> should always be called first on a
      new bitmask, to initialize the bits to zero.
     </para>
    </sect3>

    <sect3 id="odr.object.identifier"><title>OBJECT IDENTIFIER</title>

     <synopsis>
int odr_oid(ODR o, Odr_oid **p, int optional, const char *name);
     </synopsis>

     <para>
      The C OID representation is simply an array of integers, terminated by
      the value -1 (the <literal>Odr_oid</literal> type is synonymous with
      the <literal>short</literal> type).
      We suggest that you use the OID database module (see
      <xref linkend="tools.oid.database"/>) to handle object identifiers
      in your application.
     </para>

    </sect3>
   </sect2>
   <sect2 id="odr.tagging.primitive.types"><title>Tagging Primitive Types</title> <!-- tag.prim -->

    <para>
     The simplest way of tagging a type is to use the
     <function>odr_implicit_tag()</function> or 
     <function>odr_explicit_tag()</function> macros:
    </para>

    <synopsis>
int odr_implicit_tag(ODR o, Odr_fun fun, int class, int tag,
                     int optional, const char *name);

int odr_explicit_tag(ODR o, Odr_fun fun, int class, int tag,
                     int optional, const char *name);
    </synopsis>

    <para>
     To create a type derived from the integer type by implicit tagging, you
     might write:
    </para>

    <screen>
     MyInt ::= [210] IMPLICIT INTEGER
    </screen>

    <para>
     In the &odr; system, this would be written like:
    </para>

    <screen>
int myInt(ODR o, int **p, int optional, const char *name)
{
    return odr_implicit_tag(o, odr_integer, p,
			    ODR_CONTEXT, 210, optional, name);
}
    </screen>

    <para>
     The function <function>myInt()</function> can then be used like any of
     the primitive functions provided by &odr;. Note that the behavior of
     <function>odr_explicit_tag()</function>
     and <function>odr_implicit_tag()</function> macros
     act exactly the same as the functions they are applied to - they
     respond to error conditions, etc, in the same manner - they
     simply have three extra parameters. The class parameter may
     take one of the values: <literal>ODR_CONTEXT</literal>,
     <literal>ODR_PRIVATE</literal>, <literal>ODR_UNIVERSAL</literal>, or
     <literal>/ODR_APPLICATION</literal>.
    </para>

   </sect2>
   <sect2 id="odr.constructed.types"><title>Constructed Types</title>

    <para>
     Constructed types are created by combining primitive types. The
      &odr; system only implements the SEQUENCE and SEQUENCE OF constructions
     (although adding the rest of the container types should be simple
     enough, if the need arises).
    </para>

    <para>
     For implementing SEQUENCEs, the functions
    </para>

    <synopsis>
int odr_sequence_begin(ODR o, void *p, int size, const char *name);
int odr_sequence_end(ODR o);
    </synopsis>

    <para>
     are provided.
    </para>

    <para>
     The <function>odr_sequence_begin()</function> function should be
     called in the beginning of a function that implements a SEQUENCE type.
     Its parameters are the &odr; stream, a pointer (to a pointer to the type
     you're implementing), and the <literal>size</literal> of the type
     (typically a C structure). On encoding, it returns 1 if
     <literal>* p</literal> is a null pointer. The <literal>size</literal>
     parameter is ignored. On decoding, it returns 1 if the type is found in
     the data stream. <literal>size</literal> bytes of memory are allocated,
     and <literal>*p</literal> is set to point to this space.
     <function>odr_sequence_end()</function> is called at the end of the
     complex function. Assume that a type is defined like this:
    </para>

    <screen>
MySequence ::= SEQUENCE {
     intval INTEGER,
     boolval BOOLEAN OPTIONAL
}
    </screen>

    <para>
     The corresponding &odr; encoder/decoder function and the associated data
     structures could be written like this:
    </para>

    <screen>
typedef struct MySequence
{
    int *intval;
    bool_t *boolval;
} MySequence;
     
int mySequence(ODR o, MySequence **p, int optional, const char *name)
{
    if (odr_sequence_begin(o, p, sizeof(**p), name) == 0)
        return optional &amp;&amp; odr_ok(o);
    return
        odr_integer(o, &amp;(*p)->intval, 0, "intval") &amp;&amp;
        odr_bool(o, &amp;(*p)->boolval, 1, "boolval") &amp;&amp;
        odr_sequence_end(o);
}

    </screen>

    <para>
     Note the 1 in the call to <function>odr_bool()</function>, to mark
     that the sequence member is optional.
     If either of the member types had been tagged, the macros
     <function>odr_implicit_tag()</function> or
     <function>odr_explicit_tag()</function>
     could have been used.
     The new function can be used exactly like the standard functions provided
     with &odr;. It will encode, decode or pretty-print a data value of the
     <literal>MySequence</literal> type. We like to name types with an
     initial capital, as done in ASN.1 definitions, and to name the
     corresponding function with the first character of the name in lower case.
     You could, of course, name your structures, types, and functions any way
     you please - as long as you're consistent, and your code is easily readable.
     <literal>odr_ok</literal> is just that - a predicate that returns the
     state of the stream. It is used to ensure that the behavior of the new
     type is compatible with the interface of the primitive types.
    </para>

   </sect2>
   <sect2 id="odr.tagging.constructed.types">
    <title>Tagging Constructed Types</title>

    <note>
     <para>
      See <xref linkend="odr.tagging.primitive.types"/> for information on how to tag
      the primitive types, as well as types that are already defined.
     </para>
    </note>

    <sect3 id="odr.implicit.tagging">
     <title>Implicit Tagging</title>

     <para>
      Assume the type above had been defined as
     </para>

     <screen>
MySequence ::= [10] IMPLICIT SEQUENCE {
      intval INTEGER,
      boolval BOOLEAN OPTIONAL
}
     </screen>

     <para>
      You would implement this in &odr; by calling the function
     </para>

     <synopsis>
int odr_implicit_settag(ODR o, int class, int tag);
     </synopsis>

     <para>
      which overrides the tag of the type immediately following it. The
      macro <function>odr_implicit_tag()</function> works by calling
      <function>odr_implicit_settag()</function> immediately
      before calling the function pointer argument.
      Your type function could look like this:
     </para>

     <screen>
int mySequence(ODR o, MySequence **p, int optional, const char *name)
{
    if (odr_implicit_settag(o, ODR_CONTEXT, 10) == 0 ||
        odr_sequence_begin(o, p, sizeof(**p), name) == 0)
        return optional &amp;&amp; odr_ok(o);
    return
        odr_integer(o, &amp;(*p)->intval, 0, "intval") &amp;&amp;
        odr_bool(o, &amp;(*p)->boolval, 1, "boolval") &amp;&amp;
        odr_sequence_end(o);
}
     </screen>

     <para>
      The definition of the structure <literal>MySequence</literal> would be
      the same.
     </para>
    </sect3>

    <sect3 id="odr.explicit.tagging"><title>Explicit Tagging</title>

     <para>
      Explicit tagging of constructed types is a little more complicated,
      since you are in effect adding a level of construction to the data.
     </para>

     <para>
      Assume the definition:
     </para>

     <screen>
MySequence ::= [10] IMPLICIT SEQUENCE {
   intval INTEGER,
   boolval BOOLEAN OPTIONAL
}
     </screen>

     <para>
      Since the new type has an extra level of construction, two new functions
      are needed to encapsulate the base type:
     </para>

     <synopsis>
int odr_constructed_begin(ODR o, void *p, int class, int tag,
                          const char *name);

int odr_constructed_end(ODR o);
     </synopsis>

     <para>
      Assume that the IMPLICIT in the type definition above were replaced
      with EXPLICIT (or that the IMPLICIT keyword were simply deleted, which
      would be equivalent). The structure definition would look the same,
      but the function would look like this:
     </para>

     <screen>
int mySequence(ODR o, MySequence **p, int optional, const char *name)
{
    if (odr_constructed_begin(o, p, ODR_CONTEXT, 10, name) == 0)
        return optional &amp;&amp; odr_ok(o);
    if (o->direction == ODR_DECODE)
        *p = odr_malloc(o, sizeof(**p));
    if (odr_sequence_begin(o, p, sizeof(**p), 0) == 0)
    {
        *p = 0; /* this is almost certainly a protocol error */
        return 0;
    }
    return
        odr_integer(o, &amp;(*p)->intval, 0, "intval") &amp;&amp;
        odr_bool(o, &amp;(*p)->boolval, 1, "boolval") &amp;&amp;
        odr_sequence_end(o) &amp;&amp;
        odr_constructed_end(o);
}
     </screen>

     <para>
      Notice that the interface here gets kind of nasty. The reason is
      simple: Explicitly tagged, constructed types are fairly rare in
      the protocols that we care about, so the
      esthetic annoyance (not to mention the dangers of a cluttered
      interface) is less than the time that would be required to develop a
      better interface. Nevertheless, it is far from satisfying, and it's a
      point that will be worked on in the future. One option for you would
      be to simply apply the <function>odr_explicit_tag()</function> macro to
      the first function, and not
      have to worry about <function>odr_constructed_*</function> yourself.
      Incidentally, as you might have guessed, the
      <function>odr_sequence_</function> functions are themselves
      implemented using the <function>/odr_constructed_</function> functions.
     </para>

    </sect3>
   </sect2>
   <sect2 id="odr.sequence.of"><title>SEQUENCE OF</title>

    <para>
     To handle sequences (arrays) of a specific type, the function
    </para>

    <synopsis>
int odr_sequence_of(ODR o, int (*fun)(ODR o, void *p, int optional),
                    void *p, int *num, const char *name);
    </synopsis>

    <para>
     The <literal>fun</literal> parameter is a pointer to the decoder/encoder
     function of the type. <literal>p</literal> is a pointer to an array of
     pointers to your type. <literal>num</literal> is the number of elements
     in the array.
    </para>

    <para>
     Assume a type
    </para>

    <screen>
MyArray ::= SEQUENCE OF INTEGER
    </screen>

    <para>
     The C representation might be
    </para>

    <screen>
typedef struct MyArray
{
    int num_elements;
    int **elements;
} MyArray;
    </screen>

    <para>
     And the function might look like
    </para>

    <screen>
int myArray(ODR o, MyArray **p, int optional, const char *name)
{
    if (o->direction == ODR_DECODE)
        *p = odr_malloc(o, sizeof(**p));
    if (odr_sequence_of(o, odr_integer, &amp;(*p)->elements,
        &amp;(*p)->num_elements, name))
        return 1;
    *p = 0;
        return optional &amp;&amp; odr_ok(o);
}
    </screen>

   </sect2>
   <sect2 id="odr.choice.types"><title>CHOICE Types</title>

    <para>
     The choice type is used fairly often in some ASN.1 definitions, so
     some work has gone into streamlining its interface.
    </para>

    <para>
     CHOICE types are handled by the function:
    </para>

    <synopsis>
int odr_choice(ODR o, Odr_arm arm[], void *p, void *whichp,
               const char *name);
    </synopsis>

    <para>
     The <literal>arm</literal> array is used to describe each of the possible
     types that the CHOICE type may assume. Internally in your application,
     the CHOICE type is represented as a discriminated union. That is, a
     C union accompanied by an integer (or enum) identifying the active
     'arm' of the union.
     <literal>whichp</literal> is a pointer to the union discriminator.
     When encoding, it is examined to determine the current type.
     When decoding, it is set to reference the type that was found in
     the input stream.
    </para>

    <para>
     The Odr_arm type is defined thus:
    </para>

    <screen>
typedef struct odr_arm
{
    int tagmode;
    int class;
    int tag;
    int which;
    Odr_fun fun;
    char *name;
} Odr_arm;
    </screen>

    <para>
     The interpretation of the fields are:
    </para>

    <variablelist>
     <varlistentry><term>tagmode</term>
      <listitem><para>Either <literal>ODR_IMPLICIT</literal>,
	<literal>ODR_EXPLICIT</literal>, or <literal>ODR_NONE</literal> (-1)
	to mark	no tagging.</para></listitem>
     </varlistentry>

     <varlistentry><term>which</term>
      <listitem><para>The value of the discriminator that corresponds to
	this CHOICE element. Typically, it will be a #defined constant, or
	an enum member.</para></listitem>
     </varlistentry>

     <varlistentry><term>fun</term>
      <listitem><para>A pointer to a function that implements the type of
	the CHOICE member. It may be either a standard &odr; type or a type
	defined by yourself.</para></listitem>
     </varlistentry>

     <varlistentry><term>name</term>
      <listitem><para>Name of tag.</para></listitem>
     </varlistentry>
    </variablelist>

    <para>
     A handy way to prepare the array for use by the
     <function>odr_choice()</function> function is to
     define it as a static, initialized array in the beginning of your
     decoding/encoding function. Assume the type definition:
    </para>

    <screen>
MyChoice ::= CHOICE {
    untagged INTEGER,
    tagged   [99] IMPLICIT INTEGER,
    other    BOOLEAN
}
    </screen>

    <para>
     Your C type might look like
    </para>

    <screen>
typedef struct MyChoice
{
    enum
    {
        MyChoice_untagged,
        MyChoice_tagged,
        MyChoice_other
    } which;
    union
    {
        int *untagged;
        int *tagged;
        bool_t *other;
    } u;
};
    </screen>

    <para>
     And your function could look like this:
    </para>

    <screen>
int myChoice(ODR o, MyChoice **p, int optional, const char *name)
{
    static Odr_arm arm[] =
    {
      {-1, -1, -1, MyChoice_untagged, odr_integer, "untagged"},
      {ODR_IMPLICIT, ODR_CONTEXT, 99, MyChoice_tagged, odr_integer,
      "tagged"},
      {-1, -1, -1, MyChoice_other, odr_boolean, "other"},
      {-1, -1, -1, -1, 0}
    };

    if (o->direction == ODR_DECODE)
        *p = odr_malloc(o, sizeof(**p);
    else if (!*p)
        return optional &amp;&amp; odr_ok(o);

    if (odr_choice(o, arm, &amp;(*p)->u, &amp;(*p)->which), name)
        return 1;
    *p = 0;
        return optional &amp;&amp; odr_ok(o);
}
    </screen>

    <para>
     In some cases (say, a non-optional choice which is a member of a
     sequence), you can "embed" the union and its discriminator in the
     structure belonging to the enclosing type, and you won't need to
     fiddle with memory allocation to create a separate structure to
     wrap the discriminator and union.
    </para>

    <para>
     The corresponding function is somewhat nicer in the Sun XDR interface.
     Most of the complexity of this interface comes from the possibility of
     declaring sequence elements (including CHOICEs) optional.
    </para>

    <para>
     The ASN.1 specifications naturally requires that each member of a
     CHOICE have a distinct tag, so they can be told apart on decoding.
     Sometimes it can be useful to define a CHOICE that has multiple types
     that share the same tag. You'll need some other mechanism, perhaps
     keyed to the context of the CHOICE type. In effect, we would like to
     introduce a level of context-sensitiveness to our ASN.1 specification.
     When encoding an internal representation, we have no problem, as long
     as each CHOICE member has a distinct discriminator value. For
     decoding, we need a way to tell the choice function to look for a
     specific arm of the table. The function
    </para>

    <synopsis>
void odr_choice_bias(ODR o, int what);
    </synopsis>

    <para>
     provides this functionality. When called, it leaves a notice for the next
     call to <function>odr_choice()</function> to be called on the decoding
     stream <literal>o</literal> that only the <literal>arm</literal> entry with
     a <literal>which</literal> field equal to <literal>what</literal>
     should be tried.
    </para>

    <para>
     The most important application (perhaps the only one, really) is in
     the definition of application-specific EXTERNAL encoders/decoders
     which will automatically decode an ANY member given the direct or
     indirect reference.
    </para>

   </sect2>
  </sect1>

  <sect1 id="odr.debugging"><title>Debugging</title>

   <para>
    The protocol modules are suffering somewhat from a lack of diagnostic
    tools at the moment. Specifically ways to pretty-print PDUs that
    aren't recognized by the system. We'll include something to this end
    in a not-too-distant release. In the meantime, what we do when we get
    packages we don't understand is to compile the ODR module with
    <literal>ODR_DEBUG</literal> defined. This causes the module to dump tracing
    information as it processes data units. With this output and the
    protocol specification (Z39.50), it is generally fairly easy to see
    what goes wrong.
   </para>
  </sect1>
 </chapter>
 <!-- Keep this comment at the end of the file
 Local variables:
 mode: sgml
 sgml-omittag:t
 sgml-shorttag:t
 sgml-minimize-attributes:nil
 sgml-always-quote-attributes:t
 sgml-indent-step:1
 sgml-indent-data:t
 sgml-parent-document: "yaz.xml"
 sgml-local-catalogs: nil
 sgml-namecase-general:t
 End:
 -->