Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
3.  rpcgen Programming Guide rpcgen Tutorial Converting Local Procedures to Remote Procedures  Previous   Contents   Next 
   
 

For local use on a single machine, this program could be compiled and executed as follows:

$ cc printmsg.c -o printmsg
$ printmsg "Hello, there."
Message delivered!
$

If the printmessage() function is turned into a remote procedure, the function can be called from anywhere in the network.

First, determine the data types of all procedure-calling arguments and the resulting argument. The calling argument of printmessage() is a string, and the result is an integer. You can write a protocol specification in the RPC language that describes the remote version of printmessage(). The RPC language source code for such a specification is:

/* msg.x: Remote msg printing protocol */
 program MESSAGEPROG {
     version PRINTMESSAGEVERS {
        int PRINTMESSAGE(string) = 1;
 	 } = 1;
} = 0x20000001;

Remote procedures are always declared as part of remote programs. The previous code declares an entire remote program that contains the single procedure PRINTMESSAGE. In this example, the PRINTMESSAGE procedure is declared to be procedure 1, in version 1 of the remote program MESSAGEPROG, with the program number 0x20000001. See Appendix B, RPC Protocol and Language Specification for guidance on choosing program numbers.

Version numbers are incremented when functionality is changed in the remote program. Existing procedures can be changed or new ones can be added. More than one version of a remote program can be defined and a version can have more than one procedure defined.

Note that the program and procedure names are declared with all capital letters.

Note also that the argument type is string and not char * as it would be in C. This is because a char * in C is ambiguous. char usually means an array of characters, but it could also represent a pointer to a single character. In the RPC language, a null-terminated array of char is called a string.

You have just two more programs to write:

  • The remote procedure itself

  • The main client program that calls it

Example 3-2 is a remote procedure that implements the PRINTMESSAGE procedure in Example 3-1.


Example 3-2 RPC Version of printmsg.c

/*
 * msg_proc.c: implementation of the
 * remote procedure "printmessage"
 */
#include <stdio.h>
#include "msg.h"				/* msg.h generated by rpcgen */
 
int *
printmessage_1(msg, req)
	char **msg;	
	struct svc_req *req;		/* details of call */
{
	static int result;			/* must be static! */
	FILE *f;
 
	f = fopen("/dev/console", "w");
	if (f == (FILE *)NULL) {
		result = 0;
		return (&result);
	}
	fprintf(f, "%s\n", *msg);
	fclose(f);
	result = 1;
	return (&result);}

The declaration of the remote procedure printmessage_1() differs from that of the local procedure printmessage() in four ways:

  1. printmessage_1() takes a pointer to the character array instead of the pointer itself. This principle is true of all remote procedures when the -N option is not used. These procedures always take pointers to their arguments rather than the arguments themselves. Without the -N option, remote procedures are always called with a single argument. If more than one argument is required the arguments must be passed in a struct.

  2. printmessage_1() is called with two arguments. The second argument contains information on the context of an invocation: the program, version, and procedure numbers; raw and canonical credentials; and an SVCXPRT structure pointer. The SVCXPRT structure contains transport information. All of the information is made available in case the invoked procedure requires it to perform the request.

  3. printmessage_1() returns a pointer to an integer instead of the integer itself. This principle is also true of remote procedures when the -N option is not used. These procedures return pointers to the result. The result should be declared static unless the -M (multithread) or -A (Auto mode) options are used. Ordinarily, if the result is declared local to the remote procedure, references to the result by the server stub are invalid after the remote procedure returns. In the case of -M and -A options, a pointer to the result is passed as a third argument to the procedure, so the result is not declared in the procedure.

  4. An _1 is appended to the printmessage_1() name. In general, all remote procedures calls generated by rpcgen are named as follows: the procedure name in the program definition (here PRINTMESSAGE) is converted to all lowercase letters, an underbar (_) is appended to it, and the version number (here 1) is appended. This naming scheme enables you to have multiple versions of the same procedure.

The following code example shows the main client program that calls the remote procedure.


Example 3-3 Client Program to Call printmsg.c

/*
 * rprintmsg.c: remote version
 * of "printmsg.c"
 */
#include <stdio.h>
#include "msg.h"			/* msg.h generated by rpcgen */
 
main(argc, argv)
	int argc;
	char *argv[];
{
	CLIENT *clnt;
	int *result;
	char *server;
	char *message;
 
	if (argc != 3) {
		fprintf(stderr, "usage: %s host 
					message\n", argv[0]);
		exit(1);
	}
 
	server = argv[1];
	message = argv[2];
	/*
	 * Create client "handle" used for 
 * calling MESSAGEPROG on the server
	 * designated on the command line.
	 */
	clnt = clnt_create(server, MESSAGEPROG,
								PRINTMESSAGEVERS,
								"visible");
	if (clnt == (CLIENT *)NULL) {
		/*
		 * Couldn't establish connection
    * with server.
		 * Print error message and die.
		 */
		clnt_pcreateerror(server);
		exit(1);
	}
		/*
	 * Call the remote procedure
 * "printmessage" on the server
	 */
	result = printmessage_1(&message, clnt);
	if (result == (int *)NULL) {
		/*
		 * An error occurred while calling 
    * the server.
		 * Print error message and die.
		 */
		clnt_perror(clnt, server);
		exit(1);
	}
	/* Okay, we successfully called 
 * the remote procedure. 
 */
	if (*result == 0) {
		/*
		 * Server was unable to print 
    * our message.
		 * Print error message and die.
		 */
		fprintf(stderr,
		"%s: could not print your message\n",argv[0]);
		exit(1);
	}
 	/* The message got printed on the
 * server's console
 */
	printf("Message delivered to %s\n",
				server);
	clnt_destroy( clnt );
	exit(0);}

 
 
 
  Previous   Contents   Next