Changeset df49c60 in rtems for cpukit/librpc/src

Jun 12, 2000, 3:00:15 PM (20 years ago)
Joel Sherrill <joel.sherrill@…>
4.10, 4.11, 4.8, 4.9, master

Merged from 4.5.0-beta3a

83 edited


  • cpukit/librpc/src/

    r0ab65474 rdf49c60  
    2 ##  $Id$
     2## $Id$
    55AUTOMAKE_OPTIONS = foreign 1.4
    7 LIBNAME = librpc
    8 LIB = ${ARCH}/${LIBNAME}.a
     7SUBDIRS = xdr rpc
    10 C_FILES = rpc_callmsg.c rpc_prot.c svc.c svc_auth.c svc_udp.c xdr.c \
    11     xdr_array.c xdr_mem.c
    12 C_O_FILES = $(C_FILES:%.c=${ARCH}/%.o)
    14 SRCS = $(C_FILES)
    15 OBJS = $(C_O_FILES)
    17 include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
    18 include $(top_srcdir)/../../../automake/
    25 $(LIB): ${OBJS}
    26         $(make-library)
    29         $(INSTALL_DATA) $< $@
    33 EXTRA_DIST = $(C_FILES)
     9include $(top_srcdir)/../../../automake/
    3510include $(top_srcdir)/../../../automake/
  • cpukit/librpc/src/rpc/DISCLAIMER

    r0ab65474 rdf49c60  
     2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
     3 * unrestricted use provided that this legend is included on all tape
     4 * media and as a part of the software program in whole or part.  Users
     5 * may copy or modify Sun RPC without charge, but are not authorized
     6 * to license or distribute it to anyone else except as part of a product or
     7 * program developed by the user.
     8 *
     12 *
     13 * Sun RPC is provided with no support and without any obligation on the
     14 * part of Sun Microsystems, Inc. to assist in its use, correction,
     15 * modification or enhancement.
     16 *
     20 *
     21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
     22 * or profits or other special, indirect and consequential damages, even if
     23 * Sun has been advised of the possibility of such damages.
     24 *
     25 * Sun Microsystems, Inc.
     26 * 2550 Garcia Avenue
     27 * Mountain View, California  94043
     28 */
  • cpukit/librpc/src/rpc/

    r0ab65474 rdf49c60  
     2## $Id$
     5AUTOMAKE_OPTIONS = foreign 1.4 no-installman
     7SUBDIRS = PSD.doc
     9LIBNAME = librpc
     10LIB = $(ARCH)/$(LIBNAME).a
     12C_FILES = auth_none.c auth_unix.c authunix_prot.c bindresvport.c \
     13    clnt_generic.c clnt_perror.c clnt_raw.c clnt_simple.c clnt_tcp.c \
     14    clnt_udp.c get_myaddress.c getrpcent.c getrpcport.c netname.c netnamer.c \
     15    pmap_clnt.c pmap_getmaps.c pmap_getport.c pmap_prot.c pmap_prot2.c \
     16    pmap_rmt.c rpc_callmsg.c rpc_commondata.c rpc_dtablesize.c rpc_prot.c \
     17    rpcdname.c rtime.c svc.c svc_auth.c svc_auth_unix.c svc_raw.c svc_run.c \
     18    svc_simple.c svc_tcp.c svc_udp.c rtems_portmapper.c rtems_rpc.c
     19UNUSED_C_FILES = auth_des.c auth_time.c authdes_prot.c clnt_unix.c \
     20    crypt_client.c des_crypt.c des_soft.c getpublickey.c key_call.c \
     21    key_prot_xdr.c svc_auth_des.c svc_unix.c
     23C_O_FILES = $(C_FILES:%.c=$(ARCH)/%.o)
     25OBJS = $(C_O_FILES)
     27include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
     28include $(top_srcdir)/../../../automake/
     33# Add local stuff here using +=
     36AM_CPPFLAGS += '-D__P(x)=x' -D_read=read -D_write=write -D_close=close -D_RTEMS_RPC_INTERNAL_
     38$(LIB): $(OBJS)
     39        $(make-library)
     42        $(INSTALL_DATA) $< $@
     44noinst_MANS = bindresvport.3 getrpcent.3 publickey.3 rpc.3 rpc_secure.3 \
     45    rstat_svc.8 des_crypt.3 getrpcport.3 publickey.5 rpc.5 rstat.1 rtime.3
     48man_MANS = $(noinst_MANS)
     49all-local: $(ARCH) $(OBJS) $(TMPINSTALL_FILES)
     52.PRECIOUS: $(LIB)
     56include $(top_srcdir)/../../../automake/
     57include $(top_srcdir)/../../../automake/
  • cpukit/librpc/src/rpc/PSD.doc/.cvsignore

    r0ab65474 rdf49c60  
  • cpukit/librpc/src/rpc/PSD.doc/

    r0ab65474 rdf49c60  
     1## $Id$
     3AUTOMAKE_OPTIONS = foreign 1.4
     5EXTRA_DIST = \
     8include $(top_srcdir)/../../../automake/
  • cpukit/librpc/src/rpc/PSD.doc/

    r0ab65474 rdf49c60  
     2.\" Must use  --  tbl  --  with this one
     4.\" @(#)      2.2 88/08/05 4.0 RPCSRC BT
     6.if \\n%=1 .tl ''- % -''
     9.\" prevent excess underlining in nroff
     10.if n .fp 2 R
     11.OH 'Network File System: Version 2 Protocol Specification''Page %'
     12.EH 'Page %''Network File System: Version 2 Protocol Specification'
     13.if \\n%=1 .bp
     15\&Network File System: Version 2 Protocol Specification
     16.IX NFS "" "" "" PAGE MAJOR
     17.IX "Network File System" "" "" "" PAGE MAJOR
     18.IX NFS "version-2 protocol specification"
     19.IX "Network File System" "version-2 protocol specification"
     21.NH 0
     22\&Status of this Standard
     24Note: This document specifies a protocol that Sun Microsystems, Inc.,
     25and others are using.  It specifies it in standard ARPA RFC form.
     26.NH 1
     28.IX NFS introduction
     30The Sun Network Filesystem (NFS) protocol provides transparent remote
     31access to shared filesystems over local area networks.  The NFS
     32protocol is designed to be machine, operating system, network architecture,
     33and transport protocol independent.  This independence is
     34achieved through the use of Remote Procedure Call (RPC) primitives
     35built on top of an External Data Representation (XDR).  Implementations
     36exist for a variety of machines, from personal computers to
     39The supporting mount protocol allows the server to hand out remote
     40access privileges to a restricted set of clients.  It performs the
     41operating system-specific functions that allow, for example, to
     42attach remote directory trees to some local file system.
     43.NH 2
     44\&Remote Procedure Call
     45.IX "Remote Procedure Call"
     47Sun's remote procedure call specification provides a procedure-
     48oriented interface to remote services.  Each server supplies a
     49program that is a set of procedures.  NFS is one such "program".
     50The combination of host address, program number, and procedure
     51number specifies one remote service procedure.  RPC does not depend
     52on services provided by specific protocols, so it can be used with
     53any underlying transport protocol.  See the
     54.I "Remote Procedure Calls: Protocol Specification"
     55chapter of this manual.
     56.NH 2
     57\&External Data Representation
     58.IX "External Data Representation"
     60The External Data Representation (XDR) standard provides a common
     61way of representing a set of data types over a network. 
     62The NFS
     63Protocol Specification is written using the RPC data description
     65For more information, see the
     66.I " External Data Representation Standard: Protocol Specification." 
     67Sun provides implementations of XDR and
     68RPC,  but NFS does not require their use.  Any software that
     69provides equivalent functionality can be used, and if the encoding
     70is exactly the same it can interoperate with other implementations
     71of NFS.
     72.NH 2
     73\&Stateless Servers
     74.IX "stateless servers"
     75.IX servers stateless
     77The NFS protocol is stateless.  That is, a server does not need to
     78maintain any extra state information about any of its clients in
     79order to function correctly.  Stateless servers have a distinct
     80advantage over stateful servers in the event of a failure.  With
     81stateless servers, a client need only retry a request until the
     82server responds; it does not even need to know that the server has
     83crashed, or the network temporarily went down.  The client of a
     84stateful server, on the other hand, needs to either detect a server
     85crash and rebuild the server's state when it comes back up, or
     86cause client operations to fail.
     88This may not sound like an important issue, but it affects the
     89protocol in some unexpected ways.  We feel that it is worth a bit
     90of extra complexity in the protocol to be able to write very simple
     91servers that do not require fancy crash recovery.
     93On the other hand, NFS deals with objects such as files and
     94directories that inherently have state -- what good would a file be
     95if it did not keep its contents intact?  The goal is to not
     96introduce any extra state in the protocol itself.  Another way to
     97simplify recovery is by making operations "idempotent" whenever
     98possible (so that they can potentially be repeated).
     99.NH 1
     100\&NFS Protocol Definition
     101.IX NFS "protocol definition"
     102.IX NFS protocol
     104Servers have been known to change over time, and so can the
     105protocol that they use. So RPC provides a version number with each
     106RPC request. This RFC describes version two of the NFS protocol.
     107Even in the second version, there are various obsolete procedures
     108and parameters, which will be removed in later versions. An RFC
     109for version three of the NFS protocol is currently under
     111.NH 2
     112\&File System Model
     113.IX filesystem model
     115NFS assumes a file system that is hierarchical, with directories as
     116all but the bottom-level files.  Each entry in a directory (file,
     117directory, device, etc.)  has a string name.  Different operating
     118systems may have restrictions on the depth of the tree or the names
     119used, as well as using different syntax to represent the "pathname",
     120which is the concatenation of all the "components" (directory and
     121file names) in the name.  A "file system" is a tree on a single
     122server (usually a single disk or physical partition) with a specified
     123"root".  Some operating systems provide a "mount" operation to make
     124all file systems appear as a single tree, while others maintain a
     125"forest" of file systems.  Files are unstructured streams of
     126uninterpreted bytes.  Version 3 of NFS uses a slightly more general
     127file system model.
     129NFS looks up one component of a pathname at a time.  It may not be
     130obvious why it does not just take the whole pathname, traipse down
     131the directories, and return a file handle when it is done.  There are
     132several good reasons not to do this.  First, pathnames need
     133separators between the directory components, and different operating
     134systems use different separators.  We could define a Network Standard
     135Pathname Representation, but then every pathname would have to be
     136parsed and converted at each end.  Other issues are discussed in
     137\fINFS Implementation Issues\fP below.
     139Although files and directories are similar objects in many ways,
     140different procedures are used to read directories and files.  This
     141provides a network standard format for representing directories.  The
     142same argument as above could have been used to justify a procedure
     143that returns only one directory entry per call.  The problem is
     144efficiency.  Directories can contain many entries, and a remote call
     145to return each would be just too slow.
     146.NH 2
     147\&RPC Information
     148.IX NFS "RPC information"
     149.IP \fIAuthentication\fP
     150The   NFS  service uses
     151.I AUTH_UNIX ,
     152.I AUTH_DES ,
     154.I AUTH_SHORT
     156authentication, except in  the  NULL procedure where   
     157.I AUTH_NONE
     158is also allowed.
     159.IP "\fITransport Protocols\fP"
     160NFS currently is supported on UDP/IP only. 
     161.IP "\fIPort Number\fP"
     162The NFS protocol currently uses the UDP port number 2049.  This is
     163not an officially assigned port, so  later versions of the protocol
     164use the \*QPortmapping\*U facility of RPC.
     165.NH 2
     166\&Sizes of XDR Structures
     167.IX "XDR structure sizes"
     169These are the sizes, given in decimal bytes, of various XDR
     170structures used in the protocol:
     172/* \fIThe maximum number of bytes of data in a READ or WRITE request\fP  */
     173const MAXDATA = 8192;
     175/* \fIThe maximum number of bytes in a pathname argument\fP */
     176const MAXPATHLEN = 1024;
     178/* \fIThe maximum number of bytes in a file name argument\fP */
     179const MAXNAMLEN = 255;
     181/* \fIThe size in bytes of the opaque "cookie" passed by READDIR\fP */
     182const COOKIESIZE  = 4;
     184/* \fIThe size in bytes of the opaque file handle\fP */
     185const FHSIZE = 32;
     187.NH 2
     188\&Basic Data Types
     189.IX "NFS data types"
     190.IX NFS "basic data types"
     192The following XDR  definitions are basic  structures and types used
     193in other structures described further on.
     195.NH 3
     197.IX "NFS data types" stat "" \fIstat\fP
     199enum stat {
     200        NFS_OK = 0,
     201        NFSERR_PERM=1,
     202        NFSERR_NOENT=2,
     203        NFSERR_IO=5,
     204        NFSERR_NXIO=6,
     205        NFSERR_ACCES=13,
     206        NFSERR_EXIST=17,
     207        NFSERR_NODEV=19,
     208        NFSERR_NOTDIR=20,
     209        NFSERR_ISDIR=21,
     210        NFSERR_FBIG=27,
     211        NFSERR_NOSPC=28,
     212        NFSERR_ROFS=30,
     213        NFSERR_NAMETOOLONG=63,
     214        NFSERR_NOTEMPTY=66,
     215        NFSERR_DQUOT=69,
     216        NFSERR_STALE=70,
     217        NFSERR_WFLUSH=99
     223.I stat
     224type  is returned with every  procedure's  results.   A
     225value of
     226.I NFS_OK
     227indicates that the  call completed successfully and
     228the  results are  valid.  The  other  values indicate  some kind of
     229error  occurred on the  server  side  during the servicing   of the
     230procedure.  The error values are derived from UNIX error numbers.
     231.IP \fBNFSERR_PERM\fP:
     232Not owner.  The caller does not have correct ownership
     233to perform the requested operation.
     234.IP \fBNFSERR_NOENT\fP:
     235No such file or directory.    The file or directory
     236specified does not exist.
     237.IP \fBNFSERR_IO\fP:
     238Some sort of hard  error occurred when the operation was
     239in progress.  This could be a disk error, for example.
     240.IP \fBNFSERR_NXIO\fP:
     241No such device or address.
     242.IP \fBNFSERR_ACCES\fP:
     243Permission  denied.  The  caller does  not  have the
     244correct permission to perform the requested operation.
     245.IP \fBNFSERR_EXIST\fP:
     246File exists.  The file specified already exists.
     247.IP \fBNFSERR_NODEV\fP:
     248No such device.
     249.IP \fBNFSERR_NOTDIR\fP:
     250Not   a  directory.    The  caller  specified   a
     251non-directory in a directory operation.
     252.IP \fBNFSERR_ISDIR\fP:
     253Is a directory.  The caller specified  a directory in
     254a non- directory operation.
     255.IP \fBNFSERR_FBIG\fP:
     256File too large.   The  operation caused a file to grow
     257beyond the server's limit.
     258.IP \fBNFSERR_NOSPC\fP:
     259No space left on  device.   The operation caused the
     260server's filesystem to reach its limit.
     261.IP \fBNFSERR_ROFS\fP:
     262Read-only filesystem.  Write attempted on a read-only filesystem.
     264File name   too   long.  The file  name  in  an operation was too long.
     266Directory   not empty.  Attempted  to   remove  a
     267directory that was not empty.
     268.IP \fBNFSERR_DQUOT\fP:
     269Disk quota exceeded.  The client's disk  quota on the
     270server has been exceeded.
     271.IP \fBNFSERR_STALE\fP:
     272The  "fhandle" given in   the arguments was invalid.
     273That is, the file referred to by that file handle no longer exists,
     274or access to it has been revoked.
     275.IP \fBNFSERR_WFLUSH\fP:
     276The server's  write cache  used  in the
     278call got flushed to disk.
     281.NH 3
     283.IX "NFS data types" ftype "" \fIftype\fP
     285enum ftype {
     286        NFNON = 0,
     287        NFREG = 1,
     288        NFDIR = 2,
     289        NFBLK = 3,
     290        NFCHR = 4,
     291        NFLNK = 5
     295The enumeration
     296.I ftype
     297gives the type of a file.  The type
     298.I NFNON
     299indicates a non-file,
     300.I NFREG
     301is a regular file,
     302.I NFDIR
     303is a directory,
     304.I NFBLK
     305is a block-special device,
     306.I NFCHR
     307is a character-special device, and
     308.I NFLNK
     309is a symbolic link.
     311.NH 3
     313.IX "NFS data types" fhandle "" \fIfhandle\fP
     315typedef opaque fhandle[FHSIZE];
     319.I fhandle
     320is the file handle passed between the server and the client. 
     321All file operations are done using file handles to refer to a file or
     322directory.  The file handle can contain whatever information the server
     323needs to distinguish an individual file.
     325.NH 3
     327.IX "NFS data types" timeval "" \fItimeval\fP
     329struct timeval {
     330        unsigned int seconds;
     331        unsigned int useconds;
     336.I timeval
     337structure is the number of seconds and microseconds
     338since midnight January 1, 1970, Greenwich Mean Time.  It is used to
     339pass time and date information.
     341.NH 3
     343.IX "NFS data types" fattr "" \fIfattr\fP
     345struct fattr {
     346        ftype        type;
     347        unsigned int mode;
     348        unsigned int nlink;
     349        unsigned int uid;
     350        unsigned int gid;
     351        unsigned int size;
     352        unsigned int blocksize;
     353        unsigned int rdev;
     354        unsigned int blocks;
     355        unsigned int fsid;
     356        unsigned int fileid;
     357        timeval      atime;
     358        timeval      mtime;
     359        timeval      ctime;
     364.I fattr
     365structure contains the attributes of a file; "type" is the type of
     366the file; "nlink" is the number of hard links to the file (the number
     367of different names for the same file); "uid" is the user
     368identification number of the owner of the file; "gid" is the group
     369identification number of the group of the file; "size" is the size in
     370bytes of the file; "blocksize" is the size in bytes of a block of the
     371file; "rdev" is the device number of the file if it is type
     372.I NFCHR
     374.I NFBLK ;
     375"blocks" is the number of blocks the file takes up on disk; "fsid" is
     376the file system identifier for the filesystem containing the file;
     377"fileid" is a number that uniquely identifies the file within its
     378filesystem; "atime" is the time when the file was last accessed for
     379either read or write; "mtime" is the time when the file data was last
     380modified (written); and "ctime" is the time when the status of the
     381file was last changed.  Writing to the file also changes "ctime" if
     382the size of the file changes.
     384"mode" is the access mode encoded as a set of bits.  Notice that the
     385file type is specified both in the mode bits and in the file type.
     386This is really a bug in the protocol and will be fixed in future
     387versions.  The descriptions given below specify the bit positions
     388using octal numbers.
     390box tab (&) ;
     391cfI cfI
     392lfL l .
     3950040000&This is a directory; "type" field should be NFDIR.
     3960020000&This is a character special file; "type" field should be NFCHR.
     3970060000&This is a block special file; "type" field should be NFBLK.
     3980100000&This is a regular file; "type" field should be NFREG.
     3990120000&This is a symbolic link file;  "type" field should be NFLNK.
     4000140000&This is a named socket; "type" field should be NFNON.
     4010004000&Set user id on execution.
     4020002000&Set group id on execution.
     4030001000&Save swapped text even after use.
     4040000400&Read permission for owner.
     4050000200&Write permission for owner.
     4060000100&Execute and search permission for owner.
     4070000040&Read permission for group.
     4080000020&Write permission for group.
     4090000010&Execute and search permission for group.
     4100000004&Read permission for others.
     4110000002&Write permission for others.
     4120000001&Execute and search permission for others.
     417The bits are  the same as the mode   bits returned  by  the
     418.I stat(2)
     419system call in the UNIX system.  The file  type is  specified  both in
     420the mode  bits  and in  the file type.   This   is fixed  in future
     423The "rdev" field in the attributes structure is an operating system
     424specific device specifier.  It  will be  removed and generalized in
     425the next revision of the protocol.
     429.NH 3
     431.IX "NFS data types" sattr "" \fIsattr\fP
     433struct sattr {
     434        unsigned int mode;
     435        unsigned int uid;
     436        unsigned int gid;
     437        unsigned int size;
     438        timeval      atime;
     439        timeval      mtime;
     444.I sattr
     445structure contains the file attributes which can be set
     446from the client.  The fields are the same as for 
     447.I fattr
     448above.  A "size" of zero  means the file should be  truncated.
     449A value of -1 indicates a field that should be ignored.
     452.NH 3
     454.IX "NFS data types" filename "" \fIfilename\fP
     456typedef string filename<MAXNAMLEN>;
     459The type
     460.I filename
     461is used for  passing file names  or  pathname components.
     464.NH 3
     466.IX "NFS data types" path "" \fIpath\fP
     468typedef string path<MAXPATHLEN>;
     471The type
     472.I path
     473is a pathname.  The server considers it as a string
     474with no internal structure,  but to the client  it is the name of a
     475node in a filesystem tree.
     478.NH 3
     480.IX "NFS data types" attrstat "" \fIattrstat\fP
     482union attrstat switch (stat status) {
     483        case NFS_OK:
     484                fattr attributes;
     485        default:
     486                void;
     491.I attrstat
     492structure is a common procedure result.  It contains
     493a  "status" and,  if  the call   succeeded,   it also contains  the
     494attributes of the file on which the operation was done.
     497.NH 3
     499.IX "NFS data types" diropargs "" \fIdiropargs\fP
     501struct diropargs {
     502        fhandle  dir;
     503        filename name;
     508.I diropargs
     509structure is used  in  directory  operations.  The
     510"fhandle" "dir" is the directory in  which to find the file "name".
     511A directory operation is one in which the directory is affected.
     514.NH 3
     516.IX "NFS data types" diropres "" \fIdiropres\fP
     518union diropres switch (stat status) {
     519        case NFS_OK:
     520                struct {
     521                        fhandle file;
     522                        fattr   attributes;
     523                } diropok;
     524        default:
     525                void;
     529The results of a directory operation  are returned  in a
     530.I diropres
     531structure.  If the call succeeded, a new file handle "file" and the
     532"attributes" associated with that file are  returned along with the
     534.NH 2
     535\&Server Procedures
     536.IX "NFS server procedures" "" "" "" PAGE MAJOR
     538The  protocol definition  is given as   a  set  of  procedures with
     539arguments  and results defined using the   RPC  language.   A brief
     540description of the function of each procedure should provide enough
     541information to allow implementation.
     543All of  the procedures  in   the NFS  protocol  are assumed  to  be
     544synchronous.   When a procedure  returns to the  client, the client
     545can assume that the operation has completed and any data associated
     546with the request is  now on stable storage.  For  example, a client
     547.I WRITE
     548request   may  cause  the   server  to  update  data  blocks,
     549filesystem information blocks (such as indirect  blocks),  and file
     550attribute  information (size  and  modify  times).  When  the
     551.I WRITE
     552returns to the client, it can assume  that the write  is safe, even
     553in case of  a server  crash, and  it can discard the  data written.
     554This is a very important part  of the statelessness  of the server.
     555If the server waited to flush data from remote requests, the client
     556would have to  save those requests so that  it could resend them in
     557case of a server crash. t .DS
     559.el .DS L
     561.ft I
     563* Remote file service routines
     565.ft CW
     566program NFS_PROGRAM {
     567        version NFS_VERSION {
     568                void        NFSPROC_NULL(void)              = 0;
     569                attrstat    NFSPROC_GETATTR(fhandle)        = 1;
     570                attrstat    NFSPROC_SETATTR(sattrargs)      = 2;
     571                void        NFSPROC_ROOT(void)              = 3;
     572                diropres    NFSPROC_LOOKUP(diropargs)       = 4;
     573                readlinkres NFSPROC_READLINK(fhandle)       = 5;
     574                readres     NFSPROC_READ(readargs)          = 6;
     575                void        NFSPROC_WRITECACHE(void)        = 7;
     576                attrstat    NFSPROC_WRITE(writeargs)        = 8;
     577                diropres    NFSPROC_CREATE(createargs)      = 9;
     578                stat        NFSPROC_REMOVE(diropargs)       = 10;
     579                stat        NFSPROC_RENAME(renameargs)      = 11;
     580                stat        NFSPROC_LINK(linkargs)          = 12;
     581                stat        NFSPROC_SYMLINK(symlinkargs)    = 13;
     582                diropres    NFSPROC_MKDIR(createargs)       = 14;
     583                stat        NFSPROC_RMDIR(diropargs)        = 15;
     584                readdirres  NFSPROC_READDIR(readdirargs)    = 16;
     585                statfsres   NFSPROC_STATFS(fhandle)         = 17;
     586        } = 2;
     587} = 100003;
     590.NH 3
     591\&Do Nothing
     592.IX "NFS server procedures" NFSPROC_NULL() "" \fINFSPROC_NULL()\fP
     595NFSPROC_NULL(void) = 0;
     598This procedure does no work.   It is made available  in  all RPC
     599services to allow server response testing and timing.
     601.NH 3
     602\&Get File Attributes
     603.IX "NFS server procedures" NFSPROC_GETATTR() "" \fINFSPROC_GETATTR()\fP
     606NFSPROC_GETATTR (fhandle) = 1;
     609If the reply  status is
     610.I NFS_OK ,
     611then  the reply attributes contains
     612the attributes for the file given by the input fhandle.
     614.NH 3
     615\&Set File Attributes
     616.IX "NFS server procedures" NFSPROC_SETATTR() "" \fINFSPROC_SETATTR()\fP
     618struct sattrargs {
     619        fhandle file;
     620        sattr attributes;
     621        };
     624NFSPROC_SETATTR (sattrargs) = 2;
     627The  "attributes" argument  contains fields which are either  -1 or
     628are  the  new value for  the  attributes of  "file".   If the reply
     629status is
     630.I NFS_OK ,
     631then the  reply attributes have the attributes of
     632the file after the "SETATTR" operation has completed.
     634Note: The use of -1 to indicate an unused field in "attributes" is
     635changed in the next version of the protocol.
     637.NH 3
     638\&Get Filesystem Root
     639.IX "NFS server procedures" NFSPROC_ROOT "" \fINFSPROC_ROOT\fP
     642NFSPROC_ROOT(void) = 3;
     645Obsolete.  This procedure  is no longer used   because  finding the
     646root file handle of a filesystem requires moving  pathnames between
     647client  and server.  To  do  this right we would  have  to define a
     648network standard representation of pathnames.  Instead, the
     649function  of  looking up  the   root  file handle  is  done  by the
     650.I MNTPROC_MNT()
     651procedure.    (See the
     652.I "Mount Protocol Definition"
     653later in this chapter for details).
     655.NH 3
     656\&Look Up File Name
     657.IX "NFS server procedures" NFSPROC_LOOKUP() "" \fINFSPROC_LOOKUP()\fP
     660NFSPROC_LOOKUP(diropargs) = 4;
     663If  the reply "status"  is
     664.I NFS_OK ,
     665then the reply  "file" and reply
     666"attributes" are the file handle and attributes for the file "name"
     667in the directory given by "dir" in the argument.
     669.NH 3
     670\&Read From Symbolic Link
     671.IX "NFS server procedures" NFSPROC_READLINK() "" \fINFSPROC_READLINK()\fP
     673union readlinkres switch (stat status) {
     674        case NFS_OK:
     675                path data;
     676        default:
     677                void;
     681NFSPROC_READLINK(fhandle) = 5;
     684If "status" has the value
     685.I NFS_OK ,
     686then the reply "data" is the data in
     687the symbolic link given by the file referred to by the fhandle argument.
     689Note:  since   NFS always  parses pathnames    on the  client, the
     690pathname in  a symbolic  link may  mean something  different (or be
     691meaningless) on a different client or on the server if  a different
     692pathname syntax is used.
     694.NH 3
     695\&Read From File
     696.IX "NFS server procedures" NFSPROC_READ "" \fINFSPROC_READ\fP
     698struct readargs {
     699        fhandle file;
     700        unsigned offset;
     701        unsigned count;
     702        unsigned totalcount;
     705union readres switch (stat status) {
     706        case NFS_OK:
     707                fattr attributes;
     708                opaque data<NFS_MAXDATA>;
     709        default:
     710                void;
     714NFSPROC_READ(readargs) = 6;
     717Returns  up  to  "count" bytes of   "data" from  the file  given by
     718"file", starting at "offset" bytes from  the beginning of the file.
     719The first byte of the file is  at offset zero.  The file attributes
     720after the read takes place are returned in "attributes".
     722Note: The  argument "totalcount" is  unused, and is removed in the
     723next protocol revision.
     725.NH 3
     726\&Write to Cache
     727.IX "NFS server procedures" NFSPROC_WRITECACHE() "" \fINFSPROC_WRITECACHE()\fP
     730NFSPROC_WRITECACHE(void) = 7;
     733To be used in the next protocol revision.
     735.NH 3
     736\&Write to File
     737.IX "NFS server procedures" NFSPROC_WRITE() "" \fINFSPROC_WRITE()\fP
     739struct writeargs {
     740        fhandle file;         
     741        unsigned beginoffset; 
     742        unsigned offset;       
     743        unsigned totalcount;   
     744        opaque data<NFS_MAXDATA>;
     748NFSPROC_WRITE(writeargs) = 8;
     751Writes   "data" beginning  "offset"  bytes  from the  beginning  of
     752"file".  The first byte  of  the file is at  offset  zero.  If  the
     753reply "status" is NFS_OK, then  the reply "attributes" contains the
     754attributes  of the file after the  write has  completed.  The write
     755operation is atomic.  Data from this  call to
     756.I WRITE
     757will not be mixed with data from another client's calls.
     759Note: The arguments "beginoffset" and "totalcount" are ignored and
     760are removed in the next protocol revision.
     762.NH 3
     763\&Create File
     764.IX "NFS server procedures" NFSPROC_CREATE() "" \fINFSPROC_CREATE()\fP
     766struct createargs {
     767        diropargs where;
     768        sattr attributes;
     772NFSPROC_CREATE(createargs) = 9;
     775The file "name" is created  in the directory given  by "dir".   The
     776initial  attributes of the  new file  are given by "attributes".  A
     777reply "status"  of NFS_OK indicates that the  file was created, and
     778reply "file"   and   reply "attributes"  are    its file handle and
     779attributes.   Any  other reply  "status"  means that  the operation
     780failed and no file was created.
     782Note: This  routine should pass  an exclusive create flag, meaning
     783"create the file only if it is not already there".
     785.NH 3
     786\&Remove File
     787.IX "NFS server procedures" NFSPROC_REMOVE() "" \fINFSPROC_REMOVE()\fP
     790NFSPROC_REMOVE(diropargs) = 10;
     793The file "name" is  removed from the directory  given by "dir".   A
     794reply of NFS_OK means the directory entry was removed.
     796Note: possibly non-idempotent operation.
     798.NH 3
     799\&Rename File
     800.IX "NFS server procedures" NFSPROC_RENAME() "" \fINFSPROC_RENAME()\fP
     802struct renameargs {
     803        diropargs from;
     804        diropargs to;
     808NFSPROC_RENAME(renameargs) = 11;
     811The existing file "" in  the directory given by "from.dir"
     812is renamed to "" in the directory given by "to.dir".  If the
     813reply  is
     814.I NFS_OK ,
     815the file was  renamed.  The 
     817operation is
     818atomic on the server; it cannot be interrupted in the middle.
     820Note: possibly non-idempotent operation.
     822.NH 3
     823\&Create Link to File
     824.IX "NFS server procedures" NFSPROC_LINK() "" \fINFSPROC_LINK()\fP
     826struct linkargs {
     827        fhandle from;
     828        diropargs to;
     832NFSPROC_LINK(linkargs) = 12;
     835Creates the  file ""  in the directory  given   by "to.dir",
     836which is a hard link to the existing file given  by "from".  If the
     837return value is
     838.I NFS_OK ,
     839a link was created.  Any other return value
     840indicates an error, and the link was not created.
     842A hard link should have the property that changes  to either of the
     843linked files are reflected in both files.  When a hard link is made
     844to a  file, the attributes  for  the file should  have  a value for
     845"nlink" that is one greater than the value before the link.
     847Note: possibly non-idempotent operation.
     849.NH 3
     850\&Create Symbolic Link
     851.IX "NFS server procedures" NFSPROC_SYMLINK() "" \fINFSPROC_SYMLINK()\fP
     853struct symlinkargs {
     854        diropargs from;
     855        path to;
     856        sattr attributes;
     860NFSPROC_SYMLINK(symlinkargs) = 13;
     863Creates the  file "" with  ftype 
     864.I NFLNK
     865in  the  directory
     866given by "from.dir".   The new file contains  the pathname "to" and
     867has initial attributes given by "attributes".  If  the return value
     869.I NFS_OK ,
     870a link was created.  Any other return value indicates an
     871error, and the link was not created.
     873A symbolic  link is  a pointer to another file.   The name given in
     874"to" is  not interpreted by  the server, only stored in  the  newly
     875created file.  When the client references a file that is a symbolic
     876link, the contents of the symbolic  link are normally transparently
     877reinterpreted  as a pathname  to substitute.   A
     878.I READLINK
     879operation returns the data to the client for interpretation.
     881Note:  On UNIX servers the attributes are never used, since
     882symbolic links always have mode 0777.
     884.NH 3
     885\&Create Directory
     886.IX "NFS server procedures" NFSPROC_MKDIR() "" \fINFSPROC_MKDIR()\fP
     889NFSPROC_MKDIR (createargs) = 14;
     892The new directory "" is created in the directory given by
     893"where.dir".  The initial attributes of the new directory are given
     894by "attributes".  A reply "status" of NFS_OK indicates that the new
     895directory was created, and reply "file" and  reply "attributes" are
     896its file  handle and attributes.  Any  other  reply "status"  means
     897that the operation failed and no directory was created.
     899Note: possibly non-idempotent operation.
     901.NH 3
     902\&Remove Directory
     903.IX "NFS server procedures" NFSPROC_RMDIR() "" \fINFSPROC_RMDIR()\fP
     906NFSPROC_RMDIR(diropargs) = 15;
     909The existing empty directory "name" in the directory given by "dir"
     910is removed.  If the reply is
     911.I NFS_OK ,
     912the directory was removed.
     914Note: possibly non-idempotent operation.
     916.NH 3
     917\&Read From Directory
     918.IX "NFS server procedures" NFSPROC_READDIR() "" \fINFSPROC_READDIR()\fP
     920struct readdirargs {
     921        fhandle dir;           
     922        nfscookie cookie;
     923        unsigned count;         
     926struct entry {
     927        unsigned fileid;
     928        filename name;
     929        nfscookie cookie;
     930        entry *nextentry;
     933union readdirres switch (stat status) {
     934        case NFS_OK:
     935                struct {
     936                        entry *entries;
     937                        bool eof;
     938                } readdirok;
     939        default:
     940                void;
     944NFSPROC_READDIR (readdirargs) = 16;
     947Returns a variable number of  directory entries,  with a total size
     948of up to "count" bytes, from the directory given  by "dir".  If the
     949returned  value of "status"  is
     950.I NFS_OK ,
     951then  it  is followed  by a
     952variable  number  of "entry"s.    Each "entry" contains  a "fileid"
     953which consists of a  unique number  to identify the  file within  a
     954filesystem,  the  "name" of the  file, and a "cookie" which   is an
     955opaque pointer to the next entry in  the  directory.  The cookie is
     956used  in the next 
     957.I READDIR
     958call to get more  entries  starting at a
     959given point in  the directory.  The  special cookie zero (all  bits
     960zero) can be used to get the entries starting  at the  beginning of
     961the directory.  The "fileid" field should be the same number as the
     962"fileid" in the the  attributes of the  file.  (See the
     963.I "Basic Data Types"
     965The "eof" flag has a value of
     966.I TRUE
     967if there are no more entries in the directory.
     969.NH 3
     970\&Get Filesystem Attributes
     971.IX "NFS server procedures" NFSPROC_STATFS() "" \fINFSPROC_STATFS()\fP
     973union statfsres (stat status) {
     974        case NFS_OK:
     975                struct {
     976                        unsigned tsize;
     977                        unsigned bsize;
     978                        unsigned blocks;
     979                        unsigned bfree;
     980                        unsigned bavail;
     981                } info;
     982        default:
     983                void;
     987NFSPROC_STATFS(fhandle) = 17;
     990If the  reply "status"  is
     991.I NFS_OK ,
     992then the  reply "info" gives the
     993attributes for the filesystem that contains file referred to by the
     994input fhandle.  The attribute fields contain the following values:
     995.IP tsize:   
     996The optimum transfer size of the server in bytes.  This is
     997the number  of bytes the server  would like to have in the
     998data part of READ and WRITE requests.
     999.IP bsize:   
     1000The block size in bytes of the filesystem.
     1001.IP blocks: 
     1002The total number of "bsize" blocks on the filesystem.
     1003.IP bfree:   
     1004The number of free "bsize" blocks on the filesystem.
     1005.IP bavail: 
     1006The number of  "bsize" blocks  available to non-privileged users.
     1008Note: This call does not  work well if a  filesystem has  variable
     1009size blocks.
     1010.NH 1
     1011\&NFS Implementation Issues
     1012.IX NFS implementation
     1014The NFS protocol is designed to be operating system independent, but
     1015since this version was designed in a UNIX environment, many
     1016operations have semantics similar to the operations of the UNIX file
     1017system.  This section discusses some of the implementation-specific
     1018semantic issues.
     1019.NH 2
     1020\&Server/Client Relationship
     1021.IX NFS "server/client relationship"
     1023The NFS protocol is designed to allow servers to be as simple and
     1024general as possible.  Sometimes the simplicity of the server can be a
     1025problem, if the client wants to implement complicated filesystem
     1028For example, some operating systems allow removal of open files.  A
     1029process can open a file and, while it is open, remove it from the
     1030directory.  The file can be read and written as long as the process
     1031keeps it open, even though the file has no name in the filesystem.
     1032It is impossible for a stateless server to implement these semantics.
     1033The client can do some tricks such as renaming the file on remove,
     1034and only removing it on close.  We believe that the server provides
     1035enough functionality to implement most file system semantics on the
     1038Every NFS client can also potentially be a server, and remote and
     1039local mounted filesystems can be freely intermixed.  This leads to
     1040some interesting problems when a client travels down the directory
     1041tree of a remote filesystem and reaches the mount point on the server
     1042for another remote filesystem.  Allowing the server to follow the
     1043second remote mount would require loop detection, server lookup, and
     1044user revalidation.  Instead, we decided not to let clients cross a
     1045server's mount point.  When a client does a LOOKUP on a directory on
     1046which the server has mounted a filesystem, the client sees the
     1047underlying directory instead of the mounted directory.  A client can
     1048do remote mounts that match the server's mount points to maintain the
     1049server's view.
     1051.NH 2
     1052\&Pathname Interpretation
     1053.IX NFS "pathname interpretation"
     1055There are a few complications to the rule that pathnames are always
     1056parsed on the client.  For example, symbolic links could have
     1057different interpretations on different clients.  Another common
     1058problem for non-UNIX implementations is the special interpretation of
     1059the pathname ".."  to mean the parent of a given directory.  The next
     1060revision of the protocol uses an explicit flag to indicate the parent
     1062.NH 2
     1063\&Permission Issues
     1064.IX NFS "permission issues"
     1066The NFS protocol, strictly speaking, does not define the permission
     1067checking used  by servers.  However,  it is  expected that a server
     1068will do normal operating system permission checking using
     1069.I AUTH_UNIX
     1070style authentication as the basis of its protection mechanism.  The
     1071server gets the client's effective "uid", effective "gid", and groups
     1072on each call and uses them to check permission.  There are various
     1073problems with this method that can been resolved in interesting ways.
     1075Using "uid" and "gid" implies that the client and server share the
     1076same "uid" list.  Every server and client pair must have the same
     1077mapping from user to "uid" and from group to "gid".  Since every
     1078client can also be a server, this tends to imply that the whole
     1079network shares the same "uid/gid" space.
     1080.I AUTH_DES
     1081(and the  next
     1082revision of the NFS protocol) uses string names instead of numbers,
     1083but there are still complex problems to be solved.
     1085Another problem arises due to the usually stateful open operation.
     1086Most operating systems check permission at open time, and then check
     1087that the file is open on each read and write request.  With stateless
     1088servers, the server has no idea that the file is open and must do
     1089permission checking on each read and write call.  On a local
     1090filesystem, a user can open a file and then change the permissions so
     1091that no one is allowed to touch it, but will still be able to write
     1092to the file because it is open.  On a remote filesystem, by contrast,
     1093the write would fail.  To get around this problem, the server's
     1094permission checking algorithm should allow the owner of a file to
     1095access it regardless of the permission setting.
     1097A similar problem has to do with paging in from a file over the
     1098network.  The operating system usually checks for execute permission
     1099before opening a file for demand paging, and then reads blocks from
     1100the open file.  The file may not have read permission, but after it
     1101is opened it doesn't matter.  An NFS server can not tell the
     1102difference between a normal file read and a demand page-in read.  To
     1103make this work, the server allows reading of files if the "uid" given
     1104in the call has execute or read permission on the file.
     1106In most operating systems, a particular user (on the user ID zero)
     1107has access to all files no matter what permission and ownership they
     1108have.  This "super-user" permission may not be allowed on the server,
     1109since anyone who can become super-user on their workstation could
     1110gain access to all remote files.  The UNIX server by default maps
     1111user id 0 to -2 before doing its access checking.  This works except
     1112for NFS root filesystems, where super-user access cannot be avoided.
     1113.NH 2
     1114\&Setting RPC Parameters
     1115.IX NFS "setting RPC parameters"
     1117Various file system parameters and options should be set at mount
     1118time.  The mount protocol is described in the appendix below.  For
     1119example, "Soft" mounts as well as "Hard" mounts are usually both
     1120provided.  Soft mounted file systems return errors when RPC
     1121operations fail (after a given number of optional retransmissions),
     1122while hard mounted file systems continue to retransmit forever.
     1123Clients and servers may need to keep caches of recent operations to
     1124help avoid problems with non-idempotent operations.
     1125.NH 1
     1126\&Mount Protocol Definition
     1127.IX "mount protocol" "" "" "" PAGE MAJOR
     1128.sp 1
     1129.NH 2
     1131.IX "mount protocol" introduction
     1133The mount protocol is separate from, but related to, the NFS
     1134protocol.  It provides operating system specific services to get the
     1135NFS off the ground -- looking up server path names, validating user
     1136identity, and checking access permissions.  Clients use the mount
     1137protocol to get the first file handle, which allows them entry into a
     1138remote filesystem.
     1140The mount protocol is kept separate from the NFS protocol to make it
     1141easy to plug in new access checking and validation methods without
     1142changing the NFS server protocol.
     1144Notice that the protocol definition implies stateful servers because
     1145the server maintains a list of client's mount requests.  The mount
     1146list information is not critical for the correct functioning of
     1147either the client or the server.  It is intended for advisory use
     1148only, for example, to warn possible clients when a server is going
     1151Version one of the mount protocol is used with version two of the NFS
     1152protocol.  The only connecting point is the
     1153.I fhandle
     1154structure, which is the same for both protocols.
     1155.NH 2
     1156\&RPC Information
     1157.IX "mount protocol"  "RPC information"
     1158.IP \fIAuthentication\fP
     1159The mount service uses
     1160.I AUTH_UNIX
     1162.I AUTH_DES
     1163style authentication only.
     1164.IP "\fITransport Protocols\fP"
     1165The mount service is currently supported on UDP/IP only.
     1166.IP "\fIPort Number\fP"
     1167Consult the server's portmapper, described in the chapter
     1168.I "Remote Procedure Calls: Protocol Specification",
     1169to  find  the  port number on which the mount service is registered.
     1170.NH 2
     1171\&Sizes of XDR Structures
     1172.IX "mount protocol" "XDR structure sizes"
     1174These  are  the sizes,   given  in  decimal   bytes, of various XDR
     1175structures used in the protocol:
     1177/* \fIThe maximum number of bytes in a pathname argument\fP */
     1178const MNTPATHLEN = 1024;
     1180/* \fIThe maximum number of bytes in a name argument\fP */
     1181const MNTNAMLEN = 255;
     1183/* \fIThe size in bytes of the opaque file handle\fP */
     1184const FHSIZE = 32;
     1186.NH 2
     1187\&Basic Data Types
     1188.IX "mount protocol" "basic data types"
     1189.IX "mount data types"
     1191This section presents the data  types used by  the  mount protocol.
     1192In many cases they are similar to the types used in NFS.
     1194.NH 3
     1196.IX "mount data types" fhandle "" \fIfhandle\fP
     1198typedef opaque fhandle[FHSIZE];
     1201The type
     1202.I fhandle
     1203is the file handle that the server passes to the
     1204client.  All file operations are done  using file handles  to refer
     1205to a  file  or directory.   The  file handle  can  contain whatever
     1206information the server needs to distinguish an individual file.
     1208This  is the  same as the "fhandle" XDR definition in version 2 of
     1209the NFS protocol;  see
     1210.I "Basic Data Types"
     1211in the definition of the NFS protocol, above.
     1213.NH 3
     1215.IX "mount data types" fhstatus "" \fIfhstatus\fP
     1217union fhstatus switch (unsigned status) {
     1218        case 0:
     1219                fhandle directory;
     1220        default:
     1221                void;
     1225The type
     1226.I fhstatus
     1227is a union.  If a "status" of zero is returned,
     1228the  call completed   successfully, and  a  file handle   for   the
     1229"directory"  follows.  A  non-zero  status indicates  some  sort of
     1230error.  In this case the status is a UNIX error number.
     1232.NH 3
     1234.IX "mount data types" dirpath "" \fIdirpath\fP
     1236typedef string dirpath<MNTPATHLEN>;
     1239The type
     1240.I dirpath
     1241is a server pathname of a directory.
     1243.NH 3
     1245.IX "mount data types" name "" \fIname\fP
     1247typedef string name<MNTNAMLEN>;
     1250The type
     1251.I name
     1252is an arbitrary string used for various names.
     1253.NH 2
     1254\&Server Procedures
     1255.IX "mount server procedures"
     1257The following sections define the RPC procedures  supplied by a
     1258mount server. t .DS
     1260.el .DS L
     1261.ft I
     1263* Protocol description for the mount program
     1265.ft CW
     1267program MOUNTPROG {
     1268.ft I
     1270* Version 1 of the mount protocol used with
     1271* version 2 of the NFS protocol.
     1273.ft CW
     1274        version MOUNTVERS {
     1275                void        MOUNTPROC_NULL(void)    = 0;
     1276                fhstatus    MOUNTPROC_MNT(dirpath)  = 1;
     1277                mountlist   MOUNTPROC_DUMP(void)    = 2;
     1278                void        MOUNTPROC_UMNT(dirpath) = 3;
     1279                void        MOUNTPROC_UMNTALL(void) = 4;
     1280                exportlist  MOUNTPROC_EXPORT(void)  = 5;
     1281        } = 1;
     1282} = 100005;
     1285.NH 3
     1286\&Do Nothing
     1287.IX "mount server procedures" MNTPROC_NULL() "" \fIMNTPROC_NULL()\fP
     1290MNTPROC_NULL(void) = 0;
     1293This  procedure does no work.  It   is  made  available in all  RPC
     1294services to allow server response testing and timing.
     1296.NH 3
     1297\&Add Mount Entry
     1298.IX "mount server procedures" MNTPROC_MNT() "" \fIMNTPROC_MNT()\fP
     1301MNTPROC_MNT(dirpath) = 1;
     1304If the reply "status" is 0, then the reply "directory" contains the
     1305file handle for the directory "dirname".  This file handle may be
     1306used in the NFS protocol.  This procedure also adds a new entry to
     1307the mount list for this client mounting "dirname".
     1309.NH 3
     1310\&Return Mount Entries
     1311.IX "mount server procedures" MNTPROC_DUMP() "" \fIMNTPROC_DUMP()\fP
     1313struct *mountlist {
     1314        name      hostname;
     1315        dirpath   directory;
     1316        mountlist nextentry;
     1320MNTPROC_DUMP(void) = 2;
     1323Returns  the list of  remote mounted filesystems.   The "mountlist"
     1324contains one entry for each "hostname" and "directory" pair.
     1326.NH 3
     1327\&Remove Mount Entry
     1328.IX "mount server procedures" MNTPROC_UMNT() "" \fIMNTPROC_UMNT()\fP
     1331MNTPROC_UMNT(dirpath) = 3;
     1334Removes the mount list entry for the input "dirpath".
     1336.NH 3
     1337\&Remove All Mount Entries
     1338.IX "mount server procedures" MNTPROC_UMNTALL() "" \fIMNTPROC_UMNTALL()\fP
     1341MNTPROC_UMNTALL(void) = 4;
     1344Removes all of the mount list entries for this client.
     1346.NH 3
     1347\&Return Export List
     1348.IX "mount server procedures" MNTPROC_EXPORT() "" \fIMNTPROC_EXPORT()\fP
     1350struct *groups {
     1351        name grname;
     1352        groups grnext;
     1355struct *exportlist {
     1356        dirpath filesys;
     1357        groups groups;
     1358        exportlist next;
     1362MNTPROC_EXPORT(void) = 5;
     1365Returns a variable number of export list entries.  Each entry
     1366contains a filesystem name and a list of groups that are allowed to
     1367import it.  The filesystem name is in "filesys", and the group name
     1368is in the list "groups".
     1370Note:  The exportlist should contain
     1371more information about the status of the filesystem, such as a
     1372read-only flag.
  • cpukit/librpc/src/rpc/PSD.doc/

    r0ab65474 rdf49c60  
     2.\" Must use -- tbl and pic -- with this one
     4.\" @(#)     2.3 88/08/11 4.0 RPCSRC BT
     6.if \\n%=1 .tl ''- % -''
     8.IX "Network Programming" "" "" "" PAGE MAJOR OF 0
     11.\" prevent excess underlining in nroff
     12.if n .fp 2 R
     13.OH 'Remote Procedure Call Programming Guide''Page %'
     14.EH 'Page %''Remote Procedure Call Programming Guide'
     16\&Remote Procedure Call Programming Guide OF 1
     18.IX "RPC Programming Guide"
     20This document assumes a working knowledge of network theory.  It is
     21intended for programmers who wish to write network applications using
     22remote procedure calls (explained below), and who want to understand
     23the RPC mechanisms usually hidden by the
     24.I rpcgen(1)
     25protocol compiler.
     26.I rpcgen
     27is described in detail in the previous chapter, the
     28.I "\fBrpcgen\fP \fIProgramming Guide\fP".
     32.IX rpcgen "" \fIrpcgen\fP
     33Before attempting to write a network application, or to convert an
     34existing non-network application to run over the network, you may want to
     35understand the material in this chapter.  However, for most applications,
     36you can circumvent the need to cope with the details presented here by using
     37.I rpcgen .
     39.I "Generating XDR Routines"
     40section of that chapter contains the complete source for a working RPC
     41service\(ema remote directory listing service which uses
     42.I rpcgen
     43to generate XDR routines as well as client and server stubs.
     46What are remote procedure calls?  Simply put, they are the high-level
     47communications paradigm used in the operating system.
     48RPC presumes the existence of
     49low-level networking mechanisms (such as TCP/IP and UDP/IP), and upon them
     50it implements a logical client to server communications system designed
     51specifically for the support of network applications.  With RPC, the client
     52makes a procedure call to send a data packet to the server.  When the
     53packet arrives, the server calls a dispatch routine, performs whatever
     54service is requested, sends back the reply, and the procedure call returns
     55to the client.
     56.NH 0
     57\&Layers of RPC
     58.IX "layers of RPC"
     59.IX "RPC" "layers"
     61The RPC interface can be seen as being divided into three layers.\**
     63For a complete specification of the routines in the remote procedure
     64call Library, see the
     65.I rpc(3N)
     66manual page.
     69.I "The Highest Layer:"
     70.IX RPC "The Highest Layer"
     71The highest layer is totally transparent to the operating system,
     72machine and network upon which is is run.  It's probably best to
     73think of this level as a way of
     74.I using
     75RPC, rather than as
     76a \fIpart of\fP RPC proper.  Programmers who write RPC routines
     77should (almost) always make this layer available to others by way
     78of a simple C front end that entirely hides the networking.
     80To illustrate, at this level a program can simply make a call to
     81.I rnusers (),
     82a C routine which returns the number of users on a remote machine.
     83The user is not explicitly aware of using RPC \(em they simply
     84call a procedure, just as they would call
     85.I malloc() .
     87.I "The Middle Layer:"
     88.IX RPC "The Middle Layer"
     89The middle layer is really \*QRPC proper.\*U  Here, the user doesn't
     90need to consider details about sockets, the UNIX system, or other low-level
     91implementation mechanisms.  They simply make remote procedure calls
     92to routines on other machines.  The selling point here is simplicity. 
     93It's this layer that allows RPC to pass the \*Qhello world\*U test \(em
     94simple things should be simple.  The middle-layer routines are used
     95for most applications.
     97RPC calls are made with the system routines
     98.I registerrpc()
     99.I callrpc()
     101.I svc_run ().
     102The first two of these are the most fundamental:
     103.I registerrpc()
     104obtains a unique system-wide procedure-identification number, and
     105.I callrpc()
     106actually executes a remote procedure call.  At the middle level, a
     107call to
     108.I rnusers()
     109is implemented by way of these two routines.
     111The middle layer is unfortunately rarely used in serious programming
     112due to its inflexibility (simplicity).  It does not allow timeout
     113specifications or the choice of transport.  It allows no UNIX
     114process control or flexibility in case of errors.  It doesn't support
     115multiple kinds of call authentication.  The programmer rarely needs
     116all these kinds of control, but one or two of them is often necessary.
     118.I "The Lowest Layer:"
     119.IX RPC "The Lowest Layer"
     120The lowest layer does allow these details to be controlled by the
     121programmer, and for that reason it is often necessary.  Programs
     122written at this level are also most efficient, but this is rarely a
     123real issue \(em since RPC clients and servers rarely generate
     124heavy network loads.
     126Although this document only discusses the interface to C,
     127remote procedure calls can be made from any language.
     128Even though this document discusses RPC
     129when it is used to communicate
     130between processes on different machines,
     131it works just as well for communication
     132between different processes on the same machine.
     135.NH 2
     136\&The RPC Paradigm
     137.IX RPC paradigm
     139Here is a diagram of the RPC paradigm:
     141\fBFigure 1-1\fI Network Communication with the Remote Reocedure Call\fR
     144L1: arrow down 1i "client " rjust "program " rjust
     145L2: line right 1.5i "\fIcallrpc\fP" "function"
     146move up 1.5i; line dotted down 6i; move up 4.5i
     147arrow right 1i
     148L3: arrow down 1i "invoke " rjust "service " rjust
     149L4: arrow right 1.5i "call" "service"
     150L5: arrow down 1i " service" ljust " executes" ljust
     151L6: arrow left 1.5i "\fIreturn\fP" "answer"
     152L7: arrow down 1i "request " rjust "completed " rjust
     153L8: line left 1i
     154arrow left 1.5i "\fIreturn\fP" "reply"
     155L9: arrow down 1i "program " rjust "continues " rjust
     156line dashed down from L2 to L9
     157line dashed down from L4 to L7
     158line dashed up 1i from L3 "service " rjust "daemon " rjust
     159arrow dashed down 1i from L8
     160move right 1i from L3
     161box invis "Machine B"
     162move left 1.2i from L2; move down
     163box invis "Machine A"
     167.NH 1
     168\&Higher Layers of RPC
     169.NH 2
     170\&Highest Layer
     171.IX "highest layer of RPC"
     172.IX RPC "highest layer"
     174Imagine you're writing a program that needs to know
     175how many users are logged into a remote machine.
     176You can do this by calling the RPC library routine
     177.I rnusers()
     178as illustrated below: t .DS
     180.el .DS L
     181.ft CW
     182#include <stdio.h>
     184main(argc, argv)
     185        int argc;
     186        char **argv;
     188        int num;
     190        if (argc != 2) {
     191                fprintf(stderr, "usage: rnusers hostname\en");
     192                exit(1);
     193        }
     194        if ((num = rnusers(argv[1])) < 0) {
     195                fprintf(stderr, "error: rnusers\en");
     196                exit(-1);
     197        }
     198        printf("%d users on %s\en", num, argv[1]);
     199        exit(0);
     203RPC library routines such as
     204.I rnusers()
     205are in the RPC services library
     206.I librpcsvc.a
     207Thus, the program above should be compiled with
     209.ft CW
     210% cc \fIprogram.c -lrpcsvc\fP
     212.I rnusers (),
     213like the other RPC library routines, is documented in section 3R
     214of the
     215.I "System Interface Manual for the Sun Workstation" ,
     216the same section which documents the standard Sun RPC services. 
     217.IX "RPC Services"
     218See the
     219.I intro(3R)
     220manual page for an explanation of the documentation strategy
     221for these services and their RPC protocols.
     223Here are some of the RPC service library routines available to the
     224C programmer:
     226\fBTable 3-3\fI RPC Service Library Routines\RP
     228box tab (&) ;
     229cfI cfI
     230lfL l .
     234rnusers&Return number of users on remote machine
     235rusers&Return information about users on remote machine
     236havedisk&Determine if remote machine has disk
     237rstats&Get performance data from remote kernel
     238rwall&Write to specified remote machines
     239yppasswd&Update user password in Yellow Pages
     242Other RPC services \(em for example
     243.I ether()
     244.I mount
     245.I rquota()
     247.I spray
     248\(em are not available to the C programmer as library routines.
     249They do, however,
     250have RPC program numbers so they can be invoked with
     251.I callrpc()
     252which will be discussed in the next section.  Most of them also
     253have compilable
     254.I rpcgen(1)
     255protocol description files.  (The
     256.I rpcgen
     257protocol compiler radically simplifies the process of developing
     258network applications. 
     259See the \fBrpcgen\fI Programming Guide\fR
     260for detailed information about
     261.I rpcgen
     263.I rpcgen
     264protocol description files).
     266.NH 2
     267\&Intermediate Layer
     268.IX "intermediate layer of RPC"
     269.IX "RPC" "intermediate layer"
     271The simplest interface, which explicitly makes RPC calls, uses the
     273.I callrpc()
     275.I registerrpc()
     276Using this method, the number of remote users can be gotten as follows: t .DS
     278.el .DS L
     279#include <stdio.h>
     280#include <rpc/rpc.h>
     281#include <utmp.h>
     282#include <rpcsvc/rusers.h>
     284main(argc, argv)
     285        int argc;
     286        char **argv;
     288        unsigned long nusers;
     289        int stat;
     291        if (argc != 2) {
     292                fprintf(stderr, "usage: nusers hostname\en");
     293                exit(-1);
     294        }
     295        if (stat = callrpc(argv[1],
     297          xdr_void, 0, xdr_u_long, &nusers) != 0) {
     298                clnt_perrno(stat);
     299                exit(1);
     300        }
     301        printf("%d users on %s\en", nusers, argv[1]);
     302        exit(0);
     306Each RPC procedure is uniquely defined by a program number,
     307version number, and procedure number.  The program number
     308specifies a group of related remote procedures, each of
     309which has a different procedure number.  Each program also
     310has a version number, so when a minor change is made to a
     311remote service (adding a new procedure, for example), a new
     312program number doesn't have to be assigned.  When you want
     313to call a procedure to find the number of remote users, you
     314look up the appropriate program, version and procedure numbers
     315in a manual, just as you look up the name of a memory allocator
     316when you want to allocate memory.
     318The simplest way of making remote procedure calls is with the the RPC
     319library routine
     320.I callrpc()
     321It has eight parameters.  The first is the name of the remote server
     322machine.  The next three parameters are the program, version, and procedure
     323numbers\(emtogether they identify the procedure to be called.
     324The fifth and sixth parameters are an XDR filter and an argument to
     325be encoded and passed to the remote procedure. 
     326The final two parameters are a filter for decoding the results
     327returned by the remote procedure and a pointer to the place where
     328the procedure's results are to be stored.  Multiple arguments and
     329results are handled by embedding them in structures.  If
     330.I callrpc()
     331completes successfully, it returns zero; else it returns a nonzero
     332value.  The return codes (of type
     333.IX "enum clnt_stat (in RPC programming)" "" "\fIenum clnt_stat\fP (in RPC programming)"
     334cast into an integer) are found in
     335.I <rpc/clnt.h> .
     337Since data types may be represented differently on different machines,
     338.I callrpc()
     339needs both the type of the RPC argument, as well as
     340a pointer to the argument itself (and similarly for the result).  For
     342the return value is an
     343.I "unsigned long"
     345.I callrpc()
     347.I xdr_u_long()
     348as its first return parameter, which says
     349that the result is of type
     350.I "unsigned long"
     352.I &nusers
     353as its second return parameter,
     354which is a pointer to where the long result will be placed.  Since
     356takes no argument, the argument parameter of
     357.I callrpc()
     359.I xdr_void ().
     361After trying several times to deliver a message, if
     362.I callrpc()
     363gets no answer, it returns with an error code.
     364The delivery mechanism is UDP,
     365which stands for User Datagram Protocol.
     366Methods for adjusting the number of retries
     367or for using a different protocol require you to use the lower
     368layer of the RPC library, discussed later in this document.
     369The remote server procedure
     370corresponding to the above might look like this: t .DS
     372.el .DS L
     373.ft CW
     374.ft CW
     375char *
     377        char *indata;
     379        unsigned long nusers;
     381.ft I
     382        /*
     383         * Code here to compute the number of users
     384         * and place result in variable \fInusers\fP.
     385         */
     386.ft CW
     387        return((char *)&nusers);
     391It takes one argument, which is a pointer to the input
     392of the remote procedure call (ignored in our example),
     393and it returns a pointer to the result.
     394In the current version of C,
     395character pointers are the generic pointers,
     396so both the input argument and the return value are cast to
     397.I "char *" .
     399Normally, a server registers all of the RPC calls it plans
     400to handle, and then goes into an infinite loop waiting to service requests.
     401In this example, there is only a single procedure
     402to register, so the main body of the server would look like this: t .DS
     404.el .DS L
     405.ft CW
     406#include <stdio.h>
     407#include <rpc/rpc.h>
     408#include <utmp.h>
     409#include <rpcsvc/rusers.h>
     411char *nuser();
     415        registerrpc(RUSERSPROG, RUSERSVERS, RUSERSPROC_NUM,
     416                nuser, xdr_void, xdr_u_long);
     417        svc_run();              /* \fINever returns\fP */
     418        fprintf(stderr, "Error: svc_run returned!\en");
     419        exit(1);
     424.I registerrpc()
     425routine registers a C procedure as corresponding to a
     426given RPC procedure number.  The first three parameters,
     427.I RUSERPROG ,
     428.I RUSERSVERS ,
     431are the program, version, and procedure numbers
     432of the remote procedure to be registered;
     433.I nuser()
     434is the name of the local procedure that implements the remote
     435procedure; and
     436.I xdr_void()
     438.I xdr_u_long()
     439are the XDR filters for the remote procedure's arguments and
     440results, respectively.  (Multiple arguments or multiple results
     441are passed as structures).
     443Only the UDP transport mechanism can use
     444.I registerrpc()
     445thus, it is always safe in conjunction with calls generated by
     446.I callrpc() .
     448.IX "UDP 8K warning"
     449Warning: the UDP transport mechanism can only deal with
     450arguments and results less than 8K bytes in length.
     453After registering the local procedure, the server program's
     454main procedure calls
     455.I svc_run (),
     456the RPC library's remote procedure dispatcher.  It is this
     457function that calls the remote procedures in response to RPC
     458call messages.  Note that the dispatcher takes care of decoding
     459remote procedure arguments and encoding results, using the XDR
     460filters specified when the remote procedure was registered.
     461.NH 2
     462\&Assigning Program Numbers
     463.IX "program number assignment"
     464.IX "assigning program numbers"
     466Program numbers are assigned in groups of
     467.I 0x20000000
     468according to the following chart:
     470.ft CW
     471       0x0 - 0x1fffffff \fRDefined by Sun\fP
     4720x20000000 - 0x3fffffff \fRDefined by user\fP
     4730x40000000 - 0x5fffffff \fRTransient\fP
     4740x60000000 - 0x7fffffff \fRReserved\fP
     4750x80000000 - 0x9fffffff \fRReserved\fP
     4760xa0000000 - 0xbfffffff \fRReserved\fP
     4770xc0000000 - 0xdfffffff \fRReserved\fP
     4780xe0000000 - 0xffffffff \fRReserved\fP
     479.ft R
     481Sun Microsystems administers the first group of numbers, which
     482should be identical for all Sun customers.  If a customer
     483develops an application that might be of general interest, that
     484application should be given an assigned number in the first
     485range.  The second group of numbers is reserved for specific
     486customer applications.  This range is intended primarily for
     487debugging new programs.  The third group is reserved for
     488applications that generate program numbers dynamically.  The
     489final groups are reserved for future use, and should not be
     492To register a protocol specification, send a request by network
     493mail to
     494.I rpc@sun
     495or write to:
     497RPC Administrator
     498Sun Microsystems
     4992550 Garcia Ave.
     500Mountain View, CA 94043
     502Please include a compilable
     503.I rpcgen
     504\*Q.x\*U file describing your protocol.
     505You will be given a unique program number in return.
     506.IX RPC administration
     507.IX administration "of RPC"
     509The RPC program numbers and protocol specifications
     510of standard Sun RPC services can be
     511found in the include files in
     512.I "/usr/include/rpcsvc" .
     513These services, however, constitute only a small subset
     514of those which have been registered.  The complete list of
     515registered programs, as of the time when this manual was
     516printed, is:
     518\fBTable 3-2\fI RPC Registered Programs\fR
     519.TS H
     520box tab (&) ;
     521lfBI lfBI lfBI
     522lfL lfL lfI .
     523RPC Number&Program&Description
     528100001&RSTATPROG&remote stats           
     529100002&RUSERSPROG&remote users           
     531100004&YPPROG&Yellow Pages           
     532100005&MOUNTPROG&mount demon             
     533100006&DBXPROG&remote dbx             
     534100007&YPBINDPROG&yp binder               
     535100008&WALLPROG&shutdown msg           
     536100009&YPPASSWDPROG&yppasswd server         
     537100010&ETHERSTATPROG&ether stats             
     538100011&RQUOTAPROG&disk quotas             
     539100012&SPRAYPROG&spray packets           
     540100013&IBM3270PROG&3270 mapper             
     541100014&IBMRJEPROG&RJE mapper             
     542100015&SELNSVCPROG&selection service       
     543100016&RDATABASEPROG&remote database access 
     544100017&REXECPROG&remote execution       
     545100018&ALICEPROG&Alice Office Automation
     546100019&SCHEDPROG&scheduling service     
     547100020&LOCKPROG&local lock manager     
     548100021&NETLOCKPROG&network lock manager   
     549100022&X25PROG&x.25 inr protocol       
     550100023&STATMON1PROG&status monitor 1       
     551100024&STATMON2PROG&status monitor 2       
     552100025&SELNLIBPROG&selection library       
     553100026&BOOTPARAMPROG&boot parameters service
     554100027&MAZEPROG&mazewars game           
     555100028&YPUPDATEPROG&yp update               
     556100029&KEYSERVEPROG&key server             
     557100030&SECURECMDPROG&secure login           
     558100031&NETFWDIPROG&nfs net forwarder init       
     559100032&NETFWDTPROG&nfs net forwarder trans     
     560100033&SUNLINKMAP_PROG&sunlink MAP             
     561100034&NETMONPROG&network monitor               
     562100035&DBASEPROG&lightweight database   
     563100036&PWDAUTHPROG&password authorization       
     564100037&TFSPROG&translucent file svc     
     565100038&NSEPROG&nse server               
     566100039&NSE_ACTIVATE_PROG&nse activate daemon   
     567.sp .2i
     568150001&PCNFSDPROG&pc passwd authorization
     569.sp .2i
     572200002&CADDS_IMAGE&CV cadds_image               
     573.sp .2i
     574300001&ADT_RFLOCKPROG&ADT file locking 
     576.NH 2
     577\&Passing Arbitrary Data Types
     578.IX "arbitrary data types"
     580In the previous example, the RPC call passes a single
     581.I "unsigned long"
     582RPC can handle arbitrary data structures, regardless of
     583different machines' byte orders or structure layout conventions,
     584by always converting them to a network standard called
     585.I "External Data Representation"
     586(XDR) before
     587sending them over the wire.
     588The process of converting from a particular machine representation
     589to XDR format is called
     590.I serializing ,
     591and the reverse process is called
     592.I deserializing .
     593The type field parameters of
     594.I callrpc()
     596.I registerrpc()
     597can be a built-in procedure like
     598.I xdr_u_long()
     599in the previous example, or a user supplied one.
     600XDR has these built-in type routines:
     601.IX RPC "built-in routines"
     603.ft CW
     604xdr_int()      xdr_u_int()      xdr_enum()
     605xdr_long()     xdr_u_long()     xdr_bool()
     606xdr_short()    xdr_u_short()    xdr_wrapstring()
     607xdr_char()     xdr_u_char()
     609Note that the routine
     610.I xdr_string()
     611exists, but cannot be used with
     612.I callrpc()
     614.I registerrpc (),
     615which only pass two parameters to their XDR routines.
     616.I xdr_wrapstring()
     617has only two parameters, and is thus OK.  It calls
     618.I xdr_string ().
     620As an example of a user-defined type routine,
     621if you wanted to send the structure
     623.ft CW
     624struct simple {
     625        int a;
     626        short b;
     627} simple;
     629then you would call
     630.I callrpc()
     633.ft CW
     634callrpc(hostname, PROGNUM, VERSNUM, PROCNUM,
     635        xdr_simple, &simple ...);
     638.I xdr_simple()
     639is written as: t .DS
     641.el .DS L
     642.ft CW
     643#include <rpc/rpc.h>
     645xdr_simple(xdrsp, simplep)
     646        XDR *xdrsp;
     647        struct simple *simplep;
     649        if (!xdr_int(xdrsp, &simplep->a))
     650                return (0);
     651        if (!xdr_short(xdrsp, &simplep->b))
     652                return (0);
     653        return (1);
     657An XDR routine returns nonzero (true in the sense of C) if it
     658completes successfully, and zero otherwise.
     659A complete description of XDR is in the
     660.I "XDR Protocol Specification"
     661section of this manual, only few implementation examples are
     662given here.
     664In addition to the built-in primitives,
     665there are also the prefabricated building blocks:
     667.ft CW
     668xdr_array()       xdr_bytes()     xdr_reference()
     669xdr_vector()      xdr_union()     xdr_pointer()
     670xdr_string()      xdr_opaque()
     672To send a variable array of integers,
     673you might package them up as a structure like this
     675.ft CW
     676struct varintarr {
     677        int *data;
     678        int arrlnth;
     679} arr;
     681and make an RPC call such as
     683.ft CW
     684callrpc(hostname, PROGNUM, VERSNUM, PROCNUM,
     685        xdr_varintarr, &arr...);
     688.I xdr_varintarr()
     689defined as: t .DS
     691.el .DS L
     692.ft CW
     693xdr_varintarr(xdrsp, arrp)
     694        XDR *xdrsp;
     695        struct varintarr *arrp;
     697        return (xdr_array(xdrsp, &arrp->data, &arrp->arrlnth,
     698                MAXLEN, sizeof(int), xdr_int));
     701This routine takes as parameters the XDR handle,
     702a pointer to the array, a pointer to the size of the array,
     703the maximum allowable array size,
     704the size of each array element,
     705and an XDR routine for handling each array element.
     708If the size of the array is known in advance, one can use
     709.I xdr_vector (),
     710which serializes fixed-length arrays. t .DS
     712.el .DS L
     713.ft CW
     714int intarr[SIZE];
     716xdr_intarr(xdrsp, intarr)
     717        XDR *xdrsp;
     718        int intarr[];
     720        int i;
     722        return (xdr_vector(xdrsp, intarr, SIZE, sizeof(int),
     723                xdr_int));
     728XDR always converts quantities to 4-byte multiples when serializing.
     729Thus, if either of the examples above involved characters
     730instead of integers, each character would occupy 32 bits.
     731That is the reason for the XDR routine
     732.I xdr_bytes()
     733which is like
     734.I xdr_array()
     735except that it packs characters;
     736.I xdr_bytes()
     737has four parameters, similar to the first four parameters of
     738.I xdr_array ().
     739For null-terminated strings, there is also the
     740.I xdr_string()
     741routine, which is the same as
     742.I xdr_bytes()
     743without the length parameter.
     744On serializing it gets the string length from
     745.I strlen (),
     746and on deserializing it creates a null-terminated string.
     748Here is a final example that calls the previously written
     749.I xdr_simple()
     750as well as the built-in functions
     751.I xdr_string()
     753.I xdr_reference (),
     754which chases pointers: t .DS
     756.el .DS L
     757.ft CW
     758struct finalexample {
     759        char *string;
     760        struct simple *simplep;
     761} finalexample;
     763xdr_finalexample(xdrsp, finalp)
     764        XDR *xdrsp;
     765        struct finalexample *finalp;
     768        if (!xdr_string(xdrsp, &finalp->string, MAXSTRLEN))
     769                return (0);
     770        if (!xdr_reference(xdrsp, &finalp->simplep,
     771          sizeof(struct simple), xdr_simple);
     772                return (0);
     773        return (1);
     776Note that we could as easily call
     777.I xdr_simple()
     778here instead of
     779.I xdr_reference ().
     780.NH 1
     781\&Lowest Layer of RPC
     782.IX "lowest layer of RPC"
     783.IX "RPC" "lowest layer"
     785In the examples given so far,
     786RPC takes care of many details automatically for you.
     787In this section, we'll show you how you can change the defaults
     788by using lower layers of the RPC library.
     789It is assumed that you are familiar with sockets
     790and the system calls for dealing with them.
     792There are several occasions when you may need to use lower layers of
     793RPC.  First, you may need to use TCP, since the higher layer uses UDP,
     794which restricts RPC calls to 8K bytes of data.  Using TCP permits calls
     795to send long streams of data. 
     796For an example, see the
     797.I TCP
     798section below.  Second, you may want to allocate and free memory
     799while serializing or deserializing with XDR routines. 
     800There is no call at the higher level to let
     801you free memory explicitly. 
     802For more explanation, see the
     803.I "Memory Allocation with XDR"
     804section below. 
     805Third, you may need to perform authentication
     806on either the client or server side, by supplying
     807credentials or verifying them.
     808See the explanation in the
     809.I Authentication
     810section below.
     811.NH 2
     812\&More on the Server Side
     813.IX RPC "server side"
     815The server for the
     816.I nusers()
     817program shown below does the same thing as the one using
     818.I registerrpc()
     819above, but is written using a lower layer of the RPC package: t .DS
     821.el .DS L
     822.ft CW
     823#include <stdio.h>
     824#include <rpc/rpc.h>
     825#include <utmp.h>
     826#include <rpcsvc/rusers.h>
     830        SVCXPRT *transp;
     831        int nuser();
     833        transp = svcudp_create(RPC_ANYSOCK);
     834        if (transp == NULL){
     835                fprintf(stderr, "can't create an RPC server\en");
     836                exit(1);
     837        }
     838        pmap_unset(RUSERSPROG, RUSERSVERS);
     839        if (!svc_register(transp, RUSERSPROG, RUSERSVERS,
     840                          nuser, IPPROTO_UDP)) {
     841                fprintf(stderr, "can't register RUSER service\en");
     842                exit(1);
     843        }
     844        svc_run();  /* \fINever returns\fP */
     845        fprintf(stderr, "should never reach this point\en");
     848nuser(rqstp, transp)
     849        struct svc_req *rqstp;
     850        SVCXPRT *transp;
     852        unsigned long nusers;
     854        switch (rqstp->rq_proc) {
     855        case NULLPROC:
     856                if (!svc_sendreply(transp, xdr_void, 0))
     857                        fprintf(stderr, "can't reply to RPC call\en");
     858                return;
     859        case RUSERSPROC_NUM:
     860.ft I
     861                /*
     862                 * Code here to compute the number of users
     863                 * and assign it to the variable \fInusers\fP
     864                 */
     865.ft CW
     866                if (!svc_sendreply(transp, xdr_u_long, &nusers))
     867                        fprintf(stderr, "can't reply to RPC call\en");
     868                return;
     869        default:
     870                svcerr_noproc(transp);
     871                return;
     872        }
     876First, the server gets a transport handle, which is used
     877for receiving and replying to RPC messages.
     878.I registerrpc()
     880.I svcudp_create()
     881to get a UDP handle.
     882If you require a more reliable protocol, call
     883.I svctcp_create()
     885If the argument to
     886.I svcudp_create()
     888.I RPC_ANYSOCK
     889the RPC library creates a socket
     890on which to receive and reply to RPC calls.  Otherwise,
     891.I svcudp_create()
     892expects its argument to be a valid socket number.
     893If you specify your own socket, it can be bound or unbound.
     894If it is bound to a port by the user, the port numbers of
     895.I svcudp_create()
     897.I clnttcp_create()
     898(the low-level client routine) must match.
     900If the user specifies the
     901.I RPC_ANYSOCK
     902argument, the RPC library routines will open sockets.
     903Otherwise they will expect the user to do so.  The routines
     904.I svcudp_create()
     906.I clntudp_create()
     907will cause the RPC library routines to
     908.I bind()
     909their socket if it is not bound already.
     911A service may choose to register its port number with the
     912local portmapper service.  This is done is done by specifying
     913a non-zero protocol number in
     914.I svc_register ().
     915Incidently, a client can discover the server's port number by
     916consulting the portmapper on their server's machine.  This can
     917be done automatically by specifying a zero port number in
     918.I clntudp_create()
     920.I clnttcp_create ().
     922After creating an
     923.I SVCXPRT ,
     924the next step is to call
     925.I pmap_unset()
     926so that if the
     927.I nusers()
     928server crashed earlier,
     929any previous trace of it is erased before restarting.
     930More precisely,
     931.I pmap_unset()
     932erases the entry for
     934from the port mapper's tables.
     936Finally, we associate the program number for
     937.I nusers()
     938with the procedure
     939.I nuser ().
     940The final argument to
     941.I svc_register()
     942is normally the protocol being used,
     943which, in this case, is
     944.I IPPROTO_UDP
     945Notice that unlike
     946.I registerrpc (),
     947there are no XDR routines involved
     948in the registration process.
     949Also, registration is done on the program,
     950rather than procedure, level.
     952The user routine
     953.I nuser()
     954must call and dispatch the appropriate XDR routines
     955based on the procedure number.
     956Note that
     957two things are handled by
     958.I nuser()
     960.I registerrpc()
     961handles automatically.
     962The first is that procedure
     963.I NULLPROC
     964(currently zero) returns with no results.
     965This can be used as a simple test
     966for detecting if a remote program is running.
     967Second, there is a check for invalid procedure numbers.
     968If one is detected,
     969.I svcerr_noproc()
     970is called to handle the error.
     973The user service routine serializes the results and returns
     974them to the RPC caller via
     975.I svc_sendreply()
     976Its first parameter is the
     977.I SVCXPRT
     978handle, the second is the XDR routine,
     979and the third is a pointer to the data to be returned.
     980Not illustrated above is how a server
     981handles an RPC program that receives data.
     982As an example, we can add a procedure
     984which has an argument
     985.I nusers (),
     986and returns
     987.I TRUE
     989.I FALSE
     990depending on whether there are nusers logged on.
     991It would look like this: t .DS
     993.el .DS L
     994.ft CW
     995case RUSERSPROC_BOOL: {
     996        int bool;
     997        unsigned nuserquery;
     999        if (!svc_getargs(transp, xdr_u_int, &nuserquery) {
     1000                svcerr_decode(transp);
     1001                return;
     1002        }
     1003.ft I
     1004        /*
     1005         * Code to set \fInusers\fP = number of users
     1006         */
     1007.ft CW
     1008        if (nuserquery == nusers)
     1009                bool = TRUE;
     1010        else
     1011                bool = FALSE;
     1012        if (!svc_sendreply(transp, xdr_bool, &bool)) {
     1013                 fprintf(stderr, "can't reply to RPC call\en");
     1014                 return (1);
     1015        }
     1016        return;
     1021The relevant routine is
     1022.I svc_getargs()
     1023which takes an
     1024.I SVCXPRT
     1025handle, the XDR routine,
     1026and a pointer to where the input is to be placed as arguments.
     1027.NH 2
     1028\&Memory Allocation with XDR
     1029.IX "memory allocation with XDR"
     1030.IX XDR "memory allocation"
     1032XDR routines not only do input and output,
     1033they also do memory allocation.
     1034This is why the second parameter of
     1035.I xdr_array()
     1036is a pointer to an array, rather than the array itself.
     1037If it is
     1038.I NULL ,
     1040.I xdr_array()
     1041allocates space for the array and returns a pointer to it,
     1042putting the size of the array in the third argument.
     1043As an example, consider the following XDR routine
     1044.I xdr_chararr1()
     1045which deals with a fixed array of bytes with length
     1046.I SIZE . t .DS
     1048.el .DS L
     1049.ft CW
     1050xdr_chararr1(xdrsp, chararr)
     1051        XDR *xdrsp;
     1052        char chararr[];
     1054        char *p;
     1055        int len;
     1057        p = chararr;
     1058        len = SIZE;
     1059        return (xdr_bytes(xdrsp, &p, &len, SIZE));
     1062If space has already been allocated in
     1063.I chararr ,
     1064it can be called from a server like this: t .DS
     1066.el .DS L
     1067.ft CW
     1068char chararr[SIZE];
     1070svc_getargs(transp, xdr_chararr1, chararr);
     1072If you want XDR to do the allocation,
     1073you would have to rewrite this routine in the following way: t .DS
     1075.el .DS L
     1076.ft CW
     1077xdr_chararr2(xdrsp, chararrp)
     1078        XDR *xdrsp;
     1079        char **chararrp;
     1081        int len;
     1083        len = SIZE;
     1084        return (xdr_bytes(xdrsp, charrarrp, &len, SIZE));
     1087Then the RPC call might look like this: t .DS
     1089.el .DS L
     1090.ft CW
     1091char *arrptr;
     1093arrptr = NULL;
     1094svc_getargs(transp, xdr_chararr2, &arrptr);
     1095.ft I
     1097 * Use the result here
     1098 */
     1099.ft CW
     1100svc_freeargs(transp, xdr_chararr2, &arrptr);
     1102Note that, after being used, the character array can be freed with
     1103.I svc_freeargs()
     1104.I svc_freeargs()
     1105will not attempt to free any memory if the variable indicating it
     1106is NULL.  For example, in the the routine
     1107.I xdr_finalexample (),
     1108given earlier, if
     1109.I finalp->string
     1110was NULL, then it would not be freed.  The same is true for
     1111.I finalp->simplep .
     1113To summarize, each XDR routine is responsible
     1114for serializing, deserializing, and freeing memory.
     1115When an XDR routine is called from
     1116.I callrpc()
     1117the serializing part is used.
     1118When called from
     1119.I svc_getargs()
     1120the deserializer is used.
     1121And when called from
     1122.I svc_freeargs()
     1123the memory deallocator is used.  When building simple examples like those
     1124in this section, a user doesn't have to worry
     1125about the three modes. 
     1126See the
     1127.I "External Data Representation: Sun Technical Notes"
     1128for examples of more sophisticated XDR routines that determine
     1129which of the three modes they are in and adjust their behavior accordingly.
     1131.NH 2
     1132\&The Calling Side
     1133.IX RPC "calling side"
     1135When you use
     1136.I callrpc()
     1137you have no control over the RPC delivery
     1138mechanism or the socket used to transport the data.
     1139To illustrate the layer of RPC that lets you adjust these
     1140parameters, consider the following code to call the
     1141.I nusers
     1142service: t .DS
     1144.el .DS L
     1145.ft CW
     1146.vs 11
     1147#include <stdio.h>
     1148#include <rpc/rpc.h>
     1149#include <utmp.h>
     1150#include <rpcsvc/rusers.h>
     1151#include <sys/socket.h>
     1152#include <sys/time.h>
     1153#include <netdb.h>
     1155main(argc, argv)
     1156        int argc;
     1157        char **argv;
     1159        struct hostent *hp;
     1160        struct timeval pertry_timeout, total_timeout;
     1161        struct sockaddr_in server_addr;
     1162        int sock = RPC_ANYSOCK;
     1163        register CLIENT *client;
     1164        enum clnt_stat clnt_stat;
     1165        unsigned long nusers;
     1167        if (argc != 2) {
     1168                fprintf(stderr, "usage: nusers hostname\en");
     1169                exit(-1);
     1170        }
     1171        if ((hp = gethostbyname(argv[1])) == NULL) {
     1172                fprintf(stderr, "can't get addr for %s\en",argv[1]);
     1173                exit(-1);
     1174        }
     1175        pertry_timeout.tv_sec = 3;
     1176        pertry_timeout.tv_usec = 0;
     1177        bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr,
     1178                hp->h_length);
     1179        server_addr.sin_family = AF_INET;
     1180        server_addr.sin_port =  0;
     1181        if ((client = clntudp_create(&server_addr, RUSERSPROG,
     1182          RUSERSVERS, pertry_timeout, &sock)) == NULL) {
     1183                clnt_pcreateerror("clntudp_create");
     1184                exit(-1);
     1185        }
     1186        total_timeout.tv_sec = 20;
     1187        total_timeout.tv_usec = 0;
     1188        clnt_stat = clnt_call(client, RUSERSPROC_NUM, xdr_void,
     1189                0, xdr_u_long, &nusers, total_timeout);
     1190        if (clnt_stat != RPC_SUCCESS) {
     1191                clnt_perror(client, "rpc");
     1192                exit(-1);
     1193        }
     1194        clnt_destroy(client);
     1195        close(sock);
     1196        exit(0);
     1201The low-level version of
     1202.I callrpc()
     1204.I clnt_call()
     1205which takes a
     1206.I CLIENT
     1207pointer rather than a host name.  The parameters to
     1208.I clnt_call()
     1209are a
     1210.I CLIENT
     1211pointer, the procedure number,
     1212the XDR routine for serializing the argument,
     1213a pointer to the argument,
     1214the XDR routine for deserializing the return value,
     1215a pointer to where the return value will be placed,
     1216and the time in seconds to wait for a reply.
     1219.I CLIENT
     1220pointer is encoded with the transport mechanism.
     1221.I callrpc()
     1222uses UDP, thus it calls
     1223.I clntudp_create()
     1224to get a
     1225.I CLIENT
     1226pointer.  To get TCP (Transmission Control Protocol), you would use
     1227.I clnttcp_create() .
     1229The parameters to
     1230.I clntudp_create()
     1231are the server address, the program number, the version number,
     1232a timeout value (between tries), and a pointer to a socket.
     1233The final argument to
     1234.I clnt_call()
     1235is the total time to wait for a response.
     1236Thus, the number of tries is the
     1237.I clnt_call()
     1238timeout divided by the
     1239.I clntudp_create()
     1242Note that the
     1243.I clnt_destroy()
     1245always deallocates the space associated with the
     1246.I CLIENT
     1247handle.  It closes the socket associated with the
     1248.I CLIENT
     1249handle, however, only if the RPC library opened it.  It the
     1250socket was opened by the user, it stays open.  This makes it
     1251possible, in cases where there are multiple client handles
     1252using the same socket, to destroy one handle without closing
     1253the socket that other handles are using.
     1255To make a stream connection, the call to
     1256.I clntudp_create()
     1257is replaced with a call to
     1258.I clnttcp_create() .
     1260.ft CW
     1261clnttcp_create(&server_addr, prognum, versnum, &sock,
     1262               inputsize, outputsize);
     1264There is no timeout argument; instead, the receive and send buffer
     1265sizes must be specified.  When the
     1266.I clnttcp_create()
     1267call is made, a TCP connection is established.
     1268All RPC calls using that
     1269.I CLIENT
     1270handle would use this connection.
     1271The server side of an RPC call using TCP has
     1272.I svcudp_create()
     1273replaced by
     1274.I svctcp_create() .
     1276.ft CW
     1277transp = svctcp_create(RPC_ANYSOCK, 0, 0);
     1279The last two arguments to
     1280.I svctcp_create()
     1281are send and receive sizes respectively.  If `0' is specified for
     1282either of these, the system chooses a reasonable default.
     1284.NH 1
     1285\&Other RPC Features
     1286.IX "RPC" "miscellaneous features"
     1287.IX "miscellaneous RPC features"
     1289This section discusses some other aspects of RPC
     1290that are occasionally useful.
     1291.NH 2
     1292\&Select on the Server Side
     1293.IX RPC select() RPC \fIselect()\fP
     1294.IX select() "" \fIselect()\fP "on the server side"
     1296Suppose a process is processing RPC requests
     1297while performing some other activity.
     1298If the other activity involves periodically updating a data structure,
     1299the process can set an alarm signal before calling
     1300.I svc_run()
     1301But if the other activity
     1302involves waiting on a a file descriptor, the
     1303.I svc_run()
     1304call won't work.
     1305The code for
     1306.I svc_run()
     1307is as follows: t .DS
     1309.el .DS L
     1310.ft CW
     1311.vs 11
     1315        fd_set readfds;
     1316        int dtbsz = getdtablesize();
     1318        for (;;) {
     1319                readfds = svc_fds;
     1320                switch (select(dtbsz, &readfds, NULL,NULL,NULL)) {
     1322                case -1:
     1323                        if (errno == EINTR)
     1324                                continue;
     1325                        perror("select");
     1326                        return;
     1327                case 0:
     1328                        break;
     1329                default:
     1330                        svc_getreqset(&readfds);
     1331                }
     1332        }
     1338You can bypass
     1339.I svc_run()
     1340and call
     1341.I svc_getreqset()
     1343All you need to know are the file descriptors
     1344of the socket(s) associated with the programs you are waiting on.
     1345Thus you can have your own
     1346.I select()
     1347.IX select() "" \fIselect()\fP
     1348that waits on both the RPC socket,
     1349and your own descriptors.  Note that
     1350.I svc_fds()
     1351is a bit mask of all the file descriptors that RPC is using for
     1352services.  It can change everytime that
     1353.I any
     1354RPC library routine is called, because descriptors are constantly
     1355being opened and closed, for example for TCP connections.
     1356.NH 2
     1357\&Broadcast RPC
     1358.IX "broadcast RPC"
     1359.IX RPC "broadcast"
     1362.I portmapper
     1363is a daemon that converts RPC program numbers
     1364into DARPA protocol port numbers; see the
     1365.I portmap
     1366man page.  You can't do broadcast RPC without the portmapper.
     1367Here are the main differences between
     1368broadcast RPC and normal RPC calls:
     1369.IP  1.
     1370Normal RPC expects one answer, whereas
     1371broadcast RPC expects many answers
     1372(one or more answer from each responding machine).
     1373.IP  2.
     1374Broadcast RPC can only be supported by packet-oriented (connectionless)
     1375transport protocols like UPD/IP.
     1376.IP  3.
     1377The implementation of broadcast RPC
     1378treats all unsuccessful responses as garbage by filtering them out.
     1379Thus, if there is a version mismatch between the
     1380broadcaster and a remote service,
     1381the user of broadcast RPC never knows.
     1382.IP  4.
     1383All broadcast messages are sent to the portmap port.
     1384Thus, only services that register themselves with their portmapper
     1385are accessible via the broadcast RPC mechanism.
     1386.IP  5.
     1387Broadcast requests are limited in size to the MTU (Maximum Transfer
     1388Unit) of the local network.  For Ethernet, the MTU is 1500 bytes.
     1390.NH 3
     1391\&Broadcast RPC Synopsis
     1392.IX "broadcast RPC" synopsis
     1393.IX "RPC" "broadcast synopsis" t .DS
     1395.el .DS L
     1396.ft CW
     1397#include <rpc/pmap_clnt.h>
     1398        . . .
     1399enum clnt_stat  clnt_stat;
     1400        . . .
     1401clnt_stat = clnt_broadcast(prognum, versnum, procnum,
     1402  inproc, in, outproc, out, eachresult)
     1403        u_long    prognum;        /* \fIprogram number\fP */
     1404        u_long    versnum;        /* \fIversion number\fP */
     1405        u_long    procnum;        /* \fIprocedure number\fP */
     1406        xdrproc_t inproc;         /* \fIxdr routine for args\fP */
     1407        caddr_t   in;             /* \fIpointer to args\fP */
     1408        xdrproc_t outproc;        /* \fIxdr routine for results\fP */
     1409        caddr_t   out;            /* \fIpointer to results\fP */
     1410        bool_t    (*eachresult)();/* \fIcall with each result gotten\fP */
     1413The procedure
     1414.I eachresult()
     1415is called each time a valid result is obtained.
     1416It returns a boolean that indicates
     1417whether or not the user wants more responses. t .DS
     1419.el .DS L
     1420.ft CW
     1421bool_t done;
     1422        . . .
     1423done = eachresult(resultsp, raddr)
     1424        caddr_t resultsp;
     1425        struct sockaddr_in *raddr; /* \fIAddr of responding machine\fP */
     1428.I done
     1430.I TRUE ,
     1431then broadcasting stops and
     1432.I clnt_broadcast()
     1433returns successfully.
     1434Otherwise, the routine waits for another response.
     1435The request is rebroadcast
     1436after a few seconds of waiting.
     1437If no responses come back,
     1438the routine returns with
     1439.I RPC_TIMEDOUT .
     1440.NH 2
     1442.IX "batching"
     1443.IX RPC "batching"
     1445The RPC architecture is designed so that clients send a call message,
     1446and wait for servers to reply that the call succeeded.
     1447This implies that clients do not compute
     1448while servers are processing a call.
     1449This is inefficient if the client does not want or need
     1450an acknowledgement for every message sent.
     1451It is possible for clients to continue computing
     1452while waiting for a response,
     1453using RPC batch facilities.
     1455RPC messages can be placed in a \*Qpipeline\*U of calls
     1456to a desired server; this is called batching.
     1457Batching assumes that:
     14581) each RPC call in the pipeline requires no response from the server,
     1459and the server does not send a response message; and
     14602) the pipeline of calls is transported on a reliable
     1461byte stream transport such as TCP/IP.
     1462Since the server does not respond to every call,
     1463the client can generate new calls in parallel
     1464with the server executing previous calls.
     1465Furthermore, the TCP/IP implementation can buffer up
     1466many call messages, and send them to the server in one
     1467.I write()
     1468system call.  This overlapped execution
     1469greatly decreases the interprocess communication overhead of
     1470the client and server processes,
     1471and the total elapsed time of a series of calls.
     1473Since the batched calls are buffered,
     1474the client should eventually do a nonbatched call
     1475in order to flush the pipeline.
     1477A contrived example of batching follows.
     1478Assume a string rendering service (like a window system)
     1479has two similar calls: one renders a string and returns void results,
     1480while the other renders a string and remains silent.
     1481The service (using the TCP/IP transport) may look like: t .DS
     1483.el .DS L
     1484.ft CW
     1485#include <stdio.h>
     1486#include <rpc/rpc.h>
     1487#include <suntool/windows.h>
     1489void windowdispatch();
     1493        SVCXPRT *transp;
     1495        transp = svctcp_create(RPC_ANYSOCK, 0, 0);
     1496        if (transp == NULL){
     1497                fprintf(stderr, "can't create an RPC server\en");
     1498                exit(1);
     1499        }
     1500        pmap_unset(WINDOWPROG, WINDOWVERS);
     1501        if (!svc_register(transp, WINDOWPROG, WINDOWVERS,
     1502          windowdispatch, IPPROTO_TCP)) {
     1503                fprintf(stderr, "can't register WINDOW service\en");
     1504                exit(1);
     1505        }
     1506        svc_run();  /* \fINever returns\fP */
     1507        fprintf(stderr, "should never reach this point\en");
     1511windowdispatch(rqstp, transp)
     1512        struct svc_req *rqstp;
     1513        SVCXPRT *transp;
     1515        char *s = NULL;
     1517        switch (rqstp->rq_proc) {
     1518        case NULLPROC:
     1519                if (!svc_sendreply(transp, xdr_void, 0))
     1520                        fprintf(stderr, "can't reply to RPC call\en");
     1521                return;
     1522        case RENDERSTRING:
     1523                if (!svc_getargs(transp, xdr_wrapstring, &s)) {
     1524                        fprintf(stderr, "can't decode arguments\en");
     1525.ft I
     1526                        /*
     1527                         * Tell caller he screwed up
     1528                         */
     1529.ft CW
     1530                        svcerr_decode(transp);
     1531                        break;
     1532                }
     1533.ft I
     1534                /*
     1535                 * Code here to render the string \fIs\fP
     1536                 */
     1537.ft CW
     1538                if (!svc_sendreply(transp, xdr_void, NULL))
     1539                        fprintf(stderr, "can't reply to RPC call\en");
     1540                break;
     1541        case RENDERSTRING_BATCHED:
     1542                if (!svc_getargs(transp, xdr_wrapstring, &s)) {
     1543                        fprintf(stderr, "can't decode arguments\en");
     1544.ft I
     1545                        /*
     1546                         * We are silent in the face of protocol errors
     1547                         */
     1548.ft CW
     1549                        break;
     1550                }
     1551.ft I
     1552                /*
     1553                 * Code here to render string s, but send no reply!
     1554                 */
     1555.ft CW
     1556                break;
     1557        default:
     1558                svcerr_noproc(transp);
     1559                return;
     1560        }
     1561.ft I
     1562        /*
     1563         * Now free string allocated while decoding arguments
     1564         */
     1565.ft CW
     1566        svc_freeargs(transp, xdr_wrapstring, &s);
     1569Of course the service could have one procedure
     1570that takes the string and a boolean
     1571to indicate whether or not the procedure should respond.
     1573In order for a client to take advantage of batching,
     1574the client must perform RPC calls on a TCP-based transport
     1575and the actual calls must have the following attributes:
     15761) the result's XDR routine must be zero
     1577.I NULL ),
     1578and 2) the RPC call's timeout must be zero.
     1581Here is an example of a client that uses batching to render a
     1582bunch of strings; the batching is flushed when the client gets
     1583a null string (EOF): t .DS
     1585.el .DS L
     1586.ft CW
     1587.vs 11
     1588#include <stdio.h>
     1589#include <rpc/rpc.h>
     1590#include <sys/socket.h>
     1591#include <sys/time.h>
     1592#include <netdb.h>
     1593#include <suntool/windows.h>
     1595main(argc, argv)
     1596        int argc;
     1597        char **argv;
     1599        struct hostent *hp;
     1600        struct timeval pertry_timeout, total_timeout;
     1601        struct sockaddr_in server_addr;
     1602        int sock = RPC_ANYSOCK;
     1603        register CLIENT *client;
     1604        enum clnt_stat clnt_stat;
     1605        char buf[1000], *s = buf;
     1607        if ((client = clnttcp_create(&server_addr,
     1608          WINDOWPROG, WINDOWVERS, &sock, 0, 0)) == NULL) {
     1609                perror("clnttcp_create");
     1610                exit(-1);
     1611        }
     1612        total_timeout.tv_sec = 0;
     1613        total_timeout.tv_usec = 0;
     1614        while (scanf("%s", s) != EOF) {
     1615                clnt_stat = clnt_call(client, RENDERSTRING_BATCHED,
     1616                        xdr_wrapstring, &s, NULL, NULL, total_timeout);
     1617                if (clnt_stat != RPC_SUCCESS) {
     1618                        clnt_perror(client, "batched rpc");
     1619                        exit(-1);
     1620                }
     1621        }
     1623        /* \fINow flush the pipeline\fP */
     1625        total_timeout.tv_sec = 20;
     1626        clnt_stat = clnt_call(client, NULLPROC, xdr_void, NULL,
     1627                xdr_void, NULL, total_timeout);
     1628        if (clnt_stat != RPC_SUCCESS) {
     1629                clnt_perror(client, "rpc");
     1630                exit(-1);
     1631        }
     1632        clnt_destroy(client);
     1633        exit(0);
     1638Since the server sends no message,
     1639the clients cannot be notified of any of the failures that may occur.
     1640Therefore, clients are on their own when it comes to handling errors.
     1642The above example was completed to render
     1643all of the (2000) lines in the file
     1644.I /etc/termcap .
     1645The rendering service did nothing but throw the lines away.
     1646The example was run in the following four configurations:
     16471) machine to itself, regular RPC;
     16482) machine to itself, batched RPC;
     16493) machine to another, regular RPC; and
     16504) machine to another, batched RPC.
     1651The results are as follows:
     16521) 50 seconds;
     16532) 16 seconds;
     16543) 52 seconds;
     16554) 10 seconds.
     1657.I fscanf()
     1659.I /etc/termcap
     1660only requires six seconds.
     1661These timings show the advantage of protocols
     1662that allow for overlapped execution,
     1663though these protocols are often hard to design.
     1664.NH 2
     1666.IX "authentication"
     1667.IX "RPC" "authentication"
     1669In the examples presented so far,
     1670the caller never identified itself to the server,
     1671and the server never required an ID from the caller.
     1672Clearly, some network services, such as a network filesystem,
     1673require stronger security than what has been presented so far.
     1675In reality, every RPC call is authenticated by
     1676the RPC package on the server, and similarly,
     1677the RPC client package generates and sends authentication parameters.
     1678Just as different transports (TCP/IP or UDP/IP)
     1679can be used when creating RPC clients and servers,
     1680different forms of authentication can be associated with RPC clients;
     1681the default authentication type used as a default is type
     1682.I none .
     1684The authentication subsystem of the RPC package is open ended.
     1685That is, numerous types of authentication are easy to support.
     1686.NH 3
     1687\&UNIX Authentication
     1688.IX "UNIX Authentication"
     1689.IP "\fIThe Client Side\fP"
     1691When a caller creates a new RPC client handle as in:
     1693.ft CW
     1694clnt = clntudp_create(address, prognum, versnum,
     1695                      wait, sockp)
     1697the appropriate transport instance defaults
     1698the associate authentication handle to be
     1700.ft CW
     1701clnt->cl_auth = authnone_create();
     1703The RPC client can choose to use
     1704.I UNIX
     1705style authentication by setting
     1706.I clnt\->cl_auth
     1707after creating the RPC client handle:
     1709.ft CW
     1710clnt->cl_auth = authunix_create_default();
     1712This causes each RPC call associated with
     1713.I clnt
     1714to carry with it the following authentication credentials structure: t .DS
     1716.el .DS L
     1717.ft I
     1719 * UNIX style credentials.
     1720 */
     1721.ft CW
     1722struct authunix_parms {
     1723    u_long  aup_time;       /* \fIcredentials creation time\fP */
     1724    char    *aup_machname;  /* \fIhost name where client is\fP */
     1725    int     aup_uid;        /* \fIclient's UNIX effective uid\fP */
     1726    int     aup_gid;        /* \fIclient's current group id\fP */
     1727    u_int   aup_len;        /* \fIelement length of aup_gids\fP */
     1728    int     *aup_gids;      /* \fIarray of groups user is in\fP */
     1731These fields are set by
     1732.I authunix_create_default()
     1733by invoking the appropriate system calls.
     1734Since the RPC user created this new style of authentication,
     1735the user is responsible for destroying it with:
     1737.ft CW
     1740This should be done in all cases, to conserve memory.
     1742.IP "\fIThe Server Side\fP"
     1744Service implementors have a harder time dealing with authentication issues
     1745since the RPC package passes the service dispatch routine a request
     1746that has an arbitrary authentication style associated with it.
     1747Consider the fields of a request handle passed to a service dispatch routine: t .DS
     1749.el .DS L
     1750.ft I
     1752 * An RPC Service request
     1753 */
     1754.ft CW
     1755struct svc_req {
     1756    u_long    rq_prog;          /* \fIservice program number\fP */
     1757    u_long    rq_vers;          /* \fIservice protocol vers num\fP */
     1758    u_long    rq_proc;          /* \fIdesired procedure number\fP */
     1759    struct opaque_auth rq_cred; /* \fIraw credentials from wire\fP */
     1760    caddr_t   rq_clntcred;  /* \fIcredentials (read only)\fP */
     1764.I rq_cred
     1765is mostly opaque, except for one field of interest:
     1766the style or flavor of authentication credentials: t .DS
     1768.el .DS L
     1769.ft I
     1771 * Authentication info.  Mostly opaque to the programmer.
     1772 */
     1773.ft CW
     1774struct opaque_auth {
     1775    enum_t  oa_flavor;  /* \fIstyle of credentials\fP */
     1776    caddr_t oa_base;    /* \fIaddress of more auth stuff\fP */
     1777    u_int   oa_length;  /* \fInot to exceed \fIMAX_AUTH_BYTES */
     1780.IX RPC guarantees
     1781The RPC package guarantees the following
     1782to the service dispatch routine:
     1783.IP  1.
     1784That the request's
     1785.I rq_cred
     1786is well formed.  Thus the service implementor may inspect the request's
     1787.I rq_cred.oa_flavor
     1788to determine which style of authentication the caller used.
     1789The service implementor may also wish to inspect the other fields of
     1790.I rq_cred
     1791if the style is not one of the styles supported by the RPC package.
     1792.IP  2.
     1793That the request's
     1794.I rq_clntcred
     1795field is either
     1796.I NULL
     1797or points to a well formed structure
     1798that corresponds to a supported style of authentication credentials.
     1799Remember that only
     1800.I unix
     1801style is currently supported, so (currently)
     1802.I rq_clntcred
     1803could be cast to a pointer to an
     1804.I authunix_parms
     1805structure.  If
     1806.I rq_clntcred
     1808.I NULL ,
     1809the service implementor may wish to inspect the other (opaque) fields of
     1810.I rq_cred
     1811in case the service knows about a new type of authentication
     1812that the RPC package does not know about.
     1814Our remote users service example can be extended so that
     1815it computes results for all users except UID 16: t .DS
     1817.el .DS L
     1818.ft CW
     1819.vs 11
     1820nuser(rqstp, transp)
     1821        struct svc_req *rqstp;
     1822        SVCXPRT *transp;
     1824        struct authunix_parms *unix_cred;
     1825        int uid;
     1826        unsigned long nusers;
     1828.ft I
     1829        /*
     1830         * we don't care about authentication for null proc
     1831         */
     1832.ft CW
     1833        if (rqstp->rq_proc == NULLPROC) {
     1834                if (!svc_sendreply(transp, xdr_void, 0)) {
     1835                        fprintf(stderr, "can't reply to RPC call\en");
     1836                        return (1);
     1837                 }
     1838                 return;
     1839        }
     1840.ft I
     1841        /*
     1842         * now get the uid
     1843         */
     1844.ft CW
     1845        switch (rqstp->rq_cred.oa_flavor) {
     1846        case AUTH_UNIX:
     1847                unix_cred =
     1848                        (struct authunix_parms *)rqstp->rq_clntcred;
     1849                uid = unix_cred->aup_uid;
     1850                break;
     1851        case AUTH_NULL:
     1852        default:
     1853                svcerr_weakauth(transp);
     1854                return;
     1855        }
     1856        switch (rqstp->rq_proc) {
     1857        case RUSERSPROC_NUM:
     1858.ft I
     1859                /*
     1860                 * make sure caller is allowed to call this proc
     1861                 */
     1862.ft CW
     1863                if (uid == 16) {
     1864                        svcerr_systemerr(transp);
     1865                        return;
     1866                }
     1867.ft I
     1868                /*
     1869                 * Code here to compute the number of users
     1870                 * and assign it to the variable \fInusers\fP
     1871                 */
     1872.ft CW
     1873                if (!svc_sendreply(transp, xdr_u_long, &nusers)) {
     1874                        fprintf(stderr, "can't reply to RPC call\en");
     1875                        return (1);
     1876                }
     1877                return;
     1878        default:
     1879                svcerr_noproc(transp);
     1880                return;
     1881        }
     1885A few things should be noted here.
     1886First, it is customary not to check
     1887the authentication parameters associated with the
     1888.I NULLPROC
     1889(procedure number zero).
     1890Second, if the authentication parameter's type is not suitable
     1891for your service, you should call
     1892.I svcerr_weakauth() .
     1893And finally, the service protocol itself should return status
     1894for access denied; in the case of our example, the protocol
     1895does not have such a status, so we call the service primitive
     1896.I svcerr_systemerr()
     1899The last point underscores the relation between
     1900the RPC authentication package and the services;
     1901RPC deals only with
     1902.I authentication
     1903and not with individual services'
     1904.I "access control" .
     1905The services themselves must implement their own access control policies
     1906and reflect these policies as return statuses in their protocols.
     1907.NH 2
     1908\&DES Authentication
     1909.IX RPC DES
     1910.IX RPC authentication
     1912UNIX authentication is quite easy to defeat.  Instead of using
     1913.I authunix_create_default (),
     1914one can call
     1915.I authunix_create()
     1916and then modify the RPC authentication handle it returns by filling in
     1917whatever user ID and hostname they wish the server to think they have.
     1918DES authentication is thus recommended for people who want more security
     1919than UNIX authentication offers.
     1921The details of the DES authentication protocol are complicated and
     1922are not explained here. 
     1924.I "Remote Procedure Calls: Protocol Specification"
     1925for the details.
     1927In  order for  DES authentication   to  work, the
     1928.I keyserv(8c)
     1929daemon must be running  on both  the  server  and client machines.  The
     1930users on  these machines  need  public  keys  assigned by  the network
     1931administrator in  the
     1932.I publickey(5)
     1933database.  And,  they  need to have decrypted  their  secret keys
     1934using  their  login   password.  This automatically happens when one
     1935logs in using
     1936.I login(1) ,
     1937or can be done manually using
     1938.I keylogin(1) .
     1940.I "Network Services"
     1942./" XXX
     1943explains more how to setup secure networking.
     1945.IP "\fIClient Side\fP"
     1947If a client wishes to use DES authentication, it must set its
     1948authentication handle appropriately.  Here is an example:
     1950cl->cl_auth =
     1951        authdes_create(servername, 60, &server_addr, NULL);
     1953The first argument is the network name or \*Qnetname\*U of the owner of
     1954the server process.  Typically, server processes are root processes
     1955and their netname can be derived using the following call:
     1957char servername[MAXNETNAMELEN];
     1959host2netname(servername, rhostname, NULL);
     1962.I rhostname
     1963is the hostname of the machine the server process is running on.
     1964.I host2netname()
     1965fills in
     1966.I servername
     1967to contain this root process's netname.  If the
     1968server process was run by a regular user, one could use the call
     1969.I user2netname()
     1970instead.  Here is an example for a server process with the same user
     1971ID as the client:
     1973char servername[MAXNETNAMELEN];
     1975user2netname(servername, getuid(), NULL);
     1977The last argument to both of these calls,
     1978.I user2netname()
     1980.I host2netname (),
     1981is the name of the naming domain where the server is located.  The
     1982.I NULL
     1983used here means \*Quse the local domain name.\*U
     1985The second argument to
     1986.I authdes_create()
     1987is a lifetime for the credential.  Here it is set to sixty
     1988seconds.  What that means is that the credential will expire 60
     1989seconds from now.  If some mischievous user tries to reuse the
     1990credential, the server RPC subsystem will recognize that it has
     1991expired and not grant any requests.  If the same mischievous user
     1992tries to reuse the credential within the sixty second lifetime,
     1993he will still be rejected because the server RPC subsystem
     1994remembers which credentials it has already seen in the near past,
     1995and will not grant requests to duplicates.
     1997The third argument to
     1998.I authdes_create()
     1999is the address of the host to synchronize with.  In order for DES
     2000authentication to work, the server and client must agree upon the
     2001time.  Here we pass the address of the server itself, so the
     2002client and server will both be using the same time: the server's
     2003time.  The argument can be
     2004.I NULL ,
     2005which means \*Qdon't bother synchronizing.\*U You should only do this
     2006if you are sure the client and server are already synchronized.
     2008The final argument to
     2009.I authdes_create()
     2010is the address of a DES encryption key to use for encrypting
     2011timestamps and data.  If this argument is
     2012.I NULL ,
     2013as it is in this example, a random key will be chosen.  The client
     2014may find out the encryption key being used by consulting the
     2015.I ah_key
     2016field of the authentication handle.
     2018.IP "\fIServer Side\fP"
     2020The server side is a lot simpler than the client side.  Here is the
     2021previous example rewritten to use
     2022.I AUTH_DES
     2023instead of
     2024.I AUTH_UNIX : t .DS
     2026.el .DS L
     2027.ft CW
     2028.vs 11
     2029#include <sys/time.h>
     2030#include <rpc/auth_des.h>
     2031        . . .
     2032        . . .
     2033nuser(rqstp, transp)
     2034        struct svc_req *rqstp;
     2035        SVCXPRT *transp;
     2037        struct authdes_cred *des_cred;
     2038        int uid;
     2039        int gid;
     2040        int gidlen;
     2041        int gidlist[10];
     2042.ft I
     2043        /*
     2044         * we don't care about authentication for null proc
     2045         */
     2046.ft CW
     2048        if (rqstp->rq_proc == NULLPROC) {
     2049                /* \fIsame as before\fP */
     2050        }
     2052.ft I
     2053        /*
     2054         * now get the uid
     2055         */
     2056.ft CW
     2057        switch (rqstp->rq_cred.oa_flavor) {
     2058        case AUTH_DES:
     2059                des_cred =
     2060                        (struct authdes_cred *) rqstp->rq_clntcred;
     2061                if (! netname2user(des_cred->,
     2062                        &uid, &gid, &gidlen, gidlist))
     2063                {
     2064                        fprintf(stderr, "unknown user: %s\n",
     2065                                des_cred->;
     2066                        svcerr_systemerr(transp);
     2067                        return;
     2068                }
     2069                break;
     2070        case AUTH_NULL:
     2071        default:
     2072                svcerr_weakauth(transp);
     2073                return;
     2074        }
     2076.ft I
     2077        /*
     2078         * The rest is the same as before
     2079         */     
     2080.ft CW
     2083Note the use of the routine
     2084.I netname2user (),
     2085the inverse of
     2086.I user2netname ():
     2087it takes a network ID and converts to a unix ID.
     2088.I netname2user ()
     2089also supplies the group IDs which we don't use in this example,
     2090but which may be useful to other UNIX programs.
     2091.NH 2
     2092\&Using Inetd
     2093.IX inetd "" "using \fIinetd\fP"
     2095An RPC server can be started from
     2096.I inetd
     2097The only difference from the usual code is that the service
     2098creation routine should be called in the following form: t .DS
     2100.el .DS L
     2101.ft CW
     2102transp = svcudp_create(0);     /* \fIFor UDP\fP */
     2103transp = svctcp_create(0,0,0); /* \fIFor listener TCP sockets\fP */
     2104transp = svcfd_create(0,0,0);  /* \fIFor connected TCP sockets\fP */
     2107.I inet
     2108passes a socket as file descriptor 0.
     2110.I svc_register()
     2111should be called as t .DS
     2113.el .DS L
     2114.ft CW
     2115svc_register(transp, PROGNUM, VERSNUM, service, 0);
     2117with the final flag as 0,
     2118since the program would already be registered by
     2119.I inetd
     2120Remember that if you want to exit
     2121from the server process and return control to
     2122.I inet
     2123you need to explicitly exit, since
     2124.I svc_run()
     2125never returns.
     2127The format of entries in
     2128.I /etc/inetd.conf
     2129for RPC services is in one of the following two forms: t .DS
     2131.el .DS L
     2132.ft CW
     2133p_name/version dgram  rpc/udp wait/nowait user server args
     2134p_name/version stream rpc/tcp wait/nowait user server args
     2137.I p_name
     2138is the symbolic name of the program as it appears in
     2139.I rpc(5) ,
     2140.I server
     2141is the program implementing the server,
     2143.I program
     2145.I version
     2146are the program and version numbers of the service.
     2147For more information, see
     2148.I inetd.conf(5) .
     2150If the same program handles multiple versions,
     2151then the version number can be a range,
     2152as in this example: t .DS
     2154.el .DS L
     2155.ft CW
     2156rstatd/1-2 dgram rpc/udp wait root /usr/etc/rpc.rstatd
     2158.NH 1
     2159\&More Examples
     2160.sp 1
     2161.NH 2
     2163.IX "versions"
     2164.IX "RPC" "versions"
     2166By convention, the first version number of program
     2167.I PROG
     2170and the most recent version is
     2171.I PROGVERS
     2172Suppose there is a new version of the
     2173.I user
     2174program that returns an
     2175.I "unsigned short"
     2176rather than a
     2177.I long .
     2178If we name this version
     2180then a server that wants to support both versions
     2181would do a double register. t .DS
     2183.el .DS L
     2184.ft CW
     2185if (!svc_register(transp, RUSERSPROG, RUSERSVERS_ORIG,
     2186  nuser, IPPROTO_TCP)) {
     2187        fprintf(stderr, "can't register RUSER service\en");
     2188        exit(1);
     2190if (!svc_register(transp, RUSERSPROG, RUSERSVERS_SHORT,
     2191  nuser, IPPROTO_TCP)) {
     2192        fprintf(stderr, "can't register RUSER service\en");
     2193        exit(1);
     2196Both versions can be handled by the same C procedure: t .DS
     2198.el .DS L
     2199.ft CW
     2200.vs 11
     2201nuser(rqstp, transp)
     2202        struct svc_req *rqstp;
     2203        SVCXPRT *transp;
     2205        unsigned long nusers;
     2206        unsigned short nusers2;
     2208        switch (rqstp->rq_proc) {
     2209        case NULLPROC:
     2210                if (!svc_sendreply(transp, xdr_void, 0)) {
     2211                        fprintf(stderr, "can't reply to RPC call\en");
     2212            return (1);
     2213                }
     2214                return;
     2215        case RUSERSPROC_NUM:
     2216.ft I
     2217                /*
     2218         * Code here to compute the number of users
     2219         * and assign it to the variable \fInusers\fP
     2220                 */
     2221.ft CW
     2222                nusers2 = nusers;
     2223                switch (rqstp->rq_vers) {
     2224                case RUSERSVERS_ORIG:
     2225            if (!svc_sendreply(transp, xdr_u_long,
     2226                    &nusers)) {
     2227                fprintf(stderr,"can't reply to RPC call\en");
     2228                        }
     2229                        break;
     2230                case RUSERSVERS_SHORT:
     2231            if (!svc_sendreply(transp, xdr_u_short,
     2232                    &nusers2)) {
     2233                fprintf(stderr,"can't reply to RPC call\en");
     2234                        }
     2235                        break;
     2236                }
     2237        default:
     2238                svcerr_noproc(transp);
     2239                return;
     2240        }
     2245.NH 2
     2247.IX "TCP"
     2249Here is an example that is essentially
     2250.I rcp.
     2251The initiator of the RPC
     2252.I snd
     2253call takes its standard input and sends it to the server
     2254.I rcv
     2255which prints it on standard output.
     2256The RPC call uses TCP.
     2257This also illustrates an XDR procedure that behaves differently
     2258on serialization than on deserialization. t .DS
     2260.el .DS L
     2261.vs 11
     2262.ft I
     2264 * The xdr routine:
     2265 *              on decode, read from wire, write onto fp
     2266 *              on encode, read from fp, write onto wire
     2267 */
     2268.ft CW
     2269#include <stdio.h>
     2270#include <rpc/rpc.h>
     2272xdr_rcp(xdrs, fp)
     2273        XDR *xdrs;
     2274        FILE *fp;
     2276        unsigned long size;
     2277        char buf[BUFSIZ], *p;
     2279        if (xdrs->x_op == XDR_FREE)/* nothing to free */
     2280                return 1;
     2281        while (1) {
     2282                if (xdrs->x_op == XDR_ENCODE) {
     2283                        if ((size = fread(buf, sizeof(char), BUFSIZ,
     2284                          fp)) == 0 && ferror(fp)) {
     2285                                fprintf(stderr, "can't fread\en");
     2286                                return (1);
     2287                        }
     2288                }
     2289                p = buf;
     2290                if (!xdr_bytes(xdrs, &p, &size, BUFSIZ))
     2291                        return 0;
     2292                if (size == 0)
     2293                        return 1;
     2294                if (xdrs->x_op == XDR_DECODE) {
     2295                        if (fwrite(buf, sizeof(char), size,
     2296                          fp) != size) {
     2297                                fprintf(stderr, "can't fwrite\en");
     2298                                return (1);
     2299                        }
     2300                }
     2301        }
     2305.KE t .DS
     2307.el .DS L
     2308.vs 11
     2309.ft I
     2311 * The sender routines
     2312 */
     2313.ft CW
     2314#include <stdio.h>
     2315#include <netdb.h>
     2316#include <rpc/rpc.h>
     2317#include <sys/socket.h>
     2318#include <sys/time.h>
     2320main(argc, argv)
     2321        int argc;
     2322        char **argv;
     2324        int xdr_rcp();
     2325        int err;
     2327        if (argc < 2) {
     2328                fprintf(stderr, "usage: %s servername\en", argv[0]);
     2329                exit(-1);
     2330        }
     2331        if ((err = callrpctcp(argv[1], RCPPROG, RCPPROC,
     2332          RCPVERS, xdr_rcp, stdin, xdr_void, 0) != 0)) {
     2333                clnt_perrno(err);
     2334                fprintf(stderr, "can't make RPC call\en");
     2335                exit(1);
     2336        }
     2337        exit(0);
     2340callrpctcp(host, prognum, procnum, versnum,
     2341           inproc, in, outproc, out)
     2342        char *host, *in, *out;
     2343        xdrproc_t inproc, outproc;
     2345        struct sockaddr_in server_addr;
     2346        int socket = RPC_ANYSOCK;
     2347        enum clnt_stat clnt_stat;
     2348        struct hostent *hp;
     2349        register CLIENT *client;
     2350        struct timeval total_timeout;
     2352        if ((hp = gethostbyname(host)) == NULL) {
     2353                fprintf(stderr, "can't get addr for '%s'\en", host);
     2354                return (-1);
     2355        }
     2356        bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr,
     2357                hp->h_length);
     2358        server_addr.sin_family = AF_INET;
     2359        server_addr.sin_port =  0;
     2360        if ((client = clnttcp_create(&server_addr, prognum,
     2361          versnum, &socket, BUFSIZ, BUFSIZ)) == NULL) {
     2362                perror("rpctcp_create");
     2363                return (-1);
     2364        }
     2365        total_timeout.tv_sec = 20;
     2366        total_timeout.tv_usec = 0;
     2367        clnt_stat = clnt_call(client, procnum,
     2368                inproc, in, outproc, out, total_timeout);
     2369        clnt_destroy(client);
     2370        return (int)clnt_stat;
     2373.DE t .DS
     2375.el .DS L
     2376.vs 11
     2377.ft I
     2379 * The receiving routines
     2380 */
     2381.ft CW
     2382#include <stdio.h>
     2383#include <rpc/rpc.h>
     2387        register SVCXPRT *transp;
     2388     int rcp_service(), xdr_rcp();
     2390        if ((transp = svctcp_create(RPC_ANYSOCK,
     2391          BUFSIZ, BUFSIZ)) == NULL) {
     2392                fprintf("svctcp_create: error\en");
     2393                exit(1);
     2394        }
     2395        pmap_unset(RCPPROG, RCPVERS);
     2396        if (!svc_register(transp,
     2397          RCPPROG, RCPVERS, rcp_service, IPPROTO_TCP)) {
     2398                fprintf(stderr, "svc_register: error\en");
     2399                exit(1);
     2400        }
     2401        svc_run();  /* \fInever returns\fP */
     2402        fprintf(stderr, "svc_run should never return\en");
     2405rcp_service(rqstp, transp)
     2406        register struct svc_req *rqstp;
     2407        register SVCXPRT *transp;
     2409        switch (rqstp->rq_proc) {
     2410        case NULLPROC:
     2411                if (svc_sendreply(transp, xdr_void, 0) == 0) {
     2412                        fprintf(stderr, "err: rcp_service");
     2413                        return (1);
     2414                }
     2415                return;
     2416        case RCPPROC_FP:
     2417                if (!svc_getargs(transp, xdr_rcp, stdout)) {
     2418                        svcerr_decode(transp);
     2419                        return;
     2420                }
     2421                if (!svc_sendreply(transp, xdr_void, 0)) {
     2422                        fprintf(stderr, "can't reply\en");
     2423                        return;
     2424                }
     2425                return (0);
     2426        default:
     2427                svcerr_noproc(transp);
     2428                return;
     2429        }
     2433.NH 2
     2434\&Callback Procedures
     2435.IX RPC "callback procedures"
     2437Occasionally, it is useful to have a server become a client,
     2438and make an RPC call back to the process which is its client.
     2439An example is remote debugging,
     2440where the client is a window system program,
     2441and the server is a debugger running on the remote machine.
     2442Most of the time,
     2443the user clicks a mouse button at the debugging window,
     2444which converts this to a debugger command,
     2445and then makes an RPC call to the server
     2446(where the debugger is actually running),
     2447telling it to execute that command.
     2448However, when the debugger hits a breakpoint, the roles are reversed,
     2449and the debugger wants to make an rpc call to the window program,
     2450so that it can inform the user that a breakpoint has been reached.
     2452In order to do an RPC callback,
     2453you need a program number to make the RPC call on.
     2454Since this will be a dynamically generated program number,
     2455it should be in the transient range,
     2456.I "0x40000000 - 0x5fffffff" .
     2457The routine
     2458.I gettransient()
     2459returns a valid program number in the transient range,
     2460and registers it with the portmapper.
     2461It only talks to the portmapper running on the same machine as the
     2462.I gettransient()
     2463routine itself.  The call to
     2464.I pmap_set()
     2465is a test and set operation,
     2466in that it indivisibly tests whether a program number
     2467has already been registered,
     2468and if it has not, then reserves it.  On return, the
     2469.I sockp
     2470argument will contain a socket that can be used
     2471as the argument to an
     2472.I svcudp_create()
     2474.I svctcp_create()
     2475call. t .DS
     2477.el .DS L
     2478.ft CW
     2479.vs 11
     2480#include <stdio.h>
     2481#include <rpc/rpc.h>
     2482#include <sys/socket.h>
     2484gettransient(proto, vers, sockp)
     2485        int proto, vers, *sockp;
     2487        static int prognum = 0x40000000;
     2488        int s, len, socktype;
     2489        struct sockaddr_in addr;
     2491        switch(proto) {
     2492                case IPPROTO_UDP:
     2493                        socktype = SOCK_DGRAM;
     2494                        break;
     2495                case IPPROTO_TCP:
     2496                        socktype = SOCK_STREAM;
     2497                        break;
     2498                default:
     2499                        fprintf(stderr, "unknown protocol type\en");
     2500                        return 0;
     2501        }
     2502        if (*sockp == RPC_ANYSOCK) {
     2503                if ((s = socket(AF_INET, socktype, 0)) < 0) {
     2504                        perror("socket");
     2505                        return (0);
     2506                }
     2507                *sockp = s;
     2508        }
     2509        else
     2510                s = *sockp;
     2511        addr.sin_addr.s_addr = 0;
     2512        addr.sin_family = AF_INET;
     2513        addr.sin_port = 0;
     2514        len = sizeof(addr);
     2515.ft I
     2516        /*
     2517         * may be already bound, so don't check for error
     2518         */
     2519.ft CW
     2520        bind(s, &addr, len);
     2521        if (getsockname(s, &addr, &len)< 0) {
     2522                perror("getsockname");
     2523                return (0);
     2524        }
     2525        while (!pmap_set(prognum++, vers, proto,
     2526                ntohs(addr.sin_port))) continue;
     2527        return (prognum-1);
     2534The call to
     2535.I ntohs()
     2536is necessary to ensure that the port number in
     2537.I "addr.sin_port" ,
     2538which is in
     2539.I network
     2540byte order, is passed in
     2541.I host
     2542byte order (as
     2543.I pmap_set()
     2544expects).  See the
     2545.I byteorder(3N)
     2546man page for more details on the conversion of network
     2547addresses from network to host byte order.
     2550The following pair of programs illustrate how to use the
     2551.I gettransient()
     2553The client makes an RPC call to the server,
     2554passing it a transient program number.
     2555Then the client waits around to receive a callback
     2556from the server at that program number.
     2557The server registers the program
     2559so that it can receive the RPC call
     2560informing it of the callback program number.
     2561Then at some random time (on receiving an
     2562.I ALRM
     2563signal in this example), it sends a callback RPC call,
     2564using the program number it received earlier. t .DS
     2566.el .DS L
     2567.vs 11
     2568.ft I
     2570 * client
     2571 */
     2572.ft CW
     2573#include <stdio.h>
     2574#include <rpc/rpc.h>
     2576int callback();
     2577char hostname[256];
     2581        int x, ans, s;
     2582        SVCXPRT *xprt;
     2584        gethostname(hostname, sizeof(hostname));
     2585        s = RPC_ANYSOCK;
     2586        x = gettransient(IPPROTO_UDP, 1, &s);
     2587        fprintf(stderr, "client gets prognum %d\en", x);
     2588        if ((xprt = svcudp_create(s)) == NULL) {
     2589          fprintf(stderr, "rpc_server: svcudp_create\en");
     2590                exit(1);
     2591        }
     2592.ft I
     2593        /* protocol is 0 - gettransient does registering
     2594         */
     2595.ft CW
     2596        (void)svc_register(xprt, x, 1, callback, 0);
     2597        ans = callrpc(hostname, EXAMPLEPROG, EXAMPLEVERS,
     2598                EXAMPLEPROC_CALLBACK, xdr_int, &x, xdr_void, 0);
     2599        if ((enum clnt_stat) ans != RPC_SUCCESS) {
     2600                fprintf(stderr, "call: ");
     2601                clnt_perrno(ans);
     2602                fprintf(stderr, "\en");
     2603        }
     2604        svc_run();
     2605        fprintf(stderr, "Error: svc_run shouldn't return\en");
     2608callback(rqstp, transp)
     2609        register struct svc_req *rqstp;
     2610        register SVCXPRT *transp;
     2612        switch (rqstp->rq_proc) {
     2613                case 0:
     2614                        if (!svc_sendreply(transp, xdr_void, 0)) {
     2615                                fprintf(stderr, "err: exampleprog\en");
     2616                                return (1);
     2617                        }
     2618                        return (0);
     2619                case 1:
     2620                        if (!svc_getargs(transp, xdr_void, 0)) {
     2621                                svcerr_decode(transp);
     2622                                return (1);
     2623                        }
     2624                        fprintf(stderr, "client got callback\en");
     2625                        if (!svc_sendreply(transp, xdr_void, 0)) {
     2626                                fprintf(stderr, "err: exampleprog");
     2627                                return (1);
     2628                        }
     2629        }
     2633.KE t .DS
     2635.el .DS L
     2636.vs 11
     2637.ft I
     2639 * server
     2640 */
     2641.ft CW
     2642#include <stdio.h>
     2643#include <rpc/rpc.h>
     2644#include <sys/signal.h>
     2646char *getnewprog();
     2647char hostname[256];
     2648int docallback();
     2649int pnum;               /* \fIprogram number for callback routine\fP */
     2653        gethostname(hostname, sizeof(hostname));
     2654        registerrpc(EXAMPLEPROG, EXAMPLEVERS,
     2655          EXAMPLEPROC_CALLBACK, getnewprog, xdr_int, xdr_void);
     2656        fprintf(stderr, "server going into svc_run\en");
     2657        signal(SIGALRM, docallback);
     2658        alarm(10);
     2659        svc_run();
     2660        fprintf(stderr, "Error: svc_run shouldn't return\en");
     2663char *
     2665        char *pnump;
     2667        pnum = *(int *)pnump;
     2668        return NULL;
     2673        int ans;
     2675        ans = callrpc(hostname, pnum, 1, 1, xdr_void, 0,
     2676                xdr_void, 0);
     2677        if (ans != 0) {
     2678                fprintf(stderr, "server: ");
     2679                clnt_perrno(ans);
     2680                fprintf(stderr, "\en");
     2681        }
  • cpukit/librpc/src/rpc/PSD.doc/

    r0ab65474 rdf49c60  
     2.\" Must use  --  tbl  --  with this one
     4.\" @(#)      2.2 88/08/05 4.0 RPCSRC BT
     6.if \\n%=1 .tl ''- % -''
     9.\" prevent excess underlining in nroff
     10.if n .fp 2 R
     11.OH 'Remote Procedure Calls: Protocol Specification''Page %'
     12.EH 'Page %''Remote Procedure Calls: Protocol Specification'
     13.if \\n%=1 .bp
     15\&Remote Procedure Calls: Protocol Specification
     17.NH 0
     18\&Status of this Memo
     20Note: This chapter specifies a protocol that Sun Microsystems, Inc.,
     21and others are using. 
     22It has been designated RFC1050 by the ARPA Network
     23Information Center.
     25.NH 1
     28This chapter specifies  a  message protocol  used in implementing
     29Sun's Remote Procedure Call (RPC) package.  (The message protocol is
     30specified with the External Data Representation (XDR) language.
     31See the
     32.I "External Data Representation Standard: Protocol Specification"
     33for the details.  Here, we assume that  the  reader is familiar 
     34with XDR and do not attempt to justify it or its uses).  The paper
     35by Birrell and Nelson [1]  is recommended as an  excellent background
     36to  and justification of RPC.
     37.NH 2
     40This chapter discusses servers, services, programs, procedures,
     41clients, and versions.  A server is a piece of software where network
     42services are implemented.  A network service is a collection of one
     43or more remote programs.  A remote program implements one or more
     44remote procedures; the procedures, their parameters, and results are
     45documented in the specific program's protocol specification (see the
     46\fIPort Mapper Program Protocol\fP\, below, for an example).  Network
     47clients are pieces of software that initiate remote procedure calls
     48to services.  A server may support more than one version of a remote
     49program in order to be forward compatible with changing protocols.
     51For example, a network file service may be composed of two programs.
     52One program may deal with high-level applications such as file system
     53access control and locking.  The other may deal with low-level file
     54IO and have procedures like "read" and "write".  A client machine of
     55the network file service would call the procedures associated with
     56the two programs of the service on behalf of some user on the client
     58.NH 2
     59\&The RPC Model
     61The remote procedure call model is similar to the local procedure
     62call model.  In the local case, the caller places arguments to a
     63procedure in some well-specified location (such as a result
     64register).  It then transfers control to the procedure, and
     65eventually gains back control.  At that point, the results of the
     66procedure are extracted from the well-specified location, and the
     67caller continues execution.
     69The remote procedure call is similar, in that one thread of control
     70logically winds through two processes\(emone is the caller's process,
     71the other is a server's process.  That is, the caller process sends a
     72call message to the server process and waits (blocks) for a reply
     73message.  The call message contains the procedure's parameters, among
     74other things.  The reply message contains the procedure's results,
     75among other things.  Once the reply message is received, the results
     76of the procedure are extracted, and caller's execution is resumed.
     78On the server side, a process is dormant awaiting the arrival of a
     79call message.  When one arrives, the server process extracts the
     80procedure's parameters, computes the results, sends a reply message,
     81and then awaits the next call message.
     83Note that in this model, only one of the two processes is active at
     84any given time.  However, this model is only given as an example.
     85The RPC protocol makes no restrictions on the concurrency model
     86implemented, and others are possible.  For example, an implementation
     87may choose to have RPC calls be asynchronous, so that the client may
     88do useful work while waiting for the reply from the server.  Another
     89possibility is to have the server create a task to process an
     90incoming request, so that the server can be free to receive other
     92.NH 2
     93\&Transports and Semantics
     95The RPC protocol is independent of transport protocols.  That is, RPC
     96does not care how a message is passed from one process to another.
     97The protocol deals only with specification and interpretation of
     100It is important to point out that RPC does not try to implement any
     101kind of reliability and that the application must be aware of the
     102type of transport protocol underneath RPC.  If it knows it is running
     103on top of a reliable transport such as TCP/IP[6], then most of the
     104work is already done for it.  On the other hand, if it is running on
     105top of an unreliable transport such as UDP/IP[7], it must implement
     106is own retransmission and time-out policy as the RPC layer does not
     107provide this service.
     109Because of transport independence, the RPC protocol does not attach
     110specific semantics to the remote procedures or their execution.
     111Semantics can be inferred from (but should be explicitly specified
     112by) the underlying transport protocol.  For example, consider RPC
     113running on top of an unreliable transport such as UDP/IP.  If an
     114application retransmits RPC messages after short time-outs, the only
     115thing it can infer if it receives no reply is that the procedure was
     116executed zero or more times.  If it does receive a reply, then it can
     117infer that the procedure was executed at least once.
     119A server may wish to remember previously granted requests from a
     120client and not regrant them in order to insure some degree of
     121execute-at-most-once semantics.  A server can do this by taking
     122advantage of the transaction ID that is packaged with every RPC
     123request.  The main use of this transaction is by the client RPC layer
     124in matching replies to requests.  However, a client application may
     125choose to reuse its previous transaction ID when retransmitting a
     126request.  The server application, knowing this fact, may choose to
     127remember this ID after granting a request and not regrant requests
     128with the same ID in order to achieve some degree of
     129execute-at-most-once semantics.  The server is not allowed to examine
     130this ID in any other way except as a test for equality.
     132On the other hand, if using a reliable transport such as TCP/IP, the
     133application can infer from a reply message that the procedure was
     134executed exactly once, but if it receives no reply message, it cannot
     135assume the remote procedure was not executed.  Note that even if a
     136connection-oriented protocol like TCP is used, an application still
     137needs time-outs and reconnection to handle server crashes.
     139There are other possibilities for transports besides datagram- or
     140connection-oriented protocols.  For example, a request-reply protocol
     141such as VMTP[2] is perhaps the most natural transport for RPC.
     144NOTE:  At Sun, RPC is currently implemented on top of both TCP/IP
     145and UDP/IP transports.
     147.NH 2
     148\&Binding and Rendezvous Independence
     150The act of binding a client to a service is NOT part of the remote
     151procedure call specification.  This important and necessary function
     152is left up to some higher-level software.  (The software may use RPC
     153itself\(emsee the \fIPort Mapper Program Protocol\fP\, below).
     155Implementors should think of the RPC protocol as the jump-subroutine
     156instruction ("JSR") of a network; the loader (binder) makes JSR
     157useful, and the loader itself uses JSR to accomplish its task.
     158Likewise, the network makes RPC useful, using RPC to accomplish this
     160.NH 2
     163The RPC protocol provides the fields necessary for a client to
     164identify itself to a service and vice-versa.  Security and access
     165control mechanisms can be built on top of the message authentication.
     166Several different authentication protocols can be supported.  A field
     167in the RPC header indicates which protocol is being used.  More
     168information on specific authentication protocols can be found in the
     169\fIAuthentication Protocols\fP\,
     172.NH 1
     173\&RPC Protocol Requirements
     175The RPC protocol must provide for the following:
     176.IP  1.
     177Unique specification of a procedure to be called.
     178.IP  2.
     179Provisions for matching response messages to request messages.
     181.IP  3.
     182Provisions for authenticating the caller to service and vice-versa.
     184Besides these requirements, features that detect the following are
     185worth supporting because of protocol roll-over errors, implementation
     186bugs, user error, and network administration:
     187.IP  1.
     188RPC protocol mismatches.
     189.IP  2.
     190Remote program protocol version mismatches.
     191.IP  3.
     192Protocol errors (such as misspecification of a procedure's parameters).
     193.IP  4.
     194Reasons why remote authentication failed.
     195.IP  5.
     196Any other reasons why the desired procedure was not called.
     197.NH 2
     198\&Programs and Procedures
     200The RPC call message has three unsigned fields:  remote program
     201number, remote program version number, and remote procedure number.
     202The three fields uniquely identify the procedure to be called.
     203Program numbers are administered by some central authority (like
     204Sun).  Once an implementor has a program number, he can implement his
     205remote program; the first implementation would most likely have the
     206version number of 1.  Because most new protocols evolve into better,
     207stable, and mature protocols, a version field of the call message
     208identifies which version of the protocol the caller is using.
     209Version numbers make speaking old and new protocols through the same
     210server process possible.
     212The procedure number identifies the procedure to be called.  These
     213numbers are documented in the specific program's protocol
     214specification.  For example, a file service's protocol specification
     215may state that its procedure number 5 is "read" and procedure number
     21612 is "write".
     218Just as remote program protocols may change over several versions,
     219the actual RPC message protocol could also change.  Therefore, the
     220call message also has in it the RPC version number, which is always
     221equal to two for the version of RPC described here.
     223The reply message to a request  message  has enough  information to
     224distinguish the following error conditions:
     225.IP  1.
     226The remote implementation of RPC does speak protocol version 2.
     227The lowest and highest supported RPC version numbers are returned.
     228.IP  2.
     229The remote program is not available on the remote system.
     230.IP  3.
     231The remote program does not support the requested version number.
     232The lowest and highest supported remote program version numbers are
     234.IP  4.
     235The requested procedure number does not exist.  (This is usually a
     236caller side protocol or programming error.)
     237.IP  5.
     238The parameters to the remote procedure appear to be garbage from the
     239server's point of view.  (Again, this is usually caused by a
     240disagreement about the protocol between client and service.)
     241.NH 2
     244Provisions for authentication of caller to service and vice-versa are
     245provided as a part of the RPC protocol.  The call message has two
     246authentication fields, the credentials and verifier.  The reply
     247message has one authentication field, the response verifier.  The RPC
     248protocol specification defines all three fields to be the following
     249opaque type:
     251.ft CW
     252.vs 11
     253enum auth_flavor {
     254    AUTH_NULL        = 0,
     255    AUTH_UNIX        = 1,
     256    AUTH_SHORT       = 2,
     257    AUTH_DES         = 3
     258    /* \fIand more to be defined\fP */
     261struct opaque_auth {
     262    auth_flavor flavor;
     263    opaque body<400>;
     267In simple English, any
     268.I opaque_auth
     269structure is an
     270.I auth_flavor
     271enumeration followed by bytes which are  opaque to the RPC protocol
     274The interpretation and semantics  of the data contained  within the
     275authentication   fields  is specified  by  individual,  independent
     276authentication  protocol specifications.   (See
     277\fIAuthentication Protocols\fP\,
     278below, for definitions of the various authentication protocols.)
     280If authentication parameters were   rejected, the  response message
     281contains information stating why they were rejected.
     282.NH 2
     283\&Program Number Assignment
     285Program numbers are given out in groups of
     286.I 0x20000000
     287(decimal 536870912) according to the following chart:
     289box tab (&) ;
     290lfI lfI
     291rfL cfI .
     292Program Numbers&Description
     294.sp .5
     2950 - 1fffffff&Defined by Sun
     29620000000 - 3fffffff&Defined by user
     29740000000 - 5fffffff&Transient
     29860000000 - 7fffffff&Reserved
     29980000000 - 9fffffff&Reserved
     300a0000000 - bfffffff&Reserved
     301c0000000 - dfffffff&Reserved
     302e0000000 - ffffffff&Reserved
     305The first group is a range of numbers administered by Sun
     306Microsystems and should be identical for all sites.  The second range
     307is for applications peculiar to a particular site.  This range is
     308intended primarily for debugging new programs.  When a site develops
     309an application that might be of general interest, that application
     310should be given an assigned number in the first range.  The third
     311group is for applications that generate program numbers dynamically.
     312The final groups are reserved for future use, and should not be used.
     313.NH 2
     314\&Other Uses of the RPC Protocol
     316The intended use of this protocol is for calling remote procedures.
     317That is, each call message is matched with a response message.
     318However, the protocol itself is a message-passing protocol with which
     319other (non-RPC) protocols can be implemented.  Sun currently uses, or
     320perhaps abuses, the RPC message protocol for the following two
     321(non-RPC) protocols:  batching (or pipelining) and broadcast RPC.
     322These two protocols are discussed but not defined below.
     323.NH 3
     326Batching allows a client to send an arbitrarily large sequence of
     327call messages to a server; batching typically uses reliable byte
     328stream protocols (like TCP/IP) for its transport.  In the case of
     329batching, the client never waits for a reply from the server, and the
     330server does not send replies to batch requests.  A sequence of batch
     331calls is usually terminated by a legitimate RPC in order to flush the
     332pipeline (with positive acknowledgement).
     333.NH 3
     334\&Broadcast RPC
     336In broadcast RPC-based protocols, the client sends a broadcast packet
     337to the network and waits for numerous replies.  Broadcast RPC uses
     338unreliable, packet-based protocols (like UDP/IP) as its transports.
     339Servers that support broadcast protocols only respond when the
     340request is successfully processed, and are silent in the face of
     341errors.  Broadcast RPC uses the Port Mapper RPC service to achieve
     342its semantics.  See the \fIPort Mapper Program Protocol\fP\, below,
     343for more information.
     345.NH 1
     346\&The RPC Message Protocol
     348This section defines the RPC message protocol in the XDR data
     349description language.  The message is defined in a top-down style. t .DS
     351.el .DS L
     352.ft CW
     353enum msg_type {
     354        CALL  = 0,
     355        REPLY = 1
     358.ft I
     360* A reply to a call message can take on two forms:
     361* The message was either accepted or rejected.
     363.ft CW
     364enum reply_stat {
     365        MSG_ACCEPTED = 0,
     366        MSG_DENIED   = 1
     369.ft I
     371* Given that a call message was accepted,  the following is the
     372* status of an attempt to call a remote procedure.
     374.ft CW
     375enum accept_stat {
     376        SUCCESS       = 0, /* \fIRPC executed successfully       \fP*/
     377        PROG_UNAVAIL  = 1, /* \fIremote hasn't exported program  \fP*/
     378        PROG_MISMATCH = 2, /* \fIremote can't support version #  \fP*/
     379        PROC_UNAVAIL  = 3, /* \fIprogram can't support procedure \fP*/
     380        GARBAGE_ARGS  = 4  /* \fIprocedure can't decode params   \fP*/
     382.DE t .DS
     384.el .DS L
     385.ft I
     387* Reasons why a call message was rejected:
     389.ft CW
     390enum reject_stat {
     391        RPC_MISMATCH = 0, /* \fIRPC version number != 2          \fP*/
     392        AUTH_ERROR = 1    /* \fIremote can't authenticate caller \fP*/
     395.ft I
     397* Why authentication failed:
     399.ft CW
     400enum auth_stat {
     401        AUTH_BADCRED      = 1,  /* \fIbad credentials \fP*/
     402        AUTH_REJECTEDCRED = 2,  /* \fIclient must begin new session \fP*/
     403        AUTH_BADVERF      = 3,  /* \fIbad verifier \fP*/
     404        AUTH_REJECTEDVERF = 4,  /* \fIverifier expired or replayed  \fP*/
     405        AUTH_TOOWEAK      = 5   /* \fIrejected for security reasons \fP*/
     408.KE t .DS
     410.el .DS L
     411.ft I
     413* The  RPC  message:
     414* All   messages  start with   a transaction  identifier,  xid,
     415* followed  by a  two-armed  discriminated union.   The union's
     416* discriminant is a  msg_type which switches to  one of the two
     417* types   of the message.   The xid  of a \fIREPLY\fP  message always
     418* matches  that of the initiating \fICALL\fP   message.   NB: The xid
     419* field is only  used for clients  matching reply messages with
     420* call messages  or for servers detecting  retransmissions; the
     421* service side  cannot treat this id  as any type   of sequence
     422* number.
     424.ft CW
     425struct rpc_msg {
     426        unsigned int xid;
     427        union switch (msg_type mtype) {
     428                case CALL:
     429                        call_body cbody;
     430                case REPLY: 
     431                        reply_body rbody;
     432        } body;
     434.DE t .DS
     436.el .DS L
     437.ft I
     439* Body of an RPC request call:
     440* In version 2 of the  RPC protocol specification, rpcvers must
     441* be equal to 2.  The  fields prog,  vers, and proc specify the
     442* remote program, its version number, and the  procedure within
     443* the remote program to be called.  After these  fields are two
     444* authentication  parameters: cred (authentication credentials)
     445* and verf  (authentication verifier).  The  two authentication
     446* parameters are   followed by  the  parameters  to  the remote
     447* procedure,  which  are specified  by  the  specific   program
     448* protocol.
     450.ft CW
     451struct call_body {
     452        unsigned int rpcvers;  /* \fImust be equal to two (2) \fP*/
     453        unsigned int prog;
     454        unsigned int vers;
     455        unsigned int proc;
     456        opaque_auth cred;
     457        opaque_auth verf;
     458        /* \fIprocedure specific parameters start here \fP*/
     460.DE t .DS
     462.el .DS L
     463.ft I
     465* Body of a reply to an RPC request:
     466* The call message was either accepted or rejected.
     468.ft CW
     469union reply_body switch (reply_stat stat) {
     470        case MSG_ACCEPTED: 
     471                accepted_reply areply;
     472        case MSG_DENIED: 
     473                rejected_reply rreply;
     474} reply;
     475.DE t .DS
     477.el .DS L
     478.ft I
     480* Reply to   an RPC request  that  was accepted  by the server:
     481* there could be an error even though the request was accepted.
     482* The first field is an authentication verifier that the server
     483* generates in order to  validate itself  to the caller.  It is
     484* followed by    a  union whose     discriminant  is   an  enum
     485* accept_stat.  The  \fISUCCESS\fP  arm of    the union  is  protocol
     486* specific.  The \fIPROG_UNAVAIL\fP, \fIPROC_UNAVAIL\fP, and \fIGARBAGE_ARGP\fP
     487* arms of the union are void.   The \fIPROG_MISMATCH\fP arm specifies
     488* the lowest and highest version numbers of the  remote program
     489* supported by the server.
     491.ft CW
     492struct accepted_reply {
     493        opaque_auth verf;
     494        union switch (accept_stat stat) {
     495                case SUCCESS:
     496                        opaque results[0];
     497                        /* \fIprocedure-specific results start here\fP */
     498                case PROG_MISMATCH:
     499                        struct {
     500                                unsigned int low;
     501                                unsigned int high;
     502                        } mismatch_info;
     503                default:
     504.ft I
     505                        /*
     506                        * Void.  Cases include \fIPROG_UNAVAIL, PROC_UNAVAIL\fP,
     507                        * and \fIGARBAGE_ARGS\fP.
     508                        */
     509.ft CW
     510                        void;
     511        } reply_data;
     513.DE t .DS
     515.el .DS L
     516.ft I
     518* Reply to an RPC request that was rejected by the server:
     519* The request  can   be rejected for   two reasons:  either the
     520* server   is not  running a   compatible  version  of the  RPC
     521* protocol    (\fIRPC_MISMATCH\fP), or    the  server   refuses    to
     522* authenticate the  caller  (\fIAUTH_ERROR\fP).  In  case of  an  RPC
     523* version mismatch,  the server returns the  lowest and highest
     524* supported    RPC  version    numbers.  In   case   of refused
     525* authentication, failure status is returned.
     527.ft CW
     528union rejected_reply switch (reject_stat stat) {
     529        case RPC_MISMATCH:
     530                struct {
     531                        unsigned int low;
     532                        unsigned int high;
     533                } mismatch_info;
     534        case AUTH_ERROR:
     535                auth_stat stat;
     538.NH 1
     539\&Authentication Protocols
     541As previously stated, authentication parameters are opaque, but
     542open-ended to the rest of the RPC protocol.  This section defines
     543some "flavors" of authentication implemented at (and supported by)
     544Sun.  Other sites are free to invent new authentication types, with
     545the same rules of flavor number assignment as there is for program
     546number assignment.
     547.NH 2
     548\&Null Authentication
     550Often calls must be made where the caller does not know who he is or
     551the server does not care who the caller is.  In this case, the flavor
     552value (the discriminant of the \fIopaque_auth\fP's union) of the RPC
     553message's credentials, verifier, and response verifier is
     554.I AUTH_NULL .
     555The  bytes of the opaque_auth's body  are undefined.
     556It is recommended that the opaque length be zero.
     557.NH 2
     558\&UNIX Authentication
     560The caller of a remote procedure may wish to identify himself as he
     561is identified on a UNIX system.  The  value of the credential's
     562discriminant of an RPC call  message is 
     563.I AUTH_UNIX .
     564The bytes of
     565the credential's opaque body encode the following structure:
     567.ft CW
     568struct auth_unix {
     569        unsigned int stamp;
     570        string machinename<255>;
     571        unsigned int uid;
     572        unsigned int gid;
     573        unsigned int gids<10>;
     577.I stamp
     578is an  arbitrary    ID which the  caller machine   may
     579generate.  The
     580.I machinename
     581is the  name of the  caller's machine (like  "krypton").  The
     582.I uid
     583is  the caller's effective user  ID.  The 
     584.I gid
     585is  the caller's effective  group  ID.  The
     586.I gids
     587is  a
     588counted array of groups which contain the caller as  a member.  The
     589verifier accompanying the  credentials  should  be  of 
     590.I AUTH_NULL
     591(defined above).
     593The value of the discriminant of  the response verifier received in
     594the  reply  message  from  the    server  may   be   
     595.I AUTH_NULL
     597.I AUTH_SHORT .
     598In  the  case  of
     599.I AUTH_SHORT ,
     600the bytes of the response verifier's string encode an opaque
     601structure.  This new opaque structure may now be passed to the server
     602instead of the original
     603.I AUTH_UNIX
     604flavor credentials.  The server keeps a cache which maps shorthand
     605opaque structures (passed back by way of an
     606.I AUTH_SHORT
     607style response verifier) to the original credentials of the caller.
     608The caller can save network bandwidth and server cpu cycles by using
     609the new credentials.
     611The server may flush the shorthand opaque structure at any time.  If
     612this happens, the remote procedure call message will be rejected due
     613to an authentication error.  The reason for the failure will be
     615At this point, the caller may wish to try the original
     616.I AUTH_UNIX
     617style of credentials.
     619.NH 2
     620\&DES Authentication
     622UNIX authentication suffers from two major problems:
     623.IP  1.
     624The naming is too UNIX-system oriented.
     625.IP  2.
     626There is no verifier, so credentials can easily be faked.
     628DES authentication attempts to fix these two problems.
     630.NH 3
     633The first problem is handled by addressing the caller by a simple
     634string of characters instead of by an operating system specific
     635integer.  This string of characters is known as the "netname" or
     636network name of the caller.  The server is not allowed to interpret
     637the contents of the caller's name in any other way except to
     638identify the caller.  Thus, netnames should be unique for every
     639caller in the internet.
     641It is up to each operating system's implementation of DES
     642authentication to generate netnames for its users that insure this
     643uniqueness when they call upon remote servers.  Operating systems
     644already know how to distinguish users local to their systems.  It is
     645usually a simple matter to extend this mechanism to the network.
     646For example, a UNIX user at Sun with a user ID of 515 might be
     647assigned the following netname: "".  This netname
     648contains three items that serve to insure it is unique.  Going
     649backwards, there is only one naming domain called "" in the
     650internet.  Within this domain, there is only one UNIX user with
     651user ID 515.  However, there may be another user on another
     652operating system, for example VMS, within the same naming domain
     653that, by coincidence, happens to have the same user ID.  To insure
     654that these two users can be distinguished we add the operating
     655system name.  So one user is "" and the other is
     658The first field is actually a naming method rather than an
     659operating system name.  It just happens that today there is almost
     660a one-to-one correspondence between naming methods and operating
     661systems.  If the world could agree on a naming standard, the first
     662field could be the name of that standard, instead of an operating
     663system name.
     665.NH 3
     666\&DES Authentication Verifiers
     668Unlike UNIX authentication, DES authentication does have a verifier
     669so the server can validate the client's credential (and
     670vice-versa).  The contents of this verifier is primarily an
     671encrypted timestamp.  The server can decrypt this timestamp, and if
     672it is close to what the real time is, then the client must have
     673encrypted it correctly.  The only way the client could encrypt it
     674correctly is to know the "conversation key" of the RPC session.  And
     675if the client knows the conversation key, then it must be the real
     678The conversation key is a DES [5] key which the client generates
     679and notifies the server of in its first RPC call.  The conversation
     680key is encrypted using a public key scheme in this first
     681transaction.  The particular public key scheme used in DES
     682authentication is Diffie-Hellman [3] with 192-bit keys.  The
     683details of this encryption method are described later.
     685The client and the server need the same notion of the current time
     686in order for all of this to work.  If network time synchronization
     687cannot be guaranteed, then client can synchronize with the server
     688before beginning the conversation, perhaps by consulting the
     689Internet Time Server (TIME[4]).
     691The way a server determines if a client timestamp is valid is
     692somewhat complicated.  For any other transaction but the first, the
     693server just checks for two things:
     694.IP  1.
     695the timestamp is greater than the one previously seen from the
     696same client.
     697.IP  2.
     698the timestamp has not expired.
     700A timestamp is expired if the server's time is later than the sum
     701of the client's timestamp plus what is known as the client's
     702"window".  The "window" is a number the client passes (encrypted)
     703to the server in its first transaction.  You can think of it as a
     704lifetime for the credential.
     706This explains everything but the first transaction.  In the first
     707transaction, the server checks only that the timestamp has not
     708expired.  If this was all that was done though, then it would be
     709quite easy for the client to send random data in place of the
     710timestamp with a fairly good chance of succeeding.  As an added
     711check, the client sends an encrypted item in the first transaction
     712known as the "window verifier" which must be equal to the window
     713minus 1, or the server will reject the credential.
     715The client too must check the verifier returned from the server to
     716be sure it is legitimate.  The server sends back to the client the
     717encrypted timestamp it received from the client, minus one second.
     718If the client gets anything different than this, it will reject it.
     720.NH 3
     721\&Nicknames and Clock Synchronization
     723After the first transaction, the server's DES authentication
     724subsystem returns in its verifier to the client an integer
     725"nickname" which the client may use in its further transactions
     726instead of passing its netname, encrypted DES key and window every
     727time.  The nickname is most likely an index into a table on the
     728server which stores for each client its netname, decrypted DES key
     729and window.
     731Though they originally were synchronized, the client's and server's
     732clocks can get out of sync again.  When this happens the client RPC
     733subsystem most likely will get back
     735at which point it should resynchronize.
     737A client may still get the
     739error even though it is
     740synchronized with the server.  The reason is that the server's
     741nickname table is a limited size, and it may flush entries whenever
     742it wants.  A client should resend its original credential in this
     743case and the server will give it a new nickname.  If a server
     744crashes, the entire nickname table gets flushed, and all clients
     745will have to resend their original credentials.
     747.NH 3
     748\&DES Authentication Protocol (in XDR language) t .DS
     750.el .DS L
     751.ft I
     753* There are two kinds of credentials: one in which the client uses
     754* its full network name, and one in which it uses its "nickname"
     755* (just an unsigned integer) given to it by the server.  The
     756* client must use its fullname in its first transaction with the
     757* server, in which the server will return to the client its
     758* nickname.  The client may use its nickname in all further
     759* transactions with the server.  There is no requirement to use the
     760* nickname, but it is wise to use it for performance reasons.
     762.ft CW
     763enum authdes_namekind {
     764        ADN_FULLNAME = 0,
     765        ADN_NICKNAME = 1
     768.ft I
     770* A 64-bit block of encrypted DES data
     772.ft CW
     773typedef opaque des_block[8];
     775.ft I
     777* Maximum length of a network user's name
     779.ft CW
     780const MAXNETNAMELEN = 255;
     782.ft I
     784* A fullname contains the network name of the client, an encrypted
     785* conversation key and the window.  The window is actually a
     786* lifetime for the credential.  If the time indicated in the
     787* verifier timestamp plus the window has past, then the server
     788* should expire the request and not grant it.  To insure that
     789* requests are not replayed, the server should insist that
     790* timestamps are greater than the previous one seen, unless it is
     791* the first transaction.  In the first transaction, the server
     792* checks instead that the window verifier is one less than the
     793* window.
     795.ft CW
     796struct authdes_fullname {
     797string name<MAXNETNAMELEN>;  /* \fIname of client \f(CW*/
     798des_block key;               /* \fIPK encrypted conversation key \f(CW*/
     799unsigned int window;         /* \fIencrypted window \f(CW*/
     802.ft I
     804* A credential is either a fullname or a nickname
     806.ft CW
     807union authdes_cred switch (authdes_namekind adc_namekind) {
     808        case ADN_FULLNAME:
     809                authdes_fullname adc_fullname;
     810        case ADN_NICKNAME:
     811                unsigned int adc_nickname;
     814.ft I
     816* A timestamp encodes the time since midnight, January 1, 1970.
     818.ft CW
     819struct timestamp {
     820        unsigned int seconds;    /* \fIseconds \fP*/
     821        unsigned int useconds;   /* \fIand microseconds \fP*/
     824.ft I
     826* Verifier: client variety
     827* The window verifier is only used in the first transaction.  In
     828* conjunction with a fullname credential, these items are packed
     829* into the following structure before being encrypted:
     831* \f(CWstruct {\fP
     832*     \f(CWadv_timestamp;            \fP-- one DES block
     833*     \f(CWadc_fullname.window;      \fP-- one half DES block
     834*     \f(CWadv_winverf;              \fP-- one half DES block
     835* \f(CW}\fP
     836* This structure is encrypted using CBC mode encryption with an
     837* input vector of zero.  All other encryptions of timestamps use
     838* ECB mode encryption.
     840.ft CW
     841struct authdes_verf_clnt {
     842        timestamp adv_timestamp;    /* \fIencrypted timestamp       \fP*/
     843        unsigned int adv_winverf;   /* \fIencrypted window verifier \fP*/
     846.ft I
     848* Verifier: server variety
     849* The server returns (encrypted) the same timestamp the client
     850* gave it minus one second.  It also tells the client its nickname
     851* to be used in future transactions (unencrypted).
     853.ft CW
     854struct authdes_verf_svr {
     855timestamp adv_timeverf;     /* \fIencrypted verifier      \fP*/
     856unsigned int adv_nickname;  /* \fInew nickname for client \fP*/
     860.NH 3
     861\&Diffie-Hellman Encryption
     863In this scheme, there are two constants,
     864.I BASE
     866.I MODULUS .
     868particular values Sun has chosen for these for the DES
     869authentication protocol are: t .DS
     871.el .DS L
     872.ft CW
     873const BASE = 3;
     874const MODULUS =
     875        "d4a0ba0250b6fd2ec626e7efd637df76c716e22d0944b88b"; /* \fIhex \fP*/
     877.ft R
     878The way this scheme works is best explained by an example.  Suppose
     879there are two people "A" and "B" who want to send encrypted
     880messages to each other.  So, A and B both generate "secret" keys at
     881random which they do not reveal to anyone.  Let these keys be
     882represented as SK(A) and SK(B).  They also publish in a public
     883directory their "public" keys.  These keys are computed as follows: t .DS
     885.el .DS L
     886.ft CW
     887PK(A) = ( BASE ** SK(A) ) mod MODULUS
     888PK(B) = ( BASE ** SK(B) ) mod MODULUS
     890.ft R
     891The "**" notation is used here to represent exponentiation.  Now,
     892both A and B can arrive at the "common" key between them,
     893represented here as CK(A, B), without revealing their secret keys.
     895A computes: t .DS
     897.el .DS L
     898.ft CW
     899CK(A, B) = ( PK(B) ** SK(A)) mod MODULUS
     901.ft R
     902while B computes: t .DS
     904.el .DS L
     905.ft CW
     906CK(A, B) = ( PK(A) ** SK(B)) mod MODULUS
     908.ft R
     909These two can be shown to be equivalent: t .DS
     911.el .DS L
     912.ft CW
     913(PK(B) ** SK(A)) mod MODULUS = (PK(A) ** SK(B)) mod MODULUS
     915.ft R
     916We drop the "mod MODULUS" parts and assume modulo arithmetic to
     917simplify things: t .DS
     919.el .DS L
     920.ft CW
     921PK(B) ** SK(A) = PK(A) ** SK(B)
     923.ft R
     924Then, replace PK(B) by what B computed earlier and likewise for
     925PK(A). t .DS
     927.el .DS L
     928.ft CW
     929((BASE ** SK(B)) ** SK(A) = (BASE ** SK(A)) ** SK(B)
     931.ft R
     932which leads to: t .DS
     934.el .DS L
     935.ft CW
     936BASE ** (SK(A) * SK(B)) = BASE ** (SK(A) * SK(B))
     938.ft R
     939This common key CK(A, B) is not used to encrypt the timestamps used
     940in the protocol.  Rather, it is used only to encrypt a conversation
     941key which is then used to encrypt the timestamps.  The reason for
     942doing this is to use the common key as little as possible, for fear
     943that it could be broken.  Breaking the conversation key is a far
     944less serious offense, since conversations are relatively
     947The conversation key is encrypted using 56-bit DES keys, yet the
     948common key is 192 bits.  To reduce the number of bits, 56 bits are
     949selected from the common key as follows.  The middle-most 8-bytes
     950are selected from the common key, and then parity is added to the
     951lower order bit of each byte, producing a 56-bit key with 8 bits of
     954.NH 1
     955\&Record Marking Standard
     957When RPC messages are passed on top of a byte stream protocol (like
     958TCP/IP), it is necessary, or at least desirable, to delimit one
     959message from another in order to detect and possibly recover from
     960user protocol errors.  This is called record marking (RM).  Sun uses
     961this RM/TCP/IP transport for passing RPC messages on TCP streams.
     962One RPC message fits into one RM record.
     964A record is composed of one or more record fragments.  A record
     965fragment is a four-byte header followed by 0 to (2**31) - 1 bytes of
     966fragment data.  The bytes encode an unsigned binary number; as with
     967XDR integers, the byte order is from highest to lowest.  The number
     968encodes two values\(ema boolean which indicates whether the fragment
     969is the last fragment of the record (bit value 1 implies the fragment
     970is the last fragment) and a 31-bit unsigned binary value which is the
     971length in bytes of the fragment's data.  The boolean value is the
     972highest-order bit of the header; the length is the 31 low-order bits.
     973(Note that this record specification is NOT in XDR standard form!)
     976.NH 1
     977\&The RPC Language
     979Just as there was a need to describe the XDR data-types in a formal
     980language, there is also need to describe the procedures that operate
     981on these XDR data-types in a formal language as well.  We use the RPC
     982Language for this purpose.  It is an extension to the XDR language.
     983The following example is used to describe the essence of the
     985.NH 2
     986\&An Example Service Described in the RPC Language
     988Here is an example of the specification of a simple ping program. t .DS
     990.el .DS L
     991.vs 11
     992.ft I
     994* Simple ping program
     996.ft CW
     997program PING_PROG {
     998        /* \fILatest and greatest version\fP */
     999        version PING_VERS_PINGBACK {
     1000        void
     1001        PINGPROC_NULL(void) = 0;
     1003.ft I
     1004        /*
     1005        * Ping the caller, return the round-trip time
     1006        * (in microseconds). Returns -1 if the operation
     1007        * timed out.
     1008        */
     1009.ft CW
     1010        int
     1011        PINGPROC_PINGBACK(void) = 1;       
     1012} = 2;     
     1014.ft I
     1016* Original version
     1018.ft CW
     1019version PING_VERS_ORIG {
     1020        void
     1021        PINGPROC_NULL(void) = 0;
     1022        } = 1;
     1023} = 1;
     1025const PING_VERS = 2;      /* \fIlatest version \fP*/
     1030The first version described is
     1032with  two procedures,   
     1037takes no arguments and returns no results, but it is useful for
     1038computing round-trip times from the client to the server and back
     1039again.  By convention, procedure 0 of any RPC protocol should have
     1040the same semantics, and never require any kind of authentication.
     1041The second procedure is used for the client to have the server do a
     1042reverse ping operation back to the client, and it returns the amount
     1043of time (in microseconds) that the operation used.  The next version,
     1044.I PING_VERS_ORIG ,
     1045is the original version of the protocol
     1046and it does not contain
     1048procedure. It  is useful
     1049for compatibility  with old client  programs,  and as  this program
     1050matures it may be dropped from the protocol entirely.
     1052.NH 2
     1053\&The RPC Language Specification
     1055The  RPC language is identical to  the XDR language, except for the
     1056added definition of a
     1057.I program-def
     1058described below.
     1060.ft CW
     1062        "program" identifier "{"
     1063                version-def
     1064                version-def *
     1065        "}" "=" constant ";"
     1068        "version" identifier "{"
     1069                procedure-def
     1070                procedure-def *
     1071        "}" "=" constant ";"
     1074        type-specifier identifier "(" type-specifier ")"
     1075        "=" constant ";"
     1078.NH 2
     1079\&Syntax Notes
     1080.IP  1.
     1081The following keywords  are  added  and   cannot  be used   as
     1082identifiers: "program" and "version";
     1083.IP  2.
     1084A version name cannot occur more than once within the  scope of
     1085a program definition. Nor can a version number occur more than once
     1086within the scope of a program definition.
     1087.IP  3.
     1088A procedure name cannot occur  more than once within  the scope
     1089of a version definition. Nor can a procedure number occur more than
     1090once within the scope of version definition.
     1091.IP  4.
     1092Program identifiers are in the same name space as  constant and
     1093type identifiers.
     1094.IP  5.
     1095Only unsigned constants can  be assigned to programs, versions
     1096and procedures.
     1097.NH 1
     1098\&Port Mapper Program Protocol
     1100The port mapper program maps RPC program and version numbers to
     1101transport-specific port numbers.  This program makes dynamic binding
     1102of remote programs possible.
     1104This is desirable because the range of reserved port numbers is very
     1105small and the number of potential remote programs is very large.  By
     1106running only the port mapper on a reserved port, the port numbers of
     1107other remote programs can be ascertained by querying the port mapper.
     1109The port mapper also aids in broadcast RPC.  A given RPC program will
     1110usually have different port number bindings on different machines, so
     1111there is no way to directly broadcast to all of these programs.  The
     1112port mapper, however, does have a fixed port number.  So, to
     1113broadcast to a given program, the client actually sends its message
     1114to the port mapper located at the broadcast address.  Each port
     1115mapper that picks up the broadcast then calls the local service
     1116specified by the client.  When the port mapper gets the reply from
     1117the local service, it sends the reply on back to the client.
     1119.NH 2
     1120\&Port Mapper Protocol Specification (in RPC Language) t .DS
     1122.el .DS L
     1123.ft CW
     1124.vs 11
     1125const PMAP_PORT = 111;      /* \fIportmapper port number \fP*/
     1127.ft I
     1129* A mapping of (program, version, protocol) to port number
     1131.ft CW
     1132struct mapping {
     1133        unsigned int prog;
     1134        unsigned int vers;
     1135        unsigned int prot;
     1136        unsigned int port;
     1139.ft I
     1141* Supported values for the "prot" field
     1143.ft CW
     1144const IPPROTO_TCP = 6;      /* \fIprotocol number for TCP/IP \fP*/
     1145const IPPROTO_UDP = 17;     /* \fIprotocol number for UDP/IP \fP*/
     1147.ft I
     1149* A list of mappings
     1151.ft CW
     1152struct *pmaplist {
     1153        mapping map;
     1154        pmaplist next;
     1157.DE t .DS
     1159.el .DS L
     1160.vs 11
     1161.ft I
     1163* Arguments to callit
     1165.ft CW
     1166struct call_args {
     1167        unsigned int prog;
     1168        unsigned int vers;
     1169        unsigned int proc;
     1170        opaque args<>;
     1173.ft I
     1175* Results of callit
     1177.ft CW
     1178struct call_result {
     1179        unsigned int port;
     1180        opaque res<>;
     1184.KE t .DS
     1186.el .DS L
     1187.vs 11
     1188.ft I
     1190* Port mapper procedures
     1192.ft CW
     1193program PMAP_PROG {
     1194        version PMAP_VERS {
     1195                void
     1196                PMAPPROC_NULL(void)         = 0;
     1198                bool
     1199                PMAPPROC_SET(mapping)       = 1;
     1201                bool
     1202                PMAPPROC_UNSET(mapping)     = 2;
     1204                unsigned int
     1205                PMAPPROC_GETPORT(mapping)   = 3;
     1207                pmaplist
     1208                PMAPPROC_DUMP(void)         = 4;
     1210                call_result
     1211                PMAPPROC_CALLIT(call_args)  = 5;
     1212        } = 2;
     1213} = 100000;
     1216.NH 2
     1217\&Port Mapper Operation
     1219The portmapper program currently supports two protocols (UDP/IP and
     1220TCP/IP).  The portmapper is contacted by talking to it on assigned
     1221port number 111 (SUNRPC [8]) on either of these protocols.  The
     1222following is a description of each of the portmapper procedures:
     1223.IP \fBPMAPPROC_NULL:\fP
     1224This procedure does no work.  By convention, procedure zero of any
     1225protocol takes no parameters and returns no results.
     1226.IP \fBPMAPPROC_SET:\fP
     1227When a program first becomes available on a machine, it registers
     1228itself with the port mapper program on the same machine.  The program
     1229passes its program number "prog", version number "vers", transport
     1230protocol number "prot", and the port "port" on which it awaits
     1231service request.  The procedure returns a boolean response whose
     1232value is
     1233.I TRUE
     1234if the procedure successfully established the mapping and
     1235.I FALSE
     1236otherwise.  The procedure refuses to establish
     1237a mapping if one already exists for the tuple "(prog, vers, prot)".
     1238.IP \fBPMAPPROC_UNSET:\fP
     1239When a program becomes unavailable, it should unregister itself with
     1240the port mapper program on the same machine.  The parameters and
     1241results have meanings identical to those of
     1242.I PMAPPROC_SET .
     1243The protocol and port number fields of the argument are ignored.
     1245Given a program number "prog", version number "vers", and transport
     1246protocol number "prot", this procedure returns the port number on
     1247which the program is awaiting call requests.  A port value of zeros
     1248means the program has not been registered.  The "port" field of the
     1249argument is ignored.
     1250.IP \fBPMAPPROC_DUMP:\fP
     1251This procedure enumerates all entries in the port mapper's database.
     1252The procedure takes no parameters and returns a list of program,
     1253version, protocol, and port values.
     1255This procedure allows a caller to call another remote procedure on
     1256the same machine without knowing the remote procedure's port number.
     1257It is intended for supporting broadcasts to arbitrary remote programs
     1258via the well-known port mapper's port.  The parameters "prog",
     1259"vers", "proc", and the bytes of "args" are the program number,
     1260version number, procedure number, and parameters of the remote
     1263.B Note:
     1265.IP  1.
     1266This procedure only sends a response if the procedure was
     1267successfully executed and is silent (no response) otherwise.
     1268.IP  2.
     1269The port mapper communicates with the remote program using UDP/IP
     1273The procedure returns the remote program's port number, and the bytes
     1274of results are the results of the remote procedure.
     1276.NH 1
     1279[1]  Birrell, Andrew D. & Nelson, Bruce Jay; "Implementing Remote
     1280Procedure Calls"; XEROX CSL-83-7, October 1983.
     1282[2]  Cheriton, D.; "VMTP:  Versatile Message Transaction Protocol",
     1283Preliminary Version 0.3; Stanford University, January 1987.
     1285[3]  Diffie & Hellman; "New Directions in Cryptography"; IEEE
     1286Transactions on Information Theory IT-22, November 1976.
     1288[4]  Harrenstien, K.; "Time Server", RFC 738; Information Sciences
     1289Institute, October 1977.
     1291[5]  National Bureau of Standards; "Data Encryption Standard"; Federal
     1292Information Processing Standards Publication 46, January 1977.
     1294[6]  Postel, J.; "Transmission Control Protocol - DARPA Internet
     1295Program Protocol Specification", RFC 793; Information Sciences
     1296Institute, September 1981.
     1298[7]  Postel, J.; "User Datagram Protocol", RFC 768; Information Sciences
     1299Institute, August 1980.
     1301[8]  Reynolds, J.  & Postel, J.; "Assigned Numbers", RFC 923; Information
     1302Sciences Institute, October 1984.
  • cpukit/librpc/src/rpc/PSD.doc/

    r0ab65474 rdf49c60  
     2.\" Must use  --  tbl -- for this one
     4.\" @(#)       2.2 88/08/04 4.0 RPCSRC BT
     6.if \\n%=1 .tl ''- % -''
     9.\" prevent excess underlining in nroff
     10.if n .fp 2 R
     11.OH '\fBrpcgen\fP Programming Guide''Page %'
     12.EH 'Page %''\fBrpcgen\fP Programming Guide'
     13.if \\n%=1 .bp
     15\&\fBrpcgen\fP Programming Guide
     16.NH 0
     17\&The \fBrpcgen\fP Protocol Compiler
     18.IX rpcgen "" \fIrpcgen\fP "" PAGE MAJOR
     20.IX RPC "" "" \fIrpcgen\fP
     21The details of programming applications to use Remote Procedure Calls
     22can be overwhelming.  Perhaps most daunting is the writing of the XDR
     23routines necessary to convert procedure arguments and results into
     24their network format and vice-versa. 
     27.I rpcgen(1)
     28exists to help programmers write RPC applications simply and directly.
     29.I rpcgen
     30does most of the dirty work, allowing programmers to debug
     31the  main  features of their application, instead of requiring them to
     32spend most of their time debugging their network interface code.
     34.I rpcgen
     35is a  compiler.  It accepts a remote program interface definition written
     36in a language, called RPC Language, which is similar to C.  It produces a C
     37language output which includes stub versions of the client routines, a
     38server skeleton, XDR filter routines for both parameters and results, and a
     39header file that contains common definitions. The client stubs interface
     40with the RPC library and effectively hide the network from their callers.
     41The server stub similarly hides the network from the server procedures that
     42are to be invoked by remote clients.
     43.I rpcgen 's
     44output files can be compiled and linked in the usual way.  The developer
     45writes server procedures\(emin any language that observes Sun calling
     46conventions\(emand links them with the server skeleton produced by
     47.I rpcgen
     48to get an executable server program.  To use a remote program, a programmer
     49writes an ordinary main program that makes local procedure calls to the
     50client stubs produced by
     51.I rpcgen .
     52Linking this program with
     53.I rpcgen 's
     54stubs creates an executable program.  (At present the main program must be
     55written in C).
     56.I rpcgen
     57options can be used to suppress stub generation and to specify the transport
     58to be used by the server stub.
     60Like all compilers,
     61.I rpcgen
     62reduces development time
     63that would otherwise be spent coding and debugging low-level routines.
     64All compilers, including
     65.I rpcgen ,
     66do this at a small cost in efficiency
     67and flexibility.  However,   many compilers allow  escape  hatches for
     68programmers to  mix low-level code with  high-level code.
     69.I rpcgen
     70is no exception.  In speed-critical applications, hand-written routines
     71can be linked with the
     72.I rpcgen
     73output without any difficulty.  Also, one may proceed by using
     74.I rpcgen
     75output as a starting point, and then rewriting it as necessary.
     76(If you need a discussion of RPC programming without
     77.I rpcgen ,
     78see the
     79.I "Remote Procedure Call Programming Guide)\.
     80.NH 1
     81\&Converting Local Procedures into Remote Procedures
     82.IX rpcgen "local procedures" \fIrpcgen\fP
     83.IX rpcgen "remote procedures" \fIrpcgen\fP
     85Assume an application that runs on a single machine, one which we want
     86to convert to run over the network.  Here we will demonstrate such a
     87conversion by way of a simple example\(ema program that prints a
     88message to the console: t .DS
     90.el .DS L
     91.ft I
     93 * printmsg.c: print a message on the console
     94 */
     95.ft CW
     96#include <stdio.h>
     98main(argc, argv)
     99        int argc;
     100        char *argv[];
     102        char *message;
     104        if (argc < 2) {
     105                fprintf(stderr, "usage: %s <message>\en", argv[0]);
     106                exit(1);
     107        }
     108        message = argv[1];
     110        if (!printmessage(message)) {
     111                fprintf(stderr, "%s: couldn't print your message\en",
     112                        argv[0]);
     113                exit(1);
     114        }
     115        printf("Message Delivered!\en");
     116        exit(0);
     118.ft I
     120 * Print a message to the console.
     121 * Return a boolean indicating whether the message was actually printed.
     122 */
     123.ft CW
     125        char *msg;
     127        FILE *f;
     129        f = fopen("/dev/console", "w");
     130        if (f == NULL) {
     131                return (0);
     132        }
     133        fprintf(f, "%s\en", msg);
     134        fclose(f);
     135        return(1);
     139And then, of course: t .DS
     141.el .DS L
     142.ft CW
     143example%  \fBcc printmsg.c -o printmsg\fP
     144example%  \fBprintmsg "Hello, there."\fP
     145Message delivered!
     150.I printmessage()
     151was turned into  a remote procedure,
     152then it could be  called from anywhere in   the network. 
     153Ideally,  one would just  like to stick   a  keyword like 
     154.I remote
     155in  front  of a
     156procedure to turn it into a  remote procedure.  Unfortunately,
     157we  have to live  within the  constraints of  the   C language, since
     158it existed   long before  RPC did.  But   even without language
     159support, it's not very difficult to make a procedure remote.
     161In  general, it's necessary to figure  out  what the types are for
     162all procedure inputs and outputs.  In  this case,   we  have a
     164.I printmessage()
     165which takes a  string as input, and returns  an integer
     166as output.  Knowing  this, we can write a  protocol specification in RPC
     167language that  describes the remote  version of
     168.I printmessage ().
     169Here it is: t .DS
     171.el .DS L
     172.ft I
     174 * msg.x: Remote message printing protocol
     175 */
     176.ft CW
     178program MESSAGEPROG {
     179        version MESSAGEVERS {
     180                int PRINTMESSAGE(string) = 1;
     181        } = 1;
     182} = 99;
     185Remote procedures are part of remote programs, so we actually declared
     186an  entire  remote program  here  which contains  the single procedure
     188This procedure was declared to be  in version  1 of the
     189remote program.  No null procedure (procedure 0) is necessary because
     190.I rpcgen
     191generates it automatically.
     193Notice that everything is declared with all capital  letters.  This is
     194not required, but is a good convention to follow.
     196Notice also that the argument type is \*Qstring\*U and not \*Qchar *\*U.  This
     197is because a \*Qchar *\*U in C is ambiguous.  Programmers usually intend it
     198to mean  a null-terminated string   of characters, but  it  could also
     199represent a pointer to a single character or a  pointer to an array of
     200characters.  In  RPC language,  a  null-terminated  string is
     201unambiguously called a \*Qstring\*U.
     203There are  just two more things to  write.  First, there is the remote
     204procedure itself.  Here's the definition of a remote procedure
     205to implement the
     207procedure we declared above: t .DS
     209.el .DS L
     210.vs 11
     211.ft I
     213 * msg_proc.c: implementation of the remote procedure "printmessage"
     214 */
     215.ft CW
     217#include <stdio.h>
     218#include <rpc/rpc.h>    /* \fIalways needed\fP  */
     219#include "msg.h"        /* \fIneed this too: msg.h will be generated by rpcgen\fP */
     221.ft I
     223 * Remote verson of "printmessage"
     224 */
     225.ft CW
     226int *
     228        char **msg;
     230        static int result;  /* \fImust be static!\fP */
     231        FILE *f;
     233        f = fopen("/dev/console", "w");
     234        if (f == NULL) {
     235                result = 0;
     236                return (&result);
     237        }
     238        fprintf(f, "%s\en", *msg);
     239        fclose(f);
     240        result = 1;
     241        return (&result);
     246Notice here that the declaration of the remote procedure
     247.I printmessage_1()
     248differs from that of the local procedure
     249.I printmessage()
     250in three ways:
     251.IP  1.
     252It takes a pointer to a string instead of a string itself.  This
     253is true of all  remote procedures:  they always take pointers to  their
     254arguments rather than the arguments themselves.
     255.IP  2.
     256It returns a pointer to an  integer instead of  an integer itself. This is
     257also generally true of remote procedures: they always return a pointer
     258to their results.
     259.IP  3.
     260It has an \*Q_1\*U appended to its name.  In general, all remote
     261procedures called by
     262.I rpcgen
     263are named by  the following rule: the name in the program  definition 
     266is converted   to all
     267lower-case letters, an underbar (\*Q_\*U) is appended to it, and
     268finally the version number (here 1) is appended.
     270The last thing to do is declare the main client program that will call
     271the remote procedure. Here it is: t .DS
     273.el .DS L
     274.ft I
     276 * rprintmsg.c: remote version of "printmsg.c"
     277 */
     278.ft CW
     279#include <stdio.h>
     280#include <rpc/rpc.h>     /* \fIalways needed\fP  */
     281#include "msg.h"         /* \fIneed this too: msg.h will be generated by rpcgen\fP */
     283main(argc, argv)
     284        int argc;
     285        char *argv[];
     287        CLIENT *cl;
     288        int *result;
     289        char *server;
     290        char *message;
     292        if (argc < 3) {
     293                fprintf(stderr, "usage: %s host message\en", argv[0]);
     294                exit(1);
     295        }
     297.ft I
     298        /*
     299         * Save values of command line arguments
     300         */
     301.ft CW
     302        server = argv[1];
     303        message = argv[2];
     305.ft I
     306        /*
     307         * Create client "handle" used for calling \fIMESSAGEPROG\fP on the
     308         * server designated on the command line. We tell the RPC package
     309         * to use the "tcp" protocol when contacting the server.
     310         */
     311.ft CW
     312        cl = clnt_create(server, MESSAGEPROG, MESSAGEVERS, "tcp");
     313        if (cl == NULL) {
     314.ft I
     315                /*
     316                 * Couldn't establish connection with server.
     317                 * Print error message and die.
     318                 */
     319.ft CW
     320                clnt_pcreateerror(server);
     321                exit(1);
     322        }
     324.ft I
     325        /*
     326         * Call the remote procedure "printmessage" on the server
     327         */
     328.ft CW
     329        result = printmessage_1(&message, cl);
     330        if (result == NULL) {
     331.ft I
     332                /*
     333                 * An error occurred while calling the server.
     334                 * Print error message and die.
     335                 */
     336.ft CW
     337                clnt_perror(cl, server);
     338                exit(1);
     339        }
     341.ft I
     342        /*
     343         * Okay, we successfully called the remote procedure.
     344         */
     345.ft CW
     346        if (*result == 0) {
     347.ft I
     348                /*
     349                 * Server was unable to print our message.
     350                 * Print error message and die.
     351                 */
     352.ft CW
     353                fprintf(stderr, "%s: %s couldn't print your message\en",
     354                        argv[0], server);       
     355                exit(1);
     356        }
     358.ft I
     359        /*
     360         * The message got printed on the server's console
     361         */
     362.ft CW
     363        printf("Message delivered to %s!\en", server);
     366There are two things to note here:
     367.IP  1.
     368.IX "client handle, used by rpcgen" "" "client handle, used by \fIrpcgen\fP"
     369First a client \*Qhandle\*U is created using the RPC library routine
     370.I clnt_create ().
     371This client handle will be passed  to the stub routines
     372which call the remote procedure.
     373.IP  2.
     374The remote procedure 
     375.I printmessage_1()
     376is called exactly  the same way as it is  declared in
     377.I msg_proc.c
     378except for the inserted client handle as the first argument.
     380Here's how to put all of the pieces together: t .DS
     382.el .DS L
     383.ft CW
     384example%  \fBrpcgen msg.x\fP
     385example%  \fBcc rprintmsg.c msg_clnt.c -o rprintmsg\fP
     386example%  \fBcc msg_proc.c msg_svc.c -o msg_server\fP
     388Two programs were compiled here: the client program
     389.I rprintmsg
     390and the server  program
     391.I msg_server .
     392Before doing this  though, 
     393.I rpcgen
     394was used to fill in the missing pieces. 
     396Here is what
     397.I rpcgen
     398did with the input file
     399.I msg.x :
     400.IP  1.
     401It created a header file called
     402.I msg.h
     403that contained
     404.I #define 's
     406.I MESSAGEPROG ,
     410for use in  the  other modules.
     411.IP  2.
     412It created client \*Qstub\*U routines in the
     413.I msg_clnt.c
     414file.   In this case there is only one, the
     415.I printmessage_1()
     416that was referred to from the
     417.I printmsg
     418client program.  The name  of the output file for
     419client stub routines is always formed in this way:  if the name of the
     420input file is 
     421.I FOO.x ,
     422the   client  stubs   output file is    called
     423.I FOO_clnt.c .
     424.IP  3.
     425It created  the  server   program which calls   
     426.I printmessage_1()
     428.I msg_proc.c .
     429This server program is named 
     430.I msg_svc.c .
     431The rule for naming the server output file is similar  to the
     432previous one:  for an input  file   called 
     433.I FOO.x ,
     434the   output   server   file is  named
     435.I FOO_svc.c .
     437Now we're ready to have some fun.  First, copy the server to a
     438remote machine and run it.  For this  example,  the
     439machine is called \*Qmoon\*U.  Server processes are run in the
     440background, because they never exit. t .DS
     442.el .DS L
     443.ft CW
     444moon% \fBmsg_server &\fP               
     446Then on our local machine (\*Qsun\*U) we can print a message on \*Qmoon\*Us
     447console. t .DS
     449.el .DS L
     450.ft CW
     451sun% \fBprintmsg moon "Hello, moon."\fP
     453The message will get printed to \*Qmoon\*Us console.  You can print a
     454message on anybody's console (including your own) with this program if
     455you are able to copy the server to their machine and run it.
     456.NH 1
     457\&Generating XDR Routines
     458.IX RPC "generating XDR routines"
     460The previous example  only demonstrated  the  automatic generation of
     461client  and server RPC  code.
     462.I rpcgen
     463may also  be used to generate XDR routines, that  is,  the routines
     464necessary to  convert   local  data
     465structures into network format and vice-versa.  This example presents
     466a complete RPC service\(ema remote directory listing service, which uses
     467.I rpcgen
     468not  only  to generate stub routines, but also to  generate  the XDR
     469routines.  Here is the protocol description file: t .DS
     471.el .DS L
     472.ft I
     474 * dir.x: Remote directory listing protocol
     475 */
     476.ft CW
     477const MAXNAMELEN = 255;         /* \fImaximum length of a directory entry\fP */
     479typedef string nametype<MAXNAMELEN>;    /* \fIa directory entry\fP */
     481typedef struct namenode *namelist;              /* \fIa link in the listing\fP */
     483.ft I
     485 * A node in the directory listing
     486 */
     487.ft CW
     488struct namenode {
     489        nametype name;          /* \fIname of directory entry\fP */
     490        namelist next;          /* \fInext entry\fP */
     493.ft I
     495 * The result of a READDIR operation.
     496 */
     497.ft CW
     498union readdir_res switch (int errno) {
     499case 0:
     500        namelist list;  /* \fIno error: return directory listing\fP */
     502        void;           /* \fIerror occurred: nothing else to return\fP */
     505.ft I
     507 * The directory program definition
     508 */
     509.ft CW
     510program DIRPROG {
     511        version DIRVERS {
     512                readdir_res
     513                READDIR(nametype) = 1;
     514        } = 1;
     515} = 76;
     520Types (like
     521.I readdir_res
     522in the example above) can be defined using
     523the \*Qstruct\*U, \*Qunion\*U and \*Qenum\*U keywords, but those keywords
     524should not be used in subsequent declarations of variables of those types.
     525For example, if you define a union \*Qfoo\*U, you should declare using
     526only \*Qfoo\*U and not \*Qunion foo\*U.  In fact,
     527.I rpcgen
     529RPC unions into C structures and it is an error to declare them using the
     530\*Qunion\*U keyword.
     533.I rpcgen
     535.I dir.x
     536creates four output files.  Three are the same as before: header file,
     537client stub routines and server skeleton.  The fourth are the XDR routines
     538necessary for converting the data types we declared into XDR format and
     539vice-versa.  These are output in the file
     540.I dir_xdr.c .
     542Here is the implementation of the
     543.I READDIR
     544procedure. t .DS
     546.el .DS L
     547.vs 11
     548.ft I
     550 * dir_proc.c: remote readdir implementation
     551 */
     552.ft CW
     553#include <rpc/rpc.h>
     554#include <sys/dir.h>
     555#include "dir.h"
     557extern int errno;
     558extern char *malloc();
     559extern char *strdup();
     561readdir_res *
     563        nametype *dirname;
     565        DIR *dirp;
     566        struct direct *d;
     567        namelist nl;
     568        namelist *nlp;
     569        static readdir_res res; /* \fImust be static\fP! */
     571.ft I
     572        /*
     573         * Open directory
     574         */
     575.ft CW
     576        dirp = opendir(*dirname);
     577        if (dirp == NULL) {
     578                res.errno = errno;
     579                return (&res);
     580        }
     582.ft I
     583        /*
     584         * Free previous result
     585         */
     586.ft CW
     587        xdr_free(xdr_readdir_res, &res);
     589.ft I
     590        /*
     591         * Collect directory entries.
     592         * Memory allocated here will be freed by \fIxdr_free\fP
     593         * next time \fIreaddir_1\fP is called
     594         */
     595.ft CW
     596        nlp = &res.readdir_res_u.list;
     597        while (d = readdir(dirp)) {
     598                nl = *nlp = (namenode *) malloc(sizeof(namenode));
     599                nl->name = strdup(d->d_name);
     600                nlp = &nl->next;
     601        }
     602        *nlp = NULL;
     604.ft I
     605        /*
     606         * Return the result
     607         */
     608.ft CW
     609        res.errno = 0;
     610        closedir(dirp);
     611        return (&res);
     615Finally, there is the client side program to call the server: t .DS
     617.el .DS L
     618.ft I
     620 * rls.c: Remote directory listing client
     621 */
     622.ft CW
     623#include <stdio.h>
     624#include <rpc/rpc.h>    /* \fIalways need this\fP */
     625#include "dir.h"                /* \fIwill be generated by rpcgen\fI */
     627extern int errno;
     629main(argc, argv)
     630        int argc;
     631        char *argv[];
     633        CLIENT *cl;
     634        char *server;
     635        char *dir;
     636        readdir_res *result;
     637        namelist nl;
     640        if (argc != 3) {
     641                fprintf(stderr, "usage: %s host directory\en",
     642                  argv[0]);
     643                exit(1);
     644        }
     646.ft I
     647        /*
     648         * Remember what our command line arguments refer to
     649         */
     650.ft CW
     651        server = argv[1];
     652        dir = argv[2];
     654.ft I
     655        /*
     656         * Create client "handle" used for calling \fIMESSAGEPROG\fP on the
     657         * server designated on the command line. We tell the RPC package
     658         * to use the "tcp" protocol when contacting the server.
     659         */
     660.ft CW
     661        cl = clnt_create(server, DIRPROG, DIRVERS, "tcp");
     662        if (cl == NULL) {
     663.ft I
     664                /*
     665                 * Couldn't establish connection with server.
     666                 * Print error message and die.
     667                 */
     668.ft CW
     669                clnt_pcreateerror(server);
     670                exit(1);
     671        }
     673.ft I
     674        /*
     675         * Call the remote procedure \fIreaddir\fP on the server
     676         */
     677.ft CW
     678        result = readdir_1(&dir, cl);
     679        if (result == NULL) {
     680.ft I
     681                /*
     682                 * An error occurred while calling the server.
     683                 * Print error message and die.
     684                 */
     685.ft CW
     686                clnt_perror(cl, server);
     687                exit(1);
     688        }
     690.ft I
     691        /*
     692         * Okay, we successfully called the remote procedure.
     693         */
     694.ft CW
     695        if (result->errno != 0) {
     696.ft I
     697                /*
     698                 * A remote system error occurred.
     699                 * Print error message and die.
     700                 */
     701.ft CW
     702                errno = result->errno;
     703                perror(dir);
     704                exit(1);
     705        }
     707.ft I
     708        /*
     709         * Successfully got a directory listing.
     710         * Print it out.
     711         */
     712.ft CW
     713        for (nl = result->readdir_res_u.list; nl != NULL;
     714          nl = nl->next) {
     715                printf("%s\en", nl->name);
     716        }
     717        exit(0);
     720Compile everything, and run.
     722.ft CW
     723sun%  \fBrpcgen dir.x\fP
     724sun%  \fBcc rls.c dir_clnt.c dir_xdr.c -o rls\fP
     725sun%  \fBcc dir_svc.c dir_proc.c dir_xdr.c -o dir_svc\fP
     727sun%  \fBdir_svc &\fP
     729moon%  \fBrls sun /usr/pub\fP
     743.IX "debugging with rpcgen" "" "debugging with \fIrpcgen\fP"
     744A final note about
     745.I rpcgen :
     746The client program and the server procedure can be tested together
     747as a single program by simply linking them with each other rather
     748than with the client and server stubs.  The procedure calls will be
     749executed as ordinary local procedure calls and the program can be
     750debugged with a local debugger such as
     751.I dbx .
     752When the program is working, the client program can be linked to
     753the client stub produced by
     754.I rpcgen
     755and the server procedures can be linked to the server stub produced
     757.I rpcgen .
     759.I NOTE :
     760\fIIf you do this, you may want to comment out calls to RPC library
     761routines, and have client-side routines call server routines
     764.NH 1
     765\&The C-Preprocessor
     766.IX rpcgen "C-preprocessor" \fIrpcgen\fP
     768The C-preprocessor is  run on all input  files before they are
     769compiled, so all the preprocessor directives are legal within a \*Q.x\*U
     770file. Four symbols may be defined, depending upon which output file is
     771getting generated. The symbols are:
     773box tab (&);
     774lfI lfI
     775lfL l .
     778RPC_HDR&for header-file output
     779RPC_XDR&for XDR routine output
     780RPC_SVC&for server-skeleton output
     781RPC_CLNT&for client stub output
     785.I rpcgen
     786does  a little preprocessing   of its own. Any  line that
     787begins  with  a percent sign is passed  directly into the output file,
     788without any interpretation of the line.  Here is a simple example that
     789demonstrates the preprocessing features. t .DS
     791.el .DS L
     792.ft I
     794 * time.x: Remote time protocol
     795 */
     796.ft CW
     797program TIMEPROG {
     798        version TIMEVERS {
     799                unsigned int TIMEGET(void) = 1;
     800        } = 1;
     801} = 44;
     803#ifdef RPC_SVC
     804%int *
     807%        static int thetime;
     809%        thetime = time(0);
     810%        return (&thetime);
     814The '%' feature is not generally recommended, as there is no guarantee
     815that the compiler will stick the output where you intended.
     816.NH 1
     817\&\fBrpcgen\fP Programming Notes
     818.IX rpcgen "other operations" \fIrpcgen\fP
     820.NH 2
     821\&Timeout Changes
     822.IX rpcgen "timeout changes" \fIrpcgen\fP
     824RPC sets a default timeout of 25 seconds for RPC calls when
     825.I clnt_create()
     826is used.  This timeout may be changed using
     827.I clnt_control()
     828Here is a small code fragment to demonstrate use of
     829.I clnt_control ():
     831struct timeval tv;
     832CLIENT *cl;
     833.sp .5
     834cl = clnt_create("somehost", SOMEPROG, SOMEVERS, "tcp");
     835if (cl == NULL) {
     836        exit(1);
     838tv.tv_sec = 60; /* \fIchange timeout to 1 minute\fP */
     839tv.tv_usec = 0;
     840clnt_control(cl, CLSET_TIMEOUT, &tv);   
     842.NH 2
     843\&Handling Broadcast on the Server Side
     844.IX "broadcast RPC"
     845.IX rpcgen "broadcast RPC" \fIrpcgen\fP
     847When a procedure is known to be called via broadcast RPC,
     848it is usually wise for the server to not reply unless it can provide
     849some useful information to the client.  This prevents the network
     850from getting flooded by useless replies.
     852To prevent the server from replying, a remote procedure can
     853return NULL as its result, and the server code generated by
     854.I rpcgen
     855will detect this and not send out a reply.
     857Here is an example of a procedure that replies only if it
     858thinks it is an NFS server:
     860void *
     863        char notnull;   /* \fIjust here so we can use its address\fP */
     864.sp .5
     865        if (access("/etc/exports", F_OK) < 0) {
     866                return (NULL);  /* \fIprevent RPC from replying\fP */
     867        }
     868.ft I
     869        /*
     870         * return non-null pointer so RPC will send out a reply
     871         */
     872.ft L
     873        return ((void *)&notnull);
     876Note that if procedure returns type \*Qvoid *\*U, they must return a non-NULL
     877pointer if they want RPC to reply for them.
     878.NH 2
     879\&Other Information Passed to Server Procedures
     881Server procedures will often want to know more about an RPC call
     882than just its arguments.  For example, getting authentication information
     883is important to procedures that want to implement some level of security.
     884This extra information is actually supplied to the server procedure as a
     885second argument.  Here is an example to demonstrate its use.  What we've
     886done here is rewrite the previous
     887.I printmessage_1()
     888procedure to only allow root users to print a message to the console.
     890int *
     891printmessage_1(msg, rq)
     892        char **msg;
     893        struct svc_req  *rq;
     895        static in result;       /* \fIMust be static\fP */
     896        FILE *f;
     897        struct suthunix_parms *aup;
     898.sp .5
     899        aup = (struct authunix_parms *)rq->rq_clntcred;
     900        if (aup->aup_uid != 0) {
     901                result = 0;
     902                return (&result);
     903        }
     905.ft I
     906        /*
     907         * Same code as before.
     908         */
     909.ft L
     912.NH 1
     913\&RPC Language
     914.IX RPCL
     915.IX rpcgen "RPC Language" \fIrpcgen\fP
     917RPC language is an extension of XDR  language.   The sole extension is
     918the addition of the
     919.I program
     920type.  For a complete description of the XDR language syntax, see the
     921.I "External Data Representation Standard: Protocol Specification"
     922chapter.  For a description of the RPC extensions to the XDR language,
     923see the
     924.I "Remote Procedure Calls: Protocol Specification"
     927However, XDR language is so close to C that if you know C, you know most
     928of it already.  We describe here  the syntax of the RPC language,
     929showing a  few examples along the way.   We also show how  the various
     930RPC and XDR type definitions get  compiled into C  type definitions in
     931the output header file.
     933.NH 2
     936.IX rpcgen definitions \fIrpcgen\fP
     938An RPC language file consists of a series of definitions.
     939.DS L
     940.ft CW
     941    definition-list:
     942        definition ";"
     943        definition ";" definition-list
     946It recognizes five types of definitions.
     947.DS L
     948.ft CW
     949    definition:
     950        enum-definition
     951        struct-definition
     952        union-definition
     953        typedef-definition
     954        const-definition
     955        program-definition
     957.NH 2
     960.IX rpcgen structures \fIrpcgen\fP
     962An XDR struct  is declared almost exactly like  its C counterpart.  It
     963looks like the following:
     964.DS L
     965.ft CW
     966    struct-definition:
     967        "struct" struct-ident "{"
     968            declaration-list
     969        "}"
     971    declaration-list:
     972        declaration ";"
     973        declaration ";" declaration-list
     975As an example, here is an XDR structure to a two-dimensional
     976coordinate, and the C structure  that it  gets compiled into  in the
     977output header file.
     979.ft CW
     980   struct coord {             struct coord {
     981        int x;       -->           int x;
     982        int y;                     int y;
     983   };                         };
     984                              typedef struct coord coord;
     986The output is identical to the  input, except  for the added
     987.I typedef
     988at the end of the output.  This allows one to use \*Qcoord\*U instead of
     989\*Qstruct coord\*U when declaring items.
     990.NH 2
     993.IX rpcgen unions \fIrpcgen\fP
     995XDR unions are discriminated unions, and look quite different from C
     996unions. They are more analogous to  Pascal variant records than they
     997are to C unions.
     998.DS L
     999.ft CW
     1000    union-definition:
     1001        "union" union-ident "switch" "(" declaration ")" "{"
     1002            case-list
     1003        "}"
     1005    case-list:
     1006        "case" value ":" declaration ";"
     1007        "default" ":" declaration ";"
     1008        "case" value ":" declaration ";" case-list
     1010Here is an example of a type that might be returned as the result of a
     1011\*Qread data\*U operation.  If there is no error, return a block of data.
     1012Otherwise, don't return anything.
     1013.DS L
     1014.ft CW
     1015    union read_result switch (int errno) {
     1016    case 0:
     1017        opaque data[1024];
     1018    default:
     1019        void;
     1020    };
     1022It gets compiled into the following:
     1023.DS L
     1024.ft CW
     1025    struct read_result {
     1026        int errno;
     1027        union {
     1028            char data[1024];
     1029        } read_result_u;
     1030    };
     1031    typedef struct read_result read_result;
     1033Notice that the union component of the  output struct  has the name as
     1034the type name, except for the trailing \*Q_u\*U.
     1035.NH 2
     1038.IX rpcgen enumerations \fIrpcgen\fP
     1040XDR enumerations have the same syntax as C enumerations.
     1041.DS L
     1042.ft CW
     1043    enum-definition:
     1044        "enum" enum-ident "{"
     1045            enum-value-list
     1046        "}"
     1048    enum-value-list:
     1049        enum-value
     1050        enum-value "," enum-value-list
     1052    enum-value:
     1053        enum-value-ident
     1054        enum-value-ident "=" value
     1056Here is a short example of  an XDR enum,  and the C enum that  it gets
     1057compiled into.
     1058.DS L
     1059.ft CW
     1060     enum colortype {      enum colortype {
     1061          RED = 0,              RED = 0,
     1062          GREEN = 1,   -->      GREEN = 1,
     1063          BLUE = 2              BLUE = 2,
     1064     };                    };
     1065                           typedef enum colortype colortype;
     1067.NH 2
     1070.IX rpcgen typedef \fIrpcgen\fP
     1072XDR typedefs have the same syntax as C typedefs.
     1073.DS L
     1074.ft CW
     1075    typedef-definition:
     1076        "typedef" declaration
     1078Here  is an example  that defines a 
     1079.I fname_type
     1080used  for declaring
     1081file name strings that have a maximum length of 255 characters.
     1082.DS L
     1083.ft CW
     1084typedef string fname_type<255>; --> typedef char *fname_type;
     1086.NH 2
     1089.IX rpcgen constants \fIrpcgen\fP
     1091XDR constants  symbolic constants  that may be  used wherever  a
     1092integer constant is used, for example, in array size specifications.
     1093.DS L
     1094.ft CW
     1095    const-definition:
     1096        "const" const-ident "=" integer
     1098For example, the following defines a constant
     1099.I DOZEN
     1100equal to 12.
     1101.DS L
     1102.ft CW
     1103    const DOZEN = 12;  -->  #define DOZEN 12
     1105.NH 2
     1108.IX rpcgen programs \fIrpcgen\fP
     1110RPC programs are declared using the following syntax:
     1111.DS L
     1112.ft CW
     1113    program-definition:
     1114        "program" program-ident "{"
     1115            version-list
     1116        "}" "=" value
     1118    version-list:
     1119        version ";"
     1120        version ";" version-list
     1122    version:
     1123        "version" version-ident "{"
     1124            procedure-list
     1125        "}" "=" value
     1127    procedure-list:
     1128        procedure ";"
     1129        procedure ";" procedure-list
     1131    procedure:
     1132        type-ident procedure-ident "(" type-ident ")" "=" value
     1134For example, here is the time protocol, revisited: t .DS
     1136.el .DS L
     1137.ft I
     1139 * time.x: Get or set the time. Time is represented as number of seconds
     1140 * since 0:00, January 1, 1970.
     1141 */
     1142.ft CW
     1143program TIMEPROG {
     1144    version TIMEVERS {
     1145        unsigned int TIMEGET(void) = 1;
     1146        void TIMESET(unsigned) = 2;
     1147    } = 1;
     1148} = 44;       
     1150This file compiles into #defines in the output header file: t .DS
     1152.el .DS L
     1153.ft CW
     1154#define TIMEPROG 44
     1155#define TIMEVERS 1
     1156#define TIMEGET 1
     1157#define TIMESET 2
     1159.NH 2
     1162.IX rpcgen declarations \fIrpcgen\fP
     1164In XDR, there are only four kinds of declarations. 
     1165.DS L
     1166.ft CW
     1167    declaration:
     1168        simple-declaration
     1169        fixed-array-declaration
     1170        variable-array-declaration
     1171        pointer-declaration
     1173\fB1) Simple declarations\fP are just like simple C declarations.
     1174.DS L
     1175.ft CW
     1176    simple-declaration:
     1177        type-ident variable-ident
     1180.DS L
     1181.ft CW
     1182    colortype color;    --> colortype color;
     1184\fB2) Fixed-length Array Declarations\fP are just like C array declarations:
     1185.DS L
     1186.ft CW
     1187    fixed-array-declaration:
     1188        type-ident variable-ident "[" value "]"
     1191.DS L
     1192.ft CW
     1193    colortype palette[8];    --> colortype palette[8];
     1195\fB3) Variable-Length Array Declarations\fP have no explicit syntax
     1196in C, so XDR invents its own using angle-brackets.
     1197.DS L
     1198.ft CW
     1200    type-ident variable-ident "<" value ">"
     1201    type-ident variable-ident "<" ">"
     1203The maximum size is specified between the angle brackets. The size may
     1204be omitted, indicating that the array may be of any size.
     1205.DS L
     1206.ft CW
     1207    int heights<12>;    /* \fIat most 12 items\fP */
     1208    int widths<>;       /* \fIany number of items\fP */
     1210Since  variable-length  arrays have no  explicit  syntax in  C,  these
     1211declarations are actually compiled into \*Qstruct\*Us.  For example, the
     1212\*Qheights\*U declaration gets compiled into the following struct:
     1213.DS L
     1214.ft CW
     1215    struct {
     1216        u_int heights_len;  /* \fI# of items in array\fP */
     1217        int *heights_val;   /* \fIpointer to array\fP */
     1218    } heights;
     1220Note that the number of items in the array is stored in the \*Q_len\*U
     1221component and the pointer to the array is stored in the \*Q_val\*U
     1222component. The first part of each of these component's names is the
     1223same as the name of the declared XDR variable.
     1225\fB4) Pointer Declarations\fP are made in
     1226XDR  exactly as they  are  in C.  You  can't
     1227really send pointers over the network,  but  you  can use XDR pointers
     1228for sending recursive data types such as lists and trees.  The type is
     1229actually called \*Qoptional-data\*U, not \*Qpointer\*U, in XDR language.
     1230.DS L
     1231.ft CW
     1232    pointer-declaration:
     1233        type-ident "*" variable-ident
     1236.DS L
     1237.ft CW
     1238    listitem *next;  -->  listitem *next;
     1240.NH 2
     1241\&Special Cases
     1242.IX rpcgen "special cases" \fIrpcgen\fP
     1244There are a few exceptions to the rules described above.
     1246.B Booleans:
     1247C has no built-in boolean type. However, the RPC library does  a
     1248boolean type   called
     1249.I bool_t
     1250that   is either 
     1251.I TRUE
     1253.I FALSE .
     1254Things declared as  type
     1255.I bool
     1256in  XDR language  are  compiled  into
     1257.I bool_t
     1258in the output header file.
     1261.DS L
     1262.ft CW
     1263    bool married;  -->  bool_t married;
     1265.B Strings:
     1266C has  no built-in string  type, but  instead uses the null-terminated
     1267\*Qchar *\*U convention.  In XDR language, strings are declared using the
     1268\*Qstring\*U keyword, and compiled into \*Qchar *\*Us in the output header
     1269file. The  maximum size contained  in the angle brackets specifies the
     1270maximum number of characters allowed in the  strings (not counting the
     1271.I NULL
     1272character). The maximum size may be left off, indicating a string
     1273of arbitrary length.
     1276.DS L
     1277.ft CW
     1278    string name<32>;    -->  char *name;
     1279    string longname<>;  -->  char *longname;
     1281.B "Opaque  Data:"
     1282Opaque data is used in RPC and XDR to describe untyped  data, that is,
     1283just  sequences of arbitrary  bytes.  It may be  declared  either as a
     1284fixed or variable length array.
     1285.DS L
     1287.ft CW
     1288    opaque diskblock[512];  -->  char diskblock[512];
     1290    opaque filedata<1024>;  -->  struct {
     1291                                    u_int filedata_len;
     1292                                    char *filedata_val;
     1293                                 } filedata;
     1295.B Voids:
     1296In a void declaration, the variable is  not named.  The declaration is
     1297just \*Qvoid\*U and nothing else.  Void declarations can only occur in two
     1298places: union definitions and program definitions (as the  argument or
     1299result of a remote procedure).
  • cpukit/librpc/src/rpc/PSD.doc/

    r0ab65474 rdf49c60  
     2.\" Must use --  eqn -- with this one
     4.\" @(#)      2.2 88/08/05 4.0 RPCSRC
     6delim $$
     7.EN BT
     9.if \\n%=1 .tl ''- % -''
     12.\" prevent excess underlining in nroff
     13.if n .fp 2 R
     14.OH 'External Data Representation: Sun Technical Notes''Page %'
     15.EH 'Page %''External Data Representation: Sun Technical Notes'
     16.if \\n%=1 .bp
     18\&External Data Representation: Sun Technical Notes
     19.IX XDR "Sun technical notes"
     21This chapter contains technical notes on Sun's implementation of the
     22External Data Representation (XDR) standard, a set of library routines
     23that allow a C programmer to describe arbitrary data structures in a
     24machinex-independent fashion. 
     25For a formal specification of the XDR
     26standard, see the
     27.I "External Data Representation Standard: Protocol Specification".
     28XDR is the backbone of Sun's Remote Procedure Call package, in the
     29sense that data for remote procedure calls is transmitted using the
     30standard.  XDR library routines should be used to transmit data
     31that is accessed (read or written) by more than one type of machine.\**
     33.IX XDR "system routines"
     34For a compete specification of the system External Data Representation
     35routines, see the
     36.I xdr(3N)
     37manual page.
     40This chapter contains a short tutorial overview of the XDR library
     41routines, a guide to accessing currently available XDR streams, and
     42information on defining new streams and data types.  XDR was designed
     43to work across different languages, operating systems, and machine
     44architectures.  Most users (particularly RPC users) will only need
     45the information in the
     46.I "Number Filters",
     47.I "Floating Point Filters",
     49.I "Enumeration Filters"
     51Programmers wishing to implement RPC and XDR on new machines
     52will be interested in the rest of the chapter, as well as the
     53.I "External Data Representaiton Standard: Protocol Specification",
     54which will be their primary reference.
     58.I rpcgen
     59can be used to write XDR routines even in cases where no RPC calls are
     60being made.
     62On Sun systems,
     63C programs that want to use XDR routines
     64must include the file
     65.I <rpc/rpc.h> ,
     66which contains all the necessary interfaces to the XDR system.
     67Since the C library
     68.I libc.a
     69contains all the XDR routines,