Previous | Contents | Index |
You can display current RPC registration information known to the
Portmapper program. On UNIX systems use the rpcinfo command.
On OpenVMS systems use the SHOW PORTMAPPER management command. The
rpcinfo or SHOW PORTMAPPER commands can also find the RPC
services registered on a specific host and report their port numbers
and the transports for which the services are registered. For more
information, see the DIGITAL TCP/IP Services for OpenVMS Management manual.
1.5 RPC Independence from Transport Protocol
The RPC protocol is concerned only with the specification and interpretation of messages; it is independent of transport protocols because it needs no information on how a message is passed among processes.
Also, RPC does not implement any kind of reliability; the application itself must be aware of the transport protocol type underlying RPC. With a reliable transport, such as TCP/IP, the application need not do much else. However, an application must use its own retransmission and timeout policy if it is running on top of an unreliable transport, such as UDP/IP.
Because of transport independence, the RPC protocol does not actively interpret anything about remote procedures or their execution. Instead, the application infers required information from the underlying protocol (where such information should be specified explicitly). For example, if RPC is running on top of an unreliable transport (such as UDP/IP) and the application retransmits RPC messages after short timeouts, and if the application receives no reply, then it can infer only that a certain procedure was executed zero or more times. If it receives a reply, then the application infers that the procedure was executed at least once.
With a reliable transport, such as TCP/IP, the application can infer from a reply message that the procedure was executed exactly once, but if it receives no reply message, it cannot assume the remote procedure was not executed.
Even with a connection-oriented protocol such as TCP, an application still needs timeouts and reconnection procedures to handle server crashes. |
ONC RPC is currently supported on both UDP/IP and TCP/IP transports. The selection of the transport depends on the application requirements. The UDP transport, which is connectionless, is a good choice if the application has the following characteristics:
TCP (connection-oriented) is a good transport choice if the application has any of the following characteristics:
RPC can handle arbitrary data structures, regardless of the byte order or structure layout convention on a particular system. It does this by converting them to a network standard called external data representation (XDR) before sending them over the network. XDR is a system-independent description and encoding of data that can communicate between diverse systems, such as a VAX, Sun workstation, IBM PC, or CRAY.
Converting from a particular system representation to XDR format is
called serializing; the reverse process is deserializing.
1.7 Assigning Program Numbers
Program numbers are assigned in groups of 0x20000000 according to the following chart:
0x00000000--- 0x1fffffff | Defined by Sun Microsystems |
0x20000000--- 0x3fffffff | Defined by user |
0x40000000--- 0x5fffffff | Transient |
0x60000000--- 0x7fffffff | Reserved |
0x80000000--- 0x9fffffff | Reserved |
0xa0000000--- 0xbfffffff | Reserved |
0xc0000000--- 0xdfffffff | Reserved |
0xe0000000--- 0xffffffff | Reserved |
Sun Microsystems administers the first range of numbers, which should be identical for all ONC RPC users. An ONC RPC application for general use should have an assigned number in this first range. The second range of numbers is for specific, user-defined customer applications, and is primarily for debugging new programs. The third, called the Transient group, is reserved for applications that generate program numbers dynamically. The final groups are reserved for future use, and are not used.
To register a protocol specification, send a request by network mail to rpc@sun.com, or write to:
RPC Administrator Sun Microsystems 2550 Garcia Ave. Mountain View, CA 94043 |
Include a compilable RPCGEN .X file describing your protocol. You will then receive a unique program number. See Chapter 2 for more information about RPCGEN .X files.
The RPCGEN protocol compiler accepts a remote program interface definition written in RPC language, which is similar to C. It then produces C language output consisting of: client skeleton routines, server skeleton routines, XDR filter routines for both arguments and results, a header file that contains common definitions, and optionally, dispatch tables that the server uses to invoke routines that are based on authorization checks.
The client skeleton interface to the RPC library hides the network from the client program, and the server skeleton hides the network from the server procedures invoked by remote clients. You compile and link output files from RPCGEN as usual. The server code generated by RPCGEN supports INETd. You can start the server via INETd or at the command line.
You can write server procedures in any language that has system calling conventions. To get an executable server program, link the server procedure with the server skeleton from RPCGEN. To create an executable client program, write an ordinary main program that makes local procedure calls to the client skeletons, and link the program with the client skeleton from RPCGEN. If necessary, the RPCGEN options enable you to suppress skeleton generation and specify the transport to be used by the server skeleton.
The RPCGEN protocol compiler helps to reduce development time in the following ways:
Refer to the RPCGEN command description at the end of this chapter for more information about programming applications that use remote procedure calls or for writing XDR routines that convert procedure arguments and results into their network format (or vice versa). For a discussion of RPC programming without RPCGEN, see Chapter 3.
2.2 Simple Example: Using RPCGEN to Generate Client and Server RPC Code
This section shows how to convert a simple routine ---one that prints
messages to the system console on a single system (OPCOM on
OpenVMS)---to an ONC RPC application that runs remotely over the
network. To do this, the RPCGEN protocol compiler is used to generate
client and server RPC code. Example 2-1 (see file
SYS$COMMON:[SYSHLP.EXAMPLES.TCPIP.RPC]PRINTMSG.C) shows the routine
before conversion.
Compile and run the program shown in the example (you will need OPER privileges):
$ CC/DECC PRINTMSG $ LINK PRINTMSG $ MCR SYS$DISK:[]PRINTMSG "Red rubber ball" %%%%%%%%%%% OPCOM 27-SEP-1995 14:39:22.59 %%%%%%%%%%% Message from user GEORGE on BOSTON Message Delivered! $ |
If the printmessage procedure at the bottom of the printmsg.c program of Example 2-1 were converted into a remote procedure, you could call it from anywhere in the network, instead of only from the program where it is embedded. Before doing this, it is necessary to write a protocol specification in RPC language that describes the remote procedure, as shown in the next section.
Example 2-1 Printing a Remote Message Without ONC RPC |
---|
/* ** printmsg.c: OpenVMS print a message on the console */ #include <descrip.h> #include <opcdef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> extern int SYS$SNDOPR(struct dsc$descriptor_s *, unsigned short); static int printmessage(char *); main(argc, argv) int argc; char *argv[]; { char *message; int exit(); if (argc != 2) { fprintf(stderr, "usage: %s <message>\n", argv[0]); exit (1); } message = argv[1]; if (!printmessage(message)) { fprintf(stderr,"%s: couldn't print your message\n", argv[0]); exit (1); } printf("Message Delivered!\n"); exit (0); } /* ** Print a message to the console. Return a Boolean indicating ** whether the message was actually printed. */ static int printmessage(msg) char *msg; { struct dsc$descriptor_s desc; union { char buffer[256]; /* Preallocate space for text */ struct opcdef opc; } message; int status; /* ** Build the message request block. */ message.opc.opc$b_ms_type = OPC$_RQ_RQST; message.opc.opc$b_ms_target = OPC$M_NM_CENTRL; message.opc.opc$w_ms_status = 0; message.opc.opc$l_ms_rqstid = 0; strcpy((char *) &message.opc.opc$l_ms_text, msg); desc.dsc$a_pointer = (char *) &message.opc; desc.dsc$w_length = (char *) &message.opc.opc$l_ms_text - (char *) &message + strlen((char *) &message.opc.opc$l_ms_text); /* ** Send the message to the console. */ status = SYS$SNDOPR(&desc, /* MSGBUF */ 0); /* CHAN */ if (status & 1) return 1; return 0; } |
2.2.1 RPC Protocol Specification File Describing Remote Procedure
To create the specification file, you must know all the input and
output parameter types. In Example 2-1, the printmessage
procedure takes a string as input, and returns an integer as output.
Example 2-2 (see SYS$COMMON:[SYSHLP.EXAMPLES.TCPIP.RPC]MSG.X) is the
RPC protocol specification file that describes the remote version of
the printmessage procedure.
Remote procedures are part of remote programs, so Example 2-2 actually declares a remote program containing a single procedure, PRINTMESSAGE. By convention, all RPC services provide for a NULL procedure (procedure 0), normally used for "pinging." (See the DIGITAL TCP/IP Services for OpenVMS Management manual.) The RPC protocol specification file in Example 2-2 declares the PRINTMESSAGE procedure to be in version 1 of the remote program. No NULL procedure (procedure 0) is necessary in the protocol definition because RPCGEN generates it automatically.
In RPC language, the convention (though not a requirement) is to make all declarations in uppercase characters. Notice that the argument type is string, not char *, because a char * in C is ambiguous. Programmers usually intend it to mean a null-terminated string of characters, but it could also be a pointer to a single character or to an array of characters. In RPC language, a null-terminated string is unambiguously of type string.
Example 2-2 RPC Protocol Specification File Simple Example |
---|
/* * msg.x: Remote message printing protocol */ program MESSAGEPROG { version MESSAGEVERS { int PRINTMESSAGE(string) = 1; } = 1; } = 0x20000099; |
2.2.2 Implementing the Procedure Declared in the Protocol Specification
Example 2-3 (see SYS$COMMON:[SYSHLP.EXAMPLES.TCPIP.RPC]MSG_SERVER.C)
defines the remote procedure declared in the RPC protocol specification
file of the previous example.
Example 2-3 Remote Procedure Definition |
---|
/* ** msg_server.c: OpenVMS implementation of the remote procedure ** "printmessage" */ #include <descrip.h> /* OpenVMS descriptor definitions */ #include <opcdef.h> /* OpenVMS $SNDOPR() definitions */ #include <rpc/rpc.h> /* always needed */ (1) #include "msg.h" /* msg.h will be generated by RPCGEN */ extern int SYS$SNDOPR(struct dsc$descriptor_s *, unsigned short); /* ** Remote version of "printmessage" */ int * printmessage_1(msg) (2) char **msg; (3) { struct dsc$descriptor_s desc; union { char buffer[256]; /* Preallocate space for text */ struct opcdef opc; } message; static int result; int status; /* ** Build the message request block. */ message.opc.opc$b_ms_type = OPC$_RQ_RQST; message.opc.opc$b_ms_target = OPC$M_NM_CENTRL; message.opc.opc$w_ms_status = 0; message.opc.opc$l_ms_rqstid = 0; strcpy((char *) &message.opc.opc$l_ms_text, *msg); desc.dsc$a_pointer = (char *) &message.opc; desc.dsc$w_length = (char *) &message.opc.opc$l_ms_text - (char *) &message + strlen((char *) &message.opc.opc$l_ms_text); status = SYS$SNDOPR(&desc, /* MSGBUF */ 0); /* CHAN */ if (status & 1) result = 1; else result = 0; return &result; (4) } |
In this example, the declaration of the remote procedure, printmessage_1, differs from that of the local procedure printmessage in four ways:
$ DEFINE RPC TCPIP$RPC: |
Example 2-4 (see SYS$COMMON:[SYSHLP.EXAMPLES.TCPIP.RPC]RPRINTMSG.C) declares the main client program, rprintmsg.c, that calls the remote procedure.
Example 2-4 Client Program that Calls the Remote Procedure |
---|
/* ** rprintmsg.c: remote OpenVMS version of "printmsg.c" */ #include <stdio.h> #include <rpc/rpc.h> /* always needed */ #include "msg.h" /* msg.h will be generated by RPCGEN */ main(argc, argv) int argc; char *argv[]; { CLIENT *cl; char *message; int *result; char *server; 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. We tell ** the RPC package to use the TCP protocol when ** contacting the server. */ cl = clnt_create(server, MESSAGEPROG, MESSAGEVERS, "tcp"); (1) if (cl == NULL) { /* ** Couldn't establish connection with server. ** Print error message and stop. */ clnt_pcreateerror(server); exit(1); } /* ** Call the remote procedure "printmessage" on the server */ result = printmessage_1(&message, cl); (2) if (result == NULL) { (3) /* ** An error occurred while calling the server. ** Print error message and stop. */ clnt_perror(cl, server); exit(1); } /* ** Okay, we successfully called the remote procedure. */ if (*result == 0) { (4) /* ** Server was unable to print our message. ** Print error message and stop. */ fprintf(stderr, "%s: %s couldn't print your message\n", argv[0], server); exit(1); } /* ** The message got printed on the server's console */ printf("Message delivered to %s!\n", server); exit(0); } |
In this example, the following events occur:
Use the RPCGEN protocol compiler on the RPC protocol specification file, MSG.X, (from Example 2-2) to generate client and server RPC code automatically:
$ RPCGEN MSG.X |
Using RPCGEN like this---without options---automatically creates the following files from the input file MSG.X:
The /TABLE option of RPCGEN creates an additional output file of index information for dispatching service routines. See Section 2.6.4 for more information about dispatch tables. |
After the RPCGEN protocol compilation, use two cc compilation statements to create a client program and a server program:
$ CC/DECC RPRINTMSG.C $ CC/DECC MSG_CLNT.C $ LINK RPRINTMSG,MSG_CLNT,TCPIP$RPC:TCPIP$RPCXDR/LIBRARY |
$ CC/DECC MSG_SERVER.C $ CC/DECC MSG_SVC.C $ LINK MSG_SERVER,MSG_SVC,TCPIP$RPC:TCPIP$RPCXDR/LIBRARY |
If you want to use the shareable version of the RPC object library, reference the shareable version of the library, SYS$SHARE:TCPIP$RPCXDR_SHR/SHARE, in your LINK options file. |
Previous | Next | Contents | Index |