Originally developed by Sun, but now widely available on other platforms (including Digital Unix). Also known as Open Network Computing (ONC).
Sun RPC package has an RPC compiler (rpcgen) that automatically generates the client and server stubs.
RPC package uses XDR (eXternal Data Representation) to represent data sent between client and server stubs.
Has built-in representation for basic types (int, float, char).
Also provides a declarative language for specifying complex data types.
Running rpcgen date.x generates date.h, date_clnt.c and date_svc.c. The header file is included with both client and server. The respective C source files are linked with client and server code.
/* * date.x Specification of the remote date and time server */ /* * Define two procedures * bin_date_1() returns the binary date and time (no arguments) * str_date_1() takes a binary time and returns a string * */ program DATE_PROG { version DATE_VERS { long BIN_DATE(void) = 1; /* procedure number = 1 */ string STR_DATE(long) = 2; /* procedure number = 2 */ } = 1; /* version number = 1 */ } = 0x31234567; /* program number = 0x31234567 */
Notes:
/* * rdate.c client program for remote date program */ #include <stdio.h> #include <rpc/rpc.h> /* standard RPC include file */ #include "date.h" /* this file is generated by rpcgen */ main(int argc, char *argv[]) { CLIENT *cl; /* RPC handle */ char *server; long *lresult; /* return value from bin_date_1() */ char **sresult; /* return value from str_date_1() */ if (argc != 2) { fprintf(stderr, "usage: %s hostname\n", argv[0]); exit(1); } server = argv[1]; /* * Create client handle */ if ((cl = clnt_create(server, DATE_PROG, DATE_VERS, "udp")) == NULL) { /* * can't establish connection with server */ clnt_pcreateerror(server); exit(2); } /* * First call the remote procedure "bin_date". */ if ( (lresult = bin_date_1(NULL, cl)) == NULL) { clnt_perror(cl, server); exit(3); } printf("time on host %s = %ld\n",server, *lresult); /* * Now call the remote procedure str_date */ if ( (sresult = str_date_1(lresult, cl)) == NULL) { clnt_perror(cl, server); exit(4); } printf("time on host %s = %s", server, *sresult); clnt_destroy(cl); /* done with the handle */ exit(0); }
/* * dateproc.c remote procedures; called by server stub */ #include <rpc/rpc.h> /* standard RPC include file */ #include "date.h" /* this file is generated by rpcgen */ /* * Return the binary date and time */ long *bin_date_1() { static long timeval; /* must be static */ timeval = time((long *) 0); return(&timeval); } /* * Convert a binary time and return a human readable string */ char **str_date_1(long *bintime) { static char *ptr; /* must be static */ ptr = ctime(bintime); /* convert to local time */ return(&ptr); }
Notes:
< wpi /cs/cs4513/public/example/Date 1 >ls date.x dateproc.c rdate.c < wpi /cs/cs4513/public/example/Date 2 >rpcgen date.x < wpi /cs/cs4513/public/example/Date 3 >ls date.h date_clnt.c dateproc.c date.x date_svc.c rdate.c < wpi /cs/cs4513/public/example/Date 4 >cc -o rdate rdate.c date_clnt.c rdate.c: date_clnt.c: < wpi /cs/cs4513/public/example/Date 5 >cc -o dateproc dateproc.c date_svc.c dateproc.c: date_svc.c: < wpi /cs/cs4513/public/example/Date 6 >dateproc& [1] 17940 < wpi /cs/cs4513/public/example/Date 7 >rdate wpi time on host wpi = 954778980 time on host wpi = Mon Apr 3 12:23:00 2000 < wpi /cs/cs4513/public/example/Date 8 >exit exit
What happens with these processes:
Adaptation of the sample program in the rpcgen Programming Guide. Changes:
/* * msg.x Remote message printing protocol */ program MESSAGEPROG { version MESSAGEVERS { int PRINTMESSAGE(string) = 1; } = 1; } = 0x20000099;
/* * rprintmsg.c remote printing version of "printmsg.c" */ #include <stdio.h> #include <rpc/rpc.h> /* always needed */ #include "msg.h" /* msg.h wil be generated by rpcgen */ main(int argc, char *argv[]) { CLIENT *cl; int *result; char *server; char *message; if (argc != 3) { fprintf(stderr, "usage %s host message\n",argv[0]); } server = argv[1]; message = argv[2]; /* Creare client handle 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"); if (cl == 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, cl); if (result == NULL) { /* * An error occurred while calling the server. * Print error message and die */ clnt_perror(cl, 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: %s couldn't print your message\n", argv[0], server); exit(1); } /* * Message got printed at server */ printf("Message delivered to %s!\n", server); exit(0); }
/* * msg_proc.c implementation of the remote procedure call "printmessage" */ #include <stdio.h> #include <rpc/rpc.h> /* always needed */ #include "msg.h" /* msg.h will be generated by rpcgen */ /* * Remote version of "printmessage" */ int * printmessage_1(char **msg) { static int result; /* must be static! */ printf("%s\n", *msg); result = 1; return(&result); }
< wpi /cs/cs4513/public/example/Message 1 >ls msg.x msg_proc.c rprintmsg.c < wpi /cs/cs4513/public/example/Message 2 >rpcgen msg.x < wpi /cs/cs4513/public/example/Message 3 >ls msg.h msg_clnt.c msg_svc.c msg.x msg_proc.c rprintmsg.c < wpi /cs/cs4513/public/example/Message 4 >cc -o msg_server msg_proc.c msg_svc.c msg_proc.c: msg_svc.c: < wpi /cs/cs4513/public/example/Message 5 >cc -o rprintmsg rprintmsg.c msg_clnt. c rprintmsg.c: msg_clnt.c: < wpi /cs/cs4513/public/example/Message 6 >./msg_server& [1] 23501 < wpi /cs/cs4513/public/example/Message 7 >./rprintmsg wpi "Hello wpi!" Hello wpi! Message delivered to wpi! < wpi /cs/cs4513/public/example/Message 8 >Hello from sequoia Hello from crane, a Sun Hello from emu, a Linux machine exit exit
Note that the client was run on a different types of machines all sending a message to server running on wpi machine.
/* * testxdr.x */ /* * Define a procedure * str_test_1() takes a structure parameter and returns a string * */ struct testxdr{ long long_arg; string string_arg < 128 >; }; program TEST_PROG { version TEST_VERS { string STR_TEST(testxdr) = 1; /* procedure number = 1 */ } = 1; /* version number = 1 */ } = 0x31234567; /* program number = 0x31234567 */
So here is an example of how to pass multiple arguments. A long and a string in a single argument. Note that rpcgen will create another file testxdr_xdr.c that must be compiled and linked.
/* client.C */ #include <iostream.h> #include <string.h> #include <rpc/rpc.h> extern "C" { #include "testxdr.h" } main(int argc, char *argv[]) { CLIENT *c1; char *server; char **sresult; if (argc !=2){ cerr <<"usage:" << argv[0] <<" hostname\n"; exit(1); } server = argv[1]; if ((c1 = clnt_create(server, TEST_PROG, TEST_VERS, "udp")) == NULL){ clnt_pcreateerror(server); exit(2); } testxdr xdrmessage; //structure testxdr defined in testxdr.x long temp_long = 1; char *temp_str = "Client is testing"; //initialize xdrmessage xdrmessage.long_arg = temp_long; xdrmessage.string_arg = temp_str; if ((sresult = str_test_1(&xdrmessage, c1)) == NULL){ clnt_perror(c1, server); exit(4); } cout << "Client call server successfully\n "; cout << "Server send message back:\n " << server << " = " <<*sresult<<"\n"; clnt_destroy(c1); exit(0); }
//server.C remote procedures; called by server stub #include <iostream.h> #include <string.h> #include <rpc/rpc.h> //* standard RPC include file */ extern "C"{ #include "testxdr.h" } //* this file is generated by rpcgen */ /* * Accept and print out client message and return a server string */ char **str_test_1(testxdr *xdrm) { static char *ptr = "Server say Hi to client!"; /* must be static */ cout << "Message from client: "<< xdrm->string_arg << "\n"; return(&ptr); }
%rpcgen testxdr.x %cc -c *.c testxdr_clnt.c: testxdr_svc.c: testxdr_xdr.c: %g++ -o server server.C testxdr_xdr.o testxdr_svc.o %g++ -o client client.C testxdr_xdr.o testxdr_clnt.o %exit exit
cl->cl_auth =
(3 basic types). :
AUTH_NULL
. null authentification (default)
AUTH_SYS
. Unix authentification causes following fields to be
included with each RPC request: time stamp, name of the local host,
Default used by NFS (network file system).
client's effective user id, list of all client groups.
AUTH_DES
. exchanges secure information using DES (data encryption
standard) for standard. Also AUTH_KERBEROS
.
More information in the way of Internet drafts:
Look at www.ietf.org
.