Linux RPC Comer Chapter 21 (RPCgen Concept) RFC 1057 – RPC Spec. UNIX Network Programming - Stevens 1 Using Remote Procedure Calls • As a program specification technique • For program specification and as an abstraction during design • Explicitly in the implementation • For design and implementation, from scratch • For design and implementation, with standard libraries • For automated implementation 2 RPC Programming Mechanisms ONC (Open Network Computing) • XDR library routines for data conversion • XDR library routines for complex data structures • RPC run-time library routines • Program generator tool 3 RPC Programming Process • Dividing the program into local and remote procedures. Proc A Client Stub RPC Server Stub Proc B 4 RPC Dispatching (Procedure Location) Proc A1 Proc A2 RPC RPC Dispatcher Server Stub Server Stub Proc B1 Proc B2 Client Stub Client Stub 5 RPC Interface Specification Proc A RPC Client Iface Client comm Server Comm Server Iface Proc B 6 RPCgen Input and Output • Input – Q.x Interface specification file • Output – Q.h – Q_xdr.cpp – Q_clnt.cpp – Q_svc.cpp Declarations header file XDR procedure calls used to marshal arguments Client-side communications stub Server-side communications stub 7 RPC Process Flow Client application Client interface Q_clnt.cpp Q.h Q.x rpcgen compile Client compile Server Q_xdr.cpp Q_svc.cpp Remote procedures Server interface 8 RPC General Build Procedure Develop Interface Develop Client Develop Server 9 Developing the Interface MyApp.x RPCgen MyApp_clnt.c Client Stub MyApp.h MyApp_xdr.c MyApp_svc.c Server Stub 10 Developing the Server MyApp.x RPCgen MySrvr.c MyApp_xdr.c MyApp.h MyApp_svc.c Server Stub C Compiler Linker MySrvr.exe 11 Developing the Client MyApp.idl RPCgen MyClnt.c MyApp_xdr.c MyApp.h MyApp_clnt.c Client Stub C Compiler Linker MyClnt.exe 12 How the Server Prepares for a Connection • • • • • • (Be certain that Portmap is running) Create UDP service Register UDP service with Portmap Create TCP service Register TCP service with Portmap Run service... – Uses select( ) to monitor ports. 13 Start Portmap Portmap is included in all Linux distributions as a standard server. Under Red Hat Fedora Open services applet ,select portmap and start From command line (as root) /sbin/services portmap start Other distributions should be similar 14 Server concurrency mode RPC servers can be created in either single threaded or multi-threaded mode. Servers automatically create and (when done) destroy a thread for each incoming connection. 15 Register the Server Program svc_register(port#, SERV#, VER#, serv_func, proto#); port#: port on which the service is active SERV#: unique number for the service VER#: version for this particular service serv_func: name by which this function is called proto#: IPPROTO_UDP or IPPROTO_TCP 16 How the Client Establishes a Connection • • • • Make a Remote Procedure Call Find the Server Host Computer Find Server Process Port # (through Portmap) Create a (connection) to the Server Process 17 How the Client Establishes a Connection clnt_create(server, SERV#, VER#, proto#); remote procedure call... Clnt_destroy(CLIENT); 18 Example #1 • Temperature Server (Fahrenheit to Centigrade) – Parameters passed as integers – TCP / IP port connection • Source files: – temp.x – Tclient.c – tempServer.c 19 temp.x program TEMPSERV { version TEMPVERS { int TempConv(int) = 1; //procedure number } = 1; //version number } = 77; //program number 20 TClient.c #include <stdio.h>, <stdlib.h>, <string.h> #include <rpc/rpc.h> #include "temp.h" #define YES 0 #define NO 1 void main (int argc, char *argv[]) { int tempconvert(int temp, char *srvr); int temperature, nuTemp; int loopFlag; char srvr[25]; CLIENT * cl; 21 TClient.c (cont) strcpy (srvr, argv[1]); cl = clnt_create(srvr, TEMPSERV, TEMPVERS, "tcp"); loopFlag = YES; while(loopFlag == YES) { printf("Enter temperature in Faherenheit (-999 to quit)"); scanf ("%d", &temperature); ans = tempconv_1(&temperature, cl); 22 TClient.c (cont) if (ans != NULL) nuTemp = * ans; if (temperature == -999 || temperature == -9999) { loopFlag = NO; printf ("Goodbye...\n"); continue; } printf("That’s %2d in centigrade\n", nuTemp); } clnt_destroy(cl); return 0; } 23 tempServer.c #include <stdlib.h>, <unistd.h>, <stdio.h> #include <rpc/rpc.h>, "temp.h" static int count; static int nuTemp; int *tempconv_1_svc (int *val, struct svc_req * rqst) { int oldTemp; oldTemp = *val; 24 tempServer.c if (oldTemp == -9999) { printf("We're shutting down...\n"); exit (0); } printf("We got a temperature of %d, ", oldTemp); count++; nuTemp = (int)((5*(oldTemp -32)) / 9.0); printf("and we returned a value of %d\n", nuTemp); sleep(1); return (&nuTemp); } 25 Files created with rpcgen • Input: – temp.x • Output – temp.h – temp_xdr.c (NULL file) – temp_clnt.c – temp_svc.c 26 temp.h #include <rpc/rpc.h> #ifdef __cplusplus extern "C" { #endif #define TEMPSERV 77 #define TEMPVERS 1 #if defined(__STDC__) || defined(__cplusplus) #define TempConv 1 extern int * tempconv_1(int *, CLIENT *); extern int * tempconv_1_svc(int *, struct svc_req *); extern int tempserv_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t); #ifdef __cplusplus} #endif #endif /* !_TEMP_H_RPCGEN */ 27 temp_xdr.c #include <rpc/rpc.h> #include "temp.h" 28 temp_clnt.c #include <memory.h> /* for memset */ #include "temp.h“ /* Default timeout can be changed using clnt_control() */ static struct timeval TIMEOUT = { 25, 0 }; int *tempconv_1(int *argp, CLIENT *clnt){ static int clnt_res; memset((char *)&clnt_res, 0, sizeof(clnt_res)); 29 temp_clnt.c (cont) if (clnt_call (clnt, TempConv, (xdrproc_t) xdr_int, (caddr_t) argp, (xdrproc_t) xdr_int, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res);} 30 temp_svc.c #include #include #include #include #include #include #include #include "temp.h“ <stdio.h> <stdlib.h> <rpc/pmap_clnt.h> <string.h> <memory.h> <sys/socket.h> <netinet/in.h> #ifndef SIG_PF #define SIG_PF void(*)(int) #endif 31 temp_svc.c (cont) static void tempserv_1(struct svc_req *rqstp, register SVCXPRT *transp){ union { int tempconv_1_arg; } argument; char *result; xdrproc_t _xdr_argument, _xdr_result; char *(*local)(char *, struct svc_req *); switch (rqstp->rq_proc) { case NULLPROC: (void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL); return; case TempConv: _xdr_argument = (xdrproc_t) xdr_int; _xdr_result = (xdrproc_t) xdr_int; local = (char *(*)(char *, struct svc_req *)) tempconv_1_svc; break; default: svcerr_noproc (transp); 32 return; } temp_svc.c (cont) memset ((char *)&argument, 0, sizeof (argument)); if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) { svcerr_decode (transp); return; } result = (*local)((char *)&argument, rqstp); if (result != NULL && !svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) { svcerr_systemerr (transp); } if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) { fprintf (stderr, "%s", "unable to free arguments"); exit (1); } return; } 33 temp_svc.c (cont) int main (int argc, char **argv){ register SVCXPRT *transp; pmap_unset (TEMPSERV, TEMPVERS); transp = svcudp_create(RPC_ANYSOCK); if (transp == NULL) { fprintf (stderr, "%s", "can’t create udp service."); exit(1); } if (!svc_register(transp, TEMPSERV, TEMPVERS, tempserv_1, IPPROTO_UDP)) { fprintf (stderr, "%s", "unable to register (TEMPSERV, TEMPVERS, udp)."); exit(1); } 34 temp_svc.c (cont) transp = svctcp_create(RPC_ANYSOCK, 0, 0); if (transp == NULL) { fprintf (stderr, "%s", "cannot create tcp service."); exit(1); } if (!svc_register(transp, TEMPSERV, TEMPVERS, tempserv_1, IPPROTO_TCP)) { fprintf (stderr, "%s", "unable to register (TEMPSERV, TEMPVERS, tcp)."); exit(1); } svc_run (); fprintf (stderr, "%s", "svc_run returned"); exit (1); /* NOTREACHED */} 35 Sample Client Output D:\data\RPC\onrpc_temp\client\Debug>client Enter the temperature in Faherenheit (-999 That would be 0 in centigrade Enter the temperature in Faherenheit (-999 That would be 37 in centigrade Enter the temperature in Faherenheit (-999 That would be 100 in centigrade Enter the temperature in Faherenheit (-999 Goodbye... localhost to quit)32 to quit)100 to quit)212 to quit)-9999 D:\data\RPC\onrpc_temp\client\Debug> 36 Sample Server Output D:\data\RPC\examples\onrpc_temp\server\Debug>server We got a temperature of 32, and we returned a value of 0 We got a temperature of 100, and we returned a value of 37 We got a temperature of 212, and we returned a value of 100 We're shutting down... D:\data\RPC\examples\onrpc_temp\server\Debug> 37 Summary • Linux RPC Implementation models SUN ONCRPC functionality • RPC specific programming limited to linking original applications code with rpcgen interface code. 38