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