Provided by: libopenafs-dev_1.8.13.2-1ubuntu1_amd64 bug

NAME

       rxgen - Stub generator for the Rx remote procedure call package

SYNOPSIS

       rxgen [-h | -c | -C | -S | -r] [-dkp]
           [-I dir] [-P prefix] [-o outfile] [infile]

DESCRIPTION

       rxgen is a tool that generates C code to implement the Rx RPC protocol; it takes as input a description
       of an application interface similar to C and produces a number of server and/or client stub routines to
       be linked with RPC-based programs.  These stubs allow programs to invoke remote procedures through local
       procedure calls.  rxgen is based on Sun's rpcgen (version 3.9) but does not maintain compatibility with
       rpcgen RPC descriptions.

OPTIONS

       rxgen operates in several different modes.  The generated output files can be produced individually
       (using one of -h, -c, -C, or -S) or collectively.  All output files are created when the default is used
       (i.e., no options), or the output is limited to the server stubs (-C and -S) when the -r flag is used.
       The following describes the types of generated output files (for simplicity, filename refers to the main
       output filename):

       -h  Generate  C  data  definitions  (a  header  file)  from standard RPCL definitions (default extension:
           filename.h).

       -c  Compile the XDR routines required to serialize the protocol described by RPCL.  Generate XDR routines
           for all declarations (default extension: filename.xdr.c).

       -C  Generate all the client-side stub routines (default extension: filename.cs.c).  Calling a routine  in
           this file will cause the arguments to be packed up and sent via Rx (or R).

       -S  Generate  all  the  server-side  stub  routines  (default  extension:  filename.ss.c).  Arguments are
           unpacked, and the corresponding server routine is called.

       -r  Generate the two default extension files produced by the -C and -S options.

       The following options can be used on any combination of rxgen calls:

       -k  Must be specified when the generated code is intended to be used by the  kernel;  special  "includes"
           and other specifics are produced when the target output is for the kernel.

       -p  Package  combination  flag: when multiple packages are included within a single specification file, a
           single Execute Request routine will be used for all of them as a result of this flag.  The default is
           to generate individual Execute Request stubs for each package.

       -I dir
           Similar to the -I flag in the C compiler (cc). This flag is passed to the pre-processor (cpp) so that
           directory dir is searched before the standard lookup list for #include files.  As expected,  multiple
           -I flags can be used simultaneously.

       -P prefix
           The  prefix  string  following  this  switch  is prepended to all generated output files; useful when
           multiple runs want to produce different versions of the same interface (say,  kernel  and  non-kernel
           versions).

       -d  Debugging mode; only needed when rxgen is to be debugged (say, via dbx).

       -o outfile
           Specify  the name of the output file.  If none is specified, the standard output is used (-c, -h, -C,
           and -S modes only).  Note that if an output file is specified in a multi-output file option (such  as
           the  default,  or  with option -r), then the outfile replaces the name generated by default (which is
           based on the configuration's main file name).

rxgen SYNTAX SUMMARY

           Specification file:

               <Package description option> |
               <Prefix description option> |
               <StartingOpcode description option> |
               <SplitPrefix description option> |
               <Procedure description option> |
               <RPCL language description option>

           <Package description option>:

               "package" <Package_ident>

           <Prefix description option>:

               "prefix" <Prefix_ident>

           <StartingOpcode description option>:

               "startingopcode" <constant>

           <SplitPrefix description option>:

               "splitprefix" <split options> ";"

           <Split options>:

               "IN =" <Start_prefix_ident> "|"
               "OUT =" <End_prefix_ident> "|"
               <Split options>

           <Procedure description option>:

               ["proc"] [<Procedure_ident>] [<ServerStub_ident>]
                   <Argument list> ["split" | "multi"]
                   ["=" <Opcode_ident>] ";"

           <Argument list>:

               "(" <Argument definition> <Comma_joined argument> ")"

           <Argument definition>:

               <Direction option> <Standard RPCL type decl> <Arg_ident>
                   ["<" <Max_size> ">" | "[" <Max_size> "]"] | NULL

           <Comma_joined argument>:

               "," <Argument definition> | NULL

           <Direction option>:

               "IN" | "OUT" | "INOUT" | NULL

           <Max_size>:

               <constant> | NULL

           <Package_ident>:
           <Prefix_ident>:
           <String_ident>:
           <Start_prefix_ident>:
           <End_prefix_ident>:
           <Procedure_ident>:
           <ServerStub_ident>:
           <Arg_ident>:
           <Opcode_ident>:

               <identifier>

           <RPCL language description option>:
           <Standard RPCL type decl>:

               Sun's RPCL language syntax (see rpcgen(1))

rxgen COMMANDS

   Comments and Preprocessing
       The input interface may contain preprocessor directives which are passed through the C preprocessor (i.e.
       "cpp").  Since the preprocessor runs on all input files before they are actually  interpreted  by  rxgen,
       all cpp directives (#include, #ifdefs, #defines, etc.) are legal and welcomed within an rxgen input file.
       Of  course,  none  of  these  preprocessor directives will be included in any of the generated files.  To
       facilitate distinctions between the different types of output files, rxgen defines  certain  special  cpp
       symbols  for  use  by  the  rxgen  programmer.   These  are  RPC_HDR (defined when compiling into header,
       filename.h, files), RPC_XDR (defined when compiling into xdr, filename.xdr.c, files), RPC_CLIENT (defined
       when compiling into client stubs, filename.cs.c, files), and  RPC_SERVER  (defined  when  compiling  into
       server stubs, filename.ss.c, files).

       In  addition,  rxgen  does  a  little  preprocessing  of  its own.  Any line beginning with "%" is passed
       directly into the  output  file,  uninterpreted  by  rxgen.   For  a  more  heavy  en  masse  dumping  of
       uninterpreted  code,  it  would  be advised to include all such code in an "#include" file and pass it in
       preceded by "%".  The input interface may also  contain  any  C-style  comments  which  are,  of  course,
       ignored.  Interpretation  is  token-based,  thus  special  line-orientation of separate statements is not
       necessary.  rxgen also provides a quite rich and helpful set of error reports, identifying them by  exact
       line  location  and  error  type.   Also,  rxgen  will automatically generate #include lines for standard
       include files, such as rx/xdr.h and rx/rx.h, along with the generated header file from this interface.

   Prefixing stub procedures
       The package statement tells rxgen the name of the interface package.  It is used for prefixing the naming
       of all generated stub routines and the execute request procedure.  For example:

           package AFS_

       causes the execute request procedure to be named AFS_ExecuteRequest (Warning: in  the  older  version  an
       additional  "_"  was appended after the package name to the ExecuteRequest name; thus make sure you don't
       have an ExecuteRequest interface routine) and a given stub routine,  say  Fetch,  to  be  actually  named
       AFS_Fetch.   Multiple package statements (current maximum size is 10) per configuration are permitted and
       are useful when multiple sets of interfaces are implemented (see the example at the end).  Note  that  in
       such  cases,  use  of  the  -p  flag results in the generation of just one ExecuteRequest procedure which
       recognizes the multiple interfaces and whose name is prefixed by the first  package  statement.   In  the
       default  case,  independent  ExecuteRequest  procedures will be created for each packaged group of remote
       procedure calls.

       The prefix statement supplies a  name  to  prepend  to  all  calls  to  remote  procedure  names  in  the
       ExecuteRequest  stub  routine.   It  is useful when the server makes RPC calls to other servers (say, for
       debugging purposes).  For example:

           prefix S

       causes the name "S" to be prepended to the name of all routines called from the server stubs.  The server
       can then call the original name and get the client stubs.

   rxgen procedure declaration
       The proc statement is the most common (and meaningful) in the rxgen interface.   Its  syntax  description
       is:

               [proc] [<proc_name>] [<server_stub>] (<arg>, ..., <arg>)
                   [split | multi] [= <opcode>] ;

       where:

       • "proc"  is  an  optional  prefix  of  the  procedure statement. This is just a stylistic item and not a
         required procedure delimiter.

       • <proc_name> is the name of the procedure.  Note that even the name of the procedure is optional.   This
         only  makes  sense  when  the  name of the given procedure is identical to the name of the last package
         statement (i.e., "package RCallBack" and the declaration of the "RCallBack" procedure).

       • <server_stub>, if present, causes the ExecuteRequest  procedure  to  call  that  stub  instead  of  the
         automatically generated stub when a call with that opcode is decoded.

       • <opcode> is a constant or symbol that is the opcode for that procedure.  One might use the preprocessor
         features  (i.e.,  #define),  the const RPC-language feature, or the old good constants as opcodes. Some
         further evaluation/processing of opcodes is done.  Particularly, checks for duplicate and  non-existent
         opcodes  are performed, along with checks for "holes" (i.e., gaps in consecutive opcodes) in the opcode
         sequences.  For example, we use the fact  that  when  "holes"  in  opcodes  exist,  the  ExecuteRequest
         procedure uses the case statement rather than the faster (and smaller, codewise) indexed array method.

         Also,  rxgen  defines  (i.e., appends to the header file) three valuable macros for each package group:
         <package-name>LOWEST_OPCODE, <package-name>HIGHEST_OPCODE, and <package-name>NUMBER_OPCODES.  These may
         be useful to the rxgen programmer.  Also, notice that the opcode statement is an optional feature,  and
         can be omitted.  In such cases, automatic opcode numbers are generated sequentially, starting from 0.

         One  can change the initial opcode number by using the startingopcode (for lack of a better name) rxgen
         command.  Its syntax is:

             startingopcode <constant>

         where <constant> must be reasonable!  Note that one can not mix procedures, some with opcodes and  some
         without,  nor  allow  opcodes  after  the  specification  of  the startingopcode statement.  rxgen will
         complain in all such cases.

       • The argument entry represents a given parameter of the procedure.  Its syntax is:

             [IN | INOUT | OUT | <null>] <type_decl> <arg_name>
                 [<max>|<>|[max]|[]]

         If the type is an indirect type (i.e., is followed by *), it is assumed  that  the  pointer  should  be
         followed  one  level and the data pointed to is to be transmitted. This should normally be used for all
         structures/arrays and out parameters.  A noticeable exception is when explicit array/structure  maximum
         size  is  given;  since no array-of-pointer declarations are allowed one should use typedefs to achieve
         the similar effect.  The parameters could be input  parameters  (preceded  by  IN),  output  parameters
         (preceded  by  OUT),  or  input/output  parameters  (preceded  by  INOUT).   If not specified, then the
         direction of the previous parameter in the procedure is used.   (Note:  the  first  parameter  must  be
         preceded by the directional primitive!)

       • "split"  is a hack to handle stub routines that do things such as file transfers or any other operation
         that has to exchange information  (e.g.,  length  of  a  file)  before  the  call  returns  its  output
         parameters.   Because  of the particular handshake that is involved when doing remote file transfer, we
         currently break all such calls into two client-side stub routines.  The first (with the default  prefix
         of  "Begin")  is  used  to  pass  all IN and INOUT parameters to the server side.  The second (with the
         default prefix of "End") is used to get back the INOUT and OUT parameters from the server.  Between the
         two calls, the user is supposed to do the appropriate calls for the file  transfer.  For  example,  the
         following procedure declaration in package AFS_

             Fetch (IN a, b,INOUT c, OUT d) split = FETCHOPCODE;

         will roughly generate the two independent client stub routines:

             BeginAFS_Fetch (IN a, b, c)

         and

             EndAFS_Fetch(OUT c, d)

         The  splitprefix  statement is used to change the default prefix names used by the two client-side stub
         generated routines when dealing with file transfer-related procedure calls.  For example:

             splitprefix IN=Before_ OUT=After_

         will cause the naming of the two client stubs for a file transfer-related routine, say Fetch(),  to  be
         Before_AFS_Fetch() and After_AFS_Fetch(), respectively.

       • The  "multi"  option  is nearly identical to the "split" feature described above.  The only significant
         visible difference is that along with the two client stubs, the standard client stub is also generated.
         Since the intention is to handle the multi-Rx calls, we need the whole standard procedure stub  in  the
         cases where no multi-Rx call of the procedure is performed.  A side effect of the "multi" option is the
         generation  of  a  special  macro  (i.e.,  "multi_<Procedure-name>"  which passes back as arguments the
         "Begin" and "End" stubs in the header output file. This macro is used directly by the Rx  code  when  a
         multi-Rx call of this procedure is performed.

   OBSOLETE rxgen FEATURES
       Although  the  following  rxgen  commands  are still in effect, they will soon be removed since there are
       better alternatives. DO NOT USE THEM!

       The special statement is a temporary hack used to handle certain inefficiencies of standard xdr  routines
       to  handle  some user-customized declarations.  In particular, this applies to a string pointer specified
       as part of a declaration.  For example,

           special struct BBS SeqBody;

       tells rxgen that the entry "SeqBody" in the user-defined BBS xdr routine is a string (note that more than
       one string can be "special" per structure -- multiple  ones  are  separated  by  commas);  it  will  thus
       allocate  and  de-allocate space properly in the server-generated stubs that contain this structure as an
       IN or INOUT parameter.

       A better alternative to special is the customized statement,  which  is  simply  the  "customized"  token
       followed  by  the  regular declaration of a struct based on the RPCL rules. In this case, the declaration
       will be included in the generated header file (-h option) but no xdr routine will be generated  for  this
       structure -- the user will supply this.  All pointer entries in this structure will be remembered so when
       the  structure  is  used  as  an  IN or INOUT in the server stub, no core leaks will occur.  For example,
       consider

           customized struct CBS {
               long Seqlen;
               char *SeqBody;
           }

       The "xdr_CBS" routine would be provided by the user where during the DECODE xdr opcode, appropriate space
       for the "SeqBody" string is allocated.  Similarly, that space is freed during the FREE xdr opcode.

       Note: Old style "Array parameter specifications" are not supported any more.

EXAMPLES

       In case there are some requirements not available by the current RPC language, one can customize some XDR
       routines by leaving those data types undefined. For every data type that is undefined, it will be assumed
       that a routine exists with the name "xdr_" prepended  to  it.   A  selected  set  of  rxgen  features  is
       presented  below,  but  for  a more comprehensive one (unions, complex examples, etc) please refer to the
       rpcgen Programming Guide and eXternal Data Representation: Sun Technical Notes.

   Typedefs
       The RPC typedef statement is identical to the C typedef (i.e. "typedef <declaration>").  By default, most
       user declarations (i.e. structs, unions, etc) are automatically typedef'ed  by  rxgen.   Since  it  makes
       parsing simpler, its usage is recommended by rxgen scripts.

   Strings
       The  C  "char  *"  string  convention  is kind of ambiguous, since it is usually intended to mean a null-
       terminated string of characters, but it could also represent a pointer to a single character,  a  pointer
       to  an array of characters, etc.  In the RPC language, a null-terminated string is unambiguously called a
       "string".  Examples,

           string bigname<>;
           string name<MAXNAMELEN>;
           typedef string volname<MAXVOLNAME>;

       Notice that the maximum size of string can  be  arbitrary  (like  "bigname"  above)  or,  preferably,  or
       specified  in  angle brackets (i.e. "name" and "volname" above).  In practice, one should always use only
       bounded strings in interfaces.  A sample calling proc using the declarations above would be:

           GetEntryByName (IN volname name,
               OUT struct vldbentry *entry) = VL_GETENTRYBYNAME;

       or, of course,

           GetEntryByName (IN string volname<MAXVOLNAME>,
               OUT struct vldbentry *entry) = VL_GETENTRYBYNAME;

       It is very important for the user to understand when the string parameters  should  be  allocated  and/or
       freed  by  the  his/her  client  and/or  server  programs. A short analysis on string parameters handling
       follows (note that a similar method is used for the handling of variable length  arrays  as  it  will  be
       shown later on):

       • In  the  client  side: IN and INOUT string parameters are the programmer's responsibility and should be
         allocated (static or via malloc) before calling the rpc and freed (if malloc was used) after the  rpc's
         return  in  the  user's  client  program; of course, for INOUT parameters, the returned string can't be
         bigger than the malloced input string.

         OUT string parameters are automatically malloced (based on the length of the returned  string  and  not
         the  maxsize)  by  the  rxgen  client stubs (in filename.cs.c) and must be freed by the client program;
         admittedly, this could be somewhat confusing since the user needs to free something that he/she  didn't
         allocate.}

       • In  the  server  side:  IN and INOUT string parameters are automatically malloced (based on the size of
         incoming strings) by the rxgen server stubs (in filename.ss.c) before they are  passed  to  the  user's
         server  procedure;  that  space  is  automatically  freed  just  before  the rxgen server stub returns;
         therefore the user need not do anything special for IN and INOUT string parameters.

         OUT string parameters must be malloced by the user's server procedure (i.e. null pointer is  passed  to
         it  by  the rxgen server stub) and it is automatically freed at the end of the rxgen server stub.  Like
         in the client side, the OUT parameters are somewhat unorthodox (i.e. the server routine must  malloc  a
         string without ever freeing it itself; this is done by the rxgen server stub).

       Note  that  for INOUT and OUT string parameters, in both the client and server sides their arguments must
       be char of pointers (i.e. char **).

   Pointers
       Pointer declarations  in  RPC  are  also  exactly  as  they  are  in  C  (i.e.  "struct  single_vldbentry
       *vldblist;").   Of  course,  one  can't  send pointers over the network, but one can use XDR pointers for
       sending recursive data types such as lists and trees (an example of a linked list  will  be  demonstrated
       shortly).

   Arrays
       Fixed  arrays are just like standard C array declarations (i.e. "struct UpdateEntry entries[20]") without
       any side effect problems in rxgen. Since variable-length arrays have no explicit syntax in C, the  angle-
       brackets  are  used  for it and the array declarations are actually compiled into "struct"s. For example,
       declarations such as:

           const   MAXBULKSIZE     = 10000;
           const   MAXENTRIES      = 100;
           opaque  bulk<MAXBULKSIZE>;           /* At most 10000 items */
           int     hosts<>;                     /* any number of items */
           typedef vldbentry blkentries<100>;   /* Preferable array decl */

       are compiled into the following structs:

           struct {
               u_int   bulk_len;       /* no of items */
               char    *bulk_val;      /* pointer to array */
           } bulk;

       for the "bulk" array, and similarly for the "blkentries<100>" array,

           struct {
               u_int      blkentries_len;   /* no of items in array */
               vldbentry  *blkentries_val;  /* pointer to array */
           } blkentries;

       Therefore the user should be aware of the "magically" generated structure entries such as the  number  of
       items  in  the array (<array_name>_len) and the pointer to the array (<array_name>_val) since some of the
       entries will have to be filled in from the client/server programs.  A sample proc would be:

           typedef vldbentry blkentries<MAXENTRIES>;
           proc GetBlk (OUT blkentries *vlentries) = VL_GETBLK;

       or, more directly,

           GetBlk(OUT vldbentry vlentries<MAXENTRIES>) = VL_GETBLK;

       Note that although the latest method is preferable since one does not  have  to  first  use  the  typedef
       statement  (and admittedly, programmers prefer avoiding typedefs), one should realize that rxgen does the
       structure expansion and the  xdr  creation  implicitly;  therefore  the  user  should  be  aware  of  the
       "vldbentries_val" and "vldbentries_len" fields as before (see following examples).

       Array example I (least desirable)

       Procedure declaration in the interface configuration:

           proc ListAttributes (IN vldblistbyattributes *attributes,
                        INOUT blkentries *vldbentries) = VL_LISTATTRIBUTES;

       Sample CLIENT code:

           blkentries entries, *pnt;
           entries.blkentries_len = 10;   /* max # returned entries */
           entries.blkentries_val = (vldbentry *)malloc(LEN);
                                          /* It must be set */

           code = VL_ListAttributes(&attributes, &entries);
           if (!code) {
               pnt = entries.blkentries_val;
               for (i=0; i < entries.blkentries_len; i++, pnt++)
                       display_vldbentry(pnt);
               /* Make sure you free the allocated space */
               free((char *)entries.blkentries_val);
           }

       Sample SERVER code:

           VL_ListAttributes(attributes, entries)
           {
               vldbentry *singleentry = entries->blkentries_val;
               entries->blkentries_len = 0;

               while (copy_to_vldbentry(&vlentry, singleentry))
                   singleentry++, vldbentries->entries_len++;
           }

       Although  this  method  for  variable-size  arrays works fine, there are some major drawbacks.  The array
       parameter (i.e. vldbentries above) must be declared as INOUT since we need to pass the max length of  the
       expected returned array; more importantly, a big (depending on the value of "_len") chunk of junk code is
       going  to  be  transferred to the server as result of the IN(out) side-effect of the array.  It's an easy
       and convenient method if the returned array size can be predicted from the start and  when  the  size  is
       quite  high.   This method is included as an example of erroneous use (and abuse) of rxgen and should not
       be used.

       Array example II (Desirable method)

       Procedure declaration in the interface configuration (using Example I above):

           proc ListAttributes (IN vldblistbyattributes *attributes,
               OUT blkentries *vldbentries) = VL_LISTATTRIBUTES;

       Sample CLIENT code:

           blkentries entries, *pnt;

           code = VL_ListAttributes(&attributes, &entries);
           if (!code) {
               pnt = entries.blkentries_val;
               for (i=0; i < entries.blkentries_len; i++, pnt++)
                       display_vldbentry(pnt);
               /* Make sure you free the allocated space (by rxgen) */
               free((char *)entries.blkentries_val);
           }

       Sample SERVER code:

           VL_ListAttributes(attributes, entries)
           {
               vldbentry *singleentry;
               entries->blkentries_len = 0;
               singleentry = entries->blkentries_val
                   = (vldbentry *)malloc(MAXENTRIES * sizeof(vldbentry));

               while (copy_to_vldbentry(&vlentry, singleentry))
                       singleentry++, vldbentries->entries_len++;
           }

       This is the best (and simplest) way of using variable-size arrays as an  output  parameter.   It  is  the
       responsibility of the server-side stub to malloc() the adequate space which is automatically freed by the
       rxgen stub; the client side should free the space allocated by the rxgen-calling stub.

       Array example III (Linked Lists)

       Considering  the  following  3  declarations (could have applied some optimizations) in the configuration
       file:

           typedef struct single_vldbentry *vldblist;
           struct single_vldbentry {
               vldbentry vlentry;
               vldblist  next_vldb;
           };

           struct vldb_list {
               vldblist node;
           };

       and the rxgen procedure declaration:

           LinkedList (IN vldblistbyattributes *attributes,
               OUT vldb_list *linkedentries) = VL_LINKEDLIST;

       Sample CLIENT code:

           vldb_list       linkedvldbs;
           vldblist        vllist, vllist1;

           bzero(&linkedvldbs, sizeof(vldb_list));
           code = VL_LinkedList(&attributes, &nentries, &linkedvldbs);
           if (!code) {
               printf("We got %d vldb entries\n", nentries);
               for (vllist = linkedvldbs.node; vllist; vllist = vllist1) {
                   vllist1 = vllist->next_vldb;
                   display_entry(&vllist->vlentry);
                   free((char *)vllist);
               }
           }

       Sample SERVER code:

           VL_LinkedList(rxcall, attributes, nentries, linkedvldbs);
           {
               vldblist vllist, *vllistptr = &linkedvldbs->node;
               while (...) {
                   vllist = *vllistptr
                       = (single_vldbentry *)malloc (sizeof (single_vldbentry));
                   copy_to_vldbentry(&tentry, &vllist->vlentry);
                   nentries++;
                   vllistptr = &vllist->next_vldb;
               };
               *vllistptr = NULL;
           }

       Using a linked list offers many advantages: Nothing is passed to the server (the parameter  is  OUT),  no
       additional  overhead  is  involved,  and  the  caller doesn't have to explicitly prepare for an arbitrary
       return size.  A drawback is that the caller has the responsibility of malloc() (on the server)  and  free
       (on  the  client)  of  each  entry (to avoid unwanted core-leaks).  Another drawback is that since it's a
       recursive call, the C stack will grow linearly with respect to the number of nodes in the list  (so  it's
       wise to increase the Rx LWP stack if huge amounts of data are expected back -- default stack size is 4K).
       The advantages should outweigh the disadvantages here.

       It's  important  to  pay  attention  to  the comments of the three array examples above particularly when
       they're references to when the user should allocate/free space  for  the  variable  length  arrays.   The
       mechanism  is  very  similar to the handling of strings thus you might need to review the strings section
       above; note that the linked lists are handled somewhat differently...

   Miscellaneous examples
       Below is an abbreviated version of a random interface file which shows some of the common cases.

           /* Declaration of all structures used by the R.xg script interface */

           struct AFSFid {
               unsigned long Volume;
               unsigned long Vnode;
               unsigned long Unique;
           };

           typedef long ViceDataType;

           /* Note that TEST would be equivalent to "HEADER" only during the
              processing of the header, *.h, file */

           #ifdef RPC_HDR
           #define TEST "HEADER"
           #else
           #define TEST "REST"
           #endif

           /* This is the standard *.xg specification file */

           package AFS_
           splitprefix IN=BEFORE_ OUT=AFTER_;
           Prefix Test

           proc Remove(IN struct AFSFid *Did, IN string volname<64>,
               OUT struct AFSStatus *Status) = AFS_REMOVE;

           DisconnectFS AUX_disconnectFS() = AFS_DISCONNECTFS;

           proc GetVolumeInfo(IN string Vid,
               OUT struct VolumeInfo *Info) = AFS_GETVOLUMEINFO;

           /* You could have more than an interface per configuration */

           package VOTE_

           /* Using the "multi" feature; thus VOTE_Beacon can be called as an
              multi-Rx call or as a regular call */

           Beacon (IN long state, long voteStart,
               net_version *version, net_tid *tid)
               multi = VOTE_BEACON;

           package DISK_

           /* Using the "split" feature */

           SendFile (IN long file, long offset,
               long length, net_version *version)
               split = DISK_SENDFILE;

   Output of an actual interface configuration
       We'll demonstrate some of the actual output  generated  by  rxgen  by  following  an  abbreviated  actual
       interface configuration.

       Configuration file

       Contents of the interface configuration file (vldbint.xg):

           package VL_
           #include "vl_opcodes.h"   /* The opcodes are included here */
           %#include "vl_opcodes.h"  /* directly to other places */

           /* Current limitations on parameters that affect other packages
              (i.e. volume) */

           const   MAXNAMELEN      =       65;
           const   MAXNSERVERS     =       8;
           const   MAXTYPES        =       3;

           /* External (visible) representation of an individual vldb entry */

           struct vldbentry {
               char    name[MAXNAMELEN];
               long    volumeType;
               long    nServers;
               long    serverNumber[MAXNSERVERS];
               long    serverPartition[MAXNSERVERS];
               long    serverFlags[MAXNSERVERS];
               u_long  volumeId[MAXTYPES];
               long    flags;
           };

           typedef struct single_vldbentry  *vldblist;
           struct single_vldbentry {
               vldbentry VldbEntry;
               vldblist next_vldb;
           };

           struct vldb_list {
               vldblist node;
           };

           /* vldb interface calls */

           CreateEntry     (IN long Volid,
                           vldbentry *newentry) = VLCREATEENTRY;

           GetEntryByName  (IN string volumename<MAXNAMELEN>,
                           OUT vldbentry *entry) = VLGETENTRYBYNAME;

           GetNewVolumeId  (IN long bumpcount,
                           OUT long *newvolumid) = VLGETNEWVOLUMEID;

           ReplaceEntry    (IN long Volid,
                           long voltype,
                           vldbentry *newentry,
                           long ReleaseType) multi = VLREPLACEENTRY;

           ListAttributes  (IN VldbListByAttributes *attributes,
                           OUT long *nentries,
                           OUT vldbentry bulkentries<MAXVLDBLEN>)
                           = VLLISTATTRIBUTES;

           LinkedList      (IN VldbListByAttributes *attributes,
                           OUT long *nentries,
                           OUT vldb_list *linkedentries) = VLLINKEDLIST;

       For  a  detailed  description  on  the  Rx-related  calls inside the generated stubs (i.e., rx_NewCall(),
       rx_EndCall()), along with details on what happens inside certain calls (like xdrrx_create()) please refer
       to the Rx documentation. Typing "rxgen vldbint.xg" will result in the creation of four files:  vldbint.h,
       vldbint.xdr.c, vldbint.cs.c and vldbint.ss.c.  A closer look at these files follows.

       Header file (vldbint.h)

           /* Machine generated file -- Do NOT edit */

           #include "vl_opcodes.h"  /* directly to other places */
           #define MAXNAMELEN 65
           #define MAXNSERVERS 8
           #define MAXTYPES 3

           struct vldbentry {
               char name[MAXNAMELEN];
               long volumeType;
               long nServers;
               long serverNumber[MAXNSERVERS];
               long serverPartition[MAXNSERVERS];
               long serverFlags[MAXNSERVERS];
               u_long volumeId[MAXTYPES];
               long flags;
           };
           typedef struct vldbentry vldbentry;
           bool_t xdr_vldbentry();

           typedef struct single_vldbentry *vldblist;
           bool_t xdr_vldblist();

           struct single_vldbentry {
               vldbentry VldbEntry;
               vldblist next_vldb;
           };
           typedef struct single_vldbentry single_vldbentry;
           bool_t xdr_single_vldbentry();

           struct vldb_list {
               vldblist node;
           };
           typedef struct vldb_list vldb_list;
           bool_t xdr_vldb_list();

           #include <rx/rx_multi.h>
           #define multi_VL_ReplaceEntry(Volid, voltype, newentry, ReleaseType) \
               multi_Body(StartVL_ReplaceEntry(multi_call, Volid, voltype,
                          newentry, ReleaseType), EndVL_ReplaceEntry(multi_call))

           typedef struct bulkentries {
               u_int bulkentries_len;
               vldbentry *bulkentries_val;
           } bulkentries;
           bool_t xdr_bulkentries();

           /* Opcode-related useful stats for package: VL_ */
           #define VL_LOWEST_OPCODE        501
           #define VL_HIGHEST_OPCODE       506
           #define VL_NUMBER_OPCODES       6

       Notice  that  all  structures  are automatically typedef'ed and all "const"s are converted to "#define"s.
       Some data structures, such as bulkentries, are taken from procedure params  (from  ListAttributes  proc).
       Thus,  this  should be kept in mind when creating stubs piecemeal with rxgen (i.e., using the -c, -h, -C,
       or -S flags).  Also, one of the side effects of the  "multi"  option  (in  "ReplaceEntry"  proc)  is  the
       generation of the "multi_VL_ReplaceEntry" above.

       XDR routines for structures (vldbint.xdr.c)

           /* Machine generated file -- Do NOT edit */

           #include <rx/xdr.h>
           #include "vldbint.h"

           #include "vl_opcodes.h"  /* directly to other places */

           bool_t
           xdr_vldbentry(xdrs, objp)
               XDR *xdrs;
               vldbentry *objp;
           {
               if (!xdr_vector(xdrs, (char *)objp->name, MAXNAMELEN,
                               sizeof(char), xdr_char))
                   return (FALSE);
               if (!xdr_long(xdrs, &objp->volumeType))
                   return (FALSE);
               if (!xdr_long(xdrs, &objp->nServers))
                   return (FALSE);
               if (!xdr_vector(xdrs, (char *)objp->serverNumber, MAXNSERVERS,
                               sizeof(long), xdr_long))
                   return (FALSE);
               if (!xdr_vector(xdrs, (char *)objp->serverPartition,
                               MAXNSERVERS, sizeof(long), xdr_long))
                   return (FALSE);
               if (!xdr_vector(xdrs, (char *)objp->serverFlags, MAXNSERVERS,
                               sizeof(long), xdr_long))
                   return (FALSE);
               if (!xdr_vector(xdrs, (char *)objp->volumeId, MAXTYPES,
                               sizeof(u_long), xdr_u_long))
                   return (FALSE);
               if (!xdr_long(xdrs, &objp->flags))
                   return (FALSE);
               return (TRUE);
           }

           bool_t
           xdr_vldblist(xdrs, objp)
               XDR *xdrs;
               vldblist *objp;
           {
               if (!xdr_pointer(xdrs, (char **)objp,
                                sizeof(struct single_vldbentry),
                                xdr_single_vldbentry))
                   return (FALSE);
               return (TRUE);
           }

           bool_t
           xdr_single_vldbentry(xdrs, objp)
               XDR *xdrs;
               single_vldbentry *objp;
           {
               if (!xdr_vldbentry(xdrs, &objp->VldbEntry))
                   return (FALSE);
               if (!xdr_vldblist(xdrs, &objp->next_vldb))
                   return (FALSE);
               return (TRUE);
           }

           bool_t
           xdr_vldb_list(xdrs, objp)
               XDR *xdrs;
               vldb_list *objp;
           {
               if (!xdr_vldblist(xdrs, &objp->node))
                   return (FALSE);
               return (TRUE);
           }

           bool_t
           xdr_bulkentries(xdrs, objp)
               XDR *xdrs;
               bulkentries *objp;
           {
               if (!xdr_array(xdrs, (char **)&objp->bulkentries_val,
                              (u_int *)&objp->bulkentries_len, MAXVLDBLEN,
                              sizeof(vldbentry), xdr_vldbentry))
                   return (FALSE);
               return (TRUE);
           }

       Note  that  the  xdr_bulkentries()  is  automatically generated as a side effect of a procedure parameter
       declaration.  Thus, if identical multiple type parameter declarations  are  used,  then  multiply-defined
       xdr_*  stubs  will be created!  We felt this was a better alternative to having the rxgen programmer deal
       with types such as bulkentries_1, bulkentries_2...

       Client-Side stub routines (vldbint.cs.c)

           /* Machine generated file -- Do NOT edit */

           #include <rx/xdr.h>
           #include <rx/rx.h>
           #include <afs/rxgen_consts.h>
           #include "vldbint.h"

           #include "vl_opcodes.h"  /* directly to other places */

           int VL_CreateEntry(z_conn, Volid, newentry)
               register struct rx_connection *z_conn;
               long Volid;
               vldbentry * newentry;
           {
               struct rx_call *z_call = rx_NewCall(z_conn);
               static int z_op = 501;
               int z_result;
               XDR z_xdrs;

               xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);

               /* Marshal the arguments */
               if ((!xdr_int(&z_xdrs, &z_op))
                    || (!xdr_long(&z_xdrs, &Volid))
                    || (!xdr_vldbentry(&z_xdrs, newentry))) {
                       z_result = RXGEN_CC_MARSHAL;
                       goto fail;
               }

               z_result = RXGEN_SUCCESS;
           fail:
               return rx_EndCall(z_call, z_result);
           }

           int VL_GetEntryByName(z_conn, volumename, entry)
               register struct rx_connection *z_conn;
               char * volumename;
               vldbentry * entry;
           {
               struct rx_call *z_call = rx_NewCall(z_conn);
               static int z_op = 504;
               int z_result;
               XDR z_xdrs;

               xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);

               /* Marshal the arguments */
               if ((!xdr_int(&z_xdrs, &z_op))
                    || (!xdr_string(&z_xdrs, &volumename, 65))) {
                       z_result = RXGEN_CC_MARSHAL;
                       goto fail;
               }

               /* Un-marshal the reply arguments */
               z_xdrs.x_op = XDR_DECODE;
               if ((!xdr_vldbentry(&z_xdrs, entry))) {
                       z_result = RXGEN_CC_UNMARSHAL;
                       goto fail;
               }

               z_result = RXGEN_SUCCESS;
           fail:
               return rx_EndCall(z_call, z_result);
           }

           int VL_GetNewVolumeId(z_conn, bumpcount, newvolumid)
               register struct rx_connection *z_conn;
               long bumpcount;
               long * newvolumid;
           {
               struct rx_call *z_call = rx_NewCall(z_conn);
               static int z_op = 505;
               int z_result;
               XDR z_xdrs;

               xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);

               /* Marshal the arguments */
               if ((!xdr_int(&z_xdrs, &z_op))
                    || (!xdr_long(&z_xdrs, &bumpcount))) {
                       z_result = RXGEN_CC_MARSHAL;
                       goto fail;
               }

               /* Un-marshal the reply arguments */
               z_xdrs.x_op = XDR_DECODE;
               if ((!xdr_long(&z_xdrs, newvolumid))) {
                       z_result = RXGEN_CC_UNMARSHAL;
                       goto fail;
               }

               z_result = RXGEN_SUCCESS;
           fail:
               return rx_EndCall(z_call, z_result);
           }

           int VL_ReplaceEntry(z_conn, Volid, voltype, newentry, ReleaseType)
               register struct rx_connection *z_conn;
               long Volid, voltype, ReleaseType;
               vldbentry * newentry;
           {
               struct rx_call *z_call = rx_NewCall(z_conn);
               static int z_op = 506;
               int z_result;
               XDR z_xdrs;

               xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);

               /* Marshal the arguments */
               if ((!xdr_int(&z_xdrs, &z_op))
                    || (!xdr_long(&z_xdrs, &Volid))
                    || (!xdr_long(&z_xdrs, &voltype))
                    || (!xdr_vldbentry(&z_xdrs, newentry))
                    || (!xdr_long(&z_xdrs, &ReleaseType))) {
                       z_result = RXGEN_CC_MARSHAL;
                       goto fail;
               }

               z_result = RXGEN_SUCCESS;
           fail:
               return rx_EndCall(z_call, z_result);
           }

           int StartVL_ReplaceEntry(z_call, Volid, voltype, newentry, ReleaseType)
               register struct rx_call *z_call;
               long Volid, voltype, ReleaseType;
               vldbentry * newentry;
           {
               static int z_op = 506;
               int z_result;
               XDR z_xdrs;

               xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);

               /* Marshal the arguments */
               if ((!xdr_int(&z_xdrs, &z_op))
                    || (!xdr_long(&z_xdrs, &Volid))
                    || (!xdr_long(&z_xdrs, &voltype))
                    || (!xdr_vldbentry(&z_xdrs, newentry))
                    || (!xdr_long(&z_xdrs, &ReleaseType))) {
                       z_result = RXGEN_CC_MARSHAL;
                       goto fail;
               }

               z_result = RXGEN_SUCCESS;
           fail:
               return z_result;
           }

           int EndVL_ReplaceEntry(z_call)
               register struct rx_call *z_call;
           {
               int z_result;
               XDR z_xdrs;

               z_result = RXGEN_SUCCESS;
           fail:
               return z_result;
           }

           int VL_ListAttributes(z_conn, attributes, nentries, bulkentries_1)
               register struct rx_connection *z_conn;
               VldbListByAttributes * attributes;
               long * nentries;
               bulkentries * bulkentries_1;
           {
               struct rx_call *z_call = rx_NewCall(z_conn);
               static int z_op = 511;
               int z_result;
               XDR z_xdrs;

               xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);

               /* Marshal the arguments */
               if ((!xdr_int(&z_xdrs, &z_op))
                    || (!xdr_VldbListByAttributes(&z_xdrs, attributes))) {
                       z_result = RXGEN_CC_MARSHAL;
                       goto fail;
               }

               /* Un-marshal the reply arguments */
               z_xdrs.x_op = XDR_DECODE;
               if ((!xdr_long(&z_xdrs, nentries))
                    || (!xdr_bulkentries(&z_xdrs, bulkentries_1))) {
                       z_result = RXGEN_CC_UNMARSHAL;
                       goto fail;
               }

               z_result = RXGEN_SUCCESS;
           fail:
               return rx_EndCall(z_call, z_result);
           }

           int VL_LinkedList(z_conn, attributes, nentries, linkedentries)
               register struct rx_connection *z_conn;
               VldbListByAttributes * attributes;
               long * nentries;
               vldb_list * linkedentries;
           {
               struct rx_call *z_call = rx_NewCall(z_conn);
               static int z_op = 512;
               int z_result;
               XDR z_xdrs;

               xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);

               /* Marshal the arguments */
               if ((!xdr_int(&z_xdrs, &z_op))
                    || (!xdr_VldbListByAttributes(&z_xdrs, attributes))) {
                       z_result = RXGEN_CC_MARSHAL;
                       goto fail;
               }

               /* Un-marshal the reply arguments */
               z_xdrs.x_op = XDR_DECODE;
               if ((!xdr_long(&z_xdrs, nentries))
                    || (!xdr_vldb_list(&z_xdrs, linkedentries))) {
                       z_result = RXGEN_CC_UNMARSHAL;
                       goto fail;
               }

               z_result = RXGEN_SUCCESS;
           fail:
               return rx_EndCall(z_call, z_result);
           }

       Notice the side effect of the "multi" feature (three different modules for "ReplaceEntry" proc).

       Server-Side stub routines (vldbint.ss.c)

           /* Machine generated file -- Do NOT edit */

           #include <rx/xdr.h>
           #include <rx/rx.h>
           #include <afs/rxgen_consts.h>
           #include "vldbint.h"

           #include "vl_opcodes.h"  /* directly to other places */

           long _VL_CreateEntry(z_call, z_xdrs)
               struct rx_call *z_call;
               XDR *z_xdrs;
           {
               long z_result;
               long Volid;
               vldbentry newentry;

               if ((!xdr_long(z_xdrs, &Volid))
                    || (!xdr_vldbentry(z_xdrs, &newentry))) {
                       z_result = RXGEN_SS_UNMARSHAL;
                       goto fail;
               }

               z_result = VL_CreateEntry(z_call, Volid, &newentry);
           fail:
               return z_result;
           }

           long _VL_GetEntryByName(z_call, z_xdrs)
               struct rx_call *z_call;
               XDR *z_xdrs;
           {
               long z_result;
               char *volumename = (char *)0;
               vldbentry entry;

               if ((!xdr_string(z_xdrs, &volumename, 65))) {
                       z_result = RXGEN_SS_UNMARSHAL;
                       goto fail;
               }

               z_result = VL_GetEntryByName(z_call, &volumename, &entry);
               z_xdrs->x_op = XDR_ENCODE;
               if ((!xdr_vldbentry(z_xdrs, &entry)))
                       z_result = RXGEN_SS_MARSHAL;
           fail:
               z_xdrs->x_op = XDR_FREE;
               if (!xdr_string(z_xdrs, &volumename, 65)) goto fail1;
               return z_result;
           fail1:
               return RXGEN_SS_XDRFREE;
           }

           long _VL_GetNewVolumeId(z_call, z_xdrs)
               struct rx_call *z_call;
               XDR *z_xdrs;
           {
               long z_result;
               long bumpcount;
               long newvolumid;

               if ((!xdr_long(z_xdrs, &bumpcount))) {
                       z_result = RXGEN_SS_UNMARSHAL;
                       goto fail;
               }

               z_result = VL_GetNewVolumeId(z_call, bumpcount, &newvolumid);
               z_xdrs->x_op = XDR_ENCODE;
               if ((!xdr_long(z_xdrs, &newvolumid)))
                       z_result = RXGEN_SS_MARSHAL;
           fail:
               return z_result;
           }

           long _VL_ReplaceEntry(z_call, z_xdrs)
               struct rx_call *z_call;
               XDR *z_xdrs;
           {
               long z_result;
               long Volid, voltype, ReleaseType;
               vldbentry newentry;

               if ((!xdr_long(z_xdrs, &Volid))
                    || (!xdr_long(z_xdrs, &voltype))
                    || (!xdr_vldbentry(z_xdrs, &newentry))
                    || (!xdr_long(z_xdrs, &ReleaseType))) {
                       z_result = RXGEN_SS_UNMARSHAL;
                       goto fail;
               }

               z_result = VL_ReplaceEntry(z_call, Volid, voltype, &newentry,
                                          ReleaseType);
           fail:
               return z_result;
           }

           long _VL_ListAttributes(z_call, z_xdrs)
               struct rx_call *z_call;
               XDR *z_xdrs;
           {
               long z_result;
               VldbListByAttributes attributes;
               long nentries;
               bulkentries bulkentries_1;

               if ((!xdr_VldbListByAttributes(z_xdrs, &attributes))) {
                       z_result = RXGEN_SS_UNMARSHAL;
                       goto fail;
               }

               z_result = VL_ListAttributes(z_call, &attributes, &nentries,
                                            &bulkentries_1);
               z_xdrs->x_op = XDR_ENCODE;
               if ((!xdr_long(z_xdrs, &nentries))
                    || (!xdr_bulkentries(z_xdrs, &bulkentries_1)))
                       z_result = RXGEN_SS_MARSHAL;
           fail:
               z_xdrs->x_op = XDR_FREE;
               if (!xdr_bulkentries(z_xdrs, &bulkentries_1)) goto fail1;
               return z_result;
           fail1:
               return RXGEN_SS_XDRFREE;
           }

           long _VL_LinkedList(z_call, z_xdrs)
               struct rx_call *z_call;
               XDR *z_xdrs;
           {
               long z_result;
               VldbListByAttributes attributes;
               long nentries;
               vldb_list linkedentries;

               if ((!xdr_VldbListByAttributes(z_xdrs, &attributes))) {
                       z_result = RXGEN_SS_UNMARSHAL;
                       goto fail;
               }

               z_result = VL_LinkedList(z_call, &attributes, &nentries,
                                        &linkedentries);
               z_xdrs->x_op = XDR_ENCODE;
               if ((!xdr_long(z_xdrs, &nentries))
                    || (!xdr_vldb_list(z_xdrs, &linkedentries)))
                       z_result = RXGEN_SS_MARSHAL;
           fail:
               return z_result;
           }

           long _VL_CreateEntry();
           long _VL_GetEntryByName();
           long _VL_GetNewVolumeId();
           long _VL_ReplaceEntry();
           long _VL_ListAttributes();
           long _VL_LinkedList();

           static long (*StubProcsArray0[])() = {_VL_CreateEntry,
               _VL_GetEntryByName, _VL_GetNewVolumeId, _VL_ReplaceEntry,
               _VL_ListAttributes, _VL_LinkedList};

           VL_ExecuteRequest(z_call)
               register struct rx_call *z_call;
           {
               int op;
               XDR z_xdrs;
               long z_result;

               xdrrx_create(&z_xdrs, z_call, XDR_DECODE);
               if (!xdr_int(&z_xdrs, &op))
                   z_result = RXGEN_DECODE;
               else if (op < VL_LOWEST_OPCODE || op > VL_HIGHEST_OPCODE)
                   z_result = RXGEN_OPCODE;
               else
                   z_result = (*StubProcsArray0[op - VL_LOWEST_OPCODE])
                       (z_call, &z_xdrs);
               return z_result;
           }

       If there were gaps in the procedures' opcode sequence the code for VL_ExecuteRequest() routine  would  be
       have been drastically different (it would have been a case statement for each procedure).

NOTES

       rxgen is implemented from Sun's rpcgen utility.

       When  the  "%#include  <include  file">  feature is used make sure that you don't have any rxgen language
       features (i.e. %#defines) since you'll get syntax errors during compilations..

       Since this is an ongoing project many of the above may change/disappear without a major warning.

SEE ALSO

       Rxgen Syntax Summary: Summary description of rxgen's grammar.

       Rpcgen Programming Guide: Sun's RPC protocol compiler.  rxgen was implemented as  an  extension  to  that
       compiler.

       External Data Representation: Sun Technical Notes: Detailed examples in using XDR.

       RPCL Syntax Summary: Summary of Sun's Remote Procedure Call Language.

       Rx: An extended Remote Procedure Call Protocol.

       rgen: An earlier version of a similar stub generator used for the R RPC protocol.

COPYRIGHT

       IBM Corporation 2000. <http://www.ibm.com/> All Rights Reserved.

       This  documentation is covered by the IBM Public License Version 1.0.  It was converted from the original
       TeX rxgen manual to POD by Russ Allbery.

OpenAFS                                            2025-03-21                                           RXGEN(1)