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