450 likes | 585 Views
Linux RPC. Comer Chapter 21 (RPCgen Concept) RFC 1057 – RPC Spec. UNIX Network Programming - Stevens. Sockets API Limitations. Must explicitly account for differences in systems Byte order (big-endian / little-endian) Limited to sending characters (without tricking the system)
E N D
Linux RPC Comer Chapter 21 (RPCgen Concept) RFC 1057 – RPC Spec. UNIX Network Programming - Stevens
Sockets API Limitations • Must explicitly account for differences in systems • Byte order (big-endian / little-endian) • Limited to sending characters (without tricking the system) • requires source and destination to implicitly understand the data transformation.
Client / Server Between SystemsOne Solution: • eXternalData Representation (XDR) • Developed by Sun Microsystems • A standard for representing data over the network. • Includes a set of library routines for converting data between local format and XDR format (either direction).
XDR Data Types • int 32 bits • unsigned int 32 bits • bool 32 bits • enum arbitrary • hyper 64 bits • unsigned hyper 64 bits • float 32 bits • double 64 bits • opaque arbitrary • String arbitrary • fixed array arbitrary • counted array arbitrary • structure arbitrary • discriminated union arbitrary. • void 0 • symbolic constant arbitrary • optional data arbitrary
XDR Data Conversion • Objective: • Gather all parameter data into a buffer in XDR format • Procedure: • Create a buffer (xdrmem_create)
XDR Data Conversion • Objective: • Gather all parameter data into a buffer in XDR format • Procedure: • Create a buffer (xdrmem_create) #include <rpc/xdr.h> #define BUFSIZE 4000 ... XDR * xdrs; char buf[BUFSIZE]; xdrmen_create(xdrs, buf, BUFSIZE, XDR_ENCODE);
XDR Data Conversion Routines xdr_bool (xdrs, ptrBool); xdr_bytes (xdrs,str,strSize,maxsize); xdr_char (xdrs, ptrChar); xdr_double(xdrs, prtDouble); xdr_enum(xdrs, ptrInt); xdr_float(xdrs, ptrFloat); xdr_int (xdrs, ptrInt); xdr_long (xdrs, ptrLong); xdr_opaque (xdrs, ptrChar, count); xdr_pointer (xdrs, ptrObj, pbjSize, xdrObj); xdrs_short (xdrs, ptrShort); xdrs_u_char (xdrs, ptrUchar); xdrs_u_int (xdrs, ptrUint); xdrs_u_long (xdrs, ptrUlong); xdrs_u_short (xdrs, ptrUshort); xdr_union (xdrs, ptrDiscrim, ptrUnion, choiceFcn, default); xdr_vector (xdrs, ptrArray, size, elemSize, elemProc); xdr_void ( );
XDR Data Conversion • Add data items in order to the buffer (after converting to XDR format) intmyInt; ... myInt = 260; xdr_int(xdrs, &myInt);
RPC Programming MechanismsONC (Open Network Computing) • XDR library routines for data conversion • XDR library routines for complex data structures • RPC run-time library routines • Program generator tool
RPC Programming Process • Dividing the program into local and remote procedures. RPC Proc A Server Stub Client Stub Proc B
RPC Dispatching(Procedure Location) RPC Proc A2 Dispatcher Proc A1 RPC Server Stub Server Stub Client Stub Client Stub Proc B1 Proc B2
RPC Interface Specification Proc A Server Comm RPC Client Iface Server Iface Client comm Proc B
RPCgen Input and Output • Input • Q.x Interface specification file • Output • Q.h Declarations header file • Q_xdr.cpp XDR procedure calls used to marshal arguments • Q_clnt.cpp Client-side communications stub • Q_svc.cpp Server-side communications stub
RPC Process Flow Client application Client interface Q_clnt.cpp compile Client Q.h rpcgen Q.x Q_xdr.cpp compile Server Q_svc.cpp Remote procedures Server interface
RPC General Build Procedure Develop Interface Develop Client Develop Server
Developing the Interface MyApp.x RPCgen MyApp_clnt.c Client Stub MyApp.h MyApp_svc.c Server Stub MyApp_xdr.c
Developing the Server MyApp.x RPCgen MySrvr.c MyApp_xdr.c MyApp.h C Compiler MyApp_svc.c Server Stub Linker MySrvr.exe
Developing the Client MyApp.x RPCgen MyClnt.c MyApp_xdr.c MyApp.h C Compiler MyApp_clnt.c Client Stub Linker MyClnt.exe
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.
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/service portmap start Other distributions should be similar
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.
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
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
How the Client Establishes a Connection clnt_create(server, SERV#, VER#, proto#); remote procedure call... Clnt_destroy(CLIENT);
Example #1 • Temperature Server (Fahrenheit to Centigrade) • Parameters passed as integers • TCP / IP port connection • Source files: • temp.x • Tclient.c • tempServer.c
temp.x program TEMPSERV { version TEMPVERS { intTempConv(int) = 1; //procedure number } = 1; //version number } = 77; //program number
TClient.c #include <stdio.h>, <stdlib.h>, <string.h> #include <rpc/rpc.h> #include "temp.h" #define YES 0 #define NO 1 void main (intargc, char *argv[]) { inttempconvert(int temp, char *srvr); int temperature, nuTemp; intloopFlag; char srvr[25]; CLIENT * cl;
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);
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; }
tempServer.c #include <stdlib.h>, <unistd.h>, <stdio.h> #include <rpc/rpc.h>, "temp.h" static int count; static intnuTemp; int *tempconv_1_svc (int *val, structsvc_req * rqst) { intoldTemp; oldTemp = *val;
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); }
Files created with rpcgen • Input: • temp.x • Output • temp.h • temp_xdr.c (NULL file) • temp_clnt.c • temp_svc.c
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 *, structsvc_req *); extern int tempserv_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t); #ifdef __cplusplus} #endif #endif /* !_TEMP_H_RPCGEN */
temp_xdr.c #include <rpc/rpc.h> #include "temp.h"
temp_clnt.c #include <memory.h> /* for memset */ #include "temp.h“ /* Default timeout can be changed using clnt_control() */ static structtimeval TIMEOUT = { 25, 0 }; int *tempconv_1(int *argp, CLIENT *clnt){ static intclnt_res; memset((char *)&clnt_res, 0, sizeof(clnt_res));
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);}
temp_svc.c #include "temp.h“ #include <stdio.h> #include <stdlib.h> #include <rpc/pmap_clnt.h> #include <string.h> #include <memory.h> #include <sys/socket.h> #include <netinet/in.h> #ifndef SIG_PF #define SIG_PF void(*)(int) #endif
temp_svc.c (cont) static void tempserv_1(structsvc_req *rqstp, register SVCXPRT *transp){ union { int tempconv_1_arg; } argument; char *result; xdrproc_t _xdr_argument, _xdr_result; char *(*local)(char *, structsvc_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 *, structsvc_req *)) tempconv_1_svc; break; default: svcerr_noproc (transp); 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; }
temp_svc.c (cont) int main (intargc, 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); }
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 */}
Sample Client Output D:\data\RPC\onrpc_temp\client\Debug>client localhost Enter the temperature in Faherenheit (-999 to quit)32 That would be 0 in centigrade Enter the temperature in Faherenheit (-999 to quit)100 That would be 37 in centigrade Enter the temperature in Faherenheit (-999 to quit)212 That would be 100 in centigrade Enter the temperature in Faherenheit (-999 to quit)-9999 Goodbye... D:\data\RPC\onrpc_temp\client\Debug>
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>
Summary • Linux RPC Implementation models SUN ONCRPC functionality • RPC specific programming limited to linking original applications code with rpcgen interface code.