PageRenderTime 29ms CodeModel.GetById 12ms app.highlight 9ms RepoModel.GetById 2ms app.codeStats 0ms

/share/doc/psd/22.rpcgen/rpcgen.ms

https://bitbucket.org/freebsd/freebsd-head/
Unknown | 1301 lines | 1254 code | 47 blank | 0 comment | 0 complexity | 360825e13eb725255918d08a1be30e7e MD5 | raw file
   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
  23The details of programming applications to use Remote Procedure Calls 
  24can be overwhelming.  Perhaps most daunting is the writing of the XDR 
  25routines necessary to convert procedure arguments and results into 
  26their network format and vice-versa.  
  27.LP
  28Fortunately, 
  29.I rpcgen(1) 
  30exists to help programmers write RPC applications simply and directly.
  31.I rpcgen 
  32does most of the dirty work, allowing programmers to debug 
  33the  main  features of their application, instead of requiring them to
  34spend most of their time debugging their network interface code.
  35.LP
  36.I rpcgen 
  37is a  compiler.  It accepts a remote program interface definition written
  38in a language, called RPC Language, which is similar to C.  It produces a C
  39language output which includes stub versions of the client routines, a
  40server skeleton, XDR filter routines for both parameters and results, and a
  41header file that contains common definitions. The client stubs interface
  42with the RPC library and effectively hide the network from their callers.
  43The server stub similarly hides the network from the server procedures that
  44are to be invoked by remote clients.
  45.I rpcgen 's
  46output files can be compiled and linked in the usual way.  The developer
  47writes server procedures\(emin any language that observes Sun calling
  48conventions\(emand links them with the server skeleton produced by
  49.I rpcgen 
  50to get an executable server program.  To use a remote program, a programmer
  51writes an ordinary main program that makes local procedure calls to the 
  52client stubs produced by
  53.I rpcgen .
  54Linking this program with 
  55.I rpcgen 's
  56stubs creates an executable program.  (At present the main program must be 
  57written in C).
  58.I rpcgen 
  59options can be used to suppress stub generation and to specify the transport
  60to be used by the server stub.
  61.LP
  62Like all compilers, 
  63.I rpcgen 
  64reduces development time
  65that would otherwise be spent coding and debugging low-level routines.
  66All compilers, including 
  67.I rpcgen ,
  68do this at a small cost in efficiency
  69and flexibility.  However,   many compilers allow  escape  hatches for
  70programmers to  mix low-level code with  high-level code. 
  71.I rpcgen 
  72is no exception.  In speed-critical applications, hand-written routines 
  73can be linked with the 
  74.I rpcgen 
  75output without any difficulty.  Also, one may proceed by using
  76.I rpcgen 
  77output as a starting point, and then rewriting it as necessary.
  78(If you need a discussion of RPC programming without
  79.I rpcgen ,
  80see 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
  87Assume an application that runs on a single machine, one which we want 
  88to convert to run over the network.  Here we will demonstrate such a 
  89conversion by way of a simple example\(ema program that prints a 
  90message 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
 100main(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
 126printmessage(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
 141And then, of course:
 142.ie t .DS
 143.el .DS L
 144.ft CW
 145example%  \fBcc printmsg.c -o printmsg\fP
 146example%  \fBprintmsg "Hello, there."\fP
 147Message delivered!
 148example%
 149.DE
 150.LP
 151If  
 152.I printmessage() 
 153was turned into  a remote procedure,
 154then it could be  called from anywhere in   the network.  
 155Ideally,  one would just  like to stick   a  keyword like  
 156.I remote 
 157in  front  of a
 158procedure to turn it into a  remote procedure.  Unfortunately,
 159we  have to live  within the  constraints of  the   C language, since 
 160it existed   long before  RPC did.  But   even without language 
 161support, it's not very difficult to make a procedure remote.
 162.LP
 163In  general, it's necessary to figure  out  what the types are for
 164all procedure inputs and outputs.  In  this case,   we  have a 
 165procedure
 166.I printmessage() 
 167which takes a  string as input, and returns  an integer
 168as output.  Knowing  this, we can write a  protocol specification in RPC
 169language that  describes the remote  version of 
 170.I printmessage ().
 171Here 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
 180program MESSAGEPROG {
 181	version MESSAGEVERS {
 182		int PRINTMESSAGE(string) = 1;
 183	} = 1;
 184} = 99;
 185.DE
 186.LP
 187Remote procedures are part of remote programs, so we actually declared
 188an  entire  remote program  here  which contains  the single procedure
 189.I PRINTMESSAGE .
 190This procedure was declared to be  in version  1 of the
 191remote program.  No null procedure (procedure 0) is necessary because
 192.I rpcgen 
 193generates it automatically.
 194.LP
 195Notice that everything is declared with all capital  letters.  This is
 196not required, but is a good convention to follow.
 197.LP
 198Notice also that the argument type is \*Qstring\*U and not \*Qchar *\*U.  This
 199is because a \*Qchar *\*U in C is ambiguous.  Programmers usually intend it
 200to mean  a null-terminated string   of characters, but  it  could also
 201represent a pointer to a single character or a  pointer to an array of
 202characters.  In  RPC language,  a  null-terminated  string is 
 203unambiguously called a \*Qstring\*U.
 204.LP
 205There are  just two more things to  write.  First, there is the remote
 206procedure itself.  Here's the definition of a remote procedure
 207to implement the
 208.I PRINTMESSAGE
 209procedure 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
 228int *
 229printmessage_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
 248Notice here that the declaration of the remote procedure
 249.I printmessage_1() 
 250differs from that of the local procedure
 251.I printmessage() 
 252in three ways:
 253.IP  1.
 254It takes a pointer to a string instead of a string itself.  This
 255is true of all  remote procedures:  they always take pointers to  their
 256arguments rather than the arguments themselves.
 257.IP  2.
 258It returns a pointer to an  integer instead of  an integer itself. This is
 259also generally true of remote procedures: they always return a pointer
 260to their results.
 261.IP  3.
 262It has an \*Q_1\*U appended to its name.  In general, all remote
 263procedures called by 
 264.I rpcgen 
 265are named by  the following rule: the name in the program  definition  
 266(here 
 267.I PRINTMESSAGE )
 268is converted   to all
 269lower-case letters, an underbar (\*Q_\*U) is appended to it, and
 270finally the version number (here 1) is appended.
 271.LP
 272The last thing to do is declare the main client program that will call
 273the 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
 285main(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
 368There are two things to note here:
 369.IP  1.
 370.IX "client handle, used by rpcgen" "" "client handle, used by \fIrpcgen\fP"
 371First a client \*Qhandle\*U is created using the RPC library routine
 372.I clnt_create ().
 373This client handle will be passed  to the stub routines
 374which call the remote procedure.
 375.IP  2.
 376The remote procedure  
 377.I printmessage_1() 
 378is called exactly  the same way as it is  declared in 
 379.I msg_proc.c 
 380except for the inserted client handle as the first argument.
 381.LP
 382Here's how to put all of the pieces together:
 383.ie t .DS
 384.el .DS L
 385.ft CW
 386example%  \fBrpcgen msg.x\fP
 387example%  \fBcc rprintmsg.c msg_clnt.c -o rprintmsg\fP
 388example%  \fBcc msg_proc.c msg_svc.c -o msg_server\fP
 389.DE
 390Two programs were compiled here: the client program 
 391.I rprintmsg 
 392and the server  program 
 393.I msg_server .
 394Before doing this  though,  
 395.I rpcgen 
 396was used to fill in the missing pieces.  
 397.LP
 398Here is what 
 399.I rpcgen 
 400did with the input file 
 401.I msg.x :
 402.IP  1.
 403It created a header file called 
 404.I msg.h 
 405that contained
 406.I #define 's
 407for
 408.I MESSAGEPROG ,
 409.I MESSAGEVERS 
 410and    
 411.I PRINTMESSAGE 
 412for use in  the  other modules.
 413.IP  2.
 414It created client \*Qstub\*U routines in the
 415.I msg_clnt.c 
 416file.   In this case there is only one, the 
 417.I printmessage_1() 
 418that was referred to from the
 419.I printmsg 
 420client program.  The name  of the output file for
 421client stub routines is always formed in this way:  if the name of the
 422input file is  
 423.I FOO.x ,
 424the   client  stubs   output file is    called
 425.I FOO_clnt.c .
 426.IP  3.
 427It created  the  server   program which calls   
 428.I printmessage_1() 
 429in
 430.I msg_proc.c .
 431This server program is named  
 432.I msg_svc.c .
 433The rule for naming the server output file is similar  to the 
 434previous one:  for an input  file   called  
 435.I FOO.x ,
 436the   output   server   file is  named
 437.I FOO_svc.c .
 438.LP
 439Now we're ready to have some fun.  First, copy the server to a
 440remote machine and run it.  For this  example,  the
 441machine is called \*Qmoon\*U.  Server processes are run in the
 442background, because they never exit.
 443.ie t .DS
 444.el .DS L
 445.ft CW
 446moon% \fBmsg_server &\fP	       
 447.DE
 448Then on our local machine (\*Qsun\*U) we can print a message on \*Qmoon\*Us
 449console.
 450.ie t .DS
 451.el .DS L
 452.ft CW
 453sun% \fBprintmsg moon "Hello, moon."\fP
 454.DE
 455The message will get printed to \*Qmoon\*Us console.  You can print a
 456message on anybody's console (including your own) with this program if
 457you 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
 462The previous example  only demonstrated  the  automatic generation of
 463client  and server RPC  code. 
 464.I rpcgen 
 465may also  be used to generate XDR routines, that  is,  the routines
 466necessary to  convert   local  data
 467structures into network format and vice-versa.  This example presents
 468a complete RPC service\(ema remote directory listing service, which uses
 469.I rpcgen
 470not  only  to generate stub routines, but also to  generate  the XDR
 471routines.  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
 479const MAXNAMELEN = 255;		/* \fImaximum length of a directory entry\fP */
 480
 481typedef string nametype<MAXNAMELEN>;	/* \fIa directory entry\fP */
 482
 483typedef 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
 490struct 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
 500union readdir_res switch (int errno) {
 501case 0:
 502	namelist list;	/* \fIno error: return directory listing\fP */
 503default:
 504	void;		/* \fIerror occurred: nothing else to return\fP */
 505};
 506
 507.ft I
 508/*
 509 * The directory program definition
 510 */
 511.ft CW
 512program DIRPROG {
 513	version DIRVERS {
 514		readdir_res
 515		READDIR(nametype) = 1;
 516	} = 1;
 517} = 76;
 518.DE
 519.SH
 520Note:
 521.I
 522Types (like
 523.I readdir_res 
 524in the example above) can be defined using
 525the \*Qstruct\*U, \*Qunion\*U and \*Qenum\*U keywords, but those keywords
 526should not be used in subsequent declarations of variables of those types.
 527For example, if you define a union \*Qfoo\*U, you should declare using
 528only \*Qfoo\*U and not \*Qunion foo\*U.  In fact,
 529.I rpcgen 
 530compiles
 531RPC unions into C structures and it is an error to declare them using the
 532\*Qunion\*U keyword.
 533.LP
 534Running 
 535.I rpcgen 
 536on 
 537.I dir.x 
 538creates four output files.  Three are the same as before: header file,
 539client stub routines and server skeleton.  The fourth are the XDR routines
 540necessary for converting the data types we declared into XDR format and
 541vice-versa.  These are output in the file
 542.I dir_xdr.c .
 543.LP
 544Here is the implementation of the
 545.I READDIR 
 546procedure.
 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
 559extern int errno;
 560extern char *malloc();
 561extern char *strdup();
 562
 563readdir_res *
 564readdir_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
 617Finally, 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
 629extern int errno;
 630
 631main(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
 722Compile everything, and run.
 723.DS
 724.ft CW
 725sun%  \fBrpcgen dir.x\fP
 726sun%  \fBcc rls.c dir_clnt.c dir_xdr.c -o rls\fP
 727sun%  \fBcc dir_svc.c dir_proc.c dir_xdr.c -o dir_svc\fP
 728
 729sun%  \fBdir_svc &\fP
 730
 731moon%  \fBrls sun /usr/pub\fP
 732\&.
 733\&..
 734ascii
 735eqnchar
 736greek
 737kbd
 738marg8
 739tabclr
 740tabs
 741tabs4
 742moon%
 743.DE
 744.LP
 745.IX "debugging with rpcgen" "" "debugging with \fIrpcgen\fP"
 746A final note about 
 747.I rpcgen :
 748The client program and the server procedure can be tested together 
 749as a single program by simply linking them with each other rather 
 750than with the client and server stubs.  The procedure calls will be
 751executed as ordinary local procedure calls and the program can be 
 752debugged with a local debugger such as 
 753.I dbx .
 754When the program is working, the client program can be linked to 
 755the client stub produced by 
 756.I rpcgen 
 757and the server procedures can be linked to the server stub produced
 758by 
 759.I rpcgen .
 760.SH
 761.I NOTE :
 762\fIIf you do this, you may want to comment out calls to RPC library
 763routines, and have client-side routines call server routines
 764directly.\fP
 765.LP
 766.NH 1
 767\&The C-Preprocessor
 768.IX rpcgen "C-preprocessor" \fIrpcgen\fP
 769.LP
 770The C-preprocessor is  run on all input  files before they are
 771compiled, so all the preprocessor directives are legal within a \*Q.x\*U
 772file. Four symbols may be defined, depending upon which output file is
 773getting generated. The symbols are:
 774.TS
 775box tab (&);
 776lfI lfI
 777lfL l .
 778Symbol&Usage
 779_
 780RPC_HDR&for header-file output
 781RPC_XDR&for XDR routine output
 782RPC_SVC&for server-skeleton output
 783RPC_CLNT&for client stub output
 784.TE
 785.LP
 786Also, 
 787.I rpcgen 
 788does  a little preprocessing   of its own. Any  line that
 789begins  with  a percent sign is passed  directly into the output file,
 790without any interpretation of the line.  Here is a simple example that
 791demonstrates 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
 799program 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
 816The '%' feature is not generally recommended, as there is no guarantee
 817that 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
 826RPC sets a default timeout of 25 seconds for RPC calls when
 827.I clnt_create()
 828is used.  This timeout may be changed using
 829.I clnt_control()
 830Here is a small code fragment to demonstrate use of
 831.I clnt_control ():
 832.ID
 833struct timeval tv;
 834CLIENT *cl;
 835.sp .5
 836cl = clnt_create("somehost", SOMEPROG, SOMEVERS, "tcp");
 837if (cl == NULL) {
 838	exit(1);
 839}
 840tv.tv_sec = 60;	/* \fIchange timeout to 1 minute\fP */
 841tv.tv_usec = 0;
 842clnt_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
 849When a procedure is known to be called via broadcast RPC,
 850it is usually wise for the server to not reply unless it can provide
 851some useful information to the client.  This prevents the network
 852from getting flooded by useless replies.
 853.LP
 854To prevent the server from replying, a remote procedure can
 855return NULL as its result, and the server code generated by
 856.I rpcgen 
 857will detect this and not send out a reply.
 858.LP
 859Here is an example of a procedure that replies only if it
 860thinks it is an NFS server:
 861.ID
 862void *
 863reply_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
 878Note that if procedure returns type \*Qvoid *\*U, they must return a non-NULL
 879pointer if they want RPC to reply for them.
 880.NH 2
 881\&Other Information Passed to Server Procedures
 882.LP
 883Server procedures will often want to know more about an RPC call
 884than just its arguments.  For example, getting authentication information
 885is important to procedures that want to implement some level of security.
 886This extra information is actually supplied to the server procedure as a
 887second argument.  Here is an example to demonstrate its use.  What we've
 888done here is rewrite the previous
 889.I printmessage_1() 
 890procedure to only allow root users to print a message to the console.
 891.ID
 892int *
 893printmessage_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
 919RPC language is an extension of XDR  language.   The sole extension is
 920the addition of the
 921.I program 
 922type.  For a complete description of the XDR language syntax, see the
 923.I "External Data Representation Standard: Protocol Specification"
 924chapter.  For a description of the RPC extensions to the XDR language,
 925see the
 926.I "Remote Procedure Calls: Protocol Specification"
 927chapter.
 928.LP
 929However, XDR language is so close to C that if you know C, you know most
 930of it already.  We describe here  the syntax of the RPC language,
 931showing a  few examples along the way.   We also show how  the various
 932RPC and XDR type definitions get  compiled into C  type definitions in
 933the output header file.
 934.KS
 935.NH 2
 936Definitions
 937\&
 938.IX rpcgen definitions \fIrpcgen\fP
 939.LP
 940An 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
 948It 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
 960Structures
 961\&
 962.IX rpcgen structures \fIrpcgen\fP
 963.LP
 964An XDR struct  is declared almost exactly like  its C counterpart.  It
 965looks 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
 977As an example, here is an XDR structure to a two-dimensional
 978coordinate, and the C structure  that it  gets compiled into  in the
 979output 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
 988The output is identical to the  input, except  for the added
 989.I typedef
 990at the end of the output.  This allows one to use \*Qcoord\*U instead of
 991\*Qstruct coord\*U when declaring items.
 992.NH 2
 993Unions
 994\&
 995.IX rpcgen unions \fIrpcgen\fP
 996.LP
 997XDR unions are discriminated unions, and look quite different from C
 998unions. They are more analogous to  Pascal variant records than they
 999are 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
1012Here 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.
1014Otherwise, 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
1024It 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
1035Notice that the union component of the  output struct  has the name as
1036the type name, except for the trailing \*Q_u\*U.
1037.NH 2
1038Enumerations
1039\&
1040.IX rpcgen enumerations \fIrpcgen\fP
1041.LP
1042XDR 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
1058Here is a short example of  an XDR enum,  and the C enum that  it gets
1059compiled 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
1070Typedef
1071\&
1072.IX rpcgen typedef \fIrpcgen\fP
1073.LP
1074XDR typedefs have the same syntax as C typedefs.
1075.DS L
1076.ft CW
1077    typedef-definition:
1078        "typedef" declaration
1079.DE
1080Here  is an example  that defines a  
1081.I fname_type 
1082used  for declaring
1083file name strings that have a maximum length of 255 characters.
1084.DS L
1085.ft CW
1086typedef string fname_type<255>; --> typedef char *fname_type;
1087.DE
1088.NH 2
1089Constants
1090\&
1091.IX rpcgen constants \fIrpcgen\fP
1092.LP
1093XDR constants  symbolic constants  that may be  used wherever  a
1094integer 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
1100For example, the following defines a constant
1101.I DOZEN 
1102equal to 12.
1103.DS L
1104.ft CW
1105    const DOZEN = 12;  -->  #define DOZEN 12
1106.DE
1107.NH 2
1108Programs
1109\&
1110.IX rpcgen programs \fIrpcgen\fP
1111.LP
1112RPC 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
1136For 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
1145program TIMEPROG {
1146    version TIMEVERS {
1147        unsigned int TIMEGET(void) = 1;
1148        void TIMESET(unsigned) = 2;
1149    } = 1;
1150} = 44;        
1151.DE
1152This 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
1162Declarations
1163\&
1164.IX rpcgen declarations \fIrpcgen\fP
1165.LP
1166In 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
1181Example:
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
1192Example:
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 
1198in C, so XDR invents its own using angle-brackets.
1199.DS L
1200.ft CW
1201variable-array-declaration:
1202    type-ident variable-ident "<" value ">"
1203    type-ident variable-ident "<" ">"
1204.DE
1205The maximum size is specified between the angle brackets. The size may
1206be 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
1212Since  variable-length  arrays have no  explicit  syntax in  C,  these
1213declarations 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
1222Note that the number of items in the array is stored in the \*Q_len\*U
1223component and the pointer to the array is stored in the \*Q_val\*U
1224component. The first part of each of these component's names is the
1225same as the name of the declared XDR variable.
1226.LP
1227\fB4) Pointer Declarations\fP are made in 
1228XDR  exactly as they  are  in C.  You  can't
1229really send pointers over the network,  but  you  can use XDR pointers
1230for sending recursive data types such as lists and trees.  The type is
1231actually 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
1237Example:
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
1246There are a few exceptions to the rules described above.
1247.LP
1248.B Booleans:
1249C has no built-in boolean type. However, the RPC library does  a
1250boolean type   called 
1251.I bool_t 
1252that   is either  
1253.I TRUE 
1254or  
1255.I FALSE .
1256Things declared as  type 
1257.I bool 
1258in  XDR language  are  compiled  into
1259.I bool_t 
1260in the output header file.
1261.LP
1262Example:
1263.DS L
1264.ft CW
1265    bool married;  -->  bool_t married;
1266.DE
1267.B Strings:
1268C 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
1271file. The  maximum size contained  in the angle brackets specifies the
1272maximum number of characters allowed in the  strings (not counting the
1273.I NULL 
1274character). The maximum size may be left off, indicating a string
1275of arbitrary length.
1276.LP
1277Examples:
1278.DS L
1279.ft CW
1280    string name<32>;    -->  char *name;
1281    string longname<>;  -->  char *longname;
1282.DE
1283.B "Opaque  Data:"
1284Opaque data is used in RPC and XDR to describe untyped  data, that is,
1285just  sequences of arbitrary  bytes.  It may be  declared  either as a
1286fixed or variable length array.
1287.DS L
1288Examples:
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:
1298In a void declaration, the variable is  not named.  The declaration is
1299just \*Qvoid\*U and nothing else.  Void declarations can only occur in two
1300places: union definitions and program definitions (as the  argument or
1301result of a remote procedure).