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