[mod.sources] v06i092: Sun RPC Source

sources-request@mirror.UUCP (08/06/86)

Submitted by: cca!SUN.COM!marks (Mark Stein)
Mod.sources: Volume 6, Issue 92
Archive-name: rpc2/Part04

[  All I did was verify that the shar files unpacked correctly.  --r$  ]

Sun RPC source (part 4 of 11).  This software package contains code
and documentation for Revision 3.0 of the Sun Remote Procedure Call
library.  In addition, a beta version of the XDR/RPC protocol compiler
is included.  Comments about this latest release may be mailed to
sun!rpc or rpc@sun.com.

Sun RPC is a product of Sun Microsystems, Inc. and is provided for
unrestricted use provided that this legend is included on all tape
media and as a part of the software program in whole or part.  Users
may copy or modify Sun RPC without charge, but are not authorized to
license or distribute it to anyone else except as part of a product or
program developed by the user.

- - - - - - - - - C U T - H E R E - - - - - - - - - - - - - - - - - -
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	rpc/doc/rpc.prog.p2
#	rpc/doc/xdr.spec.p2
# This archive created: Mon Jul 14 16:55:08 1986
export PATH; PATH=/bin:/usr/bin:$PATH
for d in rpc rpc/doc rpc/rpclib rpc/tools rpc/toys rpc/rpclib/profiled rpc/rpcgen rpc/rpcgen/test
do
	if test ! -d $d
	then
		echo "shar: Making directory $d"
		mkdir $d
		chmod 755 $d
	fi
done
echo shar: "extracting 'rpc/doc/rpc.prog.p2'" '(33027 characters)'
if test -f 'rpc/doc/rpc.prog.p2'
then
	echo shar: "will not over-write existing file 'rpc/doc/rpc.prog.p2'"
else
sed 's/^X//' << \SHAR_EOF > 'rpc/doc/rpc.prog.p2'
X.LP
XIn order to do an RPC callback,
Xyou need a program number to make the RPC call on.
XSince this will be a dynamically generated program number,
Xit should be in the transient range, 0x40000000 - 0x5fffffff.
XThe routine
X.LW gettransient()
Xreturns a valid program number in the transient range,
Xand registers it with the portmapper.
XIt only talks to the portmapper running on the same machine as the
X.LW gettransient()
Xroutine itself.
XThe call to
X.LW pmap_set()
Xis a test and set operation,
Xin that it indivisibly tests whether a program number
Xhas already been registered,
Xand if it has not, then reserves it.
XOn return, the
X.LW sockp
Xargument will contain a socket that can be used
Xas the argument to an
X.LW svcudp_create()
Xor
X.LW svctcp_create()
Xcall.
X.BS
X.LS no
X#include <stdio.h>
X#include <rpc/rpc.h>
X#include <sys/socket.h>
X.sp.5
Xgettransient(proto, vers, sockp)
X	int proto, vers, *sockp;
X{
X	static int prognum = 0x40000000;
X	int s, len, socktype;
X	struct sockaddr_in addr;
X.sp.5
X	switch(proto) {
X		case IPPROTO_UDP:
X			socktype = SOCK_DGRAM;
X			break;
X		case IPPROTO_TCP:
X			socktype = SOCK_STREAM;
X			break;
X		default:
X			fprintf(stderr, "unknown protocol type\en");
X			return 0;
X	}
X	if (*sockp == RPC_ANYSOCK) {
X		if ((s = socket(AF_INET, socktype, 0)) < 0) {
X			perror("socket");
X			return (0);
X		}
X		*sockp = s;
X	}
X	else
X		s = *sockp;
X	addr.sin_addr.s_addr = 0;
X	addr.sin_family = AF_INET;
X	addr.sin_port = 0;
X	len = sizeof(addr);
X	/*
X	 * may be already bound, so don't check for error
X	 */
X	bind(s, &addr, len);
X	if (getsockname(s, &addr, &len)< 0) {
X		perror("getsockname");
X		return (0);
X	}
X	while (!pmap_set(prognum++, vers, proto, addr.sin_port))
X		continue;
X	return (prognum-1);
X}
X.Lf
X.BE
XThe following pair of programs illustrate how to use the
X.LW gettransient()
Xroutine.
XThe client makes an RPC call to the server,
Xpassing it a transient program number.
XThen the client waits around to receive a callback
Xfrom the server at that program number.
XThe server registers the program
X.LW EXAMPLEPROG ,
Xso that it can receive the RPC call
Xinforming it of the callback program number.
XThen at some random time (on receiving an
X.LW ALRM
Xsignal in this example), it sends a callback RPC call,
Xusing the program number it received earlier.
X.BS
X.LS no
X/*
X * client
X */
X#include <stdio.h>
X#include <rpc/rpc.h>
X.sp.5
Xint callback();
Xchar hostname[256];
X.sp.5
Xmain(argc, argv)
X	char **argv;
X{
X	int x, ans, s;
X	SVCXPRT *xprt;
X.sp.5
X	gethostname(hostname, sizeof(hostname));
X	s = RPC_ANYSOCK;
X	x = gettransient(IPPROTO_UDP, 1, &s);
X	fprintf(stderr, "client gets prognum %d\en", x);
X	if ((xprt = svcudp_create(s)) == NULL) {
X	  fprintf(stderr, "rpc_server: svcudp_create\en");
X		exit(1);
X	}
X	/* protocol is 0 - gettransient() does registering
X	 */
X	(void)svc_register(xprt, x, 1, callback, 0);
X	ans = callrpc(hostname, EXAMPLEPROG, EXAMPLEVERS,
X		EXAMPLEPROC_CALLBACK, xdr_int, &x, xdr_void, 0);
X	if (ans != RPC_SUCCESS) {
X		fprintf(stderr, "call: ");
X		clnt_perrno(ans);
X		fprintf(stderr, "\en");
X	}
X	svc_run();
X	fprintf(stderr, "Error: svc_run shouldn't return\en");
X}
X.sp.5
Xcallback(rqstp, transp)
X	register struct svc_req *rqstp;
X	register SVCXPRT *transp;
X{
X	switch (rqstp->rq_proc) {
X		case 0:
X			if (!svc_sendreply(transp, xdr_void, 0)) {
X				fprintf(stderr, "err: rusersd\en");
X				exit(1);
X			}
X			exit(0);
X		case 1:
X			if (!svc_getargs(transp, xdr_void, 0)) {
X				svcerr_decode(transp);
X				exit(1);
X			}
X			fprintf(stderr, "client got callback\en");
X			if (!svc_sendreply(transp, xdr_void, 0)) {
X				fprintf(stderr, "err: rusersd");
X				exit(1);
X			}
X	}
X}
X.sp.5
X/*
X * server
X */
X#include <stdio.h>
X#include <rpc/rpc.h>
X#include <sys/signal.h>
X.sp.5
Xchar *getnewprog();
Xchar hostname[256];
Xint docallback();
Xint pnum;		/* program number for callback routine */
X.sp.5
Xmain(argc, argv)
X	char **argv;
X{
X	gethostname(hostname, sizeof(hostname));
X	registerrpc(EXAMPLEPROG, EXAMPLEVERS,
X	  EXAMPLEPROC_CALLBACK, getnewprog, xdr_int, xdr_void);
X	fprintf(stderr, "server going into svc_run\en");
X	signal(SIGALRM, docallback);
X	alarm(10);
X	svc_run();
X	fprintf(stderr, "Error: svc_run shouldn't return\en");
X}
X.sp.5
Xchar *
Xgetnewprog(pnump)
X	char *pnump;
X{
X	pnum = *(int *)pnump;
X	return NULL;
X}
X.sp.5
Xdocallback()
X{
X	int ans;
X.sp.5
X	ans = callrpc(hostname, pnum, 1, 1, xdr_void, 0,
X		xdr_void, 0);
X	if (ans != 0) {
X		fprintf(stderr, "server: ");
X		clnt_perrno(ans);
X		fprintf(stderr, "\en");
X	}
X}
X.Lf
X.BE
X.SH
XAppendix A: Synopsis of RPC Routines
X.SH
Xauth_destroy()
X.LP
X.BS
X.LS
Xvoid
Xauth_destroy(auth)
X	AUTH *auth;
X.Lf
X.BE
XA macro that destroys the authentication information associated with
X.LW auth .
XDestruction usually involves deallocation
Xof private data structures.  The use of
X.LW auth
Xis undefined after calling
X.LW auth_destroy() .
X.SH
Xauthnone_create()
X.LP
X.BS
X.LS
XAUTH *
Xauthnone_create()
X.Lf
X.BE
XCreates and returns an RPC authentication handle that passes no
Xusable authentication information with each remote procedure call.
X.SH
Xauthunix_create()
X.LP
X.BS
X.LS
XAUTH *
Xauthunix_create(host, uid, gid, len, aup_gids)
X	char *host;
X	int uid, gid, len, *aup_gids;
X.Lf
X.BE
XCreates and returns an RPC authentication handle that contains
X.UX
Xauthentication information.
XThe parameter
X.LW host
Xis the name of the machine on which the information was created;
X.LW uid
Xis the user's user ID;
X.LW gid
Xis the user's current group ID;
X.LW len
Xand
X.LW aup_gids
Xrefer to a counted array of groups to which the user belongs.
XIt is easy to impersonate a user.
X.SH
Xauthunix_create\%_default()
X.LP
X.BS
X.LS
XAUTH *
Xauthunix_create_default()
X.Lf
X.BE
XCalls
X.LW authunix_create()
Xwith the appropriate parameters.
X.SH
Xcallrpc()
X.LP
X.BS
X.LS
Xcallrpc(host,prognum,versnum,procnum,inproc,in,outproc,out)
X	char *host;
X	u_long prognum, versnum, procnum;
X	char *in, *out;
X	xdrproc_t inproc, outproc;
X.Lf
X.BE
XCalls the remote procedure associated with
X.LW prognum ,
X.LW versnum ,
Xand
X.LW procnum
Xon the machine,
X.LW host .
XThe parameter
X.LW in
Xis the address of the procedure's argument(s), and
X.LW out
Xis the address of where to place the result(s);
X.LW inproc
Xis used to encode the procedure's parameters, and
X.LW outproc
Xis used to decode the procedure's results.
XThis routine returns zero if it succeeds, or the value of
X.LW "enum clnt_stat"
Xcast to an integer if it fails.
XThe routine
X.LW clnt_perrno()
Xis handy for translating failure statuses into messages.
XWarning: calling remote procedures with this routine
Xuses UDP/IP as a transport; see
X.LW clntudp_create()
Xfor restrictions.
X.SH
Xclnt_broadcast()
X.LP
X.BS
X.LS
Xenum clnt_stat
Xclnt_broadcast(prognum, versnum, procnum,
X  inproc, in, outproc, out, eachresult)
X	u_long prognum, versnum, procnum;
X	char *in, *out;
X	xdrproc_t inproc, outproc;
X	resultproc_t eachresult;
X.Lf
X.BE
XLike
X.LW callrpc() ,
Xexcept the call message is broadcast to all locally connected broadcast nets.
XEach time it receives a response, this routine calls
X.LW eachresult() ,
Xwhose form is
X.BS
X.LS
X	eachresult(out, addr)
X		char *out;
X		struct sockaddr_in *addr;
X.Lf
X.BE
Xwhere
X.LW out
Xis the same as
X.LW out
Xpassed to
X.LW clnt_broadcast() ,
Xexcept that the remote procedure's output is decoded there;
X.LW addr
Xpoints to the address of the machine that sent the results.  If
X.LW eachresult()
Xreturns zero,
X.LW clnt_broadcast()
Xwaits for more replies;
Xotherwise it returns with appropriate status.
X.SH
Xclnt_call()
X.LP
X.BS
X.LS
Xenum clnt_stat
Xclnt_call(clnt, procnum, inproc, in, outproc, out, tout)
X	CLIENT *clnt; long procnum;
X	xdrproc_t inproc, outproc;
X	char *in, *out;
X	struct timeval tout;
X.Lf
X.BE
XA macro that calls the remote procedure
X.LW procnum
Xassociated with the client handle,
X.LW clnt ,
Xwhich is obtained with an RPC client creation routine such as
X.LW clntudp_create() .
XThe parameter
X.LW in
Xis the address of the procedure's argument(s), and
X.LW out
Xis the address of where to place the result(s);
X.LW inproc
Xis used to encode the procedure's parameters, and
X.LW outproc
Xis used to decode the procedure's results;
X.LW tout
Xis the time allowed for results to come back.
X.SH
Xclnt_destroy()
X.LP
X.BS
X.LS
Xclnt_destroy(clnt)
X	CLIENT *clnt;
X.Lf
X.BE
XA macro that destroys the client's RPC handle.
XDestruction usually involves deallocation
Xof private data structures, including
X.LW clnt
Xitself.  Use of
X.LW clnt
Xis undefined after calling
X.LW clnt_destroy() .
XIt is the user's responsibility to close sockets associated with
X.LW clnt .
X.SH
Xclnt_freeres()
X.LP
X.BS
X.LS
Xclnt_freeres(clnt, outproc, out)
X	CLIENT *clnt;
X	xdrproc_t outproc;
X	char *out;
X.Lf
X.BE
XA macro that frees any data allocated by the RPC/XDR system
Xwhen it decoded the results of an RPC call.
XThe parameter
X.LW out
Xis the address of the results, and
X.LW outproc
Xis the XDR routine describing the results in simple primitives.
XThis routine returns one if the results were successfully freed,
Xand zero otherwise.
X.SH
Xclnt_geterr()
X.LP
X.BS
X.LS
Xvoid
Xclnt_geterr(clnt, errp)
X	CLIENT *clnt;
X	struct rpc_err *errp;
X.Lf
X.BE
XA macro that copies the error structure out of the client handle
Xto the structure at address
X.LW errp .
X.SH
Xclnt_pcreateerror()
X.LP
X.BS
X.LS
Xvoid
Xclnt_pcreateerror(s)
X	char *s;
X.Lf
X.BE
XPrints a message to standard error indicating
Xwhy a client RPC handle could not be created.
XThe message is prepended with string
X.LW s
Xand a colon.
XUsed after a
X.LW clntraw_create() ,
X.LW clnttcp_create() ,
Xor
X.LW clntudp_create()
Xcall.
X.SH
Xclnt_perrno()
X.LP
X.BS
X.LS
Xvoid
Xclnt_perrno(stat)
X	enum clnt_stat stat;
X.Lf
X.BE
XPrints a message to standard error corresponding
Xto the condition indicated by
X.LW stat .
XUsed after
X.LW callrpc() .
X.SH
Xclnt_perror()
X.LP
X.BS
X.LS
Xclnt_perror(clnt, s)
X	CLIENT *clnt;
X	char *s;
X.Lf
X.BE
XPrints a message to standard error indicating why an RPC call failed;
X.LW clnt
Xis the handle used to do the call.
XThe message is prepended with string
X.LW s
Xand a colon.
XUsed after
X.LW clnt_call() .
X.SH
Xclntraw_create()
X.LP
X.BS
X.LS
XCLIENT *
Xclntraw_create(prognum, versnum)
X	u_long prognum, versnum;
X.Lf
X.BE
XThis routine creates a toy RPC client for the remote program
X.LW prognum ,
Xversion
X.LW versnum .
XThe transport used to pass messages to the service
Xis actually a buffer within the process's address space,
Xso the corresponding RPC server should live in the same address space; see
X.LW svcraw_create() .
XThis allows simulation of RPC and acquisition of RPC overheads,
Xsuch as round trip times, without any kernel interference.
XThis routine returns
X.LW NULL
Xif it fails.
X.SH
Xclnttcp_create()
X.LP
X.BS
X.LS
XCLIENT *
Xclnttcp_create(addr,prognum,versnum,sockp,sendsz,recvsz)
X	struct sockaddr_in *addr;
X	u_long prognum, versnum;
X	int *sockp;
X	u_int sendsz, recvsz;
X.Lf
X.BE
XThis routine creates an RPC client for the remote program
X.LW prognum ,
Xversion
X.LW versnum ;
Xthe client uses TCP/IP as a transport.
XThe remote program is located at Internet address
X.LW *addr .
XIf
X.LW addr->sin_port
Xis zero, then it is set to the actual port that the remote
Xprogram is listening on (the remote
X.I portmap
Xservice is consulted for this information).
XThe parameter
X.LW *sockp
Xis a socket; if it is
X.LW RPC_ANYSOCK ,
Xthen this routine opens a new one and sets
X.LW *sockp .
XSince TCP-based RPC uses buffered I/O, the user may specify
Xthe size of the send and receive buffers with the parameters
X.LW sendsz
Xand
X.LW recvsz ;
Xvalues of zero choose suitable defaults.
XThis routine returns
X.LW NULL
Xif it fails.
X.SH
Xclntudp_create()
X.LP
X.BS
X.LS
XCLIENT *
Xclntudp_create(addr, prognum, versnum, wait, sockp)
X	struct sockaddr_in *addr;
X	u_long prognum, versnum;
X	struct timeval wait;
X	int *sockp;
X.Lf
X.BE
XThis routine creates an RPC client for the remote program
X.LW prognum ,
Xversion
X.LW versnum ;
Xthe client uses use UDP/IP as a transport.
XThe remote program is located at Internet address
X.LW *addr .
XIf
X.LW addr->sin_port
Xis zero, then it is set to actual port that the remote
Xprogram is listening on (the remote
X.I portmap
Xservice is consulted for this information).
XThe parameter
X.LW *sockp
Xis a socket; if it is
X.LW RPC_ANYSOCK ,
Xthen this routine opens a new one and sets
X.LW *sockp .
XThe UDP transport resends the call message in intervals of
X.LW wait
Xtime until a response is received or until the call times out.
XThe total time for the call to time out is specified by
X.LW clnt_call() .
XWarning: since UDP-based RPC messages can only hold up to 8 Kbytes
Xof encoded data, this transport cannot be used for procedures
Xthat take large arguments or return huge results.
X.SH
Xget_myaddress()
X.LP
X.BS
X.LS
Xvoid
Xget_myaddress(addr)
X	struct sockaddr_in *addr;
X.Lf
X.BE
XStuffs the machine's IP address into
X.LW *addr ,
Xwithout consulting the library routines that deal with
X.I /etc/hosts .
XThe port number is always set to
X.LW htons(PMAPPORT) .
X.SH
Xpmap_getmaps()
X.LP
X.BS
X.LS
Xstruct pmaplist *
Xpmap_getmaps(addr)
X	struct sockaddr_in *addr;
X.Lf
X.BE
XA user interface to the
X.I portmap
Xservice, which returns a list of the current RPC program-to-port mappings
Xon the host located at IP address
X.LW *addr .
XThis routine can return
X.LW NULL .
XThe command
X.LW "rpcinfo -p"
Xuses this routine.
X.SH
Xpmap_getport()
X.LP
X.BS
X.LS
Xu_short
Xpmap_getport(addr, prognum, versnum, protocol)
X	struct sockaddr_in *addr;
X	u_long prognum, versnum, protocol;
X.Lf
X.BE
XA user interface to the
X.I portmap
Xservice, which returns the port number
Xon which waits a service that supports program number
X.LW prognum ,
Xversion
X.LW versnum ,
Xand speaks the transport protocol associated with protocol.
XA return value of zero means that the mapping does not exist or that
Xthe RPC system failured to contact the remote
X.I portmap
Xservice.  In the latter case, the global variable
X.LW rpc_createerr
Xcontains the RPC status.
X.SH
Xpmap_rmtcall()
X.LP
X.BS
X.LS
Xenum clnt_stat
Xpmap_rmtcall(addr, prognum, versnum, procnum,
X  inproc, in, outproc, out, tout, portp)
X	struct sockaddr_in *addr;
X	u_long prognum, versnum, procnum;
X	char *in, *out;
X	xdrproc_t inproc, outproc;
X	struct timeval tout;
X	u_long *portp;
X.Lf
X.BE
XA user interface to the
X.I portmap
Xservice, which instructs
X.I portmap
Xon the host at IP address
X.LW *addr
Xto make an RPC call on your behalf to a procedure on that host.
XThe parameter
X.LW *portp
Xwill be modified to the program's port number if the procedure succeeds.
XThe definitions of other parameters are discussed in
X.LW callrpc()
Xand
X.LW clnt_call() .
XThis procedure should be used for a ``ping'' and nothing else.
XSee also
X.LW clnt_broadcast() .
X.SH
Xpmap_set()
X.LP
X.BS
X.LS
Xpmap_set(prognum, versnum, protocol, port)
X	u_long prognum, versnum, protocol;
X	u_short port;
X.Lf
X.BE
XA user interface to the
X.I portmap
Xservice, which establishes a mapping between the triple
X.LW [prognum,versnum,protocol]
Xand
X.LW port
Xon the machine's
X.I portmap
Xservice.  The value of protocol is most likely
X.LW IPPROTO_UDP
Xor
X.LW IPPROTO_TCP .
XThis routine returns one if it succeeds, zero otherwise.
XAutomatically done by
X.LW svc_register() .
X.SH
Xpmap_unset()
X.LP
X.BS
X.LS
Xpmap_unset(prognum, versnum)
X	u_long prognum, versnum;
X.Lf
X.BE
XA user interface to the
X.I portmap
Xservice, which destroys all mappings between the triple
X.LW [prognum,versnum,*]
Xand
X.LW ports
Xon the machine's
X.I portmap
Xservice.
XThis routine returns one if it succeeds, zero otherwise.
X.SH
Xregisterrpc()
X.LP
X.BS
X.LS
Xregisterrpc(prognum,versnum,procnum,procname,inproc,outproc)
X	u_long prognum, versnum, procnum;
X	char *(*procname)();
X	xdrproc_t inproc, outproc;
X.Lf
X.BE
XRegisters procedure
X.LW procname
Xwith the RPC service package.  If a request arrives for program
X.LW prognum ,
Xversion
X.LW versnum ,
Xand procedure
X.LW procnum ,
X.LW procname
Xis called with a pointer to its parameter(s);
X.LW progname
Xshould return a pointer to its static result(s);
X.LW inproc
Xis used to decode the parameters while
X.LW outproc
Xis used to encode the results.
XThis routine returns zero if the registration succeeded, \-1 otherwise.
XWarning: remote procedures registered in this form
Xare accessed using the UDP/IP transport; see
X.LW svcudp_create()
Xfor restrictions.
X.SH
Xrpc_createerr
X.LP
X.BS
X.LS
Xstruct rpc_createerr	rpc_createerr;
X.Lf
X.BE
XA global variable whose value is set by any RPC client creation routine
Xthat does not succeed.  Use the routine
X.LW clnt_pcreateerror()
Xto print the reason why.
X.SH
Xsvc_destroy()
X.LP
X.BS
X.LS
Xsvc_destroy(xprt)
X	SVCXPRT *xprt;
X.Lf
X.BE
XA macro that destroys the RPC service transport handle,
X.LW xprt .
XDestruction usually involves deallocation
Xof private data structures, including
X.LW xprt
Xitself.  Use of
X.LW xprt
Xis undefined after calling this routine.
X.SH
Xsvc_fds
X.LP
X.BS
X.LS
Xint	svc_fds;
X.Lf
X.BE
XA global variable reflecting the RPC service side's
Xread file descriptor bit mask; it is suitable as a parameter to the
X.LW select()
Xsystem call.  This is only of interest
Xif a service implementor does not call
X.LW svc_run() ,
Xbut rather does his own asynchronous event processing.
XThis variable is read-only (do not pass its address to
X.LW select() !),
Xyet it may change after calls to
X.LW svc_getreq()
Xor any creation routines.
X.SH
Xsvc_freeargs()
X.LP
X.BS
X.LS
Xsvc_freeargs(xprt, inproc, in)
X	SVCXPRT *xprt;
X	xdrproc_t inproc;
X	char *in;
X.Lf
X.BE
XA macro that frees any data allocated by the RPC/XDR system
Xwhen it decoded the arguments to a service procedure using
X.LW svc_getargs() .
XThis routine returns one if the results were successfully freed,
Xand zero otherwise.
X.SH
Xsvc_getargs()
X.LP
X.BS
X.LS
Xsvc_getargs(xprt, inproc, in)
X	SVCXPRT *xprt;
X	xdrproc_t inproc;
X	char *in;
X.Lf
X.BE
XA macro that decodes the arguments of an RPC request
Xassociated with the RPC service transport handle,
X.LW xprt .
XThe parameter
X.LW in
Xis the address where the arguments will be placed;
X.LW inproc
Xis the XDR routine used to decode the arguments.
XThis routine returns one if decoding succeeds, and zero otherwise.
X.SH
Xsvc_getcaller()
X.LP
X.BS
X.LS
Xstruct sockaddr_in
Xsvc_getcaller(xprt)
X	SVCXPRT *xprt;
X.Lf
X.BE
XThe approved way of getting the network address of the caller
Xof a procedure associated with the RPC service transport handle,
X.LW xprt .
X.SH
Xsvc_getreq()
X.LP
X.BS
X.LS
Xsvc_getreq(rdfds)
X	int rdfds;
X.Lf
X.BE
XThis routine is only of interest if a service implementor does not call
X.LW svc_run() ,
Xbut instead implements custom asynchronous event processing.
XIt is called when the
X.LW select()
Xsystem call has determined that an RPC request
Xhas arrived on some RPC socket(s);
X.LW rdfds
Xis the resultant read file descriptor bit mask.
XThe routine returns when all sockets associated with the value of
X.LW rdfds
Xhave been serviced.
X.SH
Xsvc_register()
X.LP
X.BS
X.LS
Xsvc_register(xprt, prognum, versnum, dispatch, protocol)
X	SVCXPRT *xprt;
X	u_long prognum, versnum;
X	void (*dispatch)();
X	u_long protocol;
X.Lf
X.BE
XAssociates
X.LW prognum
Xand
X.LW versnum
Xwith the service dispatch procedure,
X.LW dispatch() .
XIf
X.LW protocol
Xis zero, the service is not registered with the
X.I portmap
Xservice.  If
X.LW protocol
Xis non-zero, then a mapping of the triple
X.LW [prognum,versnum,protocol]
Xto
X.LW xprt->xp_port
Xis established with the local
X.I portmap
Xservice (generally
X.LW protocol
Xis zero,
X.LW IPPROTO_UDP
Xor
X.LW IPPROTO_TCP ).
XThe procedure
X.LW dispatch()
Xhas the following form:
X.BS
X.LS
X	dispatch(request, xprt)
X		struct svc_req *request;
X		SVCXPRT *xprt;
X.Lf
X.BE
XThe
X.LW svc_register()
Xroutine returns one if it succeeds, and zero otherwise.
X.SH
Xsvc_run()
X.LP
X.BS
X.LS
Xsvc_run()
X.Lf
X.BE
XThis routine never returns.  It waits for RPC requests to arrive,
Xand calls the appropriate service procedure using
X.LW svc_getreq()
Xwhen one arrives.  This procedure is usually waiting for a
X.LW select()
Xsystem call to return.
X.SH
Xsvc_sendreply()
X.LP
X.BS
X.LS
Xsvc_sendreply(xprt, outproc, out)
X	SVCXPRT *xprt;
X	xdrproc_t outproc;
X	char *out;
X.Lf
X.BE
XCalled by an RPC service's dispatch routine
Xto send the results of a remote procedure call.
XThe parameter
X.LW xprt
Xis the caller's associated transport handle;
X.LW outproc
Xis the XDR routine which is used to encode the results; and
X.LW out
Xis the address of the results.
XThis routine returns one if it succeeds, zero otherwise.
X.SH
Xsvc_unregister()
X.LP
X.BS
X.LS
Xvoid
Xsvc_unregister(prognum, versnum)
X	u_long prognum, versnum;
X.Lf
X.BE
XRemoves all mapping of the double
X.LW [prognum,versnum]
Xto dispatch routines, and of the triple
X.LW [prognum,versnum,*]
Xto port number.
X.SH
Xsvcerr_auth()
X.LP
X.BS
X.LS
Xvoid
Xsvcerr_auth(xprt, why)
X	SVCXPRT *xprt;
X	enum auth_stat why;
X.Lf
X.BE
XCalled by a service dispatch routine that refuses to perform
Xa remote procedure call due to an authentication error.
X.SH
Xsvcerr_decode()
X.LP
X.BS
X.LS
Xvoid
Xsvcerr_decode(xprt)
X	SVCXPRT *xprt;
X.Lf
X.BE
XCalled by a service dispatch routine that can't successfully
Xdecode its parameters.  See also
X.LW svc_getargs() .
X.SH
Xsvcerr_noproc()
X.LP
X.BS
X.LS
Xvoid
Xsvcerr_noproc(xprt)
X	SVCXPRT *xprt;
X.Lf
X.BE
XCalled by a service dispatch routine that doesn't implement
Xthe desired procedure number the caller request.
X.SH
Xsvcerr_noprog()
X.LP
X.BS
X.LS
Xvoid
Xsvcerr_noprog(xprt)
X	SVCXPRT *xprt;
X.Lf
X.BE
XCalled when the desired program is not registered with the RPC package.
XService implementors usually don't need this routine.
X.SH
Xsvcerr_progvers()
X.LP
X.BS
X.LS
Xvoid
Xsvcerr_progvers(xprt)
X	SVCXPRT *xprt;
X.Lf
X.BE
XCalled when the desired version of a program is not registered
Xwith the RPC package.
XService implementors usually don't need this routine.
X.SH
Xsvcerr_systemerr()
X.LP
X.BS
X.LS
Xvoid
Xsvcerr_systemerr(xprt)
X	SVCXPRT *xprt;
X.Lf
X.BE
XCalled by a service dispatch routine when it detects a system error
Xnot covered by any particular protocol.
XFor example, if a service can no longer allocate storage,
Xit may call this routine.
X.SH
Xsvcerr_weakauth()
X.LP
X.BS
X.LS
Xvoid
Xsvcerr_weakauth(xprt)
X	SVCXPRT *xprt;
X.Lf
X.BE
XCalled by a service dispatch routine that refuses to perform
Xa remote procedure call due to insufficient (but correct)
Xauthentication parameters.  The routine calls
X.LW svcerr_auth(xprt,AUTH_TOOWEAK) .
X.SH
Xsvcraw_create()
X.LP
X.BS
X.LS
XSVCXPRT *
Xsvcraw_create()
X.Lf
X.BE
XThis routine creates a toy RPC service transport,
Xto which it returns a pointer.  The transport
Xis really a buffer within the process's address space,
Xso the corresponding RPC client should live in the same address space; see
X.LW clntraw_create() .
XThis routine allows simulation of RPC and acquisition of RPC overheads
X(such as round trip times), without any kernel interference.
XThis routine returns
X.LW NULL
Xif it fails.
X.SH
Xsvctcp_create()
X.LP
X.BS
X.LS
XSVCXPRT *
Xsvctcp_create(sock, send_buf_size, recv_buf_size)
X	int sock;
X	u_int send_buf_size, recv_buf_size;
X.Lf
X.BE
XThis routine creates a TCP/IP-based RPC service transport,
Xto which it returns a pointer.
XThe transport is associated with the socket
X.LW sock ,
Xwhich may be
X.LW RPC_ANYSOCK ,
Xin which case a new socket is created.
XIf the socket is not bound to a local TCP port, then this routine
Xbinds it to an arbitrary port.  Upon completion,
X.LW xprt->xp_sock
Xis the transport's socket number, and
X.LW xprt->xp_port
Xis the transport's port number.
XThis routine returns
X.LW NULL
Xif it fails.  Since TCP-based RPC uses buffered I/O,
Xusers may specify the size of the
X.LW send
Xand
X.LW receive
Xbuffers; values of zero choose suitable defaults.
X.SH
Xsvcudp_create()
X.LP
X.BS
X.LS
XSVCXPRT *
Xsvcudp_create(sock)
X	int sock;
X.Lf
X.BE
XThis routine creates a UDP/IP-based RPC service transport,
Xto which it returns a pointer.
XThe transport is associated with the socket
X.LW sock ,
Xwhich may be
X.LW RPC_ANYSOCK ,
Xin which case a new socket is created.
XIf the socket is not bound to a local UDP port, then this routine
Xbinds it to an arbitrary port.  Upon completion,
X.LW xprt->xp_sock
Xis the transport's socket number, and
X.LW xprt->xp_port
Xis the transport's port number.
XThis routine returns
X.LW NULL
Xif it fails.
XWarning: since UDP-based RPC messages can only hold up to 8 Kbytes
Xof encoded data, this transport cannot be used for procedures
Xthat take large arguments or return huge results.
X.SH
Xxdr_accepted_reply()
X.LP
X.BS
X.LS
Xxdr_accepted_reply(xdrs, ar)
X	XDR *xdrs;
X	struct accepted_reply *ar;
X.Lf
X.BE
XUsed for describing RPC messages, externally.
XThis routine is useful for users who wish to generate
XRPC-style messages without using the RPC package.
X.SH
Xxdr_array()
X.LP
X.BS
X.LS
Xxdr_array(xdrs, arrp, sizep, maxsize, elsize, elproc)
X	XDR *xdrs;
X	char **arrp;
X	u_int *sizep, maxsize, elsize;
X	xdrproc_t elproc;
X.Lf
X.BE
XA filter primitive that translates between arrays
Xand their corresponding external representations.
XThe parameter
X.LW arrp
Xis the address of the pointer to the array, while
X.LW sizep
Xis the address of the element count of the array;
Xthis element count cannot exceed
X.LW maxsize .
XThe parameter
X.LW elsize
Xis the
X.LW sizeof()
Xeach of the array's elements, and
X.LW elproc
Xis an XDR filter that translates between
Xthe array elements' C form, and their external representation.
XThis routine returns one if it succeeds, zero otherwise.
X.SH
Xxdr_authunix_parms()
X.LP
X.BS
X.LS
Xxdr_authunix_parms(xdrs, aupp)
X	XDR *xdrs;
X	struct authunix_parms *aupp;
X.Lf
X.BE
XUsed for describing UNIX credentials, externally.
XThis routine is useful for users who wish to generate
Xthese credentials without using the RPC authentication package.
X.SH
Xxdr_bool()
X.LP
X.BS
X.LS
Xxdr_bool(xdrs, bp)
X	XDR *xdrs;
X	bool_t *bp;
X.Lf
X.BE
XA filter primitive that translates between booleans (C integers)
Xand their external representations.
XWhen encoding data, this filter produces values of either one or zero.
XThis routine returns one if it succeeds, zero otherwise.
X.SH
Xxdr_bytes()
X.LP
X.BS
X.LS
Xxdr_bytes(xdrs, sp, sizep, maxsize)
X	XDR *xdrs;
X	char **sp;
X	u_int *sizep, maxsize;
X.Lf
X.BE
XA filter primitive that translates between counted byte strings
Xand their external representations.
XThe parameter
X.LW sp
Xis the address of the string pointer.
XThe length of the string is located at address
X.LW sizep ;
Xstrings cannot be longer than
X.LW maxsize .
XThis routine returns one if it succeeds, zero otherwise.
X.SH
Xxdr_callhdr()
X.LP
X.BS
X.LS
Xvoid
Xxdr_callhdr(xdrs, chdr)
X	XDR *xdrs;
X	struct rpc_msg *chdr;
X.Lf
X.BE
XUsed for describing RPC messages, externally.
XThis routine is useful for users who wish to generate
XRPC-style messages without using the RPC package.
X.SH
Xxdr_callmsg()
X.LP
X.BS
X.LS
Xxdr_callmsg(xdrs, cmsg)
X	XDR *xdrs;
X	struct rpc_msg *cmsg;
X.Lf
X.BE
XUsed for describing RPC messages, externally.
XThis routine is useful for users who wish to generate
XRPC-style messages without using the RPC package.
X.SH
Xxdr_double()
X.LP
X.BS
X.LS
Xxdr_double(xdrs, dp)
X	XDR *xdrs;
X	double *dp;
X.Lf
X.BE
XA filter primitive that translates between C
X.LW double
Xprecision numbers and their external representations.
XThis routine returns one if it succeeds, zero otherwise.
X.SH
Xxdr_enum()
X.LP
X.BS
X.LS
Xxdr_enum(xdrs, ep)
X	XDR *xdrs;
X	enum_t *ep;
X.Lf
X.BE
XA filter primitive that translates between C
X.LW enum s
X(actually integers) and their external representations.
XThis routine returns one if it succeeds, zero otherwise.
X.SH
Xxdr_float()
X.LP
X.BS
X.LS
Xxdr_float(xdrs, fp)
X	XDR *xdrs;
X	float *fp;
X.Lf
X.BE
XA filter primitive that translates between C
X.LW float s
Xand their external representations.
XThis routine returns one if it succeeds, zero otherwise.
X.SH
Xxdr_inline()
X.LP
X.BS
X.LS
Xlong *
Xxdr_inline(xdrs, len)
X	XDR *xdrs;
X	int len;
X.Lf
X.BE
XA macro that invokes the in-line routine associated with the XDR stream,
X.LW xdrs .
XThe routine returns a pointer
Xto a contiguous piece of the stream's buffer;
X.LW len
Xis the byte length of the desired buffer.
XNote that pointer is cast to
X.LW "long *" .
XWarning:
X.LW xdr_inline()
Xmay return
X.LW NULL
X(0) if it cannot allocate a contiguous piece of a buffer.
XTherefore the behavior may vary among stream instances;
Xit exists for the sake of efficiency.
X.SH
Xxdr_int()
X.LP
X.BS
X.LS
Xxdr_int(xdrs, ip)
X	XDR *xdrs;
X	int *ip;
X.Lf
X.BE
XA filter primitive that translates between C integers
Xand their external representations.
XThis routine returns one if it succeeds, zero otherwise.
X.SH
Xxdr_long()
X.LP
X.BS
X.LS
Xxdr_long(xdrs, lp)
X	XDR *xdrs;
X	long *lp;
X.Lf
X.BE
XA filter primitive that translates between C
X.LW long
Xintegers and their external representations.
XThis routine returns one if it succeeds, zero otherwise.
X.SH
Xxdr_opaque()
X.LP
X.BS
X.LS
Xxdr_opaque(xdrs, cp, cnt)
X	XDR *xdrs;
X	char *cp;
X	u_int cnt;
X.Lf
X.BE
XA filter primitive that translates between fixed size opaque data
Xand its external representation.
XThe parameter
X.LW cp
Xis the address of the opaque object, and
X.LW cnt
Xis its size in bytes.
XThis routine returns one if it succeeds, zero otherwise.
X.SH
Xxdr_opaque_auth()
X.LP
X.BS
X.LS
Xxdr_opaque_auth(xdrs, ap)
X	XDR *xdrs;
X	struct opaque_auth *ap;
X.Lf
X.BE
XUsed for describing RPC messages, externally.
XThis routine is useful for users who wish to generate
XRPC-style messages without using the RPC package.
X.SH
Xxdr_pmap()
X.LP
X.BS
X.LS
Xxdr_pmap(xdrs, regs)
X	XDR *xdrs;
X	struct pmap *regs;
X.Lf
X.BE
XUsed for describing parameters to various
X.I portmap
Xprocedures, externally.
XThis routine is useful for users who wish to generate
Xthese parameters without using the
X.LW pmap
Xinterface.
X.SH
Xxdr_pmaplist()
X.LP
X.BS
X.LS
Xxdr_pmaplist(xdrs, rp)
X	XDR *xdrs;
X	struct pmaplist **rp;
X.Lf
X.BE
XUsed for describing a list of port mappings, externally.
XThis routine is useful for users who wish to generate
Xthese parameters without using the
X.LW pmap
Xinterface.
X.SH
Xxdr_reference()
X.LP
X.BS
X.LS
Xxdr_reference(xdrs, pp, size, proc)
X	XDR *xdrs;
X	char **pp;
X	u_int size;
X	xdrproc_t proc;
X.Lf
X.BE
XA primitive that provides pointer chasing within structures.
XThe parameter
X.LW pp
Xis the address of the pointer;
X.LW size
Xis the
X.LW sizeof()
Xthe structure that
X.LW *pp
Xpoints to; and
X.LW proc
Xis an XDR procedure that filters the structure
Xbetween its C form and its external representation.
XThis routine returns one if it succeeds, zero otherwise.
X.SH
Xxdr_rejected_reply()
X.LP
X.BS
X.LS
Xxdr_rejected_reply(xdrs, rr)
X	XDR *xdrs;
X	struct rejected_reply *rr;
X.Lf
X.BE
XUsed for describing RPC messages, externally.
XThis routine is useful for users who wish to generate
XRPC-style messages without using the RPC package.
X.SH
Xxdr_replymsg()
X.LP
X.BS
X.LS
Xxdr_replymsg(xdrs, rmsg)
X	XDR *xdrs;
X	struct rpc_msg *rmsg;
X.Lf
X.BE
XUsed for describing RPC messages, externally.
XThis routine is useful for users who wish to generate
XRPC style messages without using the RPC package.
X.SH
Xxdr_short()
X.LP
X.BS
X.LS
Xxdr_short(xdrs, sp)
X	XDR *xdrs;
X	short *sp;
X.Lf
X.BE
XA filter primitive that translates between C
X.LW short
Xintegers and their external representations.
XThis routine returns one if it succeeds, zero otherwise.
X.SH
Xxdr_string()
X.LP
X.BS
X.LS
Xxdr_string(xdrs, sp, maxsize)
X	XDR *xdrs;
X	char **sp;
X	u_int maxsize;
X.Lf
X.BE
XA filter primitive that translates between C strings and their
Xcorresponding external representations.
XStrings cannot be longer than
X.LW maxsize .
XNote that
X.LW sp
Xis the address of the string's pointer.
XThis routine returns one if it succeeds, zero otherwise.
X.SH
Xxdr_u_int()
X.LP
X.BS
X.LS
Xxdr_u_int(xdrs, up)
X	XDR *xdrs;
X	unsigned *up;
X.Lf
X.BE
XA filter primitive that translates between C
X.LW unsigned
Xintegers and their external representations.
XThis routine returns one if it succeeds, zero otherwise.
X.SH
Xxdr_u_long()
X.LP
X.BS
X.LS
Xxdr_u_long(xdrs, ulp)
X	XDR *xdrs;
X	unsigned long *ulp;
X.Lf
X.BE
XA filter primitive that translates between C
X.LW "unsigned long"
Xintegers and their external representations.
XThis routine returns one if it succeeds, zero otherwise.
X.SH
Xxdr_u_short()
X.LP
X.BS
X.LS
Xxdr_u_short(xdrs, usp)
X	XDR *xdrs;
X	unsigned short *usp;
X.Lf
X.BE
XA filter primitive that translates between C
X.LW "unsigned short"
Xintegers and their external representations.
XThis routine returns one if it succeeds, zero otherwise.
X.SH
Xxdr_union()
X.LP
X.BS
X.LS
Xxdr_union(xdrs, dscmp, unp, choices, dfault)
X	XDR *xdrs;
X	int *dscmp;
X	char *unp;
X	struct xdr_discrim *choices;
X	xdrproc_t dfault;
X.Lf
X.BE
XA filter primitive that translates between a discriminated C
X.LW union
Xand its corresponding external representation.  The parameter
X.LW dscmp
Xis the address of the union's discriminant, while
X.LW unp
Xin the address of the union.
XThis routine returns one if it succeeds, zero otherwise.
X.SH
Xxdr_void()
X.LP
X.BS
X.LS
Xxdr_void()
X.Lf
X.BE
XThis routine always returns one.
X.SH
Xxdr_wrapstring()
X.LP
X.BS
X.LS
Xxdr_wrapstring(xdrs, sp)
X	XDR *xdrs;
X	char **sp;
X.Lf
X.BE
XA primitive that calls
X.LW xdr_string(xdrs,sp,MAXUNSIGNED);
Xwhere
X.LW MAXUNSIGNED
Xis the maximum value of an unsigned integer.
XThis is handy because the RPC package passes
Xonly two parameters XDR routines, whereas
X.LW xdr_string() ,
Xone of the most frequently used primitives, requires three parameters.
XThis routine returns one if it succeeds, zero otherwise.
X.SH
Xxprt_register()
X.LP
X.BS
X.LS
Xvoid
Xxprt_register(xprt)
X	SVCXPRT *xprt;
X.Lf
X.BE
XAfter RPC service transport handles are created,
Xthey should register themselves with the RPC service package.
XThis routine modifies the global variable
X.LW svc_fds .
XService implementors usually don't need this routine.
X.SH
Xxprt_unregister()
X.LP
X.BS
X.LS
Xvoid
Xxprt_unregister(xprt)
X	SVCXPRT *xprt;
X.Lf
X.BE
XBefore an RPC service transport handle is destroyed,
Xit should unregister itself with the RPC service package.
XThis routine modifies the global variable
X.LW svc_fds .
XService implementors usually don't need this routine.
SHAR_EOF
if test 33027 -ne "`wc -c < 'rpc/doc/rpc.prog.p2'`"
then
	echo shar: "error transmitting 'rpc/doc/rpc.prog.p2'" '(should have been 33027 characters)'
fi
chmod 444 'rpc/doc/rpc.prog.p2'
fi
echo shar: "extracting 'rpc/doc/xdr.spec.p2'" '(16007 characters)'
if test -f 'rpc/doc/xdr.spec.p2'
then
	echo shar: "will not over-write existing file 'rpc/doc/xdr.spec.p2'"
else
sed 's/^X//' << \SHAR_EOF > 'rpc/doc/xdr.spec.p2'
X.LS
Xbool_t
Xxdr_wrap_list(xdrs, glp)
X	XDR *xdrs;
X	gnumbers_list *glp;
X{
X	return(xdr_reference(xdrs, glp, sizeof(struct gnnode),
X	    xdr_gnnode));
X}
X.Lf
X.LS
Xstruct xdr_discrim choices[2] = {
X	/*
X	 * called if another node needs (de)serializing
X	 */
X	{ TRUE, xdr_wrap_list },
X	/*
X	 * called when no more nodes need (de)serializing
X	 */
X	{ FALSE, xdr_void }
X}
X.sp.5
Xbool_t
Xxdr_gnumbers_list(xdrs, glp)
X	XDR *xdrs;
X	gnumbers_list *glp;
X{
X	bool_t more_data;
X.sp.5
X	more_data = (*glp != (gnumbers_list)NULL);
X	return(xdr_union(xdrs, &more_data, glp, choices, NULL);
X}
X.Lf
XThe entry routine is
X.LW xdr_gnumbers_list() ;
Xits job is to translate between the boolean value
X.LW more_data
Xand the list pointer values.
XIf there is no more data, the
X.LW xdr_union()
Xprimitive calls
X.LW xdr_void()
Xand the recursion is terminated.
XOtherwise,
X.LW xdr_union()
Xcalls
X.LW xdr_wrap_list() ,
Xwhose job is to dereference the list pointers.
XThe
X.LW xdr_gnnode()
Xroutine actually (de)serializes data of the current node
Xof the linked list, and recursively calls
X.LW xdr_gnumbers_list()
Xto handle the remainder of the list.
X.LP
XYou should convince yourself that these routines
Xfunction correctly in all three directions
X.LW (XDR_ENCODE ,
X.LW XDR_DECODE ,
Xand
X.LW XDR_FREE)
Xfor linked lists of any length (including zero).
XNote that the boolean
X.LW more_data
Xis always initialized, but in the
X.LW XDR_DECODE
Xcase it is overwritten by an externally generated value.
XAlso note that the value of the
X.LW bool_t
Xis lost in the stack.
XThe essence of the value is reflected in the list's pointers.
X.LP
XThe unfortunate side effect of (de)serializing a list
Xwith these routines is that the C stack grows linearly
Xwith respect to the number of nodes in the list.
XThis is due to the recursion.
XThe routines are also hard to 
Xcode (and understand) due to the number and nature of primitives involved
X(such as
X.LW xdr_reference ,
X.LW xdr_union ,
Xand
X.LW xdr_void ).
X.LP
XThe following routine collapses the recursive routines.
XIt also has other optimizations that are discussed below.
X.LS
Xbool_t
Xxdr_gnumbers_list(xdrs, glp)
X	XDR *xdrs;
X	gnumbers_list *glp;
X{
X	bool_t more_data;
X.sp.5
X	while (TRUE) {
X		more_data = (*glp != (gnumbers_list)NULL);
X		if (!xdr_bool(xdrs, &more_data))
X			return(FALSE);
X		if (!more_data)
X			return(TRUE);  /* we are done */
X		if (!xdr_reference(xdrs, glp, sizeof(struct gnnode),
X		    xdr_gnumbers))
X			return(FALSE);
X		glp = &((*glp)->nxt); 
X	}
X}
X.Lf
XThe claim is that this one routine is easier to code and understand than the
Xthree recursive routines above.
X(It is also buggy, as discussed below.)
XThe parameter
X.LW glp
Xis treated as the address of the pointer 
Xto the head of the
Xremainder of the list to be (de)serialized.
XThus,
X.LW glp
Xis set to the
Xaddress of the current node's
X.LW nxt
Xfield at the end of the while loop.
XThe discriminated union is implemented in-line; the variable
X.LW more_data
Xhas the same use in this routine as in the routines above.
XIts value is
Xrecomputed and re-(de)serialized each iteration of the loop.
XSince
X.LW *glp
Xis a pointer to a node, the pointer is dereferenced using 
X.LW xdr_reference() .
XNote that the third parameter is truly the size of a node
X(data values plus
X.LW nxt
Xpointer), while
X.LW xdr_gnumbers()
Xonly (de)serializes the data values.
XWe can get away with this tricky optimization only because the
X.LW nxt
Xdata comes after all legitimate external data.
X.LP
XThe routine is buggy in the
X.LW XDR_FREE
Xcase.  The bug is that
X.LW xdr_reference()
Xwill free the node
X.LW *glp .
XUpon return the assignment
X.LW "glp = &((*glp)->nxt)"
Xcannot be guaranteed to work since
X.LW *glp
Xis no longer a legitimate node.
XThe following is a rewrite that works in all cases.
XThe hard part is to avoid dereferencing a pointer
Xwhich has not been initialized or which has been freed.
X.LS
Xbool_t
Xxdr_gnumbers_list(xdrs, glp)
X	XDR *xdrs;
X	gnumbers_list *glp;
X{
X	bool_t more_data;
X	bool_t freeing;
X	gnumbers_list *next;  /* the next value of glp */
X.sp.5
X	freeing = (xdrs->x_op == XDR_FREE);
X	while (TRUE) {
X		more_data = (*glp != (gnumbers_list)NULL);
X		if (!xdr_bool(xdrs, &more_data))
X			return(FALSE);
X		if (!more_data)
X			return(TRUE);  /* we are done */
X		if (freeing)
X			next = &((*glp)->nxt);
X		if (!xdr_reference(xdrs, glp, sizeof(struct gnnode),
X		    xdr_gnumbers))
X			return(FALSE);
X		glp = (freeing) ? next : &((*glp)->nxt);
X	}
X}
X.Lf
XNote that this is the first example in this document
Xthat actually inspects the direction of the operation
X.LW xdrs->x_op ). (
XThe claim is that the correct iterative implementation is still 
Xeasier to understand or code than the recursive implementation.
XIt is certainly more efficient with respect to C stack requirements.
X.NH 2
XThe Record Marking Standard
X.LP
XA record is composed of one or more record fragments.
XA record fragment is a four-byte header followed by
X$ 0 ~ "\fRto\fP" ~ {2 sup 31} - 1$ bytes of fragment data.
XThe bytes encode an unsigned binary number;
Xas with XDR integers, the byte order is from highest to lowest.
XThe number encodes two values \(em
Xa boolean that indicates whether the fragment is the last fragment
Xof the record (bit value 1 implies the fragment is the last fragment),
Xand a 31-bit unsigned binary value
Xwhich is the length in bytes of the fragment's data.
XThe boolean value is the high-order bit of the
Xheader; the length is the 31 low-order bits.
X.LP
X(Note that this record specification is
X.I not
Xin XDR standard form
Xand cannot be implemented using XDR primitives!)
X.\"
X.bp
X.SH
XAppendix A -- Synopsis of XDR Routines
X.LP
X.LW xdr_array()
X.LS
Xxdr_array(xdrs, arrp, sizep, maxsize, elsize, elproc)
X	XDR *xdrs;
X	char **arrp;
X	u_int *sizep, maxsize, elsize;
X	xdrproc_t elproc;
X.Lf
XA filter primitive that translates between arrays
Xand their corresponding external representations.
XThe parameter
X.LW arrp
Xis the address of the pointer to the array, while
X.LW sizep
Xis the address of the element count of the array;
Xthis element count cannot exceed
X.LW maxsize .
XThe parameter
X.LW elsize
Xis the
X.LW sizeof()
Xeach of the array's elements, and
X.LW elproc
Xis an XDR filter that translates between
Xthe array elements' C form, and their external representation.  
XThis routine returns one if it succeeds, zero otherwise.
X.LP
X.LW xdr_bool()
X.LS
Xxdr_bool(xdrs, bp)
X	XDR *xdrs;
X	bool_t *bp;
X.Lf
XA filter primitive that translates between booleans (C integers)
Xand their external representations.
XWhen encoding data, this filter produces values of either one or zero.
XThis routine returns one if it succeeds, zero otherwise.
X.LP
X.LW xdr_bytes()
X.LS
Xxdr_bytes(xdrs, sp, sizep, maxsize)
X	XDR *xdrs;
X	char **sp;
X	u_int *sizep, maxsize;
X.Lf
XA filter primitive that translates between counted byte strings
Xand their external representations.
XThe parameter
X.LW sp
Xis the address of the string pointer.
XThe length of the string is located at address
X.LW sizep ;
Xstrings cannot be longer than
X.LW maxsize .
XThis routine returns one if it succeeds, zero otherwise.
X.LP
X.LW xdr_destroy()
X.LS
Xvoid
Xxdr_destroy(xdrs)
X	XDR *xdrs;
X.Lf
XA macro that invokes the destroy routine
Xassociated with the XDR stream,
X.LW xdrs .
XDestruction usually involves freeing private data structures
Xassociated with the stream.  Using
X.LW xdrs
Xafter invoking
X.LW xdr_destroy()
Xis undefined.
X.LP
X.LW xdr_double()
X.LS
Xxdr_double(xdrs, dp)
X	XDR *xdrs;
X	double *dp;
X.Lf
XA filter primitive that translates between C
X.LW double
Xprecision numbers and their external representations.
XThis routine returns one if it succeeds, zero otherwise.
X.LP
X.LW xdr_enum()
X.LS
Xxdr_enum(xdrs, ep)
X	XDR *xdrs;
X	enum_t *ep;
X.Lf
XA filter primitive that translates between C
X.LW enum s
X(actually integers) and their external representations.
XThis routine returns one if it succeeds, zero otherwise.
X.LP
X.LW xdr_float()
X.LS
Xxdr_float(xdrs, fp)
X	XDR *xdrs;
X	float *fp;
X.Lf
XA filter primitive that translates between C
X.LW float s
Xand their external representations.
XThis routine returns one if it succeeds, zero otherwise.
X.LP
X.LW xdr_getpos()
X.LS
Xu_int
Xxdr_getpos(xdrs)
X	XDR *xdrs;
X.Lf
XA macro that invokes the get-position routine
Xassociated with the XDR stream,
X.LW xdrs .
XThe routine returns an unsigned integer,
Xwhich indicates the position of the XDR byte stream.
XA desirable feature of XDR streams
Xis that simple arithmetic works with this number,
Xalthough the XDR stream instances need not guarantee this.
X.LP
X.LW xdr_inline()
X.LS
Xlong *
Xxdr_inline(xdrs, len)
X	XDR *xdrs;
X	int len;
X.Lf
XA macro that invokes the in-line routine associated with the XDR stream,
X.LW xdrs .
XThe routine returns a pointer
Xto a contiguous piece of the stream's buffer;
X.LW len
Xis the byte length of the desired buffer.
XNote that the pointer is cast to
X.LW "long *" .
XWarning:
X.LW xdr_inline()
Xmay return 
X.LW NULL
Xif it cannot allocate a contiguous piece of a buffer.
XTherefore the behavior may vary among stream instances;
Xit exists for the sake of efficiency.
X.LP
X.LW xdr_int()
X.LS
Xxdr_int(xdrs, ip)
X	XDR *xdrs;
X	int *ip;
X.Lf
XA filter primitive that translates between C integers
Xand their external representations.
XThis routine returns one if it succeeds, zero otherwise.
X.LP
X.LW xdr_long()
X.LS
Xxdr_long(xdrs, lp)
X	XDR *xdrs;
X	long *lp;
X.Lf
XA filter primitive that translates between C
X.LW long
Xintegers and their external representations.
XThis routine returns one if it succeeds, zero otherwise.
X.LP
X.LW xdr_opaque()
X.LS
Xxdr_opaque(xdrs, cp, cnt)
X	XDR *xdrs;
X	char *cp;
X	u_int cnt;
X.Lf
XA filter primitive that translates between fixed size opaque data
Xand its external representation.
XThe parameter
X.LW cp
Xis the address of the opaque object, and
X.LW cnt
Xis its size in bytes.
XThis routine returns one if it succeeds, zero otherwise.
X.LP
X.LW xdr_reference()
X.LS
Xxdr_reference(xdrs, pp, size, proc)
X	XDR *xdrs;
X	char **pp;
X	u_int size;
X	xdrproc_t proc;
X.Lf
XA primitive that provides pointer chasing within structures.
XThe parameter
X.LW pp
Xis the address of the pointer;
X.LW size
Xis the
X.LW sizeof()
Xthe structure that
X.LW *pp
Xpoints to; and
X.LW proc
Xis an XDR procedure that filters the structure
Xbetween its C form and its external representation.
XThis routine returns one if it succeeds, zero otherwise.
X.LP
X.LW xdr_setpos()
X.LS
Xxdr_setpos(xdrs, pos)
X	XDR *xdrs;
X	u_int pos;
X.Lf
XA macro that invokes the set position routine associated with the XDR stream
X.LW xdrs .
XThe parameter
X.LW pos
Xis a position value obtained from
X.LW xdr_getpos() .
XThis routine returns one if the XDR stream could be repositioned,
Xand zero otherwise.
XWarning: it is difficult to reposition some types of XDR streams,
Xso this routine may fail with one type of stream and succeed with another. 
X.LP
X.LW xdr_short()
X.LS
Xxdr_short(xdrs, sp)
X	XDR *xdrs;
X	short *sp;
X.Lf
XA filter primitive that translates between C
X.LW short
Xintegers and their external representations.
XThis routine returns one if it succeeds, zero otherwise.
X.LP
X.LW xdr_string()
X.LS
Xxdr_string(xdrs, sp, maxsize)
X	XDR *xdrs;
X	char **sp;
X	u_int maxsize;
X.Lf
XA filter primitive that translates between C strings and their
Xcorresponding external representations.
XStrings cannot cannot be longer than
X.LW maxsize .
XNote that
X.LW sp
Xis the address of the string's pointer.
XThis routine returns one if it succeeds, zero otherwise.
X.LP
X.LW xdr_u_int()
X.LS
Xxdr_u_int(xdrs, up)
X	XDR *xdrs;
X	unsigned *up;
X.Lf
XA filter primitive that translates between C
X.LW unsigned
Xintegers and their external representations.
XThis routine returns one if it succeeds, zero otherwise.
X.LP
X.LW xdr_u_long()
X.LS
Xxdr_u_long(xdrs, ulp)
X	XDR *xdrs;
X	unsigned long *ulp;
X.Lf
XA filter primitive that translates between C
X.LW "unsigned long"
Xintegers and their external representations.
XThis routine returns one if it succeeds, zero otherwise.
X.LP
X.LW xdr_u_short()
X.LS
Xxdr_u_short(xdrs, usp)
X	XDR *xdrs;
X	unsigned short *usp;
X.Lf
XA filter primitive that translates between C
X.LW "unsigned short"
Xintegers and their external representations.
XThis routine returns one if it succeeds, zero otherwise.
X.br
X.ne 2i
X.LW xdr_union()
X.LS
Xxdr_union(xdrs, dscmp, unp, choices, dfault)
X	XDR *xdrs;
X	int *dscmp;
X	char *unp;
X	struct xdr_discrim *choices;
X	xdrproc_t dfault;
X.Lf
XA filter primitive that translates between a discriminated C
X.LW union
Xand its corresponding external representation.  The parameter 
X.LW dscmp
Xis the address of the union's discriminant, while
X.Lunp
Xin the address of the union.
XThis routine returns one if it succeeds, zero otherwise.
X.LP
X.LW xdr_void()
X.LS
Xxdr_void()
X.Lf
XThis routine always returns one.
XIt may be passed to RPC routines that require a function parameter,
Xwhere nothing is to be done.
X.LP
X.LW xdr_wrapstring()
X.LS
Xxdr_wrapstring(xdrs, sp)
X	XDR *xdrs;
X	char **sp;
X.Lf
XA primitive that calls
X.LW xdr_string(xdrs,sp,MAXUNSIGNED);
Xwhere
X.LW MAXUNSIGNED
Xis the maximum value of an unsigned integer.
XThis is handy because the RPC package passes
Xonly two parameters XDR routines, whereas
X.LW xdr_string() ,
Xone of the most frequently used primitives, requires three parameters.
XThis routine returns one if it succeeds, zero otherwise.
X.LP
X.LW xdrmem_create()
X.LS
Xvoid
Xxdrmem_create(xdrs, addr, size, op)
X	XDR *xdrs;
X	char *addr;
X	u_int size;
X	enum xdr_op op;
X.Lf
XThis routine initializes the XDR stream object pointed to by
X.LW xdrs .
XThe stream's data is written to, or read from,
Xa chunk of memory at location
X.LW addr
Xwhose length is no more than
X.LW size
Xbytes long.  The
X.LW op
Xdetermines the direction of the XDR stream
X(either
X.LW XDR_ENCODE ,
X.LW XDR_DECODE ,
Xor
X.LW XDR_FREE ).
X.LP
X.LW xdrrec_create()
X.LS
Xvoid
Xxdrrec_create(xdrs,
X  sendsize, recvsize, handle, readit, writeit)
X	XDR *xdrs;
X	u_int sendsize, recvsize;
X	char *handle;
X	int (*readit)(), (*writeit)();
X.Lf
XThis routine initializes the XDR stream object pointed to by
X.LW xdrs .
XThe stream's data is written to a buffer of size
X.LW sendsize ;
Xa value of zero indicates the system should use a suitable default.
XThe stream's data is read from a buffer of size
X.LW recvsize ;
Xit too can be set to a suitable default by passing a zero value.
XWhen a stream's output buffer is full,
X.LW writeit()
Xis called.  Similarly, when a stream's input buffer is empty,
X.LW readit()
Xis called.  The behavior of these two routines
Xis similar to the
X.UX
Xsystem calls
X.LW read
Xand
X.LW write ,
Xexcept that
X.LW handle
Xis passed to the former routines as the first parameter.
XNote that the XDR stream's
X.LW op
Xfield must be set by the caller.
XWarning: this XDR stream implements an intermediate record stream.
XTherefore there are additional bytes in the stream
Xto provide record boundary information.
X.LP
X.LW xdrrec_endofrecord()
X.LS
Xxdrrec_endofrecord(xdrs, sendnow)
X	XDR *xdrs;
X	int sendnow;
X.Lf
XThis routine can be invoked only on streams created by
X.LW xdrrec_create() .
XThe data in the output buffer is marked as a completed record,
Xand the output buffer is optionally written out if
X.LW sendnow
Xis non-zero.  This routine returns one if it succeeds, zero otherwise.
X.LP
X.LW xdrrec_eof()
X.LS
Xxdrrec_eof(xdrs)
X	XDR *xdrs;
X	int empty;
X.Lf
XThis routine can be invoked only on streams created by
X.LW xdrrec_create() .
XAfter consuming the rest of the current record in the stream,
Xthis routine returns one if the stream has no more input, zero otherwise.
X.LP
X.LW xdrrec_skiprecord()
X.LS
Xxdrrec_skiprecord(xdrs)
X	XDR *xdrs;
X.Lf
XThis routine can be invoked only on streams created by
X.LW xdrrec_create() .
XIt tells the XDR implementation that the rest of the current record
Xin the stream's input buffer should be discarded.
XThis routine returns one if it succeeds, zero otherwise.
X.LP
X.LW xdrstdio_create()
X.LS
Xvoid
Xxdrstdio_create(xdrs, file, op)
X	XDR *xdrs;
X	FILE *file;
X	enum xdr_op op;
X.Lf
XThis routine initializes the XDR stream object pointed to by
X.LW xdrs .
XThe XDR stream data is written to, or read from, the Standard I/O stream
X.LW file .
XThe parameter
X.LW op
Xdetermines the direction of the XDR stream (either
X.LW XDR_ENCODE ,
X.LW XDR_DECODE ,
Xor
X.LW XDR_FREE ).
XWarning: the destroy routine associated with such XDR streams calls
X.LW fflush()
Xon the
X.LW file
Xstream, but never
X.LW fclose() . 
SHAR_EOF
if test 16007 -ne "`wc -c < 'rpc/doc/xdr.spec.p2'`"
then
	echo shar: "error transmitting 'rpc/doc/xdr.spec.p2'" '(should have been 16007 characters)'
fi
chmod 444 'rpc/doc/xdr.spec.p2'
fi
exit 0
#	End of shell archive