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<-dkp>]
11 [B<-I> I<dir>] [B<-P> I<prefix>] [B<-o> I<outfile>] [I<infile>]
18 B<rxgen> is a tool that generates C code to implement the Rx RPC protocol;
19 it takes as input a description of an application interface similar to C
20 and produces a number of server and/or client stub routines to be linked
21 with RPC-based programs. These stubs allow programs to invoke remote
22 procedures through local procedure calls. B<rxgen> is based on Sun's
23 B<rpcgen> (version 3.9) but does not maintain compatibility with rpcgen
28 B<rxgen> operates in several different modes. The generated output files
29 can be produced individually (using one of B<-h>, B<-c>, B<-C>, or B<-S>)
30 or 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>
32 and B<-S>) when the B<-r> flag is used. The following describes the types
33 of generated output files (for simplicity, I<filename> refers to the main
40 Generate C data definitions (a header file) from standard RPCL definitions
41 (default extension: I<filename>.h).
45 Compile the XDR routines required to serialize the protocol described by
46 RPCL. Generate XDR routines for all declarations (default extension:
51 Generate all the client-side stub routines (default extension:
52 I<filename>.cs.c). Calling a routine in this file will cause the
53 arguments to be packed up and sent via Rx (or R).
57 Generate all the server-side stub routines (default extension:
58 I<filename>.ss.c). Arguments are unpacked, and the corresponding server
63 Generate the two default extension files produced by the B<-C> and B<-S>
68 The following options can be used on any combination of B<rxgen> calls:
74 Must be specified when the generated code is intended to be used by the
75 kernel; special "includes" and other specifics are produced when the
76 target output is for the kernel.
80 Package combination flag: when multiple packages are included within a
81 single specification file, a single Execute Request routine will be used
82 for all of them as a result of this flag. The default is to generate
83 individual Execute Request stubs for each package.
87 Similar to the B<-I> flag in the C compiler (B<cc>). This flag is passed
88 to the pre-processor (B<cpp>) so that directory I<dir> is searched before
89 the standard lookup list for #include files. As expected, multiple B<-I>
90 flags can be used simultaneously.
94 The I<prefix> string following this switch is prepended to all generated
95 output files; useful when multiple runs want to produce different versions
96 of the same interface (say, kernel and non-kernel versions).
100 Debugging mode; only needed when B<rxgen> is to be debugged (say, via
103 =item B<-o> I<outfile>
105 Specify the name of the output file. If none is specified, the standard
106 output is used (B<-c>, B<-h>, B<-C>, and B<-S> modes only). Note that if
107 an output file is specified in a multi-output file option (such as the
108 default, or with option B<-r>), then the I<outfile> replaces the name
109 generated by default (which is based on the configuration's main file
114 =head1 B<rxgen> SYNTAX SUMMARY
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>
125 <Package description option>:
127 "package" <Package_ident>
129 <Prefix description option>:
131 "prefix" <Prefix_ident>
133 <StartingOpcode description option>:
135 "startingopcode" <constant>
137 <SplitPrefix description option>:
139 "splitprefix" <split options> ";"
143 "IN =" <Start_prefix_ident> "|"
144 "OUT =" <End_prefix_ident> "|"
147 <Procedure description option>:
149 ["proc"] [<Procedure_ident>] [<ServerStub_ident>]
150 <Argument list> ["split" | "multi"]
151 ["=" <Opcode_ident>] ";"
155 "(" <Argument definition> <Comma_joined argument> ")"
157 <Argument definition>:
159 <Direction option> <Standard RPCL type decl> <Arg_ident>
160 ["<" <Max_size> ">" | "[" <Max_size> "]"] | NULL
162 <Comma_joined argument>:
164 "," <Argument definition> | NULL
168 "IN" | "OUT" | "INOUT" | NULL
177 <Start_prefix_ident>:
186 <RPCL language description option>:
187 <Standard RPCL type decl>:
189 Sun's RPCL language syntax (see rpcgen(1))
191 =head1 B<rxgen> COMMANDS
193 =head2 Comments and Preprocessing
195 The input interface may contain preprocessor directives which are passed
196 through the C preprocessor (i.e. C<cpp>). Since the preprocessor runs on
197 all input files before they are actually interpreted by B<rxgen>, all
198 B<cpp> directives (#include, #ifdefs, #defines, etc.) are legal and
199 welcomed within an B<rxgen> input file. Of course, none of these
200 preprocessor directives will be included in any of the generated files.
201 To facilitate distinctions between the different types of output files,
202 B<rxgen> defines certain special B<cpp> symbols for use by the B<rxgen>
203 programmer. These are RPC_HDR (defined when compiling into header,
204 I<filename>.h, files), RPC_XDR (defined when compiling into xdr,
205 I<filename>.xdr.c, files), RPC_CLIENT (defined when compiling into client
206 stubs, I<filename>.cs.c, files), and RPC_SERVER (defined when compiling
207 into server stubs, I<filename>.ss.c, files).
209 In addition, B<rxgen> does a little preprocessing of its own. Any line
210 beginning with C<%> is passed directly into the output file, uninterpreted
211 by B<rxgen>. For a more heavy en masse dumping of uninterpreted code, it
212 would be advised to include all such code in an C<#include> file and pass
213 it in preceded by C<%>. The input interface may also contain any C-style
214 comments which are, of course, ignored. Interpretation is token-based,
215 thus special line-orientation of separate statements is not necessary.
216 B<rxgen> also provides a quite rich and helpful set of error reports,
217 identifying them by exact line location and error type. Also, B<rxgen>
218 will automatically generate #include lines for standard include files,
219 such as F<rx/xdr.h> and F<rx/rx.h>, along with the generated header file
222 =head2 Prefixing stub procedures
224 The I<package> statement tells B<rxgen> the name of the interface package.
225 It is used for prefixing the naming of all generated stub routines and the
226 execute request procedure. For example:
230 causes the execute request procedure to be named AFS_ExecuteRequest
231 (Warning: in the older version an additional C<_> was appended after the
232 package name to the ExecuteRequest name; thus make sure you don't have an
233 ExecuteRequest interface routine) and a given stub routine, say Fetch, to
234 be actually named AFS_Fetch. Multiple package statements (current maximum
235 size is 10) per configuration are permitted and are useful when multiple
236 sets of interfaces are implemented (see the example at the end). Note
237 that in such cases, use of the B<-p> flag results in the generation of
238 just one ExecuteRequest procedure which recognizes the multiple interfaces
239 and whose name is prefixed by the first package statement. In the default
240 case, independent ExecuteRequest procedures will be created for each
241 packaged group of remote procedure calls.
243 The I<prefix> statement supplies a name to prepend to all calls to remote
244 procedure names in the ExecuteRequest stub routine. It is useful when the
245 server makes RPC calls to other servers (say, for debugging purposes).
250 causes the name C<S> to be prepended to the name of all routines called
251 from the server stubs. The server can then call the original name and get
254 =head2 B<rxgen> procedure declaration
256 The I<proc> statement is the most common (and meaningful) in the B<rxgen>
257 interface. Its syntax description is:
259 [proc] [<proc_name>] [<server_stub>] (<arg>, ..., <arg>)
260 [split | multi] [= <opcode>] ;
268 C<proc> is an optional prefix of the procedure statement. This is just a
269 stylistic item and not a required procedure delimiter.
273 <proc_name> is the name of the procedure. Note that even the name of the
274 procedure is optional. This only makes sense when the name of the given
275 procedure is identical to the name of the last I<package> statement (i.e.,
276 C<package RCallBack> and the declaration of the C<RCallBack> procedure).
280 <server_stub>, if present, causes the ExecuteRequest procedure to call
281 that stub instead of the automatically generated stub when a call with
282 that opcode is decoded.
286 <opcode> is a constant or symbol that is the opcode for that procedure.
287 One might use the preprocessor features (i.e., #define), the I<const>
288 RPC-language feature, or the old good constants as opcodes. Some further
289 evaluation/processing of opcodes is done. Particularly, checks for
290 duplicate and non-existent opcodes are performed, along with checks for
291 "holes" (i.e., gaps in consecutive opcodes) in the opcode sequences. For
292 example, we use the fact that when "holes" in opcodes exist, the
293 ExecuteRequest procedure uses the I<case> statement rather than the faster
294 (and smaller, codewise) indexed array method.
296 Also, B<rxgen> defines (i.e., appends to the header file) three valuable
297 macros for each package group: <package-name>LOWEST_OPCODE,
298 <package-name>HIGHEST_OPCODE, and <package-name>NUMBER_OPCODES. These may
299 be useful to the B<rxgen> programmer. Also, notice that the I<opcode>
300 statement is an optional feature, and can be omitted. In such cases,
301 automatic opcode numbers are generated sequentially, starting from 0.
303 One can change the initial opcode number by using the I<startingopcode>
304 (for lack of a better name) B<rxgen> command. Its syntax is:
306 startingopcode <constant>
308 where <constant> must be reasonable! Note that one can not mix
309 procedures, some with opcodes and some without, nor allow opcodes after
310 the specification of the I<startingopcode> statement. B<rxgen> will
311 complain in all such cases.
315 The I<argument> entry represents a given parameter of the procedure. Its
318 [IN | INOUT | OUT | <null>] <type_decl> <arg_name>
321 If the type is an indirect type (i.e., is followed by *), it is assumed
322 that the pointer should be followed one level and the data pointed to is
323 to be transmitted. This should normally be used for all structures/arrays
324 and out parameters. A noticeable exception is when explicit
325 array/structure maximum size is given; since no array-of-pointer
326 declarations are allowed one should use typedefs to achieve the similar
327 effect. The parameters could be input parameters (preceded by IN), output
328 parameters (preceded by OUT), or input/output parameters (preceded by
329 INOUT). If not specified, then the direction of the previous parameter in
330 the procedure is used. (Note: the first parameter must be preceded by the
331 directional primitive!)
335 C<split> is a hack to handle stub routines that do things such as file
336 transfers or any other operation that has to exchange information (e.g.,
337 length of a file) before the call returns its output parameters. Because
338 of the particular handshake that is involved when doing remote file
339 transfer, we currently break all such calls into two client-side stub
340 routines. The first (with the default prefix of C<Begin>) is used to pass
341 all IN and INOUT parameters to the server side. The second (with the
342 default prefix of C<End>) is used to get back the INOUT and OUT parameters
343 from the server. Between the two calls, the user is supposed to do the
344 appropriate calls for the file transfer. For example, the following
345 procedure declaration in package AFS_
347 Fetch (IN a, b,INOUT c, OUT d) split = FETCHOPCODE;
349 will roughly generate the two independent client stub routines:
351 BeginAFS_Fetch (IN a, b, c)
355 EndAFS_Fetch(OUT c, d)
357 The I<splitprefix> statement is used to change the default prefix names
358 used by the two client-side stub generated routines when dealing with file
359 transfer-related procedure calls. For example:
361 splitprefix IN=Before_ OUT=After_
363 will cause the naming of the two client stubs for a file transfer-related
364 routine, say Fetch(), to be Before_AFS_Fetch() and After_AFS_Fetch(),
369 The C<multi> option is nearly identical to the C<split> feature described
370 above. The only significant visible difference is that along with the two
371 client stubs, the standard client stub is also generated. Since the
372 intention is to handle the multi-Rx calls, we need the whole standard
373 procedure stub in the cases where no multi-Rx call of the procedure is
374 performed. A side effect of the C<multi> option is the generation of a
375 special macro (i.e., C<< multi_<Procedure-name> >> which passes back as
376 arguments the C<Begin> and C<End> stubs in the header output file. This
377 macro is used directly by the Rx code when a multi-Rx call of this
378 procedure is performed.
382 =head2 OBSOLETE B<rxgen> FEATURES
384 Although the following rxgen commands are still in effect, they will soon
385 be removed since there are better alternatives. DO NOT USE THEM!
387 The I<special> statement is a temporary hack used to handle certain
388 inefficiencies of standard xdr routines to handle some user-customized
389 declarations. In particular, this applies to a string pointer specified
390 as part of a declaration. For example,
392 special struct BBS SeqBody;
394 tells B<rxgen> that the entry C<SeqBody> in the user-defined BBS xdr
395 routine is a string (note that more than one string can be "special" per
396 structure -- multiple ones are separated by commas); it will thus allocate
397 and de-allocate space properly in the server-generated stubs that contain
398 this structure as an IN or INOUT parameter.
400 A better alternative to I<special> is the I<customized> statement, which
401 is simply the C<customized> token followed by the regular declaration of a
402 struct based on the RPCL rules. In this case, the declaration will be
403 included in the generated header file (B<-h> option) but no xdr routine
404 will be generated for this structure -- the user will supply this. All
405 pointer entries in this structure will be remembered so when the structure
406 is used as an IN or INOUT in the server stub, no core leaks will occur.
407 For example, consider
409 customized struct CBS {
414 The C<xdr_CBS> routine would be provided by the user where during the
415 DECODE xdr opcode, appropriate space for the C<SeqBody> string is
416 allocated. Similarly, that space is freed during the FREE xdr opcode.
418 Note: Old style "Array parameter specifications" are not supported any
423 In case there are some requirements not available by the current RPC
424 language, one can customize some XDR routines by leaving those data types
425 undefined. For every data type that is undefined, it will be assumed that
426 a routine exists with the name C<xdr_> prepended to it. A selected set of
427 B<rxgen> features is presented below, but for a more comprehensive one
428 (unions, complex examples, etc) please refer to the I<rpcgen Programming
429 Guide> and I<eXternal Data Representation: Sun Technical Notes>.
433 The RPC typedef statement is identical to the C typedef (i.e. C<< typedef
434 <declaration> >>). By default, most user declarations (i.e. structs,
435 unions, etc) are automatically typedef'ed by B<rxgen>. Since it makes
436 parsing simpler, its usage is recommended by B<rxgen> scripts.
440 The C C<char *> string convention is kind of ambiguous, since it is
441 usually intended to mean a null-terminated string of characters, but it
442 could also represent a pointer to a single character, a pointer to an
443 array of characters, etc. In the RPC language, a null-terminated string
444 is unambiguously called a "string". Examples,
447 string name<MAXNAMELEN>;
448 typedef string volname<MAXVOLNAME>;
450 Notice that the maximum size of string can be arbitrary (like C<bigname>
451 above) or, preferably, or specified in angle brackets (i.e. C<name> and
452 C<volname> above). In practice, one should always use only bounded
453 strings in interfaces. A sample calling proc using the declarations above
456 GetEntryByName (IN volname name,
457 OUT struct vldbentry *entry) = VL_GETENTRYBYNAME;
461 GetEntryByName (IN string volname<MAXVOLNAME>,
462 OUT struct vldbentry *entry) = VL_GETENTRYBYNAME;
464 It is very important for the user to understand when the string parameters
465 should be allocated and/or freed by the his/her client and/or server
466 programs. A short analysis on string parameters handling follows (note
467 that a similar method is used for the handling of variable length arrays
468 as it will be shown later on):
474 In the client side: IN and INOUT string parameters are the programmer's
475 responsibility and should be allocated (static or via malloc) before
476 calling the rpc and freed (if malloc was used) after the rpc's return in
477 the user's client program; of course, for INOUT parameters, the returned
478 string can't be bigger than the malloced input string.
480 OUT string parameters are automatically malloced (based on the length of
481 the returned string and not the maxsize) by the B<rxgen> client stubs (in
482 I<filename>.cs.c) and must be freed by the client program; admittedly,
483 this could be somewhat confusing since the user needs to free something
484 that he/she didn't allocate.}
488 In the server side: IN and INOUT string parameters are automatically
489 malloced (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
491 procedure; that space is automatically freed just before the rxgen server
492 stub returns; therefore the user need not do anything special for IN and
493 INOUT string parameters.
495 OUT 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
497 automatically freed at the end of the B<rxgen> server stub. Like in the
498 client side, the OUT parameters are somewhat unorthodox (i.e. the server
499 routine must malloc a string without ever freeing it itself; this is done
500 by the B<rxgen> server stub).
504 Note that for INOUT and OUT string parameters, in both the client and
505 server sides their arguments must be char of pointers (i.e. char **).
509 Pointer 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
511 pointers over the network, but one can use XDR pointers for sending
512 recursive data types such as lists and trees (an example of a linked list
513 will be demonstrated shortly).
517 Fixed arrays are just like standard C array declarations (i.e. C<struct
518 UpdateEntry entries[20]>) without any side effect problems in
519 B<rxgen>. Since variable-length arrays have no explicit syntax in C, the
520 angle-brackets are used for it and the array declarations are actually
521 compiled into "struct"s. For example, declarations such as:
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 */
529 are compiled into the following structs:
532 u_int bulk_len; /* no of items */
533 char *bulk_val; /* pointer to array */
536 for the C<bulk> array, and similarly for the C<< blkentries<100> >> array,
539 u_int blkentries_len; /* no of items in array */
540 vldbentry *blkentries_val; /* pointer to array */
543 Therefore the user should be aware of the "magically" generated structure
544 entries such as the number of items in the array (<array_name>_len) and
545 the pointer to the array (<array_name>_val) since some of the entries will
546 have to be filled in from the client/server programs. A sample proc would
549 typedef vldbentry blkentries<MAXENTRIES>;
550 proc GetBlk (OUT blkentries *vlentries) = VL_GETBLK;
554 GetBlk(OUT vldbentry vlentries<MAXENTRIES>) = VL_GETBLK;
556 Note that although the latest method is preferable since one does not have
557 to first use the typedef statement (and admittedly, programmers prefer
558 avoiding typedefs), one should realize that B<rxgen> does the structure
559 expansion and the xdr creation implicitly; therefore the user should be
560 aware of the C<vldbentries_val> and C<vldbentries_len> fields as before
561 (see following examples).
563 =head3 Array example I (least desirable)
565 Procedure declaration in the interface configuration:
567 proc ListAttributes (IN vldblistbyattributes *attributes,
568 INOUT blkentries *vldbentries) = VL_LISTATTRIBUTES;
572 blkentries entries, *pnt;
573 entries.blkentries_len = 10; /* max # returned entries */
574 entries.blkentries_val = (vldbentry *)malloc(LEN);
577 code = VL_ListAttributes(&attributes, &entries);
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);
588 VL_ListAttributes(attributes, entries)
590 vldbentry *singleentry = entries->blkentries_val;
591 entries->blkentries_len = 0;
593 while (copy_to_vldbentry(&vlentry, singleentry))
594 singleentry++, vldbentries->entries_len++;
597 Although this method for variable-size arrays works fine, there are some
598 major drawbacks. The array parameter (i.e. vldbentries above) must be
599 declared as INOUT since we need to pass the max length of the expected
600 returned array; more importantly, a big (depending on the value of
601 C<_len>) chunk of junk code is going to be transferred to the server as
602 result of the IN(out) side-effect of the array. It's an easy and
603 convenient method if the returned array size can be predicted from the
604 start and when the size is quite high. This method is included as an
605 example of erroneous use (and abuse) of B<rxgen> and should not be used.
607 =head3 Array example II (Desirable method)
609 Procedure declaration in the interface configuration (using Example I
612 proc ListAttributes (IN vldblistbyattributes *attributes,
613 OUT blkentries *vldbentries) = VL_LISTATTRIBUTES;
617 blkentries entries, *pnt;
619 code = VL_ListAttributes(&attributes, &entries);
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);
630 VL_ListAttributes(attributes, entries)
632 vldbentry *singleentry;
633 entries->blkentries_len = 0;
634 singleentry = entries->blkentries_val
635 = (vldbentry *)malloc(MAXENTRIES * sizeof(vldbentry));
637 while (copy_to_vldbentry(&vlentry, singleentry))
638 singleentry++, vldbentries->entries_len++;
641 This is the best (and simplest) way of using variable-size arrays as an
642 output parameter. It is the responsibility of the server-side stub to
643 malloc() the adequate space which is automatically freed by the B<rxgen>
644 stub; the client side should free the space allocated by the
645 B<rxgen>-calling stub.
647 =head3 Array example III (Linked Lists)
649 Considering the following 3 declarations (could have applied some
650 optimizations) in the configuration file:
652 typedef struct single_vldbentry *vldblist;
653 struct single_vldbentry {
662 and the rxgen procedure declaration:
664 LinkedList (IN vldblistbyattributes *attributes,
665 OUT vldb_list *linkedentries) = VL_LINKEDLIST;
669 vldb_list linkedvldbs;
670 vldblist vllist, vllist1;
672 bzero(&linkedvldbs, sizeof(vldb_list));
673 code = VL_LinkedList(&attributes, &nentries, &linkedvldbs);
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);
685 VL_LinkedList(rxcall, attributes, nentries, linkedvldbs);
687 vldblist vllist, *vllistptr = &linkedvldbs->node;
690 = (single_vldbentry *)malloc (sizeof (single_vldbentry));
691 copy_to_vldbentry(&tentry, &vllist->vlentry);
693 vllistptr = &vllist->next_vldb;
698 Using a linked list offers many advantages: Nothing is passed to the
699 server (the parameter is OUT), no additional overhead is involved, and the
700 caller doesn't have to explicitly prepare for an arbitrary return size. A
701 drawback is that the caller has the responsibility of malloc() (on the
702 server) and free (on the client) of each entry (to avoid unwanted
703 core-leaks). Another drawback is that since it's a recursive call, the C
704 stack 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
706 expected back -- default stack size is 4K). The advantages should
707 outweigh the disadvantages here.
709 It's important to pay attention to the comments of the three array
710 examples above particularly when they're references to when the user
711 should allocate/free space for the variable length arrays. The mechanism
712 is very similar to the handling of strings thus you might need to review
713 the strings section above; note that the linked lists are handled somewhat
716 =head2 Miscellaneous examples
718 Below is an abbreviated version of a random interface file which shows
719 some of the common cases.
721 /* Declaration of all structures used by the R.xg script interface */
724 unsigned long Volume;
726 unsigned long Unique;
729 typedef long ViceDataType;
731 /* Note that TEST would be equivalent to "HEADER" only during the
732 processing of the header, *.h, file */
735 #define TEST "HEADER"
740 /* This is the standard *.xg specification file */
743 splitprefix IN=BEFORE_ OUT=AFTER_;
746 proc Remove(IN struct AFSFid *Did, IN string volname<64>,
747 OUT struct AFSStatus *Status) = AFS_REMOVE;
749 DisconnectFS AUX_disconnectFS() = AFS_DISCONNECTFS;
751 proc GetVolumeInfo(IN string Vid,
752 OUT struct VolumeInfo *Info) = AFS_GETVOLUMEINFO;
754 /* You could have more than an interface per configuration */
758 /* Using the "multi" feature; thus VOTE_Beacon can be called as an
759 multi-Rx call or as a regular call */
761 Beacon (IN long state, long voteStart,
762 net_version *version, net_tid *tid)
767 /* Using the "split" feature */
769 SendFile (IN long file, long offset,
770 long length, net_version *version)
771 split = DISK_SENDFILE;
773 =head2 Output of an actual interface configuration
775 We'll demonstrate some of the actual output generated by B<rxgen> by
776 following an abbreviated actual interface configuration.
778 =head3 Configuration file
780 Contents of the interface configuration file (F<vldbint.xg>):
783 #include "vl_opcodes.h" /* The opcodes are included here */
784 %#include "vl_opcodes.h" /* directly to other places */
786 /* Current limitations on parameters that affect other packages
789 const MAXNAMELEN = 65;
790 const MAXNSERVERS = 8;
793 /* External (visible) representation of an individual vldb entry */
796 char name[MAXNAMELEN];
799 long serverNumber[MAXNSERVERS];
800 long serverPartition[MAXNSERVERS];
801 long serverFlags[MAXNSERVERS];
802 u_long volumeId[MAXTYPES];
806 typedef struct single_vldbentry *vldblist;
807 struct single_vldbentry {
816 /* vldb interface calls */
818 CreateEntry (IN long Volid,
819 vldbentry *newentry) = VLCREATEENTRY;
821 GetEntryByName (IN string volumename<MAXNAMELEN>,
822 OUT vldbentry *entry) = VLGETENTRYBYNAME;
824 GetNewVolumeId (IN long bumpcount,
825 OUT long *newvolumid) = VLGETNEWVOLUMEID;
827 ReplaceEntry (IN long Volid,
830 long ReleaseType) multi = VLREPLACEENTRY;
832 ListAttributes (IN VldbListByAttributes *attributes,
834 OUT vldbentry bulkentries<MAXVLDBLEN>)
837 LinkedList (IN VldbListByAttributes *attributes,
839 OUT vldb_list *linkedentries) = VLLINKEDLIST;
841 For a detailed description on the Rx-related calls inside the generated
842 stubs (i.e., rx_NewCall(), rx_EndCall()), along with details on what happens
843 inside certain calls (like xdrrx_create()) please refer to the Rx
844 documentation. Typing C<rxgen vldbint.xg> will result in the creation of
845 four files: F<vldbint.h>, F<vldbint.xdr.c>, F<vldbint.cs.c> and
846 F<vldbint.ss.c>. A closer look at these files follows.
848 =head3 Header file (F<vldbint.h>)
850 /* Machine generated file -- Do NOT edit */
852 #include "vl_opcodes.h" /* directly to other places */
853 #define MAXNAMELEN 65
854 #define MAXNSERVERS 8
858 char name[MAXNAMELEN];
861 long serverNumber[MAXNSERVERS];
862 long serverPartition[MAXNSERVERS];
863 long serverFlags[MAXNSERVERS];
864 u_long volumeId[MAXTYPES];
867 typedef struct vldbentry vldbentry;
868 bool_t xdr_vldbentry();
870 typedef struct single_vldbentry *vldblist;
871 bool_t xdr_vldblist();
873 struct single_vldbentry {
877 typedef struct single_vldbentry single_vldbentry;
878 bool_t xdr_single_vldbentry();
883 typedef struct vldb_list vldb_list;
884 bool_t xdr_vldb_list();
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))
891 typedef struct bulkentries {
892 u_int bulkentries_len;
893 vldbentry *bulkentries_val;
895 bool_t xdr_bulkentries();
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
902 Notice that all structures are automatically typedef'ed and all C<const>s
903 are converted to C<#define>s. Some data structures, such as bulkentries,
904 are taken from procedure params (from ListAttributes proc). Thus, this
905 should be kept in mind when creating stubs piecemeal with B<rxgen> (i.e.,
906 using the B<-c>, B<-h>, B<-C>, or B<-S> flags). Also, one of the side
907 effects of the C<multi> option (in C<ReplaceEntry> proc) is the generation
908 of the C<multi_VL_ReplaceEntry> above.
910 =head3 XDR routines for structures (vldbint.xdr.c)
912 /* Machine generated file -- Do NOT edit */
917 #include "vl_opcodes.h" /* directly to other places */
920 xdr_vldbentry(xdrs, objp)
924 if (!xdr_vector(xdrs, (char *)objp->name, MAXNAMELEN,
925 sizeof(char), xdr_char))
927 if (!xdr_long(xdrs, &objp->volumeType))
929 if (!xdr_long(xdrs, &objp->nServers))
931 if (!xdr_vector(xdrs, (char *)objp->serverNumber, MAXNSERVERS,
932 sizeof(long), xdr_long))
934 if (!xdr_vector(xdrs, (char *)objp->serverPartition,
935 MAXNSERVERS, sizeof(long), xdr_long))
937 if (!xdr_vector(xdrs, (char *)objp->serverFlags, MAXNSERVERS,
938 sizeof(long), xdr_long))
940 if (!xdr_vector(xdrs, (char *)objp->volumeId, MAXTYPES,
941 sizeof(u_long), xdr_u_long))
943 if (!xdr_long(xdrs, &objp->flags))
949 xdr_vldblist(xdrs, objp)
953 if (!xdr_pointer(xdrs, (char **)objp,
954 sizeof(struct single_vldbentry),
955 xdr_single_vldbentry))
961 xdr_single_vldbentry(xdrs, objp)
963 single_vldbentry *objp;
965 if (!xdr_vldbentry(xdrs, &objp->VldbEntry))
967 if (!xdr_vldblist(xdrs, &objp->next_vldb))
973 xdr_vldb_list(xdrs, objp)
977 if (!xdr_vldblist(xdrs, &objp->node))
983 xdr_bulkentries(xdrs, objp)
987 if (!xdr_array(xdrs, (char **)&objp->bulkentries_val,
988 (u_int *)&objp->bulkentries_len, MAXVLDBLEN,
989 sizeof(vldbentry), xdr_vldbentry))
994 Note that the xdr_bulkentries() is automatically generated as a side
995 effect of a procedure parameter declaration. Thus, if identical multiple
996 type parameter declarations are used, then multiply-defined xdr_* stubs
997 will be created! We felt this was a better alternative to having the
998 B<rxgen> programmer deal with types such as bulkentries_1,
1001 =head3 Client-Side stub routines (vldbint.cs.c)
1003 /* Machine generated file -- Do NOT edit */
1007 #include <afs/rxgen_consts.h>
1008 #include "vldbint.h"
1010 #include "vl_opcodes.h" /* directly to other places */
1012 int VL_CreateEntry(z_conn, Volid, newentry)
1013 register struct rx_connection *z_conn;
1015 vldbentry * newentry;
1017 struct rx_call *z_call = rx_NewCall(z_conn);
1018 static int z_op = 501;
1022 xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
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;
1032 z_result = RXGEN_SUCCESS;
1034 return rx_EndCall(z_call, z_result);
1037 int VL_GetEntryByName(z_conn, volumename, entry)
1038 register struct rx_connection *z_conn;
1042 struct rx_call *z_call = rx_NewCall(z_conn);
1043 static int z_op = 504;
1047 xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
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;
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;
1063 z_result = RXGEN_SUCCESS;
1065 return rx_EndCall(z_call, z_result);
1068 int VL_GetNewVolumeId(z_conn, bumpcount, newvolumid)
1069 register struct rx_connection *z_conn;
1073 struct rx_call *z_call = rx_NewCall(z_conn);
1074 static int z_op = 505;
1078 xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1080 /* Marshal the arguments */
1081 if ((!xdr_int(&z_xdrs, &z_op))
1082 || (!xdr_long(&z_xdrs, &bumpcount))) {
1083 z_result = RXGEN_CC_MARSHAL;
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;
1094 z_result = RXGEN_SUCCESS;
1096 return rx_EndCall(z_call, z_result);
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;
1104 struct rx_call *z_call = rx_NewCall(z_conn);
1105 static int z_op = 506;
1109 xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
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;
1121 z_result = RXGEN_SUCCESS;
1123 return rx_EndCall(z_call, z_result);
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;
1131 static int z_op = 506;
1135 xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
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;
1147 z_result = RXGEN_SUCCESS;
1152 int EndVL_ReplaceEntry(z_call)
1153 register struct rx_call *z_call;
1158 z_result = RXGEN_SUCCESS;
1163 int VL_ListAttributes(z_conn, attributes, nentries, bulkentries_1)
1164 register struct rx_connection *z_conn;
1165 VldbListByAttributes * attributes;
1167 bulkentries * bulkentries_1;
1169 struct rx_call *z_call = rx_NewCall(z_conn);
1170 static int z_op = 511;
1174 xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1176 /* Marshal the arguments */
1177 if ((!xdr_int(&z_xdrs, &z_op))
1178 || (!xdr_VldbListByAttributes(&z_xdrs, attributes))) {
1179 z_result = RXGEN_CC_MARSHAL;
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;
1191 z_result = RXGEN_SUCCESS;
1193 return rx_EndCall(z_call, z_result);
1196 int VL_LinkedList(z_conn, attributes, nentries, linkedentries)
1197 register struct rx_connection *z_conn;
1198 VldbListByAttributes * attributes;
1200 vldb_list * linkedentries;
1202 struct rx_call *z_call = rx_NewCall(z_conn);
1203 static int z_op = 512;
1207 xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1209 /* Marshal the arguments */
1210 if ((!xdr_int(&z_xdrs, &z_op))
1211 || (!xdr_VldbListByAttributes(&z_xdrs, attributes))) {
1212 z_result = RXGEN_CC_MARSHAL;
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;
1224 z_result = RXGEN_SUCCESS;
1226 return rx_EndCall(z_call, z_result);
1229 Notice the side effect of the C<multi> feature (three different modules
1230 for C<ReplaceEntry> proc).
1232 =head3 Server-Side stub routines (vldbint.ss.c)
1234 /* Machine generated file -- Do NOT edit */
1238 #include <afs/rxgen_consts.h>
1239 #include "vldbint.h"
1241 #include "vl_opcodes.h" /* directly to other places */
1243 long _VL_CreateEntry(z_call, z_xdrs)
1244 struct rx_call *z_call;
1251 if ((!xdr_long(z_xdrs, &Volid))
1252 || (!xdr_vldbentry(z_xdrs, &newentry))) {
1253 z_result = RXGEN_SS_UNMARSHAL;
1257 z_result = VL_CreateEntry(z_call, Volid, &newentry);
1262 long _VL_GetEntryByName(z_call, z_xdrs)
1263 struct rx_call *z_call;
1267 char *volumename = (char *)0;
1270 if ((!xdr_string(z_xdrs, &volumename, 65))) {
1271 z_result = RXGEN_SS_UNMARSHAL;
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;
1280 z_xdrs->x_op = XDR_FREE;
1281 if (!xdr_string(z_xdrs, &volumename, 65)) goto fail1;
1284 return RXGEN_SS_XDRFREE;
1287 long _VL_GetNewVolumeId(z_call, z_xdrs)
1288 struct rx_call *z_call;
1295 if ((!xdr_long(z_xdrs, &bumpcount))) {
1296 z_result = RXGEN_SS_UNMARSHAL;
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;
1308 long _VL_ReplaceEntry(z_call, z_xdrs)
1309 struct rx_call *z_call;
1313 long Volid, voltype, ReleaseType;
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;
1324 z_result = VL_ReplaceEntry(z_call, Volid, voltype, &newentry,
1330 long _VL_ListAttributes(z_call, z_xdrs)
1331 struct rx_call *z_call;
1335 VldbListByAttributes attributes;
1337 bulkentries bulkentries_1;
1339 if ((!xdr_VldbListByAttributes(z_xdrs, &attributes))) {
1340 z_result = RXGEN_SS_UNMARSHAL;
1344 z_result = VL_ListAttributes(z_call, &attributes, &nentries,
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;
1351 z_xdrs->x_op = XDR_FREE;
1352 if (!xdr_bulkentries(z_xdrs, &bulkentries_1)) goto fail1;
1355 return RXGEN_SS_XDRFREE;
1358 long _VL_LinkedList(z_call, z_xdrs)
1359 struct rx_call *z_call;
1363 VldbListByAttributes attributes;
1365 vldb_list linkedentries;
1367 if ((!xdr_VldbListByAttributes(z_xdrs, &attributes))) {
1368 z_result = RXGEN_SS_UNMARSHAL;
1372 z_result = VL_LinkedList(z_call, &attributes, &nentries,
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;
1382 long _VL_CreateEntry();
1383 long _VL_GetEntryByName();
1384 long _VL_GetNewVolumeId();
1385 long _VL_ReplaceEntry();
1386 long _VL_ListAttributes();
1387 long _VL_LinkedList();
1389 static long (*StubProcsArray0[])() = {_VL_CreateEntry,
1390 _VL_GetEntryByName, _VL_GetNewVolumeId, _VL_ReplaceEntry,
1391 _VL_ListAttributes, _VL_LinkedList};
1393 VL_ExecuteRequest(z_call)
1394 register struct rx_call *z_call;
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;
1406 z_result = (*StubProcsArray0[op - VL_LOWEST_OPCODE])
1411 If there were gaps in the procedures' opcode sequence the code for
1412 VL_ExecuteRequest() routine would be have been drastically different (it
1413 would have been a case statement for each procedure).
1417 B<rxgen> is implemented from Sun's B<rpcgen> utility.
1419 When the C<%#include <include file>> feature is used make sure that you
1420 don't have any B<rxgen> language features (i.e. %#defines) since you'll
1421 get syntax errors during compilations..
1423 Since this is an ongoing project many of the above may change/disappear
1424 without a major warning.
1428 I<Rxgen Syntax Summary>: Summary description of rxgen's grammar.
1430 I<Rpcgen Programming Guide>: Sun's RPC protocol compiler. B<rxgen> was
1431 implemented as an extension to that compiler.
1433 I<External Data Representation: Sun Technical Notes>: Detailed examples in
1436 I<RPCL Syntax Summary>: Summary of Sun's Remote Procedure Call Language.
1438 I<Rx>: An extended Remote Procedure Call Protocol.
1440 I<rgen>: An earlier version of a similar stub generator used for the R RPC
1445 IBM Corporation 2000. <http://www.ibm.com/> All Rights Reserved.
1447 This documentation is covered by the IBM Public License Version 1.0. It
1448 was converted from the original TeX B<rxgen> manual to POD by Russ