source: rtems/c/src/librpc/src/rpc/PSD.doc/rpcgen.ms @ df49c60

4.104.114.84.95
Last change on this file since df49c60 was df49c60, checked in by Joel Sherrill <joel.sherrill@…>, on 06/12/00 at 15:00:15

Merged from 4.5.0-beta3a

  • Property mode set to 100644
File size: 31.2 KB
Line 
1.\"
2.\" Must use  --  tbl -- for this one
3.\"
4.\" @(#)rpcgen.ms       2.2 88/08/04 4.0 RPCSRC
5.de BT
6.if \\n%=1 .tl ''- % -''
7..
8.ND
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
14.SH
15\&\fBrpcgen\fP Programming Guide
16.NH 0
17\&The \fBrpcgen\fP Protocol Compiler
18.IX rpcgen "" \fIrpcgen\fP "" PAGE MAJOR
19.LP
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. 
25.LP
26Fortunately,
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.
33.LP
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.
59.LP
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
84.LP
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:
89.ie t .DS
90.el .DS L
91.ft I
92/*
93 * printmsg.c: print a message on the console
94 */
95.ft CW
96#include <stdio.h>
97
98main(argc, argv)
99        int argc;
100        char *argv[];
101{
102        char *message;
103
104        if (argc < 2) {
105                fprintf(stderr, "usage: %s <message>\en", argv[0]);
106                exit(1);
107        }
108        message = argv[1];
109
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);
117}
118.ft I
119/*
120 * Print a message to the console.
121 * Return a boolean indicating whether the message was actually printed.
122 */
123.ft CW
124printmessage(msg)
125        char *msg;
126{
127        FILE *f;
128
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);
136}
137.DE
138.LP
139And then, of course:
140.ie t .DS
141.el .DS L
142.ft CW
143example%  \fBcc printmsg.c -o printmsg\fP
144example%  \fBprintmsg "Hello, there."\fP
145Message delivered!
146example%
147.DE
148.LP
149If 
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.
160.LP
161In  general, it's necessary to figure  out  what the types are for
162all procedure inputs and outputs.  In  this case,   we  have a
163procedure
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:
170.ie t .DS
171.el .DS L
172.ft I
173/*
174 * msg.x: Remote message printing protocol
175 */
176.ft CW
177
178program MESSAGEPROG {
179        version MESSAGEVERS {
180                int PRINTMESSAGE(string) = 1;
181        } = 1;
182} = 99;
183.DE
184.LP
185Remote procedures are part of remote programs, so we actually declared
186an  entire  remote program  here  which contains  the single procedure
187.I PRINTMESSAGE .
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.
192.LP
193Notice that everything is declared with all capital  letters.  This is
194not required, but is a good convention to follow.
195.LP
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.
202.LP
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
206.I PRINTMESSAGE
207procedure we declared above:
208.ie t .DS
209.el .DS L
210.vs 11
211.ft I
212/*
213 * msg_proc.c: implementation of the remote procedure "printmessage"
214 */
215.ft CW
216
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 */
220
221.ft I
222/*
223 * Remote verson of "printmessage"
224 */
225.ft CW
226int *
227printmessage_1(msg)
228        char **msg;
229{
230        static int result;  /* \fImust be static!\fP */
231        FILE *f;
232
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);
242}
243.vs
244.DE
245.LP
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 
264(here
265.I PRINTMESSAGE )
266is converted   to all
267lower-case letters, an underbar (\*Q_\*U) is appended to it, and
268finally the version number (here 1) is appended.
269.LP
270The last thing to do is declare the main client program that will call
271the remote procedure. Here it is:
272.ie t .DS
273.el .DS L
274.ft I
275/*
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 */
282
283main(argc, argv)
284        int argc;
285        char *argv[];
286{
287        CLIENT *cl;
288        int *result;
289        char *server;
290        char *message;
291
292        if (argc < 3) {
293                fprintf(stderr, "usage: %s host message\en", argv[0]);
294                exit(1);
295        }
296
297.ft I
298        /*
299         * Save values of command line arguments
300         */
301.ft CW
302        server = argv[1];
303        message = argv[2];
304
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        }
323
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        }
340
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        }
357
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);
364}
365.DE
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.
379.LP
380Here's how to put all of the pieces together:
381.ie 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
387.DE
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. 
395.LP
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
405for
406.I MESSAGEPROG ,
407.I MESSAGEVERS
408and   
409.I PRINTMESSAGE
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()
427in
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 .
436.LP
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.
441.ie t .DS
442.el .DS L
443.ft CW
444moon% \fBmsg_server &\fP               
445.DE
446Then on our local machine (\*Qsun\*U) we can print a message on \*Qmoon\*Us
447console.
448.ie t .DS
449.el .DS L
450.ft CW
451sun% \fBprintmsg moon "Hello, moon."\fP
452.DE
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"
459.LP
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:
470.ie t .DS
471.el .DS L
472.ft I
473/*
474 * dir.x: Remote directory listing protocol
475 */
476.ft CW
477const MAXNAMELEN = 255;         /* \fImaximum length of a directory entry\fP */
478
479typedef string nametype<MAXNAMELEN>;    /* \fIa directory entry\fP */
480
481typedef struct namenode *namelist;              /* \fIa link in the listing\fP */
482
483.ft I
484/*
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 */
491};
492
493.ft I
494/*
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 */
501default:
502        void;           /* \fIerror occurred: nothing else to return\fP */
503};
504
505.ft I
506/*
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;
516.DE
517.SH
518Note:
519.I
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
528compiles
529RPC unions into C structures and it is an error to declare them using the
530\*Qunion\*U keyword.
531.LP
532Running
533.I rpcgen
534on
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 .
541.LP
542Here is the implementation of the
543.I READDIR
544procedure.
545.ie t .DS
546.el .DS L
547.vs 11
548.ft I
549/*
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"
556
557extern int errno;
558extern char *malloc();
559extern char *strdup();
560
561readdir_res *
562readdir_1(dirname)
563        nametype *dirname;
564{
565        DIR *dirp;
566        struct direct *d;
567        namelist nl;
568        namelist *nlp;
569        static readdir_res res; /* \fImust be static\fP! */
570
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        }
581
582.ft I
583        /*
584         * Free previous result
585         */
586.ft CW
587        xdr_free(xdr_readdir_res, &res);
588
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;
603
604.ft I
605        /*
606         * Return the result
607         */
608.ft CW
609        res.errno = 0;
610        closedir(dirp);
611        return (&res);
612}
613.vs
614.DE
615Finally, there is the client side program to call the server:
616.ie t .DS
617.el .DS L
618.ft I
619/*
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 */
626
627extern int errno;
628
629main(argc, argv)
630        int argc;
631        char *argv[];
632{
633        CLIENT *cl;
634        char *server;
635        char *dir;
636        readdir_res *result;
637        namelist nl;
638
639
640        if (argc != 3) {
641                fprintf(stderr, "usage: %s host directory\en",
642                  argv[0]);
643                exit(1);
644        }
645
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];
653
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        }
672
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        }
689
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        }
706
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);
718}
719.DE
720Compile everything, and run.
721.DS
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
726
727sun%  \fBdir_svc &\fP
728
729moon%  \fBrls sun /usr/pub\fP
730\&.
731\&..
732ascii
733eqnchar
734greek
735kbd
736marg8
737tabclr
738tabs
739tabs4
740moon%
741.DE
742.LP
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
756by
757.I rpcgen .
758.SH
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
762directly.\fP
763.LP
764.NH 1
765\&The C-Preprocessor
766.IX rpcgen "C-preprocessor" \fIrpcgen\fP
767.LP
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:
772.TS
773box tab (&);
774lfI lfI
775lfL l .
776Symbol&Usage
777_
778RPC_HDR&for header-file output
779RPC_XDR&for XDR routine output
780RPC_SVC&for server-skeleton output
781RPC_CLNT&for client stub output
782.TE
783.LP
784Also,
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.
790.ie t .DS
791.el .DS L
792.ft I
793/*
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;
802
803#ifdef RPC_SVC
804%int *
805%timeget_1()
806%{
807%        static int thetime;
808%
809%        thetime = time(0);
810%        return (&thetime);
811%}
812#endif
813.DE
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
819.sp
820.NH 2
821\&Timeout Changes
822.IX rpcgen "timeout changes" \fIrpcgen\fP
823.LP
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 ():
830.ID
831struct timeval tv;
832CLIENT *cl;
833.sp .5
834cl = clnt_create("somehost", SOMEPROG, SOMEVERS, "tcp");
835if (cl == NULL) {
836        exit(1);
837}
838tv.tv_sec = 60; /* \fIchange timeout to 1 minute\fP */
839tv.tv_usec = 0;
840clnt_control(cl, CLSET_TIMEOUT, &tv);   
841.DE
842.NH 2
843\&Handling Broadcast on the Server Side
844.IX "broadcast RPC"
845.IX rpcgen "broadcast RPC" \fIrpcgen\fP
846.LP
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.
851.LP
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.
856.LP
857Here is an example of a procedure that replies only if it
858thinks it is an NFS server:
859.ID
860void *
861reply_if_nfsserver()
862{
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);
874}
875.DE
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
880.LP
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.
889.ID
890int *
891printmessage_1(msg, rq)
892        char **msg;
893        struct svc_req  *rq;
894{
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        }
904.sp
905.ft I
906        /*
907         * Same code as before.
908         */
909.ft L
910}
911.DE
912.NH 1
913\&RPC Language
914.IX RPCL
915.IX rpcgen "RPC Language" \fIrpcgen\fP
916.LP
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"
925chapter.
926.LP
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.
932.KS
933.NH 2
934Definitions
935\&
936.IX rpcgen definitions \fIrpcgen\fP
937.LP
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
944.DE
945.KE
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
956.DE
957.NH 2
958Structures
959\&
960.IX rpcgen structures \fIrpcgen\fP
961.LP
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        "}"
970
971    declaration-list:
972        declaration ";"
973        declaration ";" declaration-list
974.DE
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.
978.DS
979.ft CW
980   struct coord {             struct coord {
981        int x;       -->           int x;
982        int y;                     int y;
983   };                         };
984                              typedef struct coord coord;
985.DE
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
991Unions
992\&
993.IX rpcgen unions \fIrpcgen\fP
994.LP
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        "}"
1004
1005    case-list:
1006        "case" value ":" declaration ";"
1007        "default" ":" declaration ";"
1008        "case" value ":" declaration ";" case-list
1009.DE
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    };
1021.DE
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;
1032.DE
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
1036Enumerations
1037\&
1038.IX rpcgen enumerations \fIrpcgen\fP
1039.LP
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        "}"
1047
1048    enum-value-list:
1049        enum-value
1050        enum-value "," enum-value-list
1051
1052    enum-value:
1053        enum-value-ident
1054        enum-value-ident "=" value
1055.DE
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;
1066.DE
1067.NH 2
1068Typedef
1069\&
1070.IX rpcgen typedef \fIrpcgen\fP
1071.LP
1072XDR typedefs have the same syntax as C typedefs.
1073.DS L
1074.ft CW
1075    typedef-definition:
1076        "typedef" declaration
1077.DE
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;
1085.DE
1086.NH 2
1087Constants
1088\&
1089.IX rpcgen constants \fIrpcgen\fP
1090.LP
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
1097.DE
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
1104.DE
1105.NH 2
1106Programs
1107\&
1108.IX rpcgen programs \fIrpcgen\fP
1109.LP
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
1117
1118    version-list:
1119        version ";"
1120        version ";" version-list
1121
1122    version:
1123        "version" version-ident "{"
1124            procedure-list
1125        "}" "=" value
1126
1127    procedure-list:
1128        procedure ";"
1129        procedure ";" procedure-list
1130
1131    procedure:
1132        type-ident procedure-ident "(" type-ident ")" "=" value
1133.DE
1134For example, here is the time protocol, revisited:
1135.ie t .DS
1136.el .DS L
1137.ft I
1138/*
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;       
1149.DE
1150This file compiles into #defines in the output header file:
1151.ie 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
1158.DE
1159.NH 2
1160Declarations
1161\&
1162.IX rpcgen declarations \fIrpcgen\fP
1163.LP
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
1172.DE
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
1178.DE
1179Example:
1180.DS L
1181.ft CW
1182    colortype color;    --> colortype color;
1183.DE
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 "]"
1189.DE
1190Example:
1191.DS L
1192.ft CW
1193    colortype palette[8];    --> colortype palette[8];
1194.DE
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
1199variable-array-declaration:
1200    type-ident variable-ident "<" value ">"
1201    type-ident variable-ident "<" ">"
1202.DE
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 */
1209.DE
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;
1219.DE
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.
1224.LP
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
1234.DE
1235Example:
1236.DS L
1237.ft CW
1238    listitem *next;  -->  listitem *next;
1239.DE
1240.NH 2
1241\&Special Cases
1242.IX rpcgen "special cases" \fIrpcgen\fP
1243.LP
1244There are a few exceptions to the rules described above.
1245.LP
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
1252or 
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.
1259.LP
1260Example:
1261.DS L
1262.ft CW
1263    bool married;  -->  bool_t married;
1264.DE
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.
1274.LP
1275Examples:
1276.DS L
1277.ft CW
1278    string name<32>;    -->  char *name;
1279    string longname<>;  -->  char *longname;
1280.DE
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
1286Examples:
1287.ft CW
1288    opaque diskblock[512];  -->  char diskblock[512];
1289
1290    opaque filedata<1024>;  -->  struct {
1291                                    u_int filedata_len;
1292                                    char *filedata_val;
1293                                 } filedata;
1294.DE
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).
Note: See TracBrowser for help on using the repository browser.