3 rxgen - Stub generator for the Rx remote procedure call package
10 B<rxgen> [B<-h> | B<-c> | B<-C> | B<-S> | B<-r>] [B<-dkpR>]
11 [B<-I> I<dir>] [B<-P> I<prefix>] [B<-o> I<outfile>] [I<infile>]
13 B<rxgen> B<-s> I<transport> [B<-o> I<outfile>] [I<infile>]
15 B<rxgen> B<-l> [B<-o> I<outfile>] [I<infile>]
17 B<rxgen> B<-m> [B<-o> I<outfile>] [I<infile>]
24 B<rxgen> is a tool that generates C code to implement the Rx RPC protocol;
25 it takes as input a description of an application interface similar to C
26 and produces a number of server and/or client stub routines to be linked
27 with RPC-based programs. These stubs allow programs to invoke remote
28 procedures through local procedure calls. B<rxgen> is an extension of
29 Sun's B<rpcgen> (version 3.9) and retains full B<rpcgen> functionality (at
30 least as of that version). Please refer to rpcgen(1) for more details on
31 the Sun's RPC specific flags, and to the RPC programming guide regarding
32 the RPC language along with useful examples.
36 B<rxgen> operates in several different modes. The generated output files
37 can be produced individually (using one of B<-h>, B<-c>, B<-C>, or B<-S>)
38 or collectively. All output files are created when the default is used
39 (i.e., no options), or the output is limited to the server stubs (B<-C>
40 and B<-S>) when the B<-r> flag is used. The following describes the types
41 of generated output files (for simplicity, I<filename> refers to the main
48 Generate C data definitions (a header file) from standard RPCL definitions
49 (default extension: I<filename>.h).
53 Compile the XDR routines required to serialize the protocol described by
54 RPCL. Generate XDR routines for all declarations (default extension:
59 Generate all the client-side stub routines (default extension:
60 I<filename>.cs.c). Calling a routine in this file will cause the
61 arguments to be packed up and sent via Rx (or R).
65 Generate all the server-side stub routines (default extension:
66 I<filename>.ss.c). Arguments are unpacked, and the corresponding server
71 Generate the two default extension files produced by the B<-C> and B<-S>
76 The following options can be used on any combination of B<rxgen> calls:
82 Generate code for the older \R protocol, as opposed to Rx, which is the
87 Must be specified when the generated code is intended to be used by the
88 kernel; special "includes" and other specifics are produced when the
89 target output is for the kernel.
93 Package combination flag: when multiple packages are included within a
94 single specification file, a single Execute Request routine will be used
95 for all of them as a result of this flag. The default is to generate
96 individual Execute Request stubs for each package.
100 Similar to the B<-I> flag in the C compiler (B<cc>). This flag is passed
101 to the pre-processor (B<cpp>) so that directory I<dir> is searched before
102 the standard lookup list for #include files. As expected, multiple B<-I>
103 flags can be used simultaneously.
105 =item B<-P> I<prefix>
107 The I<prefix> string following this switch is prepended to all generated
108 output files; useful when multiple runs want to produce different versions
109 of the same interface (say, kernel and non-kernel versions).
113 Debugging mode; only needed when B<rxgen> is to be debugged (say, via
116 =item B<-o> I<outfile>
118 Specify the name of the output file. If none is specified, the standard
119 output is used (B<-c>, B<-h>, B<-C>, and B<-S> modes only). Note that if
120 an output file is specified in a multi-output file option (such as the
121 default, or with option B<-r>), then the I<outfile> replaces the name
122 generated by default (which is based on the configuration's main file
127 The B<-s>, B<-l>, and B<-m> options are present only for B<rpcgen>
128 support. See rpcgen(1) for information on their use.
130 =head1 B<rxgen> SYNTAX SUMMARY
134 <Package description option> |
135 <Prefix description option> |
136 <StartingOpcode description option> |
137 <SplitPrefix description option> |
138 <Procedure description option> |
139 <RPCL language description option>
141 <Package description option>:
143 "package" <Package_ident>
145 <Prefix description option>:
147 "prefix" <Prefix_ident>
149 <StartingOpcode description option>:
151 "startingopcode" <constant>
153 <SplitPrefix description option>:
155 "splitprefix" <split options> ";"
159 "IN =" <Start_prefix_ident> "|"
160 "OUT =" <End_prefix_ident> "|"
163 <Procedure description option>:
165 ["proc"] [<Procedure_ident>] [<ServerStub_ident>]
166 <Argument list> ["split" | "multi"]
167 ["=" <Opcode_ident>] ";"
171 "(" <Argument definition> <Comma_joined argument> ")"
173 <Argument definition>:
175 <Direction option> <Standard RPCL type decl> <Arg_ident>
176 ["<" <Max_size> ">" | "[" <Max_size> "]"] | NULL
178 <Comma_joined argument>:
180 "," <Argument definition> | NULL
184 "IN" | "OUT" | "INOUT" | NULL
193 <Start_prefix_ident>:
202 <RPCL language description option>:
203 <Standard RPCL type decl>:
205 Sun's RPCL language syntax (see rpcgen(1))
207 =head1 B<rxgen> COMMANDS
209 =head2 Comments and Preprocessing
211 The input interface may contain preprocessor directives which are passed
212 through the C preprocessor (i.e. C<cpp>). Since the preprocessor runs on
213 all input files before they are actually interpreted by B<rxgen>, all
214 B<cpp> directives (#include, #ifdefs, #defines, etc.) are legal and
215 welcomed within an B<rxgen> input file. Of course, none of these
216 preprocessor directives will be included in any of the generated files.
217 To facilitate distinctions between the different types of output files,
218 B<rxgen> defines certain special B<cpp> symbols for use by the B<rxgen>
219 programmer. These are RPC_HDR (defined when compiling into header,
220 I<filename>.h, files), RPC_XDR (defined when compiling into xdr,
221 I<filename>.xdr.c, files), RPC_CLIENT (defined when compiling into client
222 stubs, I<filename>.cs.c, files), and RPC_SERVER (defined when compiling
223 into server stubs, I<filename>.ss.c, files).
225 In addition, B<rxgen> does a little preprocessing of its own. Any line
226 beginning with C<%> is passed directly into the output file, uninterpreted
227 by B<rxgen>. For a more heavy en masse dumping of uninterpreted code, it
228 would be adviced to include all such code in an C<#include> file and pass
229 it in preceded by C<%>. The input interface may also contain any C-style
230 comments which are, of course, ignored. Interpretation is token-based,
231 thus special line-orientation of separate statements is not necessary.
232 B<rxgen> also provides a quite rich and helpful set of error reports,
233 identifying them by exact line location and error type. Also, B<rxgen>
234 will automatically generate #include lines for standard include files,
235 such as F<rx/xdr.h> and F<rx/rx.h>, along with the generated header file
238 =head2 Prefixing stub procedures
240 The I<package> statement tells B<rxgen> the name of the interface package.
241 It is used for prefixing the naming of all generated stub routines and the
242 execute request procedure. For example:
246 causes the execute request procedure to be named AFS_ExecuteRequest
247 (Warning: in the older version an additional C<_> was appended after the
248 package name to the ExecuteRequest name; thus make sure you don't have an
249 ExecuteRequest interface routine) and a given stub routine, say Fetch, to
250 be actually named AFS_Fetch. Multiple package statements (current maximum
251 size is 10) per configuration are permitted and are useful when multiple
252 sets of interfaces are implemented (see the example at the end). Note
253 that in such cases, use of the B<-p> flag results in the generation of
254 just one ExecuteRequest procedure which recognizes the multiple interfaces
255 and whose name is prefixed by the first package statement. In the default
256 case, independent ExecuteRequest procedures will be created for each
257 packaged group of remote procedure calls.
259 The I<prefix> statement supplies a name to prepend to all calls to remote
260 procedure names in the ExecuteRequest stub routine. It is useful when the
261 server makes RPC calls to other servers (say, for debugging purposes).
266 causes the name C<S> to be prepended to the name of all routines called
267 from the server stubs. The server can then call the original name and get
270 =head2 B<rxgen> procedure declaration
272 The I<proc> statement is the most common (and meaningful) in the B<rxgen>
273 interface. Its syntax description is:
275 [proc] [<proc_name>] [<server_stub>] (<arg>, ..., <arg>)
276 [split | multi] [= <opcode>] ;
284 C<proc> is an optional prefix of the procedure statement. This is just a
285 stylistic item and not a required procedure delimiter.
289 <proc_name> is the name of the procedure. Note that even the name of the
290 procedure is optional. This only makes sense when the name of the given
291 procedure is identical to the name of the last I<package> statement (i.e.,
292 C<package RCallBack> and the declaration of the C<RCallBack> procedure).
296 <server_stub>, if present, causes the ExecuteRequest procedure to call
297 that stub instead of the automatically generated stub when a call with
298 that opcode is decoded.
302 <opcode> is a constant or symbol that is the opcode for that procedure.
303 One might use the preprocessor features (i.e., #define), the I<const>
304 RPC-language feature, or the old good constants as opcodes. Some further
305 evaluation/processing of opcodes is done. Particularly, checks for
306 duplicate and non-existent opcodes are performed, along with checks for
307 "holes" (i.e., gaps in consecutive opcodes) in the opcode sequences. For
308 example, we use the fact that when "holes" in opcodes exist, the
309 ExecuteRequest procedure uses the I<case> statement rather than the faster
310 (and smaller, codewise) indexed array method.
312 Also, B<rxgen> defines (i.e., appends to the header file) three valuable
313 macros for each package group: <package-name>LOWEST_OPCODE,
314 <package-name>HIGHEST_OPCODE, and <package-name>NUMBER_OPCODES. These may
315 be useful to the B<rxgen> programmer. Also, notice that the I<opcode>
316 statement is an optional feature, and can be omitted. In such cases,
317 automatic opcode numbers are generated sequentially, starting from 0.
319 One can change the initial opcode number by using the I<startingopcode>
320 (for lack of a better name) B<rxgen> command. Its syntax is:
322 startingopcode <constant>
324 where <constant> must be reasonable! Note that one can not mix
325 procedures, some with opcodes and some without, nor allow opcodes after
326 the specification of the I<startingopcode> statement. B<rxgen> will
327 complain in all such cases.
331 The I<argument> entry represents a given parameter of the procedure. Its
334 [IN | INOUT | OUT | <null>] <type_decl> <arg_name>
337 If the type is an indirect type (i.e., is followed by *), it is assumed
338 that the pointer should be followed one level and the data pointed to is
339 to be transmitted. This should normally be used for all structures/arrays
340 and out parameters. A noticeable exception is when explicit
341 array/structure maximum size is given; since no array-of-pointer
342 declarations are allowed one should use typedefs to achieve the similar
343 effect. The parameters could be input parameters (preceded by IN), output
344 parameters (preceded by OUT), or input/output parameters (preceded by
345 INOUT). If not specified, then the direction of the previous parameter in
346 the procedure is used. (Note: the first parameter must be preceded by the
347 directional primitive!)
351 C<split> is a hack to handle stub routines that do things such as file
352 transfers or any other operation that has to exchange information (e.g.,
353 length of a file) before the call returns its output parameters. Because
354 of the particular handshake that is involved when doing remote file
355 transfer, we currently break all such calls into two client-side stub
356 routines. The first (with the default prefix of C<Begin>) is used to pass
357 all IN and INOUT parameters to the server side. The second (with the
358 default prefix of C<End>) is used to get back the INOUT and OUT parameters
359 from the server. Between the two calls, the user is supposed to do the
360 appropriate calls for the file transfer. For example, the following
361 procedure declaration in package AFS_
363 Fetch (IN a, b,INOUT c, OUT d) split = FETCHOPCODE;
365 will roughly generate the two independent client stub routines:
367 BeginAFS_Fetch (IN a, b, c)
371 EndAFS_Fetch(OUT c, d)
373 The I<splitprefix> statement is used to change the default prefix names
374 used by the two client-side stub generated routines when dealing with file
375 transfer-related procedure calls. For example:
377 splitprefix IN=Before_ OUT=After_
379 will cause the naming of the two client stubs for a file transfer-related
380 routine, say Fetch(), to be Before_AFS_Fetch() and After_AFS_Fetch(),
385 The C<multi> option is nearly identical to the C<split> feature described
386 above. The only significant visible difference is that along with the two
387 client stubs, the standard client stub is also generated. Since the
388 intention is to handle the multi-Rx calls, we need the whole standard
389 procedure stub in the cases where no multi-Rx call of the procedure is
390 performed. A side effect of the C<multi> option is the generation of a
391 special macro (i.e., C<< multi_<Procedure-name> >> which passes back as
392 arguments the C<Begin> and C<End> stubs in the header output file. This
393 macro is used directly by the Rx code when a multi-Rx call of this
394 procedure is performed.
398 =head2 OBSOLETE B<rxgen> FEATURES
400 Although the following rxgen commands are still in effect, they will soon
401 be removed since there are better alternatives. DO NOT USE THEM!
403 The I<special> statement is a temporary hack used to handle certain
404 inefficiencies of standard xdr routines to handle some user-customized
405 declarations. In particular, this applies to a string pointer specified
406 as part of a declaration. For example,
408 special struct BBS SeqBody;
410 tells B<rxgen> that the entry C<SeqBody> in the user-defined BBS xdr
411 routine is a string (note that more than one string can be "special" per
412 structure -- multiple ones are separated by commas); it will thus allocate
413 and de-allocate space properly in the server-generated stubs that contain
414 this structure as an IN or INOUT parameter.
416 A better alternative to I<special> is the I<customized> statement, which
417 is simply the C<customized> token followed by the regular declaration of a
418 struct based on the RPCL rules. In this case, the declaration will be
419 included in the generated header file (B<-h> option) but no xdr routine
420 will be generated for this structure -- the user will supply this. All
421 pointer entries in this structure will be remembered so when the structure
422 is used as an IN or INOUT in the server stub, no core leaks will occur.
423 For example, consider
425 customized struct CBS {
430 The C<xdr_CBS> routine would be provided by the user where during the
431 DECODE xdr opcode, appropriate space for the C<SeqBody> string is
432 allocated. Similarly, that space is freed during the FREE xdr opcode.
434 Note: Old style "Array parameter specifications" are not supported any
439 In case there are some requirements not available by the current RPC
440 language, one can customize some XDR routines by leaving those data types
441 undefined. For every data type that is undefined, it will be assumed that
442 a routine exists with the name C<xdr_> prepended to it. A selected set of
443 B<rxgen> features is presented below, but for a more comprehensive one
444 (unions, complex examples, etc) please refer to the I<rpcgen Programming
445 Guide> and I<eXternal Data Representation: Sun Technical Notes>.
449 The RPC typedef statement is identical to the C typedef (i.e. C<< typedef
450 <declaration> >>). By default, most user declarations (i.e. structs,
451 unions, etc) are automatically typedef'ed by B<rxgen>. Since it makes
452 parsing simpler, its usage is recommended by B<rxgen> scripts.
456 The C C<char *> string convention is kind of ambiguous, since it is
457 usually intended to mean a null-terminated string of characters, but it
458 could also represent a pointer to a single character, a pointer to an
459 array of characters, etc. In the RPC language, a null-terminated string
460 is unambiguously called a "string". Examples,
463 string name<MAXNAMELEN>;
464 typedef string volname<MAXVOLNAME>;
466 Notice that the maximum size of string can be arbitrary (like C<bigname>
467 above) or, preferably, or specified in angle brackets (i.e. C<name> and
468 C<volname> above). In practice, one should always use only bounded
469 strings in interfaces. A sample calling proc using the declarations above
472 GetEntryByName (IN volname name,
473 OUT struct vldbentry *entry) = VL_GETENTRYBYNAME;
477 GetEntryByName (IN string volname<MAXVOLNAME>,
478 OUT struct vldbentry *entry) = VL_GETENTRYBYNAME;
480 It is very important for the user to understand when the string parameters
481 should be allocated and/or freed by the his/her client and/or server
482 programs. A short analysis on string parameters handling follows (note
483 that a similar method is used for the handling of variable length arrays
484 as it will be shown later on):
490 In the client side: IN and INOUT string parameters are the programmer's
491 responsibility and should be allocated (static or via malloc) before
492 calling the rpc and freed (if malloc was used) after the rpc's return in
493 the user's client program; of course, for INOUT parameters, the returned
494 string can't be bigger than the malloced input string.
496 OUT string parameters are automatically malloced (based on the length of
497 the returned string and not the maxsize) by the B<rxgen> client stubs (in
498 I<filename>.cs.c) and must be freed by the client program; admittedly,
499 this could be somewhat confusing since the user needs to free something
500 that he/she didn't allocate.}
504 In the server side: IN and INOUT string parameters are automatically
505 malloced (based on the size of incoming strings) by the rxgen server stubs
506 (in I<filename>.ss.c) before they are passed to the user's server
507 procedure; that space is automatically freed just before the rxgen server
508 stub returns; therefore the user need not do anything special for IN and
509 INOUT string parameters.
511 OUT string parameters must be malloced by the user's server procedure
512 (i.e. null pointer is passed to it by the rxgen server stub) and it is
513 automatically freed at the end of the B<rxgen> server stub. Like in the
514 client side, the OUT parameters are somewhat unorthodox (i.e. the server
515 routine must malloc a string without ever freeing it itself; this is done
516 by the B<rxgen> server stub).
520 Note that for INOUT and OUT string parameters, in both the client and
521 server sides their arguments must be char of pointers (i.e. char **).
525 Pointer declarations in RPC are also exactly as they are in C
526 (i.e. C<struct single_vldbentry *vldblist;>). Of course, one can't send
527 pointers over the network, but one can use XDR pointers for sending
528 recursive data types such as lists and trees (an example of a linked list
529 will be demonstrated shortly).
533 Fixed arrays are just like standard C array declarations (i.e. C<struct
534 UpdateEntry entries[20]>) without any side effect problems in
535 B<rxgen>. Since variable-length arrays have no explicit syntax in C, the
536 angle-brackets are used for it and the array declarations are actually
537 compiled into "struct"s. For example, declarations such as:
539 const MAXBULKSIZE = 10000;
540 const MAXENTRIES = 100;
541 opaque bulk<MAXBULKSIZE>; /* At most 10000 items */
542 int hosts<>; /* any number of items */
543 typedef vldbentry blkentries<100>; /* Preferable array decl */
545 are compiled into the following structs:
548 u_int bulk_len; /* no of items */
549 char *bulk_val; /* pointer to array */
552 for the C<bulk> array, and similarly for the C<< blkentries<100> >> array,
555 u_int blkentries_len; /* no of items in array */
556 vldbentry *blkentries_val; /* pointer to array */
559 Therefore the user should be aware of the "magically" generated structure
560 entries such as the number of items in the array (<array_name>_len) and
561 the pointer to the array (<array_name>_val) since some of the entries will
562 have to be filled in from the client/server programs. A sample proc would
565 typedef vldbentry blkentries<MAXENTRIES>;
566 proc GetBlk (OUT blkentries *vlentries) = VL_GETBLK;
570 GetBlk(OUT vldbentry vlentries<MAXENTRIES>) = VL_GETBLK;
572 Note that although the latest method is preferable since one does not have
573 to first use the typedef statement (and admittedly, programmers prefer
574 avoiding typedefs), one should realize that B<rxgen> does the structure
575 expansion and the xdr creation implicitly; therefore the user should be
576 aware of the C<vldbentries_val> and C<vldbentries_len> fields as before
577 (see following examples).
579 =head3 Array example I (least desirable)
581 Procedure declaration in the interface configuration:
583 proc ListAttributes (IN vldblistbyattributes *attributes,
584 INOUT blkentries *vldbentries) = VL_LISTATTRIBUTES;
588 blkentries entries, *pnt;
589 entries.blkentries_len = 10; /* max # returned entries */
590 entries.blkentries_val = (vldbentry *)malloc(LEN);
593 code = VL_ListAttributes(&attributes, &entries);
595 pnt = entries.blkentries_val;
596 for (i=0; i < entries.blkentries_len; i++, pnt++)
597 display_vldbentry(pnt);
598 /* Make sure you free the allocated space */
599 free((char *)entries.blkentries_val);
604 VL_ListAttributes(attributes, entries)
606 vldbentry *singleentry = entries->blkentries_val;
607 entries->blkentries_len = 0;
609 while (copy_to_vldbentry(&vlentry, singleentry))
610 singleentry++, vldbentries->entries_len++;
613 Although this method for variable-size arrays works fine, there are some
614 major drawbacks. The array parameter (i.e. vldbentries above) must be
615 declared as INOUT since we need to pass the max length of the expected
616 returned array; more importantly, a big (depending on the value of
617 C<_len>) chunk of junk code is going to be transferred to the server as
618 result of the IN(out) side-effect of the array. It's an easy and
619 convenient method if the returned array size can be predicted from the
620 start and when the size is quite high. This method is included as an
621 example of erroneous use (and abuse) of B<rxgen> and should not be used.
623 =head3 Array example II (Desirable method)
625 Procedure declaration in the interface configuration (using Example I
628 proc ListAttributes (IN vldblistbyattributes *attributes,
629 OUT blkentries *vldbentries) = VL_LISTATTRIBUTES;
633 blkentries entries, *pnt;
635 code = VL_ListAttributes(&attributes, &entries);
637 pnt = entries.blkentries_val;
638 for (i=0; i < entries.blkentries_len; i++, pnt++)
639 display_vldbentry(pnt);
640 /* Make sure you free the allocated space (by rxgen) */
641 free((char *)entries.blkentries_val);
646 VL_ListAttributes(attributes, entries)
648 vldbentry *singleentry;
649 entries->blkentries_len = 0;
650 singleentry = entries->blkentries_val
651 = (vldbentry *)malloc(MAXENTRIES * sizeof(vldbentry));
653 while (copy_to_vldbentry(&vlentry, singleentry))
654 singleentry++, vldbentries->entries_len++;
657 This is the best (and simplest) way of using variable-size arrays as an
658 output parameter. It is the responsibility of the server-side stub to
659 malloc() the adequate space which is automatically freed by the B<rxgen>
660 stub; the client side should free the space allocated by the
661 B<rxgen>-calling stub.
663 =head3 Array example III (Linked Lists)
665 Considering the following 3 declarations (could have applied some
666 optimizations) in the configuration file:
668 typedef struct single_vldbentry *vldblist;
669 struct single_vldbentry {
678 and the rxgen procedure declaration:
680 LinkedList (IN vldblistbyattributes *attributes,
681 OUT vldb_list *linkedentries) = VL_LINKEDLIST;
685 vldb_list linkedvldbs;
686 vldblist vllist, vllist1;
688 bzero(&linkedvldbs, sizeof(vldb_list));
689 code = VL_LinkedList(&attributes, &nentries, &linkedvldbs);
691 printf("We got %d vldb entries\n", nentries);
692 for (vllist = linkedvldbs.node; vllist; vllist = vllist1) {
693 vllist1 = vllist->next_vldb;
694 display_entry(&vllist->vlentry);
695 free((char *)vllist);
701 VL_LinkedList(rxcall, attributes, nentries, linkedvldbs);
703 vldblist vllist, *vllistptr = &linkedvldbs->node;
706 = (single_vldbentry *)malloc (sizeof (single_vldbentry));
707 copy_to_vldbentry(&tentry, &vllist->vlentry);
709 vllistptr = &vllist->next_vldb;
714 Using a linked list offers many advantages: Nothing is passed to the
715 server (the parameter is OUT), no additional overhead is involved, and the
716 caller doesn't have to explicitly prepare for an arbitrary return size. A
717 drawback is that the caller has the responsibility of malloc() (on the
718 server) and free (on the client) of each entry (to avoid unwanted
719 core-leaks). Another drawback is that since it's a recursive call, the C
720 stack will grow linearly with respect to the number of nodes in the list
721 (so it's wise to increase the Rx LWP stack if huge amounts of data are
722 expected back -- default stack size is 4K). The advantages should
723 outweight the disadvantages here.
725 It's important to pay attention to the comments of the three array
726 examples above particularly when they're references to when the user
727 should allocate/free space for the variable length arrays. The mechanism
728 is very similar to the handling of strings thus you might need to review
729 the strings section above; note that the linked lists are handled somewhat
732 =head2 Miscellaneous examples
734 Below is an abbreviated version of a random interface file which shows
735 some of the common cases.
737 /* Declaration of all structures used by the R.xg script interface */
740 unsigned long Volume;
742 unsigned long Unique;
745 typedef long ViceDataType;
747 /* Note that TEST would be equivalent to "HEADER" only during the
748 processing of the header, *.h, file */
751 #define TEST "HEADER"
756 /* This is the standard *.xg specification file */
759 splitprefix IN=BEFORE_ OUT=AFTER_;
762 proc Remove(IN struct AFSFid *Did, IN string volname<64>,
763 OUT struct AFSStatus *Status) = AFS_REMOVE;
765 DisconnectFS AUX_disconnectFS() = AFS_DISCONNECTFS;
767 proc GetVolumeInfo(IN string Vid,
768 OUT struct VolumeInfo *Info) = AFS_GETVOLUMEINFO;
770 /* You could have more than an interface per configuration */
774 /* Using the "multi" feature; thus VOTE_Beacon can be called as an
775 multi-Rx call or as a regular call */
777 Beacon (IN long state, long voteStart,
778 net_version *version, net_tid *tid)
783 /* Using the "split" feature */
785 SendFile (IN long file, long offset,
786 long length, net_version *version)
787 split = DISK_SENDFILE;
789 =head2 Output of an actual interface configuration
791 We'll demonstrate some of the actual output generated by B<rxgen> by
792 following an abbreviated actual interface configuration.
794 =head3 Configuration file
796 Contents of the interface configuration file (F<vldbint.xg>):
799 #include "vl_opcodes.h" /* The opcodes are included here */
800 %#include "vl_opcodes.h" /* directly to other places */
802 /* Current limitations on parameters that affect other packages
805 const MAXNAMELEN = 65;
806 const MAXNSERVERS = 8;
809 /* External (visible) representation of an individual vldb entry */
812 char name[MAXNAMELEN];
815 long serverNumber[MAXNSERVERS];
816 long serverPartition[MAXNSERVERS];
817 long serverFlags[MAXNSERVERS];
818 u_long volumeId[MAXTYPES];
822 typedef struct single_vldbentry *vldblist;
823 struct single_vldbentry {
832 /* vldb interface calls */
834 CreateEntry (IN long Volid,
835 vldbentry *newentry) = VLCREATEENTRY;
837 GetEntryByName (IN string volumename<MAXNAMELEN>,
838 OUT vldbentry *entry) = VLGETENTRYBYNAME;
840 GetNewVolumeId (IN long bumpcount,
841 OUT long *newvolumid) = VLGETNEWVOLUMEID;
843 ReplaceEntry (IN long Volid,
846 long ReleaseType) multi = VLREPLACEENTRY;
848 ListAttributes (IN VldbListByAttributes *attributes,
850 OUT vldbentry bulkentries<MAXVLDBLEN>)
853 LinkedList (IN VldbListByAttributes *attributes,
855 OUT vldb_list *linkedentries) = VLLINKEDLIST;
857 We'll concentrate only on the Rx generated code since the R generated code
858 (B<-R> option) will soon be obsolete. For a detailed description on the
859 Rx-related calls inside the generated stubs (i.e., rx_NewCall(),
860 rx_EndCall()), along with details on what happens inside certain calls
861 (like xdrrx_create()) please refer to the Rx documentation. Typing C<rxgen
862 vldbint.xg> will result in the creation of four files: F<vldbint.h>,
863 F<vldbint.xdr.c>, F<vldbint.cs.c> and F<vldbint.ss.c>. A closer look at
866 =head3 Header file (F<vldbint.h>)
868 /* Machine generated file -- Do NOT edit */
870 #include "vl_opcodes.h" /* directly to other places */
871 #define MAXNAMELEN 65
872 #define MAXNSERVERS 8
876 char name[MAXNAMELEN];
879 long serverNumber[MAXNSERVERS];
880 long serverPartition[MAXNSERVERS];
881 long serverFlags[MAXNSERVERS];
882 u_long volumeId[MAXTYPES];
885 typedef struct vldbentry vldbentry;
886 bool_t xdr_vldbentry();
888 typedef struct single_vldbentry *vldblist;
889 bool_t xdr_vldblist();
891 struct single_vldbentry {
895 typedef struct single_vldbentry single_vldbentry;
896 bool_t xdr_single_vldbentry();
901 typedef struct vldb_list vldb_list;
902 bool_t xdr_vldb_list();
904 #include <rx/rx_multi.h>
905 #define multi_VL_ReplaceEntry(Volid, voltype, newentry, ReleaseType) \
906 multi_Body(StartVL_ReplaceEntry(multi_call, Volid, voltype,
907 newentry, ReleaseType), EndVL_ReplaceEntry(multi_call))
909 typedef struct bulkentries {
910 u_int bulkentries_len;
911 vldbentry *bulkentries_val;
913 bool_t xdr_bulkentries();
915 /* Opcode-related useful stats for package: VL_ */
916 #define VL_LOWEST_OPCODE 501
917 #define VL_HIGHEST_OPCODE 506
918 #define VL_NUMBER_OPCODES 6
920 Notice that all structures are automatically typedef'ed and all C<const>s
921 are converted to C<#define>s. Some data structures, such as bulkentries,
922 are taken from procedure params (from ListAttributes proc). Thus, this
923 should be kept in mind when creating stubs piecemeal with B<rxgen> (i.e.,
924 using the B<-c>, B<-h>, B<-C>, or B<-S> flags). Also, one of the side
925 effects of the C<multi> option (in C<ReplaceEntry> proc) is the generation
926 of the C<multi_VL_ReplaceEntry> above.
928 =head3 XDR routines for structures (vldbint.xdr.c)
930 /* Machine generated file -- Do NOT edit */
935 #include "vl_opcodes.h" /* directly to other places */
938 xdr_vldbentry(xdrs, objp)
942 if (!xdr_vector(xdrs, (char *)objp->name, MAXNAMELEN,
943 sizeof(char), xdr_char))
945 if (!xdr_long(xdrs, &objp->volumeType))
947 if (!xdr_long(xdrs, &objp->nServers))
949 if (!xdr_vector(xdrs, (char *)objp->serverNumber, MAXNSERVERS,
950 sizeof(long), xdr_long))
952 if (!xdr_vector(xdrs, (char *)objp->serverPartition,
953 MAXNSERVERS, sizeof(long), xdr_long))
955 if (!xdr_vector(xdrs, (char *)objp->serverFlags, MAXNSERVERS,
956 sizeof(long), xdr_long))
958 if (!xdr_vector(xdrs, (char *)objp->volumeId, MAXTYPES,
959 sizeof(u_long), xdr_u_long))
961 if (!xdr_long(xdrs, &objp->flags))
967 xdr_vldblist(xdrs, objp)
971 if (!xdr_pointer(xdrs, (char **)objp,
972 sizeof(struct single_vldbentry),
973 xdr_single_vldbentry))
979 xdr_single_vldbentry(xdrs, objp)
981 single_vldbentry *objp;
983 if (!xdr_vldbentry(xdrs, &objp->VldbEntry))
985 if (!xdr_vldblist(xdrs, &objp->next_vldb))
991 xdr_vldb_list(xdrs, objp)
995 if (!xdr_vldblist(xdrs, &objp->node))
1001 xdr_bulkentries(xdrs, objp)
1005 if (!xdr_array(xdrs, (char **)&objp->bulkentries_val,
1006 (u_int *)&objp->bulkentries_len, MAXVLDBLEN,
1007 sizeof(vldbentry), xdr_vldbentry))
1012 Note that the xdr_bulkentries() is automatically generated as a side
1013 effect of a procedure parameter declaration. Thus, if identical multiple
1014 type parameter declarations are used, then multiply-defined xdr_* stubs
1015 will be created! We felt this was a better alternative to having the
1016 B<rxgen> programmer deal with types such as bulkentries_1,
1019 =head3 Client-Side stub routines (vldbint.cs.c)
1021 /* Machine generated file -- Do NOT edit */
1025 #include <afs/rxgen_consts.h>
1026 #include "vldbint.h"
1028 #include "vl_opcodes.h" /* directly to other places */
1030 int VL_CreateEntry(z_conn, Volid, newentry)
1031 register struct rx_connection *z_conn;
1033 vldbentry * newentry;
1035 struct rx_call *z_call = rx_NewCall(z_conn);
1036 static int z_op = 501;
1040 xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1042 /* Marshal the arguments */
1043 if ((!xdr_int(&z_xdrs, &z_op))
1044 || (!xdr_long(&z_xdrs, &Volid))
1045 || (!xdr_vldbentry(&z_xdrs, newentry))) {
1046 z_result = RXGEN_CC_MARSHAL;
1050 z_result = RXGEN_SUCCESS;
1052 return rx_EndCall(z_call, z_result);
1055 int VL_GetEntryByName(z_conn, volumename, entry)
1056 register struct rx_connection *z_conn;
1060 struct rx_call *z_call = rx_NewCall(z_conn);
1061 static int z_op = 504;
1065 xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1067 /* Marshal the arguments */
1068 if ((!xdr_int(&z_xdrs, &z_op))
1069 || (!xdr_string(&z_xdrs, &volumename, 65))) {
1070 z_result = RXGEN_CC_MARSHAL;
1074 /* Un-marshal the reply arguments */
1075 z_xdrs.x_op = XDR_DECODE;
1076 if ((!xdr_vldbentry(&z_xdrs, entry))) {
1077 z_result = RXGEN_CC_UNMARSHAL;
1081 z_result = RXGEN_SUCCESS;
1083 return rx_EndCall(z_call, z_result);
1086 int VL_GetNewVolumeId(z_conn, bumpcount, newvolumid)
1087 register struct rx_connection *z_conn;
1091 struct rx_call *z_call = rx_NewCall(z_conn);
1092 static int z_op = 505;
1096 xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1098 /* Marshal the arguments */
1099 if ((!xdr_int(&z_xdrs, &z_op))
1100 || (!xdr_long(&z_xdrs, &bumpcount))) {
1101 z_result = RXGEN_CC_MARSHAL;
1105 /* Un-marshal the reply arguments */
1106 z_xdrs.x_op = XDR_DECODE;
1107 if ((!xdr_long(&z_xdrs, newvolumid))) {
1108 z_result = RXGEN_CC_UNMARSHAL;
1112 z_result = RXGEN_SUCCESS;
1114 return rx_EndCall(z_call, z_result);
1117 int VL_ReplaceEntry(z_conn, Volid, voltype, newentry, ReleaseType)
1118 register struct rx_connection *z_conn;
1119 long Volid, voltype, ReleaseType;
1120 vldbentry * newentry;
1122 struct rx_call *z_call = rx_NewCall(z_conn);
1123 static int z_op = 506;
1127 xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1129 /* Marshal the arguments */
1130 if ((!xdr_int(&z_xdrs, &z_op))
1131 || (!xdr_long(&z_xdrs, &Volid))
1132 || (!xdr_long(&z_xdrs, &voltype))
1133 || (!xdr_vldbentry(&z_xdrs, newentry))
1134 || (!xdr_long(&z_xdrs, &ReleaseType))) {
1135 z_result = RXGEN_CC_MARSHAL;
1139 z_result = RXGEN_SUCCESS;
1141 return rx_EndCall(z_call, z_result);
1144 int StartVL_ReplaceEntry(z_call, Volid, voltype, newentry, ReleaseType)
1145 register struct rx_call *z_call;
1146 long Volid, voltype, ReleaseType;
1147 vldbentry * newentry;
1149 static int z_op = 506;
1153 xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1155 /* Marshal the arguments */
1156 if ((!xdr_int(&z_xdrs, &z_op))
1157 || (!xdr_long(&z_xdrs, &Volid))
1158 || (!xdr_long(&z_xdrs, &voltype))
1159 || (!xdr_vldbentry(&z_xdrs, newentry))
1160 || (!xdr_long(&z_xdrs, &ReleaseType))) {
1161 z_result = RXGEN_CC_MARSHAL;
1165 z_result = RXGEN_SUCCESS;
1170 int EndVL_ReplaceEntry(z_call)
1171 register struct rx_call *z_call;
1176 z_result = RXGEN_SUCCESS;
1181 int VL_ListAttributes(z_conn, attributes, nentries, bulkentries_1)
1182 register struct rx_connection *z_conn;
1183 VldbListByAttributes * attributes;
1185 bulkentries * bulkentries_1;
1187 struct rx_call *z_call = rx_NewCall(z_conn);
1188 static int z_op = 511;
1192 xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1194 /* Marshal the arguments */
1195 if ((!xdr_int(&z_xdrs, &z_op))
1196 || (!xdr_VldbListByAttributes(&z_xdrs, attributes))) {
1197 z_result = RXGEN_CC_MARSHAL;
1201 /* Un-marshal the reply arguments */
1202 z_xdrs.x_op = XDR_DECODE;
1203 if ((!xdr_long(&z_xdrs, nentries))
1204 || (!xdr_bulkentries(&z_xdrs, bulkentries_1))) {
1205 z_result = RXGEN_CC_UNMARSHAL;
1209 z_result = RXGEN_SUCCESS;
1211 return rx_EndCall(z_call, z_result);
1214 int VL_LinkedList(z_conn, attributes, nentries, linkedentries)
1215 register struct rx_connection *z_conn;
1216 VldbListByAttributes * attributes;
1218 vldb_list * linkedentries;
1220 struct rx_call *z_call = rx_NewCall(z_conn);
1221 static int z_op = 512;
1225 xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1227 /* Marshal the arguments */
1228 if ((!xdr_int(&z_xdrs, &z_op))
1229 || (!xdr_VldbListByAttributes(&z_xdrs, attributes))) {
1230 z_result = RXGEN_CC_MARSHAL;
1234 /* Un-marshal the reply arguments */
1235 z_xdrs.x_op = XDR_DECODE;
1236 if ((!xdr_long(&z_xdrs, nentries))
1237 || (!xdr_vldb_list(&z_xdrs, linkedentries))) {
1238 z_result = RXGEN_CC_UNMARSHAL;
1242 z_result = RXGEN_SUCCESS;
1244 return rx_EndCall(z_call, z_result);
1247 Notice the side effect of the C<multi> feature (three different modules
1248 for C<ReplaceEntry> proc).
1250 =head3 Server-Side stub routines (vldbint.ss.c)
1252 /* Machine generated file -- Do NOT edit */
1256 #include <afs/rxgen_consts.h>
1257 #include "vldbint.h"
1259 #include "vl_opcodes.h" /* directly to other places */
1261 long _VL_CreateEntry(z_call, z_xdrs)
1262 struct rx_call *z_call;
1269 if ((!xdr_long(z_xdrs, &Volid))
1270 || (!xdr_vldbentry(z_xdrs, &newentry))) {
1271 z_result = RXGEN_SS_UNMARSHAL;
1275 z_result = VL_CreateEntry(z_call, Volid, &newentry);
1280 long _VL_GetEntryByName(z_call, z_xdrs)
1281 struct rx_call *z_call;
1285 char *volumename = (char *)0;
1288 if ((!xdr_string(z_xdrs, &volumename, 65))) {
1289 z_result = RXGEN_SS_UNMARSHAL;
1293 z_result = VL_GetEntryByName(z_call, &volumename, &entry);
1294 z_xdrs->x_op = XDR_ENCODE;
1295 if ((!xdr_vldbentry(z_xdrs, &entry)))
1296 z_result = RXGEN_SS_MARSHAL;
1298 z_xdrs->x_op = XDR_FREE;
1299 if (!xdr_string(z_xdrs, &volumename, 65)) goto fail1;
1302 return RXGEN_SS_XDRFREE;
1305 long _VL_GetNewVolumeId(z_call, z_xdrs)
1306 struct rx_call *z_call;
1313 if ((!xdr_long(z_xdrs, &bumpcount))) {
1314 z_result = RXGEN_SS_UNMARSHAL;
1318 z_result = VL_GetNewVolumeId(z_call, bumpcount, &newvolumid);
1319 z_xdrs->x_op = XDR_ENCODE;
1320 if ((!xdr_long(z_xdrs, &newvolumid)))
1321 z_result = RXGEN_SS_MARSHAL;
1326 long _VL_ReplaceEntry(z_call, z_xdrs)
1327 struct rx_call *z_call;
1331 long Volid, voltype, ReleaseType;
1334 if ((!xdr_long(z_xdrs, &Volid))
1335 || (!xdr_long(z_xdrs, &voltype))
1336 || (!xdr_vldbentry(z_xdrs, &newentry))
1337 || (!xdr_long(z_xdrs, &ReleaseType))) {
1338 z_result = RXGEN_SS_UNMARSHAL;
1342 z_result = VL_ReplaceEntry(z_call, Volid, voltype, &newentry,
1348 long _VL_ListAttributes(z_call, z_xdrs)
1349 struct rx_call *z_call;
1353 VldbListByAttributes attributes;
1355 bulkentries bulkentries_1;
1357 if ((!xdr_VldbListByAttributes(z_xdrs, &attributes))) {
1358 z_result = RXGEN_SS_UNMARSHAL;
1362 z_result = VL_ListAttributes(z_call, &attributes, &nentries,
1364 z_xdrs->x_op = XDR_ENCODE;
1365 if ((!xdr_long(z_xdrs, &nentries))
1366 || (!xdr_bulkentries(z_xdrs, &bulkentries_1)))
1367 z_result = RXGEN_SS_MARSHAL;
1369 z_xdrs->x_op = XDR_FREE;
1370 if (!xdr_bulkentries(z_xdrs, &bulkentries_1)) goto fail1;
1373 return RXGEN_SS_XDRFREE;
1376 long _VL_LinkedList(z_call, z_xdrs)
1377 struct rx_call *z_call;
1381 VldbListByAttributes attributes;
1383 vldb_list linkedentries;
1385 if ((!xdr_VldbListByAttributes(z_xdrs, &attributes))) {
1386 z_result = RXGEN_SS_UNMARSHAL;
1390 z_result = VL_LinkedList(z_call, &attributes, &nentries,
1392 z_xdrs->x_op = XDR_ENCODE;
1393 if ((!xdr_long(z_xdrs, &nentries))
1394 || (!xdr_vldb_list(z_xdrs, &linkedentries)))
1395 z_result = RXGEN_SS_MARSHAL;
1400 long _VL_CreateEntry();
1401 long _VL_GetEntryByName();
1402 long _VL_GetNewVolumeId();
1403 long _VL_ReplaceEntry();
1404 long _VL_ListAttributes();
1405 long _VL_LinkedList();
1407 static long (*StubProcsArray0[])() = {_VL_CreateEntry,
1408 _VL_GetEntryByName, _VL_GetNewVolumeId, _VL_ReplaceEntry,
1409 _VL_ListAttributes, _VL_LinkedList};
1411 VL_ExecuteRequest(z_call)
1412 register struct rx_call *z_call;
1418 xdrrx_create(&z_xdrs, z_call, XDR_DECODE);
1419 if (!xdr_int(&z_xdrs, &op))
1420 z_result = RXGEN_DECODE;
1421 else if (op < VL_LOWEST_OPCODE || op > VL_HIGHEST_OPCODE)
1422 z_result = RXGEN_OPCODE;
1424 z_result = (*StubProcsArray0[op - VL_LOWEST_OPCODE])
1429 If there were gaps in the procedures' opcode sequence the code for
1430 VL_ExecuteRequest() routine would be have been drastically different (it
1431 would have been a case statement for each procedure).
1435 B<rxgen> is implemented from Sun's B<rpcgen> utility. All of the standard
1436 B<rpcgen>'s functionality is fully maintained. Note that some active
1437 B<rpcgen> options that don't apply to B<rxgen>'s purpose aren't referenced
1438 here (i.e., B<-s>, B<-l>, B<-m> options) and the interested reader should
1439 refer to rpcgen(1) for details.
1441 When the C<%#include <include file>> feature is used make sure that you
1442 don't have any B<rxgen> language features (i.e. %#defines) since you'll
1443 get syntax errors during compilations..
1445 Since this is an ongoing project many of the above may change/disappear
1446 without a major warning.
1450 I<Rxgen Syntax Summary>: Summary description of rxgen's grammar.
1452 I<Rpcgen Programming Guide>: Sun's RPC protocol compiler. B<rxgen> was
1453 implemented as an extension to that compiler.
1455 I<External Data Representation: Sun Technical Notes>: Detailed examples in
1458 I<RPCL Syntax Summary>: Summary of Sun's Remote Procedure Call Language.
1460 I<Rx>: An extended Remote Procedure Call Protocol.
1462 I<rgen>: An earlier version of a similar stub generator used for the R RPC
1467 IBM Corporation 2000. <http://www.ibm.com/> All Rights Reserved.
1469 This documentation is covered by the IBM Public License Version 1.0. It
1470 was converted from the original TeX B<rxgen> manual to POD by Russ