.\"	@(#)bmac.std	2.2	9/9/83;
.\" standard format troff commands
.\" citation formatting strings
.ds [[ [
.ds ]] ]
.ds ], ,\|
.ds ]- -
.ds [. " \&
.ds .] .
.ds [, " \&
.ds ,] ,
.ds [? " \&
.ds ?] ?
.ds [: " \&
.ds :] :
.ds [; " \&
.ds ;] ;
.ds [! " \&
.ds !] !
.ds [" " \&
.ds "] \&"
.ds [' " \&
.ds '] '
.ds [< " \&
.ds >]
.\" reference formmating strings
.ds a] " \&
.ds b] , \&
.ds c] , \&
.ds n] "\& and \&
.ds m] "\& and \&
.ds p] .
.\" reference formmating macros
.de s[   \" start reference
.nh
.IP [\\*([F] 5m
..
.de e[   \" end reference
.[-
..
.de []   \" start to display collected references
.LP
..
.de ][   \" choose format
.ie !"\\*([J"" \{\
.    ie !"\\*([V"" .nr t[ 1    \" journal
.    el            .nr t[ 5    \" conference paper
.\}
.el .ie !"\\*([B"" .nr t[ 3    \" article in book
.el .ie !"\\*([R"" .nr t[ 4    \" technical report
.el .ie !"\\*([I"" .nr t[ 2    \" book
.el                .nr t[ 0    \" other
.\\n(t[[
..
.de 0[   \" other
.s[
.if !"\\*([A"" \\*([A\\c
.if !"\\*([T"" , \\*([T\\c
.if !"\\*([V"" , Vol. \\*([V\\c
.if !"\\*([O"" , \\*([O\\c
.if !"\\*([D"" , \\*([D\\c
\&.
.e[
..
.de 1[ \" journal article
.s[
.if !"\\*([A"" \\*([A,
.if !"\\*([T""  \\*([T,
\\fI\\*([J \\*([V\\fP\c
.if !"\\*([N"" ,\\*([N
.if !"\\*([D"" (\\*([D)\c
.if !"\\*([P"" , \\*([P\c
.if !"\\*([I"" , \\*([I\c
\\&.
.if !"\\*([O"" \\*([O.
.e[
..
.de 2[ \" book
.s[
.ie !"\\*([A"" \\*([A,
.el .if !"\\*([E"" \{\
.       ie \\n([E-1 \\*([E, eds.,
.       el \\*([E, ed.,\}
.if !"\\*([T"" \\fI\\*([T\\fP,
.rm a[
.if !"\\*([I"" .ds a[ \\*([I
.if !"\\*([C"" \{\
.       if !"\\*(a["" .as a[ , \\&
.       as a[ \\*([C\}
.if !"\\*([D"" \{\
.       if !"\\*(a["" .as a[ , \\&
.       as a[ \\*([D\}
\\*(a[.
.if !"\\*([G"" Gov. ordering no. \\*([G.
.if !"\\*([O"" \\*([O.
.e[
..
.de 3[ \" article in book
.s[
.if !"\\*([A"" \\*([A,
.if !"\\*([T"" \\*([T,
in \\fI\\*([B\\fP\c
.if !"\\*([V"" , vol. \\*([V
.if !~\\*([E~~ \{\
.       ie , \\n([E-1  \\*([E (editors)\c
.       el , \\*([E (editor)\c\}
.if !"\\*([I"" , \\*([I\c
.if !"\\*([C"" , \\*([C\c
.if !"\\*([D"" , \\*([D\c
.if !"\\*([P"" , \\*([P\c
\\&.
.if !"\\*([O"" \\*([O.
.e[
..
.de 4[ \" report
.s[
.if !"\\*([A"" \\*([A,
.if !~\\*([E~~ \{\
.       ie \\n([E-1 \\*([E, editors.
.       el \\*([E, editor.\}
\\*([T,
\\*([R\c
.if !"\\*([G"" \& (\\*([G)\c
.if !"\\*([I"" , \\*([I\c
.if !"\\*([C"" , \\*([C\c
.if !"\\*([D"" , \\*([D\c
\\&.
.if !"\\*([O"" \\*([O.
.e[
..
.de 5[ \" conference paper
.s[
.if !"\\*([A"" \\*([A,
.if !"\\*([T"" \\*([T,
\\fI\\*([J\\fP,
.if !"\\*([C"" \\*([C,
.if !"\\*([D"" \\*([D\c
.if !"\\*([P"" , \\*([P\c
\\&.
.if !"\\*([O"" \\*([O.
.e[
..
.de [-   \" clean up after yourself
.rm [A [B [C [D
.rm [E [F [G
.rm [I [J [K
.rm [N [O [P
.rm [R [T
.rm [V [W
..
.de s[   \" start reference
.nh
.IP \\*([F. 5n
..
.\" define .IP for bib...
.de IP
.ip \\$1 \\$2
..
.ll 6i
.po 1.375i
.m1 0.5i
.m2 0.5i
.m3 0.625i
.m4 0.375i
.nr pp 10	\"text point size
.nr sp 10	\"section heading point size
.nr fp 9	\"footnote point size
.nr qp 10	\"quote point size
.nr $r 11	\"line spacing
.nr $R 10	\"line spacing in displays
.he ''''
.fo ''%''
.(l C
.ps +3
RPCC - A Stub Compiler for Sun RPC
.sp
Irving Reid
.ps -2
.sp
Department of Computational Science
University of Saskatchewan
Saskatoon, Saskatchewan
Canada   S7N 0W0
Usenet: reid@sask.UUCP
.ps -1
.)l
.sp 0.25i
.(l C
.ps +2
Abstract
.ps -2
.)l
.sp
.pp
.in +.5i
.ll -.5i
A new system is described which compiles stubs for the Sun RPC system
directly from annotated C programs.  The specification, implementation, and
usage of RPCC are described.  RPCC is compared to some existing stub
compilers, most notably \fIrpcgen\fP, the stub compiler provided by Sun
Microsystems.
.in -.5i
.ll +.5i
.sh 1 Introduction
.pp
Remote Procedure Call (RPC) is a primitive for handling communication
between parts of a program running as separate processes.  In order to
simplify the interaction between the processes, RPC restricts communication
to the same semantics as a local procedure call.  The calling program
invokes the called procedure and then waits until the called procedure
returns its result before it continues execution.  Communication is through
the passed parameters and returned values.  In general, the process which
calls the remote procedure is the \fIclient\fP, and the process which
receives the call and performs the action is the \fIserver\fP.
.pp
RPC is implemented as a series of local procedure calls at the client which
establish a connection, package up the parameters, and send the call to the
server.  At the server end, the parameters are unpacked and handed to the
desired procedure; the returned values are then packaged up and sent back.
The returned values are unpacked at the client and handed back to the
calling process as the result of the call.  Note that the processes may, but
need not, be running on different machines; RPC is just as useful for
inter-process communication on a single machine as it is for network
communication.
.sh 2 "Support for RPC"
.pp
Different machines can, and often do, have different representations for
data in memory.  For example, Suns and Vaxen do not store the bytes
within an integer in the same order.  Floating point numbers create even
greater problems.  If an RPC system is to be useful on a network connecting
machines with different internal representations, some means must be
provided to convert data from one representation to another.  A number of
solutions for this problem have been proposed.  It is possible for every
processor to keep track of the internal representation of every other, and
convert the data before it is sent.  This will be impossible for broadcast
messages.  The receiving processor could convert the data into its own
format.  This is more practical, but it still requires that each machine be
able to convert data from every other machine's representation.
.pp
A simpler solution is to force every processor to convert the data into one
standard format before it is sent onto the network.  Each processor would
only need to know how to convert network format data to and from its own
internal representation.  While this reduces software complexity, it could
increase overhead.  Two processors with identical internal representations
will be forced to translate their data to and from the network format, even
though it is not strictly necessary.  Hybrid solutions have been proposed
where a specific internal representation is chosen for a particular
connection.  This would allow similar processors to communicate in native
format, while different processors would work in some agreed-upon network
format.  This would still not work with broadcast messages.
.pp
The other issue any RPC system must address is naming.  The caller must be
able to specify which procedure is to be run.  More sophisticated systems
allow the caller to name the host machine (if it is not a broadcast call),
server on that machine, version of the server, and procedure within that
server.  This makes naming much more flexible.  Version identifiers provide
support for development of new versions of servers without disabling
existing versions; likewise, explicit host naming allows a process to
address a call to the same server on any chosen machine.
.pp
The Sun RPC implementation provides support for Remote Procedure Call in the
4.2BSD Unix(tm.) networking environment.  Data on the network are kept in a
fixed internal representation, the Sun External Data Representation (XDR)
\*([[6\*(]].  Library functions are provided to
assist the programmer in converting data to and from the XDR, and for
establishing the underlying network connections.  The programmer is
responsible for providing XDR conversion routines for non-standard data
structures and for writing stubs to do the actual remote call.  Host
addressing is done either through network names or Internet addresses.
Servers are given unique program and version numbers, and procedures within
each server are also numbered.
.sh 2 "Stub Compilers"
.pp
Stub compilers, and RPCC in particular, automatically generate the code
which addresses the remote procedure and converts data into and out of
network format.  The \*(lqstubs\*(rq themselves are functions which make the
remote call completely transparent.  Because RPCC generates both the server
and client, the client stub can simply be given the server name and program,
version and procedure numbers.  The client stub puts all the parameters into
a single structure and invokes the Sun RPC library routines to perform the
call.  The server stub receives the call and takes the parameters out of the
structure to pass them to the remote procedure.
.pp
The RPCC stub compiler automatically generates XDR functions and procedure
stubs from C programs, using the Sun RPC library routines provided.
Programs are annotated by putting the special comment \fC/*REMOTE*/\fP before
functions which are to be called using RPC.  RPCC determines the data
structures being communicated and produces the necessary routines for
converting these to and from the XDR; it also generates a stub procedure
with the same name as the remote procedure, for the client to call, and
another stub which calls the procedure at the server end.  Simple escapes
are provided to allow programmers to use their own XDR routines for special
purposes.
.pp
Because all RPCC directives are C comments, programs using RPCC may be
compiled and tested without RPC.  The program can then be fed unchanged to
RPCC to produce the stubs and XDR routines.  The programmer need not worry
about introducing errors while converting a program from ordinary to remote
procedure calls.
.pp
RPCC differs from \fIrpcgen\fP\*([[4\*(]], the stub compiler
provided by Sun, in a number of ways.  Rpcgen uses a different language,
which is close enough to C that it may be confusing to the programmer.  The
specifications for rpcgen are separate from the program and may become
inconsistent.  Rpcgen produces only the XDR routines and not procedure
stubs, and does not handle many valid C structures.
.sh 1 "Major Design Issues"
.pp
A number of problems must be solved in designing a stub compiler.  First,
some communication mechanism and network data representation must be
provided.  In this case, these are provided by Sun RPC.  The remaining
issues depend on the level of service desired.  How transparent should a
remote procedure call be?  How can the compiler determine which functions
may be called remotely?  Which data types should be supported, and how
should they be specified?
.pp
\fIRpcgen\fP solves the problems of data type and function interface
specification by inventing a new language, \fIrpcl\fP (for Remote Procedure
Call Language).  The language allows the programmer to specify data types
including all simple C types, structures (though not nested structures, in
the version distributed with SunOS 3.2), strings, and two special types:
counted length arrays, which consist of a count of the number of elements
and a pointer to the first element; and discriminated unions, which contain
a variable determining how the contents of the union should be interpreted,
followed by the actual union.  Parameter
types are specified with a C-like syntax, but a completely different syntax
is used for specifying procedure and program numbers.
Procedures are
restricted to a single parameter and return value, and true
call-by-reference (where changed reference parameters are copied back) is
not supported.
.pp
Nordin's Remote Operation Calls\*([<\*([[3\*(]]\*(>] provide an
alternate method of specifying remote interfaces.  Comments are placed in
the source file to specify the program and procedure names and the parameter
types.  Different comments are used depending on whether a file is exporting
or importing the remote interface.  An X.400 based name-server is used for
both setting up communications and for storing type-checking information
about remote procedures.  Nordin's stub compiler handles both value and
reference parameters, correctly copying back new values of reference
parameters.  The actual return value is not passed back; results are
returned through reference parameters.  It
seems (from the published description) to only handle simple data types.
.pp
Where both of these methods break down is that the specification is separate
from the implementation.  Thus is is possible for a program which runs
correctly when compiled as a single process to fail when it is compiled with
the stub compiler, if the specification does not reflect the actual state of
the program.  The primary motivation behind RPCC is that of \fIsource
transparency\fP.  A system which derives the remote interface directly from
the C program will be more reliable,  since the programmer does not have to
worry about keeping a separate specification up to date.  Also, it becomes
possible to use the C compiler and \fIlint\fP to test program code, as long
as stub compiler directives do not change the syntax of the language.  This
is achieved by using C comments to direct the stub compiler.
.pp
The first problem is to identify which procedures must have an RPC
interface.  Because C does not have any modular structure aside from files
and static and extern declarations, we cannot deduce this information from
module interfaces.  Instead, each procedure which will be called through RPC
is marked with the comment \fC/*REMOTE*/.\fP  The stub compiler will parse
out the parameter and return types for the function, and generate any
necessary XDR functions.
.pp
Many common data structures in C are implemented using pointers to objects.
Strings are the prime example of this.  A pointer to a character is almost
always actually a pointer to the first of a null-terminated array of
characters.  Because this sort of trickery cannot be reliably determined by
a stub compiler, no attempt is made to second-guess the programmer.  A
pointer to a character is just that; if the programmer wishes to pack
strings a typedef and the \fC/*XDR=name*/\fP directive must be used.
Similarly, Sun RPC assigns no special meaning to null pointers; attempting
to pass one will usually crash the program.  If the programmer wishes to
preserve null pointers, for instance to pass a null-terminated linked list,
a user-defined XDR function must be used.
.pp
The C \*(lqunion\*(rq allows a number of different representations to apply
to a single memory location.  In general, there is no way to know which
representation applies at any given time.  \fIRpcgen\fP provides a
\fIdiscriminated union\fP, in which a control variable uniquely determines
the representation which should be used at run time.  While a similar
mechanism could be provided through RPCC directives, the complexity of such
a measure precluded its implementation.
.pp
This author's mind boggles at the semantic and implementation problems
involved in carrying function pointers across machines.  Mercifully, there
is little call for such a facility; no attempt is made to support it.
.pp
The Sun RPC library procedures used by RPCC restrict remote procedures to a
single parameter and return value, each of which may be an arbitrary data
type.  In order to handle general procedure calls, the RPCC client stub must
take the parameters from multi-parameter functions and create a single
structure to hold them all.  The server stub must take these parameters back
out of the structure before they are passed to the remote procedure.
.sh 1 "Using RPCC"
.pp
The simplest use of RPCC is to take a working program and make one function
in that program into a remote procedure.  The function must be in a separate
file from the main (client) program, so that they can be compiled separately
using \fIcc\fP after the stubs have been generated.  The function to be
called remotely should be immediately preceded by the special comment
\fC/*REMOTE*/\fP.  The client program must somewhere define a character
string called \fCHostName\fP, which must (at the time the stub is invoked)
contain the name of the machine the server is running on.  The generated
program uses the default program and version numbers \fCRUSERSPROG\fP and
\fCRUSERSVERS\fP from <rpcsvc/rusers.h>.  The remote procedures are numbered
in the order they are found in the source files.
.pp
As an example, we will develop a program called \fCradd\fP (Remote ADD),
which is contrived to demonstrate a few features.  The program consists of a
main routine which calls a function \fCadd()\fP of two integer parameters.
\fCAdd()\fP returns a pointer to a \fCstruct add_val\fP, which contains the
two summands and the sum; this is chosen to demonstrate XDR function
generation for structures.  The main routine is defined in file
\fCmain.c\fP, \fCadd()\fP is defined in file \fCadd.c\fP, and the structure
is defined in file \fCdefs.h\fP.  Compiling this with the command
.br
.ft C
cc -o radd main.c add.c
.ft P
.br
produces a program \fCradd\fP which runs on a single machine.
.pp
The stubs are generated by running RPCC on all of the files which contain
remote functions for a given server.  Necessary definitions are placed in
the file \fCX_xdr.h\fP, XDR conversion functions in \fCX_xdr.c\fP, client
stubs in \fCX_client.c\fP, and server stubs and the server \fCmain()\fP in
\fCX_server.c\fP.
All remote procedures must be done at
once, since RPCC gives consecutive numbers to all the procedures found in
one run and puts the output in fixed file names.  The commands
.sp
.ft C
rpcc add.c
.br
cc -o client main.c X_xdr.c X_client.c
.br
cc -o server X_server.c X_xdr.c add.c
.ft P
.sp
will produce an RPC version of \fCradd\fP where the program \fCserver\fP can
be run on one machine and \fCclient\fP on another.  Listings of \fCradd\fP,
as well as the code produced by RPCC, may be found in Appendix A.
.sh 2 "User Defined XDR Functions"
.pp
Automatic generation of XDR functions for some common data structures, such
as strings, unions, and variable length arrays, is not supported by RPCC.
In order to support a wider variety of data structures, RPCC allows the
programmer to associate handwritten XDR functions with specific data types
or structure elements.  This is done using another special comment, of the
form \fC/*XDR=name*/\fP.  The comment is placed immediately before the name
in the typedef or structure declaration.  For example,
.sp
.nf
.ft C
typedef char * /*XDR=xdr_wrapstring*/ STRING;
.sp
struct /*XDR=xdr_foo*/ foo
{
	int bar;
	int fumble;
};
.sp
struct joe
{
	int bob;
	short /*XDR=xdr_sue*/ sue;
};
.ft P
.fi
.sp
will associate the Sun XDR function \fCxdr_wrapstring()\fP (necessary for
passing string parameters) with the type STRING, the user-defined function
\fCxdr_foo()\fP with the type \fCstruct foo\fP, and \fCxdr_sue()\fP with
field \fCsue\fP within \fCstruct joe\fP.  Anywhere RPCC would normally
generate an XDR function for that type or invoke one for that type or field,
the specified XDR function will be used instead.
.sh 2 "More Sophisticated Uses"
.pp
The stubs generated by RPCC are limited by the middle-level interface to the
Sun RPC library.  The middle-level interface does not support call-back,
authentication, broadcast RPC, or use of different network protocols.  All
of these can be performed using lower level interfaces to the Sun library,
described in Sections 3 and 4 of the Remote Procedure Call Programming Guide
\*([[5\*(]].  Some hand modification of the RPCC stubs may be necessary
(for instance, removing the main program from \fCX_server.c\fP) in order to
use the stubs with lower-level RPC facilities.  This could be supported with
compiler options in future.
.sh 1 Implementation
.pp
RPCC is implemented in C in the 4.2BSD Unix environment.  Lex and Yacc were
used to generate the scanner and parser, respectively, which parse the
declarations from the C source and build tree data structures which
represent the functions, parameters and data types for which stubs should be
generated.  After all the source is processed, the definition trees are
traversed to generate the necessary code.
.pp
The front end from \fIlint\fP or \fIpcc\fP could have been used to parse the
source; this would have provided a more general and robust parser.  However,
sufficient documentation for the output from these was unavailable during
the time the system was being implemented.  Modifying the \fIpcc\fP source
was not an option because it would preclude the use of RPCC at sites without
source licenses.  Rather than trying to reverse-engineer the existing front
ends, a simple parser was implemented which only reads the global and
function definitions from files, and ignores all code and declarations
inside functions.  This removed all need for expression parsing, which is
the largest part of any C grammar.
.pp
Once the declarations have been parsed, RPCC takes each remote
function in turn and generates any stubs necessary.  Each remote procedure
is given a number, through a #define in X_xdr.h.    For each remote
procedure \fCname\fP, the constant \fCRP_name\fP gives the unique
number for that procedure.  Definitions for all structures and enums,
including structures created to handle multiple parameters, and external
definitions for all XDR and stub functions are also written into X_xdr.h.
The data structure trees for the function are traversed bottom-up and XDR
functions are generated where needed.  These functions are named
\fCxdr_name()\fP, where \fCname\fP is the name of the data type or
struct.
.pp
After all XDR routines are generated, the client and server stubs are
created.  These are placed in X_client.c and X_server.c.  The client stub
places multiple parameters into a structure if necessary, and then uses
\fCcallrpc()\fP to call the remote procedure.  The server main routine
registers the server stub using \fCregisterrpc()\fP and then waits for a
call to arrive; when a call comes in, the server stub unpacks multiple
parameters if they exist, calls the remote procedure, and returns the
result; the Sun library (through \fCregisterrpc()\fP) ensures that the
return value is packed correctly.
.sh 1 "Current Limitations"
.pp
The current implementation supports all simple data types: int, char, long,
short, signed, unsigned, float, double, and void; it can also handle
arbitrarily nested structures, enums, fixed length arrays, and pointers to
any supported data type (provided the pointers are not null).  Unions,
variable length arrays, and pointers to functions are not directly
supported, though the programmer can use support functions provided with Sun
RPC to simplify implementation of unions and variable length arrays.
.pp
The current implementation does not support reference parameters.
Modified parameters will not be copied back, so the changes will not be
reflected in the host environment.  Support for this would be relatively
simple to implement; any parameter which contains a pointer reference would
be included in a structure with the return value.  The server stub would
return the reference parameter along with the return value, and the client
stub would unpack it into the local reference parameter, leaving the
modified value in the caller's address space.
.sh 1 "Future Work"
.pp
Many possible extensions have been
mentioned in the preceding text.  Some method should be devised to handle
unions.  More support should be added for programmers who wish to use the
lower-level RPC library routines.  The system should handle reference
parameters correctly.
.pp
In the long run, the Sun RPC library routines provide a very cumbersome
interface, especially at lower levels.  RPC programming in general would be
much simpler with a system like the standard I/O library.  Remote procedure
calls would go to a default server, set up at program initialisation time.
Other servers could be \*(lqopened\*(rq and handled using a server
descriptor, much like stdio uses file descriptors.  Passing a server
descriptor to a calling stub will cause that stub to call its counterpart at
the specified server.  This could also be used to support callback, by
making the client's server descriptor one of the parameters to the server
stub.
.pp
C is a rather difficult language to handle RPC in, because it does not
directly support packaging of sections of a program into separate modules
with cleanly defined interfaces.  RPC is much cleaner in modular languages
with some support for object oriented programming, such as Eden's EPL\*([<\*([[1\*(]]\*(>] and Argus' version of Clu\*([<\*([[2\*(]]\*(>].  Perhaps C++, with its
support for modules and object-oriented programming, would be better as a
base language.  However, until C++ comes into much wider use some C tools
are still necessary.
.sh 1 Conclusions
.pp
The Sun RPC library, running on the Berkeley Unix networking system,
provides a workable interface for generating applications using Remote
Procedure Call.  There are a number of drawbacks, most notably the
relatively high overhead of high-level RPC and the complexity of the
low-level interface.  This is offset by the support for heterogeneous
environments and the relative simplicity of writing applications using the
high-level services.
.pp
RPCC provides the programmer with a direct migration path from
single process to multiple process applications by generating Remote
Procedure Call stubs directly from C code.  This differs from known existing
C stub compilers, which require a separate specification of the remote
interface.  By making the RPC extensions source transparent, traditional C
tools can be used to develop applications as single processes which can
then be recompiled into client and server modules without modifying the
source code.
.sh 1 Acknowledgements
.pp
The author is most grateful to Derek Eager and Susan Tourigny for comments
on drafts of this paper.  This work has been supported in part by a grant
from the Natural Sciences and Engineering Research Council of Canada.
.sh 1 References
.[]
.[-
.ds [F 1
.ds [A G\*(p]\*(a]T\*(p] Almes
.as [A \*(c]A\*(p]\*(a]P\*(p] Black
.as [A \*(c]E\*(p]\*(a]D\*(p] Lazowska
.as [A \*(m]J\*(p]\*(a]D\*(p] Noe
.ds [T The Eden System: A Technical Review
.ds [J IEEE Transactions on Software Engineering
.ds [V SE-11
.nr [P 1
.ds [P 43-59
.ds [D January 1985
.][
.[-
.ds [F 2
.ds [A B\*(p] Liskov
.ds [T Primitives for Distributed Computing
.ds [J Proceedings of the 7th Symp. on Operating System Prin.
.nr [P 1
.ds [P 33-42
.ds [D 1979
.][
.[-
.ds [F 3
.ds [A B\*(p] Nordin
.as [A \*(c]I\*(p]\*(a]A\*(p] Macleod
.as [A \*(m]T\*(p]\*(a]P\*(p] Martin
.ds [T Remote Operations Across a Network of Small Computers
.ds [J Proceedings of the 1986 ACM Sigsmall/PC Symposium on Small Systems
.ds [C San Francisco
.ds [D Dec. 3-5, 1986
.][
.[-
.ds [F 4
.ds [T rpcgen - An RPC Protocol Compiler
.ds [I Sun Microsystems, Inc.
.ds [D 1986
.][
.[-
.ds [F 5
.ds [T Remote Procedure Call Programming Guide
.ds [I Sun Microsystems, Inc.
.ds [D 1986
.][
.[-
.ds [F 6
.ds [T External Data Representation Protocol Specification.
.ds [I Sun Microsystems, Inc.
.ds [D 1986.
.][
.bp
.lp
.ps +2
Appendix A - sources for \*(lqradd\*(rq
.ps -2
.sp
.nf
.ft C
\fB==> main.c <==\fP
/* main program for rpcc demonstration */
#include <stdio.h>
#include "defs.h"
char *HostName = "sketch";

main()
{
    struct add_val	*temp, *add();

    temp = add(2, 3);
    printf("%d + %d = %d\\n", temp->p1, temp->p2, temp->sum);
    exit(0);
}
\fB==> add.c <==\fP
/* add function for radd - rpcc example program */
#include "defs.h"
/*REMOTE*/
struct add_val *
add(p1, p2)
int	p1, p2;
{
    static struct add_val result;

    result.p1 = p1;
    result.p2 = p2;
    result.sum = p1 + p2;
    return(&result);
}
\fB==> defs.h <==\fP
/* data definitions for radd - rpcc example program */
struct add_val
{
    int	p1, p2;
    int	sum;
};
\fB==> X_client.c <==\fP
/* Sun RPC interface automatically generated by RPCC */
#include "X_xdr.h"
extern char *HostName;

struct add_val	*add(p1, p2)
int	p1;
int	p2;
{
    struct add_val	*retval;
    struct X__0	temp;

    temp.p1 = p1;
    temp.p2 = p2;
    if (callrpc(HostName, RUSERSPROG, RUSERSVERS, RP_add,
		xdr_X__0, &temp, xdr_X__1, &retval) != 0)
    {
	write(2, "remote call to add failed\\n", 26);
	exit(1);
    }
    return(retval);
}
\fB==> X_server.c <==\fP
/* Sun RPC interface automatically generated by RPCC */
#include "X_xdr.h"

char *
XX_add(args)
struct X__0	*args;
{
    static struct add_val	*retval;
    retval = add(args->p1, args->p2);
    return((char *)&retval);
}

main()
{
    registerrpc(RUSERSPROG, RUSERSVERS, RP_add,
		XX_add, xdr_X__0, xdr_X__1);
    svc_run();
    write(2, "Error: svc_run returned\\n", 24);
    exit(1);
}
\fB==> X_xdr.c <==\fP
/* Sun RPC interface automatically generated by RPCC */
#include "X_xdr.h"
bool_t
xdr_add_val(xdrsp, str)
XDR	*xdrsp;
struct add_val	*str;
{
    if(!xdr_int(xdrsp, &str->p1))
	return(FALSE);
    if(!xdr_int(xdrsp, &str->p2))
	return(FALSE);
    if(!xdr_int(xdrsp, &str->sum))
	return(FALSE);
    return(TRUE);
}

bool_t
xdr_X__0(xdrsp, str)
XDR	*xdrsp;
struct X__0	*str;
{
    if(!xdr_int(xdrsp, &str->p1))
	return(FALSE);
    if(!xdr_int(xdrsp, &str->p2))
	return(FALSE);
    return(TRUE);
}

bool_t
xdr_X__1(xdrsp, str)
XDR	*xdrsp;
struct add_val	**str;
{
    if(!xdr_reference(xdrsp, str, sizeof(**str), xdr_add_val))
	return(FALSE);
    return(TRUE);
}
\fB==> X_xdr.h <==\fP
#include <rpc/rpc.h>
#include <rpcsvc/rusers.h>
struct add_val
{
    int p1;
    int p2;
    int sum;
};
#define RP_add	1
struct add_val	*add();
bool_t xdr_add_val();
struct X__0
{
    int	p1;
    int	p2;
};
bool_t xdr_X__0();
bool_t xdr_X__1();
.ft R
