Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / doc / man-pages / pod1 / rxgen.pod
CommitLineData
805e021f
CE
1=head1 NAME
2
3rxgen - Stub generator for the Rx remote procedure call package
4
5=head1 SYNOPSIS
6
7=for html
8<div class="synopsis">
9
10B<rxgen> [B<-h> | B<-c> | B<-C> | B<-S> | B<-r>] [B<-dkp>]
11 [B<-I> I<dir>] [B<-P> I<prefix>] [B<-o> I<outfile>] [I<infile>]
12
13=for html
14</div>
15
16=head1 DESCRIPTION
17
18B<rxgen> is a tool that generates C code to implement the Rx RPC protocol;
19it takes as input a description of an application interface similar to C
20and produces a number of server and/or client stub routines to be linked
21with RPC-based programs. These stubs allow programs to invoke remote
22procedures through local procedure calls. B<rxgen> is based on Sun's
23B<rpcgen> (version 3.9) but does not maintain compatibility with rpcgen
24RPC descriptions.
25
26=head1 OPTIONS
27
28B<rxgen> operates in several different modes. The generated output files
29can be produced individually (using one of B<-h>, B<-c>, B<-C>, or B<-S>)
30or collectively. All output files are created when the default is used
31(i.e., no options), or the output is limited to the server stubs (B<-C>
32and B<-S>) when the B<-r> flag is used. The following describes the types
33of generated output files (for simplicity, I<filename> refers to the main
34output filename):
35
36=over 4
37
38=item B<-h>
39
40Generate C data definitions (a header file) from standard RPCL definitions
41(default extension: I<filename>.h).
42
43=item B<-c>
44
45Compile the XDR routines required to serialize the protocol described by
46RPCL. Generate XDR routines for all declarations (default extension:
47I<filename>.xdr.c).
48
49=item B<-C>
50
51Generate all the client-side stub routines (default extension:
52I<filename>.cs.c). Calling a routine in this file will cause the
53arguments to be packed up and sent via Rx (or R).
54
55=item B<-S>
56
57Generate all the server-side stub routines (default extension:
58I<filename>.ss.c). Arguments are unpacked, and the corresponding server
59routine is called.
60
61=item B<-r>
62
63Generate the two default extension files produced by the B<-C> and B<-S>
64options.
65
66=back
67
68The following options can be used on any combination of B<rxgen> calls:
69
70=over 4
71
72=item B<-k>
73
74Must be specified when the generated code is intended to be used by the
75kernel; special "includes" and other specifics are produced when the
76target output is for the kernel.
77
78=item B<-p>
79
80Package combination flag: when multiple packages are included within a
81single specification file, a single Execute Request routine will be used
82for all of them as a result of this flag. The default is to generate
83individual Execute Request stubs for each package.
84
85=item B<-I> I<dir>
86
87Similar to the B<-I> flag in the C compiler (B<cc>). This flag is passed
88to the pre-processor (B<cpp>) so that directory I<dir> is searched before
89the standard lookup list for #include files. As expected, multiple B<-I>
90flags can be used simultaneously.
91
92=item B<-P> I<prefix>
93
94The I<prefix> string following this switch is prepended to all generated
95output files; useful when multiple runs want to produce different versions
96of the same interface (say, kernel and non-kernel versions).
97
98=item B<-d>
99
100Debugging mode; only needed when B<rxgen> is to be debugged (say, via
101B<dbx>).
102
103=item B<-o> I<outfile>
104
105Specify the name of the output file. If none is specified, the standard
106output is used (B<-c>, B<-h>, B<-C>, and B<-S> modes only). Note that if
107an output file is specified in a multi-output file option (such as the
108default, or with option B<-r>), then the I<outfile> replaces the name
109generated by default (which is based on the configuration's main file
110name).
111
112=back
113
114=head1 B<rxgen> SYNTAX SUMMARY
115
116 Specification file:
117
118 <Package description option> |
119 <Prefix description option> |
120 <StartingOpcode description option> |
121 <SplitPrefix description option> |
122 <Procedure description option> |
123 <RPCL language description option>
124
125 <Package description option>:
126
127 "package" <Package_ident>
128
129 <Prefix description option>:
130
131 "prefix" <Prefix_ident>
132
133 <StartingOpcode description option>:
134
135 "startingopcode" <constant>
136
137 <SplitPrefix description option>:
138
139 "splitprefix" <split options> ";"
140
141 <Split options>:
142
143 "IN =" <Start_prefix_ident> "|"
144 "OUT =" <End_prefix_ident> "|"
145 <Split options>
146
147 <Procedure description option>:
148
149 ["proc"] [<Procedure_ident>] [<ServerStub_ident>]
150 <Argument list> ["split" | "multi"]
151 ["=" <Opcode_ident>] ";"
152
153 <Argument list>:
154
155 "(" <Argument definition> <Comma_joined argument> ")"
156
157 <Argument definition>:
158
159 <Direction option> <Standard RPCL type decl> <Arg_ident>
160 ["<" <Max_size> ">" | "[" <Max_size> "]"] | NULL
161
162 <Comma_joined argument>:
163
164 "," <Argument definition> | NULL
165
166 <Direction option>:
167
168 "IN" | "OUT" | "INOUT" | NULL
169
170 <Max_size>:
171
172 <constant> | NULL
173
174 <Package_ident>:
175 <Prefix_ident>:
176 <String_ident>:
177 <Start_prefix_ident>:
178 <End_prefix_ident>:
179 <Procedure_ident>:
180 <ServerStub_ident>:
181 <Arg_ident>:
182 <Opcode_ident>:
183
184 <identifier>
185
186 <RPCL language description option>:
187 <Standard RPCL type decl>:
188
189 Sun's RPCL language syntax (see rpcgen(1))
190
191=head1 B<rxgen> COMMANDS
192
193=head2 Comments and Preprocessing
194
195The input interface may contain preprocessor directives which are passed
196through the C preprocessor (i.e. C<cpp>). Since the preprocessor runs on
197all input files before they are actually interpreted by B<rxgen>, all
198B<cpp> directives (#include, #ifdefs, #defines, etc.) are legal and
199welcomed within an B<rxgen> input file. Of course, none of these
200preprocessor directives will be included in any of the generated files.
201To facilitate distinctions between the different types of output files,
202B<rxgen> defines certain special B<cpp> symbols for use by the B<rxgen>
203programmer. These are RPC_HDR (defined when compiling into header,
204I<filename>.h, files), RPC_XDR (defined when compiling into xdr,
205I<filename>.xdr.c, files), RPC_CLIENT (defined when compiling into client
206stubs, I<filename>.cs.c, files), and RPC_SERVER (defined when compiling
207into server stubs, I<filename>.ss.c, files).
208
209In addition, B<rxgen> does a little preprocessing of its own. Any line
210beginning with C<%> is passed directly into the output file, uninterpreted
211by B<rxgen>. For a more heavy en masse dumping of uninterpreted code, it
212would be advised to include all such code in an C<#include> file and pass
213it in preceded by C<%>. The input interface may also contain any C-style
214comments which are, of course, ignored. Interpretation is token-based,
215thus special line-orientation of separate statements is not necessary.
216B<rxgen> also provides a quite rich and helpful set of error reports,
217identifying them by exact line location and error type. Also, B<rxgen>
218will automatically generate #include lines for standard include files,
219such as F<rx/xdr.h> and F<rx/rx.h>, along with the generated header file
220from this interface.
221
222=head2 Prefixing stub procedures
223
224The I<package> statement tells B<rxgen> the name of the interface package.
225It is used for prefixing the naming of all generated stub routines and the
226execute request procedure. For example:
227
228 package AFS_
229
230causes the execute request procedure to be named AFS_ExecuteRequest
231(Warning: in the older version an additional C<_> was appended after the
232package name to the ExecuteRequest name; thus make sure you don't have an
233ExecuteRequest interface routine) and a given stub routine, say Fetch, to
234be actually named AFS_Fetch. Multiple package statements (current maximum
235size is 10) per configuration are permitted and are useful when multiple
236sets of interfaces are implemented (see the example at the end). Note
237that in such cases, use of the B<-p> flag results in the generation of
238just one ExecuteRequest procedure which recognizes the multiple interfaces
239and whose name is prefixed by the first package statement. In the default
240case, independent ExecuteRequest procedures will be created for each
241packaged group of remote procedure calls.
242
243The I<prefix> statement supplies a name to prepend to all calls to remote
244procedure names in the ExecuteRequest stub routine. It is useful when the
245server makes RPC calls to other servers (say, for debugging purposes).
246For example:
247
248 prefix S
249
250causes the name C<S> to be prepended to the name of all routines called
251from the server stubs. The server can then call the original name and get
252the client stubs.
253
254=head2 B<rxgen> procedure declaration
255
256The I<proc> statement is the most common (and meaningful) in the B<rxgen>
257interface. Its syntax description is:
258
259 [proc] [<proc_name>] [<server_stub>] (<arg>, ..., <arg>)
260 [split | multi] [= <opcode>] ;
261
262where:
263
264=over 2
265
266=item *
267
268C<proc> is an optional prefix of the procedure statement. This is just a
269stylistic item and not a required procedure delimiter.
270
271=item *
272
273<proc_name> is the name of the procedure. Note that even the name of the
274procedure is optional. This only makes sense when the name of the given
275procedure is identical to the name of the last I<package> statement (i.e.,
276C<package RCallBack> and the declaration of the C<RCallBack> procedure).
277
278=item *
279
280<server_stub>, if present, causes the ExecuteRequest procedure to call
281that stub instead of the automatically generated stub when a call with
282that opcode is decoded.
283
284=item *
285
286<opcode> is a constant or symbol that is the opcode for that procedure.
287One might use the preprocessor features (i.e., #define), the I<const>
288RPC-language feature, or the old good constants as opcodes. Some further
289evaluation/processing of opcodes is done. Particularly, checks for
290duplicate and non-existent opcodes are performed, along with checks for
291"holes" (i.e., gaps in consecutive opcodes) in the opcode sequences. For
292example, we use the fact that when "holes" in opcodes exist, the
293ExecuteRequest procedure uses the I<case> statement rather than the faster
294(and smaller, codewise) indexed array method.
295
296Also, B<rxgen> defines (i.e., appends to the header file) three valuable
297macros for each package group: <package-name>LOWEST_OPCODE,
298<package-name>HIGHEST_OPCODE, and <package-name>NUMBER_OPCODES. These may
299be useful to the B<rxgen> programmer. Also, notice that the I<opcode>
300statement is an optional feature, and can be omitted. In such cases,
301automatic opcode numbers are generated sequentially, starting from 0.
302
303One can change the initial opcode number by using the I<startingopcode>
304(for lack of a better name) B<rxgen> command. Its syntax is:
305
306 startingopcode <constant>
307
308where <constant> must be reasonable! Note that one can not mix
309procedures, some with opcodes and some without, nor allow opcodes after
310the specification of the I<startingopcode> statement. B<rxgen> will
311complain in all such cases.
312
313=item *
314
315The I<argument> entry represents a given parameter of the procedure. Its
316syntax is:
317
318 [IN | INOUT | OUT | <null>] <type_decl> <arg_name>
319 [<max>|<>|[max]|[]]
320
321If the type is an indirect type (i.e., is followed by *), it is assumed
322that the pointer should be followed one level and the data pointed to is
323to be transmitted. This should normally be used for all structures/arrays
324and out parameters. A noticeable exception is when explicit
325array/structure maximum size is given; since no array-of-pointer
326declarations are allowed one should use typedefs to achieve the similar
327effect. The parameters could be input parameters (preceded by IN), output
328parameters (preceded by OUT), or input/output parameters (preceded by
329INOUT). If not specified, then the direction of the previous parameter in
330the procedure is used. (Note: the first parameter must be preceded by the
331directional primitive!)
332
333=item *
334
335C<split> is a hack to handle stub routines that do things such as file
336transfers or any other operation that has to exchange information (e.g.,
337length of a file) before the call returns its output parameters. Because
338of the particular handshake that is involved when doing remote file
339transfer, we currently break all such calls into two client-side stub
340routines. The first (with the default prefix of C<Begin>) is used to pass
341all IN and INOUT parameters to the server side. The second (with the
342default prefix of C<End>) is used to get back the INOUT and OUT parameters
343from the server. Between the two calls, the user is supposed to do the
344appropriate calls for the file transfer. For example, the following
345procedure declaration in package AFS_
346
347 Fetch (IN a, b,INOUT c, OUT d) split = FETCHOPCODE;
348
349will roughly generate the two independent client stub routines:
350
351 BeginAFS_Fetch (IN a, b, c)
352
353and
354
355 EndAFS_Fetch(OUT c, d)
356
357The I<splitprefix> statement is used to change the default prefix names
358used by the two client-side stub generated routines when dealing with file
359transfer-related procedure calls. For example:
360
361 splitprefix IN=Before_ OUT=After_
362
363will cause the naming of the two client stubs for a file transfer-related
364routine, say Fetch(), to be Before_AFS_Fetch() and After_AFS_Fetch(),
365respectively.
366
367=item *
368
369The C<multi> option is nearly identical to the C<split> feature described
370above. The only significant visible difference is that along with the two
371client stubs, the standard client stub is also generated. Since the
372intention is to handle the multi-Rx calls, we need the whole standard
373procedure stub in the cases where no multi-Rx call of the procedure is
374performed. A side effect of the C<multi> option is the generation of a
375special macro (i.e., C<< multi_<Procedure-name> >> which passes back as
376arguments the C<Begin> and C<End> stubs in the header output file. This
377macro is used directly by the Rx code when a multi-Rx call of this
378procedure is performed.
379
380=back
381
382=head2 OBSOLETE B<rxgen> FEATURES
383
384Although the following rxgen commands are still in effect, they will soon
385be removed since there are better alternatives. DO NOT USE THEM!
386
387The I<special> statement is a temporary hack used to handle certain
388inefficiencies of standard xdr routines to handle some user-customized
389declarations. In particular, this applies to a string pointer specified
390as part of a declaration. For example,
391
392 special struct BBS SeqBody;
393
394tells B<rxgen> that the entry C<SeqBody> in the user-defined BBS xdr
395routine is a string (note that more than one string can be "special" per
396structure -- multiple ones are separated by commas); it will thus allocate
397and de-allocate space properly in the server-generated stubs that contain
398this structure as an IN or INOUT parameter.
399
400A better alternative to I<special> is the I<customized> statement, which
401is simply the C<customized> token followed by the regular declaration of a
402struct based on the RPCL rules. In this case, the declaration will be
403included in the generated header file (B<-h> option) but no xdr routine
404will be generated for this structure -- the user will supply this. All
405pointer entries in this structure will be remembered so when the structure
406is used as an IN or INOUT in the server stub, no core leaks will occur.
407For example, consider
408
409 customized struct CBS {
410 long Seqlen;
411 char *SeqBody;
412 }
413
414The C<xdr_CBS> routine would be provided by the user where during the
415DECODE xdr opcode, appropriate space for the C<SeqBody> string is
416allocated. Similarly, that space is freed during the FREE xdr opcode.
417
418Note: Old style "Array parameter specifications" are not supported any
419more.
420
421=head1 EXAMPLES
422
423In case there are some requirements not available by the current RPC
424language, one can customize some XDR routines by leaving those data types
425undefined. For every data type that is undefined, it will be assumed that
426a routine exists with the name C<xdr_> prepended to it. A selected set of
427B<rxgen> features is presented below, but for a more comprehensive one
428(unions, complex examples, etc) please refer to the I<rpcgen Programming
429Guide> and I<eXternal Data Representation: Sun Technical Notes>.
430
431=head2 Typedefs
432
433The RPC typedef statement is identical to the C typedef (i.e. C<< typedef
434<declaration> >>). By default, most user declarations (i.e. structs,
435unions, etc) are automatically typedef'ed by B<rxgen>. Since it makes
436parsing simpler, its usage is recommended by B<rxgen> scripts.
437
438=head2 Strings
439
440The C C<char *> string convention is kind of ambiguous, since it is
441usually intended to mean a null-terminated string of characters, but it
442could also represent a pointer to a single character, a pointer to an
443array of characters, etc. In the RPC language, a null-terminated string
444is unambiguously called a "string". Examples,
445
446 string bigname<>;
447 string name<MAXNAMELEN>;
448 typedef string volname<MAXVOLNAME>;
449
450Notice that the maximum size of string can be arbitrary (like C<bigname>
451above) or, preferably, or specified in angle brackets (i.e. C<name> and
452C<volname> above). In practice, one should always use only bounded
453strings in interfaces. A sample calling proc using the declarations above
454would be:
455
456 GetEntryByName (IN volname name,
457 OUT struct vldbentry *entry) = VL_GETENTRYBYNAME;
458
459or, of course,
460
461 GetEntryByName (IN string volname<MAXVOLNAME>,
462 OUT struct vldbentry *entry) = VL_GETENTRYBYNAME;
463
464It is very important for the user to understand when the string parameters
465should be allocated and/or freed by the his/her client and/or server
466programs. A short analysis on string parameters handling follows (note
467that a similar method is used for the handling of variable length arrays
468as it will be shown later on):
469
470=over 2
471
472=item *
473
474In the client side: IN and INOUT string parameters are the programmer's
475responsibility and should be allocated (static or via malloc) before
476calling the rpc and freed (if malloc was used) after the rpc's return in
477the user's client program; of course, for INOUT parameters, the returned
478string can't be bigger than the malloced input string.
479
480OUT string parameters are automatically malloced (based on the length of
481the returned string and not the maxsize) by the B<rxgen> client stubs (in
482I<filename>.cs.c) and must be freed by the client program; admittedly,
483this could be somewhat confusing since the user needs to free something
484that he/she didn't allocate.}
485
486=item *
487
488In the server side: IN and INOUT string parameters are automatically
489malloced (based on the size of incoming strings) by the rxgen server stubs
490(in I<filename>.ss.c) before they are passed to the user's server
491procedure; that space is automatically freed just before the rxgen server
492stub returns; therefore the user need not do anything special for IN and
493INOUT string parameters.
494
495OUT string parameters must be malloced by the user's server procedure
496(i.e. null pointer is passed to it by the rxgen server stub) and it is
497automatically freed at the end of the B<rxgen> server stub. Like in the
498client side, the OUT parameters are somewhat unorthodox (i.e. the server
499routine must malloc a string without ever freeing it itself; this is done
500by the B<rxgen> server stub).
501
502=back
503
504Note that for INOUT and OUT string parameters, in both the client and
505server sides their arguments must be char of pointers (i.e. char **).
506
507=head2 Pointers
508
509Pointer declarations in RPC are also exactly as they are in C
510(i.e. C<struct single_vldbentry *vldblist;>). Of course, one can't send
511pointers over the network, but one can use XDR pointers for sending
512recursive data types such as lists and trees (an example of a linked list
513will be demonstrated shortly).
514
515=head2 Arrays
516
517Fixed arrays are just like standard C array declarations (i.e. C<struct
518UpdateEntry entries[20]>) without any side effect problems in
519B<rxgen>. Since variable-length arrays have no explicit syntax in C, the
520angle-brackets are used for it and the array declarations are actually
521compiled into "struct"s. For example, declarations such as:
522
523 const MAXBULKSIZE = 10000;
524 const MAXENTRIES = 100;
525 opaque bulk<MAXBULKSIZE>; /* At most 10000 items */
526 int hosts<>; /* any number of items */
527 typedef vldbentry blkentries<100>; /* Preferable array decl */
528
529are compiled into the following structs:
530
531 struct {
532 u_int bulk_len; /* no of items */
533 char *bulk_val; /* pointer to array */
534 } bulk;
535
536for the C<bulk> array, and similarly for the C<< blkentries<100> >> array,
537
538 struct {
539 u_int blkentries_len; /* no of items in array */
540 vldbentry *blkentries_val; /* pointer to array */
541 } blkentries;
542
543Therefore the user should be aware of the "magically" generated structure
544entries such as the number of items in the array (<array_name>_len) and
545the pointer to the array (<array_name>_val) since some of the entries will
546have to be filled in from the client/server programs. A sample proc would
547be:
548
549 typedef vldbentry blkentries<MAXENTRIES>;
550 proc GetBlk (OUT blkentries *vlentries) = VL_GETBLK;
551
552or, more directly,
553
554 GetBlk(OUT vldbentry vlentries<MAXENTRIES>) = VL_GETBLK;
555
556Note that although the latest method is preferable since one does not have
557to first use the typedef statement (and admittedly, programmers prefer
558avoiding typedefs), one should realize that B<rxgen> does the structure
559expansion and the xdr creation implicitly; therefore the user should be
560aware of the C<vldbentries_val> and C<vldbentries_len> fields as before
561(see following examples).
562
563=head3 Array example I (least desirable)
564
565Procedure declaration in the interface configuration:
566
567 proc ListAttributes (IN vldblistbyattributes *attributes,
568 INOUT blkentries *vldbentries) = VL_LISTATTRIBUTES;
569
570Sample CLIENT code:
571
572 blkentries entries, *pnt;
573 entries.blkentries_len = 10; /* max # returned entries */
574 entries.blkentries_val = (vldbentry *)malloc(LEN);
575 /* It must be set */
576
577 code = VL_ListAttributes(&attributes, &entries);
578 if (!code) {
579 pnt = entries.blkentries_val;
580 for (i=0; i < entries.blkentries_len; i++, pnt++)
581 display_vldbentry(pnt);
582 /* Make sure you free the allocated space */
583 free((char *)entries.blkentries_val);
584 }
585
586Sample SERVER code:
587
588 VL_ListAttributes(attributes, entries)
589 {
590 vldbentry *singleentry = entries->blkentries_val;
591 entries->blkentries_len = 0;
592
593 while (copy_to_vldbentry(&vlentry, singleentry))
594 singleentry++, vldbentries->entries_len++;
595 }
596
597Although this method for variable-size arrays works fine, there are some
598major drawbacks. The array parameter (i.e. vldbentries above) must be
599declared as INOUT since we need to pass the max length of the expected
600returned array; more importantly, a big (depending on the value of
601C<_len>) chunk of junk code is going to be transferred to the server as
602result of the IN(out) side-effect of the array. It's an easy and
603convenient method if the returned array size can be predicted from the
604start and when the size is quite high. This method is included as an
605example of erroneous use (and abuse) of B<rxgen> and should not be used.
606
607=head3 Array example II (Desirable method)
608
609Procedure declaration in the interface configuration (using Example I
610above):
611
612 proc ListAttributes (IN vldblistbyattributes *attributes,
613 OUT blkentries *vldbentries) = VL_LISTATTRIBUTES;
614
615Sample CLIENT code:
616
617 blkentries entries, *pnt;
618
619 code = VL_ListAttributes(&attributes, &entries);
620 if (!code) {
621 pnt = entries.blkentries_val;
622 for (i=0; i < entries.blkentries_len; i++, pnt++)
623 display_vldbentry(pnt);
624 /* Make sure you free the allocated space (by rxgen) */
625 free((char *)entries.blkentries_val);
626 }
627
628Sample SERVER code:
629
630 VL_ListAttributes(attributes, entries)
631 {
632 vldbentry *singleentry;
633 entries->blkentries_len = 0;
634 singleentry = entries->blkentries_val
635 = (vldbentry *)malloc(MAXENTRIES * sizeof(vldbentry));
636
637 while (copy_to_vldbentry(&vlentry, singleentry))
638 singleentry++, vldbentries->entries_len++;
639 }
640
641This is the best (and simplest) way of using variable-size arrays as an
642output parameter. It is the responsibility of the server-side stub to
643malloc() the adequate space which is automatically freed by the B<rxgen>
644stub; the client side should free the space allocated by the
645B<rxgen>-calling stub.
646
647=head3 Array example III (Linked Lists)
648
649Considering the following 3 declarations (could have applied some
650optimizations) in the configuration file:
651
652 typedef struct single_vldbentry *vldblist;
653 struct single_vldbentry {
654 vldbentry vlentry;
655 vldblist next_vldb;
656 };
657
658 struct vldb_list {
659 vldblist node;
660 };
661
662and the rxgen procedure declaration:
663
664 LinkedList (IN vldblistbyattributes *attributes,
665 OUT vldb_list *linkedentries) = VL_LINKEDLIST;
666
667Sample CLIENT code:
668
669 vldb_list linkedvldbs;
670 vldblist vllist, vllist1;
671
672 bzero(&linkedvldbs, sizeof(vldb_list));
673 code = VL_LinkedList(&attributes, &nentries, &linkedvldbs);
674 if (!code) {
675 printf("We got %d vldb entries\n", nentries);
676 for (vllist = linkedvldbs.node; vllist; vllist = vllist1) {
677 vllist1 = vllist->next_vldb;
678 display_entry(&vllist->vlentry);
679 free((char *)vllist);
680 }
681 }
682
683Sample SERVER code:
684
685 VL_LinkedList(rxcall, attributes, nentries, linkedvldbs);
686 {
687 vldblist vllist, *vllistptr = &linkedvldbs->node;
688 while (...) {
689 vllist = *vllistptr
690 = (single_vldbentry *)malloc (sizeof (single_vldbentry));
691 copy_to_vldbentry(&tentry, &vllist->vlentry);
692 nentries++;
693 vllistptr = &vllist->next_vldb;
694 };
695 *vllistptr = NULL;
696 }
697
698Using a linked list offers many advantages: Nothing is passed to the
699server (the parameter is OUT), no additional overhead is involved, and the
700caller doesn't have to explicitly prepare for an arbitrary return size. A
701drawback is that the caller has the responsibility of malloc() (on the
702server) and free (on the client) of each entry (to avoid unwanted
703core-leaks). Another drawback is that since it's a recursive call, the C
704stack will grow linearly with respect to the number of nodes in the list
705(so it's wise to increase the Rx LWP stack if huge amounts of data are
706expected back -- default stack size is 4K). The advantages should
707outweigh the disadvantages here.
708
709It's important to pay attention to the comments of the three array
710examples above particularly when they're references to when the user
711should allocate/free space for the variable length arrays. The mechanism
712is very similar to the handling of strings thus you might need to review
713the strings section above; note that the linked lists are handled somewhat
714differently...
715
716=head2 Miscellaneous examples
717
718Below is an abbreviated version of a random interface file which shows
719some of the common cases.
720
721 /* Declaration of all structures used by the R.xg script interface */
722
723 struct AFSFid {
724 unsigned long Volume;
725 unsigned long Vnode;
726 unsigned long Unique;
727 };
728
729 typedef long ViceDataType;
730
731 /* Note that TEST would be equivalent to "HEADER" only during the
732 processing of the header, *.h, file */
733
734 #ifdef RPC_HDR
735 #define TEST "HEADER"
736 #else
737 #define TEST "REST"
738 #endif
739
740 /* This is the standard *.xg specification file */
741
742 package AFS_
743 splitprefix IN=BEFORE_ OUT=AFTER_;
744 Prefix Test
745
746 proc Remove(IN struct AFSFid *Did, IN string volname<64>,
747 OUT struct AFSStatus *Status) = AFS_REMOVE;
748
749 DisconnectFS AUX_disconnectFS() = AFS_DISCONNECTFS;
750
751 proc GetVolumeInfo(IN string Vid,
752 OUT struct VolumeInfo *Info) = AFS_GETVOLUMEINFO;
753
754 /* You could have more than an interface per configuration */
755
756 package VOTE_
757
758 /* Using the "multi" feature; thus VOTE_Beacon can be called as an
759 multi-Rx call or as a regular call */
760
761 Beacon (IN long state, long voteStart,
762 net_version *version, net_tid *tid)
763 multi = VOTE_BEACON;
764
765 package DISK_
766
767 /* Using the "split" feature */
768
769 SendFile (IN long file, long offset,
770 long length, net_version *version)
771 split = DISK_SENDFILE;
772
773=head2 Output of an actual interface configuration
774
775We'll demonstrate some of the actual output generated by B<rxgen> by
776following an abbreviated actual interface configuration.
777
778=head3 Configuration file
779
780Contents of the interface configuration file (F<vldbint.xg>):
781
782 package VL_
783 #include "vl_opcodes.h" /* The opcodes are included here */
784 %#include "vl_opcodes.h" /* directly to other places */
785
786 /* Current limitations on parameters that affect other packages
787 (i.e. volume) */
788
789 const MAXNAMELEN = 65;
790 const MAXNSERVERS = 8;
791 const MAXTYPES = 3;
792
793 /* External (visible) representation of an individual vldb entry */
794
795 struct vldbentry {
796 char name[MAXNAMELEN];
797 long volumeType;
798 long nServers;
799 long serverNumber[MAXNSERVERS];
800 long serverPartition[MAXNSERVERS];
801 long serverFlags[MAXNSERVERS];
802 u_long volumeId[MAXTYPES];
803 long flags;
804 };
805
806 typedef struct single_vldbentry *vldblist;
807 struct single_vldbentry {
808 vldbentry VldbEntry;
809 vldblist next_vldb;
810 };
811
812 struct vldb_list {
813 vldblist node;
814 };
815
816 /* vldb interface calls */
817
818 CreateEntry (IN long Volid,
819 vldbentry *newentry) = VLCREATEENTRY;
820
821 GetEntryByName (IN string volumename<MAXNAMELEN>,
822 OUT vldbentry *entry) = VLGETENTRYBYNAME;
823
824 GetNewVolumeId (IN long bumpcount,
825 OUT long *newvolumid) = VLGETNEWVOLUMEID;
826
827 ReplaceEntry (IN long Volid,
828 long voltype,
829 vldbentry *newentry,
830 long ReleaseType) multi = VLREPLACEENTRY;
831
832 ListAttributes (IN VldbListByAttributes *attributes,
833 OUT long *nentries,
834 OUT vldbentry bulkentries<MAXVLDBLEN>)
835 = VLLISTATTRIBUTES;
836
837 LinkedList (IN VldbListByAttributes *attributes,
838 OUT long *nentries,
839 OUT vldb_list *linkedentries) = VLLINKEDLIST;
840
841For a detailed description on the Rx-related calls inside the generated
842stubs (i.e., rx_NewCall(), rx_EndCall()), along with details on what happens
843inside certain calls (like xdrrx_create()) please refer to the Rx
844documentation. Typing C<rxgen vldbint.xg> will result in the creation of
845four files: F<vldbint.h>, F<vldbint.xdr.c>, F<vldbint.cs.c> and
846F<vldbint.ss.c>. A closer look at these files follows.
847
848=head3 Header file (F<vldbint.h>)
849
850 /* Machine generated file -- Do NOT edit */
851
852 #include "vl_opcodes.h" /* directly to other places */
853 #define MAXNAMELEN 65
854 #define MAXNSERVERS 8
855 #define MAXTYPES 3
856
857 struct vldbentry {
858 char name[MAXNAMELEN];
859 long volumeType;
860 long nServers;
861 long serverNumber[MAXNSERVERS];
862 long serverPartition[MAXNSERVERS];
863 long serverFlags[MAXNSERVERS];
864 u_long volumeId[MAXTYPES];
865 long flags;
866 };
867 typedef struct vldbentry vldbentry;
868 bool_t xdr_vldbentry();
869
870 typedef struct single_vldbentry *vldblist;
871 bool_t xdr_vldblist();
872
873 struct single_vldbentry {
874 vldbentry VldbEntry;
875 vldblist next_vldb;
876 };
877 typedef struct single_vldbentry single_vldbentry;
878 bool_t xdr_single_vldbentry();
879
880 struct vldb_list {
881 vldblist node;
882 };
883 typedef struct vldb_list vldb_list;
884 bool_t xdr_vldb_list();
885
886 #include <rx/rx_multi.h>
887 #define multi_VL_ReplaceEntry(Volid, voltype, newentry, ReleaseType) \
888 multi_Body(StartVL_ReplaceEntry(multi_call, Volid, voltype,
889 newentry, ReleaseType), EndVL_ReplaceEntry(multi_call))
890
891 typedef struct bulkentries {
892 u_int bulkentries_len;
893 vldbentry *bulkentries_val;
894 } bulkentries;
895 bool_t xdr_bulkentries();
896
897 /* Opcode-related useful stats for package: VL_ */
898 #define VL_LOWEST_OPCODE 501
899 #define VL_HIGHEST_OPCODE 506
900 #define VL_NUMBER_OPCODES 6
901
902Notice that all structures are automatically typedef'ed and all C<const>s
903are converted to C<#define>s. Some data structures, such as bulkentries,
904are taken from procedure params (from ListAttributes proc). Thus, this
905should be kept in mind when creating stubs piecemeal with B<rxgen> (i.e.,
906using the B<-c>, B<-h>, B<-C>, or B<-S> flags). Also, one of the side
907effects of the C<multi> option (in C<ReplaceEntry> proc) is the generation
908of the C<multi_VL_ReplaceEntry> above.
909
910=head3 XDR routines for structures (vldbint.xdr.c)
911
912 /* Machine generated file -- Do NOT edit */
913
914 #include <rx/xdr.h>
915 #include "vldbint.h"
916
917 #include "vl_opcodes.h" /* directly to other places */
918
919 bool_t
920 xdr_vldbentry(xdrs, objp)
921 XDR *xdrs;
922 vldbentry *objp;
923 {
924 if (!xdr_vector(xdrs, (char *)objp->name, MAXNAMELEN,
925 sizeof(char), xdr_char))
926 return (FALSE);
927 if (!xdr_long(xdrs, &objp->volumeType))
928 return (FALSE);
929 if (!xdr_long(xdrs, &objp->nServers))
930 return (FALSE);
931 if (!xdr_vector(xdrs, (char *)objp->serverNumber, MAXNSERVERS,
932 sizeof(long), xdr_long))
933 return (FALSE);
934 if (!xdr_vector(xdrs, (char *)objp->serverPartition,
935 MAXNSERVERS, sizeof(long), xdr_long))
936 return (FALSE);
937 if (!xdr_vector(xdrs, (char *)objp->serverFlags, MAXNSERVERS,
938 sizeof(long), xdr_long))
939 return (FALSE);
940 if (!xdr_vector(xdrs, (char *)objp->volumeId, MAXTYPES,
941 sizeof(u_long), xdr_u_long))
942 return (FALSE);
943 if (!xdr_long(xdrs, &objp->flags))
944 return (FALSE);
945 return (TRUE);
946 }
947
948 bool_t
949 xdr_vldblist(xdrs, objp)
950 XDR *xdrs;
951 vldblist *objp;
952 {
953 if (!xdr_pointer(xdrs, (char **)objp,
954 sizeof(struct single_vldbentry),
955 xdr_single_vldbentry))
956 return (FALSE);
957 return (TRUE);
958 }
959
960 bool_t
961 xdr_single_vldbentry(xdrs, objp)
962 XDR *xdrs;
963 single_vldbentry *objp;
964 {
965 if (!xdr_vldbentry(xdrs, &objp->VldbEntry))
966 return (FALSE);
967 if (!xdr_vldblist(xdrs, &objp->next_vldb))
968 return (FALSE);
969 return (TRUE);
970 }
971
972 bool_t
973 xdr_vldb_list(xdrs, objp)
974 XDR *xdrs;
975 vldb_list *objp;
976 {
977 if (!xdr_vldblist(xdrs, &objp->node))
978 return (FALSE);
979 return (TRUE);
980 }
981
982 bool_t
983 xdr_bulkentries(xdrs, objp)
984 XDR *xdrs;
985 bulkentries *objp;
986 {
987 if (!xdr_array(xdrs, (char **)&objp->bulkentries_val,
988 (u_int *)&objp->bulkentries_len, MAXVLDBLEN,
989 sizeof(vldbentry), xdr_vldbentry))
990 return (FALSE);
991 return (TRUE);
992 }
993
994Note that the xdr_bulkentries() is automatically generated as a side
995effect of a procedure parameter declaration. Thus, if identical multiple
996type parameter declarations are used, then multiply-defined xdr_* stubs
997will be created! We felt this was a better alternative to having the
998B<rxgen> programmer deal with types such as bulkentries_1,
999bulkentries_2...
1000
1001=head3 Client-Side stub routines (vldbint.cs.c)
1002
1003 /* Machine generated file -- Do NOT edit */
1004
1005 #include <rx/xdr.h>
1006 #include <rx/rx.h>
1007 #include <afs/rxgen_consts.h>
1008 #include "vldbint.h"
1009
1010 #include "vl_opcodes.h" /* directly to other places */
1011
1012 int VL_CreateEntry(z_conn, Volid, newentry)
1013 register struct rx_connection *z_conn;
1014 long Volid;
1015 vldbentry * newentry;
1016 {
1017 struct rx_call *z_call = rx_NewCall(z_conn);
1018 static int z_op = 501;
1019 int z_result;
1020 XDR z_xdrs;
1021
1022 xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1023
1024 /* Marshal the arguments */
1025 if ((!xdr_int(&z_xdrs, &z_op))
1026 || (!xdr_long(&z_xdrs, &Volid))
1027 || (!xdr_vldbentry(&z_xdrs, newentry))) {
1028 z_result = RXGEN_CC_MARSHAL;
1029 goto fail;
1030 }
1031
1032 z_result = RXGEN_SUCCESS;
1033 fail:
1034 return rx_EndCall(z_call, z_result);
1035 }
1036
1037 int VL_GetEntryByName(z_conn, volumename, entry)
1038 register struct rx_connection *z_conn;
1039 char * volumename;
1040 vldbentry * entry;
1041 {
1042 struct rx_call *z_call = rx_NewCall(z_conn);
1043 static int z_op = 504;
1044 int z_result;
1045 XDR z_xdrs;
1046
1047 xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1048
1049 /* Marshal the arguments */
1050 if ((!xdr_int(&z_xdrs, &z_op))
1051 || (!xdr_string(&z_xdrs, &volumename, 65))) {
1052 z_result = RXGEN_CC_MARSHAL;
1053 goto fail;
1054 }
1055
1056 /* Un-marshal the reply arguments */
1057 z_xdrs.x_op = XDR_DECODE;
1058 if ((!xdr_vldbentry(&z_xdrs, entry))) {
1059 z_result = RXGEN_CC_UNMARSHAL;
1060 goto fail;
1061 }
1062
1063 z_result = RXGEN_SUCCESS;
1064 fail:
1065 return rx_EndCall(z_call, z_result);
1066 }
1067
1068 int VL_GetNewVolumeId(z_conn, bumpcount, newvolumid)
1069 register struct rx_connection *z_conn;
1070 long bumpcount;
1071 long * newvolumid;
1072 {
1073 struct rx_call *z_call = rx_NewCall(z_conn);
1074 static int z_op = 505;
1075 int z_result;
1076 XDR z_xdrs;
1077
1078 xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1079
1080 /* Marshal the arguments */
1081 if ((!xdr_int(&z_xdrs, &z_op))
1082 || (!xdr_long(&z_xdrs, &bumpcount))) {
1083 z_result = RXGEN_CC_MARSHAL;
1084 goto fail;
1085 }
1086
1087 /* Un-marshal the reply arguments */
1088 z_xdrs.x_op = XDR_DECODE;
1089 if ((!xdr_long(&z_xdrs, newvolumid))) {
1090 z_result = RXGEN_CC_UNMARSHAL;
1091 goto fail;
1092 }
1093
1094 z_result = RXGEN_SUCCESS;
1095 fail:
1096 return rx_EndCall(z_call, z_result);
1097 }
1098
1099 int VL_ReplaceEntry(z_conn, Volid, voltype, newentry, ReleaseType)
1100 register struct rx_connection *z_conn;
1101 long Volid, voltype, ReleaseType;
1102 vldbentry * newentry;
1103 {
1104 struct rx_call *z_call = rx_NewCall(z_conn);
1105 static int z_op = 506;
1106 int z_result;
1107 XDR z_xdrs;
1108
1109 xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1110
1111 /* Marshal the arguments */
1112 if ((!xdr_int(&z_xdrs, &z_op))
1113 || (!xdr_long(&z_xdrs, &Volid))
1114 || (!xdr_long(&z_xdrs, &voltype))
1115 || (!xdr_vldbentry(&z_xdrs, newentry))
1116 || (!xdr_long(&z_xdrs, &ReleaseType))) {
1117 z_result = RXGEN_CC_MARSHAL;
1118 goto fail;
1119 }
1120
1121 z_result = RXGEN_SUCCESS;
1122 fail:
1123 return rx_EndCall(z_call, z_result);
1124 }
1125
1126 int StartVL_ReplaceEntry(z_call, Volid, voltype, newentry, ReleaseType)
1127 register struct rx_call *z_call;
1128 long Volid, voltype, ReleaseType;
1129 vldbentry * newentry;
1130 {
1131 static int z_op = 506;
1132 int z_result;
1133 XDR z_xdrs;
1134
1135 xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1136
1137 /* Marshal the arguments */
1138 if ((!xdr_int(&z_xdrs, &z_op))
1139 || (!xdr_long(&z_xdrs, &Volid))
1140 || (!xdr_long(&z_xdrs, &voltype))
1141 || (!xdr_vldbentry(&z_xdrs, newentry))
1142 || (!xdr_long(&z_xdrs, &ReleaseType))) {
1143 z_result = RXGEN_CC_MARSHAL;
1144 goto fail;
1145 }
1146
1147 z_result = RXGEN_SUCCESS;
1148 fail:
1149 return z_result;
1150 }
1151
1152 int EndVL_ReplaceEntry(z_call)
1153 register struct rx_call *z_call;
1154 {
1155 int z_result;
1156 XDR z_xdrs;
1157
1158 z_result = RXGEN_SUCCESS;
1159 fail:
1160 return z_result;
1161 }
1162
1163 int VL_ListAttributes(z_conn, attributes, nentries, bulkentries_1)
1164 register struct rx_connection *z_conn;
1165 VldbListByAttributes * attributes;
1166 long * nentries;
1167 bulkentries * bulkentries_1;
1168 {
1169 struct rx_call *z_call = rx_NewCall(z_conn);
1170 static int z_op = 511;
1171 int z_result;
1172 XDR z_xdrs;
1173
1174 xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1175
1176 /* Marshal the arguments */
1177 if ((!xdr_int(&z_xdrs, &z_op))
1178 || (!xdr_VldbListByAttributes(&z_xdrs, attributes))) {
1179 z_result = RXGEN_CC_MARSHAL;
1180 goto fail;
1181 }
1182
1183 /* Un-marshal the reply arguments */
1184 z_xdrs.x_op = XDR_DECODE;
1185 if ((!xdr_long(&z_xdrs, nentries))
1186 || (!xdr_bulkentries(&z_xdrs, bulkentries_1))) {
1187 z_result = RXGEN_CC_UNMARSHAL;
1188 goto fail;
1189 }
1190
1191 z_result = RXGEN_SUCCESS;
1192 fail:
1193 return rx_EndCall(z_call, z_result);
1194 }
1195
1196 int VL_LinkedList(z_conn, attributes, nentries, linkedentries)
1197 register struct rx_connection *z_conn;
1198 VldbListByAttributes * attributes;
1199 long * nentries;
1200 vldb_list * linkedentries;
1201 {
1202 struct rx_call *z_call = rx_NewCall(z_conn);
1203 static int z_op = 512;
1204 int z_result;
1205 XDR z_xdrs;
1206
1207 xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1208
1209 /* Marshal the arguments */
1210 if ((!xdr_int(&z_xdrs, &z_op))
1211 || (!xdr_VldbListByAttributes(&z_xdrs, attributes))) {
1212 z_result = RXGEN_CC_MARSHAL;
1213 goto fail;
1214 }
1215
1216 /* Un-marshal the reply arguments */
1217 z_xdrs.x_op = XDR_DECODE;
1218 if ((!xdr_long(&z_xdrs, nentries))
1219 || (!xdr_vldb_list(&z_xdrs, linkedentries))) {
1220 z_result = RXGEN_CC_UNMARSHAL;
1221 goto fail;
1222 }
1223
1224 z_result = RXGEN_SUCCESS;
1225 fail:
1226 return rx_EndCall(z_call, z_result);
1227 }
1228
1229Notice the side effect of the C<multi> feature (three different modules
1230for C<ReplaceEntry> proc).
1231
1232=head3 Server-Side stub routines (vldbint.ss.c)
1233
1234 /* Machine generated file -- Do NOT edit */
1235
1236 #include <rx/xdr.h>
1237 #include <rx/rx.h>
1238 #include <afs/rxgen_consts.h>
1239 #include "vldbint.h"
1240
1241 #include "vl_opcodes.h" /* directly to other places */
1242
1243 long _VL_CreateEntry(z_call, z_xdrs)
1244 struct rx_call *z_call;
1245 XDR *z_xdrs;
1246 {
1247 long z_result;
1248 long Volid;
1249 vldbentry newentry;
1250
1251 if ((!xdr_long(z_xdrs, &Volid))
1252 || (!xdr_vldbentry(z_xdrs, &newentry))) {
1253 z_result = RXGEN_SS_UNMARSHAL;
1254 goto fail;
1255 }
1256
1257 z_result = VL_CreateEntry(z_call, Volid, &newentry);
1258 fail:
1259 return z_result;
1260 }
1261
1262 long _VL_GetEntryByName(z_call, z_xdrs)
1263 struct rx_call *z_call;
1264 XDR *z_xdrs;
1265 {
1266 long z_result;
1267 char *volumename = (char *)0;
1268 vldbentry entry;
1269
1270 if ((!xdr_string(z_xdrs, &volumename, 65))) {
1271 z_result = RXGEN_SS_UNMARSHAL;
1272 goto fail;
1273 }
1274
1275 z_result = VL_GetEntryByName(z_call, &volumename, &entry);
1276 z_xdrs->x_op = XDR_ENCODE;
1277 if ((!xdr_vldbentry(z_xdrs, &entry)))
1278 z_result = RXGEN_SS_MARSHAL;
1279 fail:
1280 z_xdrs->x_op = XDR_FREE;
1281 if (!xdr_string(z_xdrs, &volumename, 65)) goto fail1;
1282 return z_result;
1283 fail1:
1284 return RXGEN_SS_XDRFREE;
1285 }
1286
1287 long _VL_GetNewVolumeId(z_call, z_xdrs)
1288 struct rx_call *z_call;
1289 XDR *z_xdrs;
1290 {
1291 long z_result;
1292 long bumpcount;
1293 long newvolumid;
1294
1295 if ((!xdr_long(z_xdrs, &bumpcount))) {
1296 z_result = RXGEN_SS_UNMARSHAL;
1297 goto fail;
1298 }
1299
1300 z_result = VL_GetNewVolumeId(z_call, bumpcount, &newvolumid);
1301 z_xdrs->x_op = XDR_ENCODE;
1302 if ((!xdr_long(z_xdrs, &newvolumid)))
1303 z_result = RXGEN_SS_MARSHAL;
1304 fail:
1305 return z_result;
1306 }
1307
1308 long _VL_ReplaceEntry(z_call, z_xdrs)
1309 struct rx_call *z_call;
1310 XDR *z_xdrs;
1311 {
1312 long z_result;
1313 long Volid, voltype, ReleaseType;
1314 vldbentry newentry;
1315
1316 if ((!xdr_long(z_xdrs, &Volid))
1317 || (!xdr_long(z_xdrs, &voltype))
1318 || (!xdr_vldbentry(z_xdrs, &newentry))
1319 || (!xdr_long(z_xdrs, &ReleaseType))) {
1320 z_result = RXGEN_SS_UNMARSHAL;
1321 goto fail;
1322 }
1323
1324 z_result = VL_ReplaceEntry(z_call, Volid, voltype, &newentry,
1325 ReleaseType);
1326 fail:
1327 return z_result;
1328 }
1329
1330 long _VL_ListAttributes(z_call, z_xdrs)
1331 struct rx_call *z_call;
1332 XDR *z_xdrs;
1333 {
1334 long z_result;
1335 VldbListByAttributes attributes;
1336 long nentries;
1337 bulkentries bulkentries_1;
1338
1339 if ((!xdr_VldbListByAttributes(z_xdrs, &attributes))) {
1340 z_result = RXGEN_SS_UNMARSHAL;
1341 goto fail;
1342 }
1343
1344 z_result = VL_ListAttributes(z_call, &attributes, &nentries,
1345 &bulkentries_1);
1346 z_xdrs->x_op = XDR_ENCODE;
1347 if ((!xdr_long(z_xdrs, &nentries))
1348 || (!xdr_bulkentries(z_xdrs, &bulkentries_1)))
1349 z_result = RXGEN_SS_MARSHAL;
1350 fail:
1351 z_xdrs->x_op = XDR_FREE;
1352 if (!xdr_bulkentries(z_xdrs, &bulkentries_1)) goto fail1;
1353 return z_result;
1354 fail1:
1355 return RXGEN_SS_XDRFREE;
1356 }
1357
1358 long _VL_LinkedList(z_call, z_xdrs)
1359 struct rx_call *z_call;
1360 XDR *z_xdrs;
1361 {
1362 long z_result;
1363 VldbListByAttributes attributes;
1364 long nentries;
1365 vldb_list linkedentries;
1366
1367 if ((!xdr_VldbListByAttributes(z_xdrs, &attributes))) {
1368 z_result = RXGEN_SS_UNMARSHAL;
1369 goto fail;
1370 }
1371
1372 z_result = VL_LinkedList(z_call, &attributes, &nentries,
1373 &linkedentries);
1374 z_xdrs->x_op = XDR_ENCODE;
1375 if ((!xdr_long(z_xdrs, &nentries))
1376 || (!xdr_vldb_list(z_xdrs, &linkedentries)))
1377 z_result = RXGEN_SS_MARSHAL;
1378 fail:
1379 return z_result;
1380 }
1381
1382 long _VL_CreateEntry();
1383 long _VL_GetEntryByName();
1384 long _VL_GetNewVolumeId();
1385 long _VL_ReplaceEntry();
1386 long _VL_ListAttributes();
1387 long _VL_LinkedList();
1388
1389 static long (*StubProcsArray0[])() = {_VL_CreateEntry,
1390 _VL_GetEntryByName, _VL_GetNewVolumeId, _VL_ReplaceEntry,
1391 _VL_ListAttributes, _VL_LinkedList};
1392
1393 VL_ExecuteRequest(z_call)
1394 register struct rx_call *z_call;
1395 {
1396 int op;
1397 XDR z_xdrs;
1398 long z_result;
1399
1400 xdrrx_create(&z_xdrs, z_call, XDR_DECODE);
1401 if (!xdr_int(&z_xdrs, &op))
1402 z_result = RXGEN_DECODE;
1403 else if (op < VL_LOWEST_OPCODE || op > VL_HIGHEST_OPCODE)
1404 z_result = RXGEN_OPCODE;
1405 else
1406 z_result = (*StubProcsArray0[op - VL_LOWEST_OPCODE])
1407 (z_call, &z_xdrs);
1408 return z_result;
1409 }
1410
1411If there were gaps in the procedures' opcode sequence the code for
1412VL_ExecuteRequest() routine would be have been drastically different (it
1413would have been a case statement for each procedure).
1414
1415=head1 NOTES
1416
1417B<rxgen> is implemented from Sun's B<rpcgen> utility.
1418
1419When the C<%#include <include file>> feature is used make sure that you
1420don't have any B<rxgen> language features (i.e. %#defines) since you'll
1421get syntax errors during compilations..
1422
1423Since this is an ongoing project many of the above may change/disappear
1424without a major warning.
1425
1426=head1 SEE ALSO
1427
1428I<Rxgen Syntax Summary>: Summary description of rxgen's grammar.
1429
1430I<Rpcgen Programming Guide>: Sun's RPC protocol compiler. B<rxgen> was
1431implemented as an extension to that compiler.
1432
1433I<External Data Representation: Sun Technical Notes>: Detailed examples in
1434using XDR.
1435
1436I<RPCL Syntax Summary>: Summary of Sun's Remote Procedure Call Language.
1437
1438I<Rx>: An extended Remote Procedure Call Protocol.
1439
1440I<rgen>: An earlier version of a similar stub generator used for the R RPC
1441protocol.
1442
1443=head1 COPYRIGHT
1444
1445IBM Corporation 2000. <http://www.ibm.com/> All Rights Reserved.
1446
1447This documentation is covered by the IBM Public License Version 1.0. It
1448was converted from the original TeX B<rxgen> manual to POD by Russ
1449Allbery.