Netbula White Paper

Porting Sun RPC to JRPC
Direct translation of SUN ONC RPC to JAVA

Copyright(C) Netbula, LLC 1997-1999 All rights reserved

To maintain full compatibilty between Sun RPC and JRPC, it is important to port the original C code for Sun RPC directly to Java(tm) without major alterations. Java(tm) is an OO language, it always speaks about classes. C does not have classes, it has only structs and functions. Fortunately, the Sun RPC is actually written in an Object-oriented fashion, only in C. In porting Sun RPC to Java(tm), we were able to identify the object classes used and their methods in the original C code and perform strightforward mappings to Java(tm). Once the classes and methods are identified, we could perform a simple translation of C code to Java(tm), thus maintain maximum compatibility.

Since C does not have classes, to represent an object with associated method, one has to use a C struct which contains function pointers, this C struct serves as an abstract base class, concrete object is created by assigning specific function pointers to the fields of the struct.

Let's look at the following core classes in Sun RPC, namely, XDR and CLIENT

The XDR classes

   typedef struct {
	
                enum xdr_op	x_op;		/* operation; fast additional param */
	
                struct xdr_ops {
		
                      bool_t	(*x_getlong)();	/* get a long from underlying stream */
                      bool_t	(*x_putlong)();	/* put a long to " */
                      bool_t	(*x_getbytes)();/* get some bytes from " */
		                bool_t	(*x_putbytes)();/* put some bytes to " */
                      u_int	(*x_getpostn)();/* returns bytes off from beginning */
                      bool_t  (*x_setpostn)();/* lets you reposition the stream */
                      long *	(*x_inline)();	/* buf quick ptr to buffered data */
                      void	(*x_destroy)();	/* free privates of this xdr_stream */
                } *x_ops;

	
   }XDR;

The XDR struct represents an abstract XDR stream, which has serveral abstract methods such as getlong(), putlong() to be implemented by the specific streams, such as memory stream, stdio stream, and tcp stream. For example,. the xdrmem_create() function creates an XDR stream filled with methods for input/output from a memory buffer.


Also, we have built-in methods, such as

xdr_int(XDR*, int*)

which is clearly a method of the XDR abstract class, implemented using the getlong(), putlong() functions.


Obviously, we have the following class relations:

class XDR {

asbtract getbytes(byte[]);

abstract void putbytes(byte[]);

void enc_int( int ) { /*convert int to bytes and call abstract putbytes() */ }

int dec_int() { /* call getbytes() and then convert to an int */}


}

The following classes only implements the abstract getbytes() and putbytes().

class XDRMem extends XDR { }

class XDRRec extends XDR { }

class XDRIOStream extends XDR { }

The following table summarizes the mapping from C to Java(tm)

C

Java(tm)

xdr.C XDR.java
xdr_mem.c XDRMem.java
xdr_rec.c XDRRec.java
xdr_stdio.c XDRIOStream.java

The RPC Client Classes

typedef struct _onc_client_t {
           AUTH	*cl_auth;			/* authenticator */
	
           struct clnt_ops {
		
               enum clnt_stat	(*cl_call)(struct _onc_client_t*, u_long, xdrproc_t, void*, xdrproc_t, void*, struct timeval);	/* call remote procedure */
		
               void		(*cl_geterr)();	/* get specific error code */
		
           } *cl_ops;
	
} CLIENT;

Similarly, an RPC client is represented by the structure named CLIENT, which has method cl_call() for making an RPC call, it also has an important member named AUTH for authentication purpose.


Just like the case with XDR, a CLIENT is abstract, it can't be directly used, only the non-abstract CLIENT created for specific protocols can be used to call RPC. clnttcp_create() creates a CLIENT handle for the TCP protocol, which contains a cl_call function pointer (clnttcp_call) specific to TCP, in OO language, clnttcp_create() is the constructor for a TCP client. Similarly, clntudp_create() is the constructor for a UDP client, and clntudp_call() is the overidden cl_call method.

The following table shows the direct mapping of the C code to JRPC classes

C

Java(tm)

CLIENT abstract class RPCClient {

abstract call();

}
Clnt_TCP.C ClientTCP.java:

class ClientTCP extends RPCClient {

/* Implements the call() method

specific to TCP

*/

}
clnttcp_create() Constructor of ClientTCP class
clnttcp_call() function call() method in ClientTCP
Clnt_UDP.C ClientUDP.java:

class ClientUDP extends RPCClient{

//implement the call() method specific to UDP

}
clntudp_create() Constructor of ClientUDP class
clntudp_call() function call() method in ClientUDP

The Sun RPC has another function to create a CLIENT, namely, clnt_create(). This function is a convenience function to create either a TCP or a UDP client based on the protocol string passed, associated with this there is a macro CLNT_CALL() which makes RPC on a generic CLIENT.

The C code for clnt_create(), looks like this

CLIENT *clnt_create( char *hostname, unsigned prog, unsigned vers, char *proto){

IF proto is "tcp" use clnttcp_create() to create a TCP client

ELSE use clntudp_create() to create a UDP client

}

The above logic is straightforwardly mapped to the constructor of the ClientGeneric class in Java(tm) RPC

C

Java(tm)

Clnt_Generic.C ClientGeneric.Java(tm), class name ClientGeneric
clnt_create() Constructor of ClientGeneric class, which creates an RPCClient based on whether protocol is TCP, UDP or HTTP. The created client handle is saved in a member variable cl.
CLNT_CALL() call() method of the ClientGeneric class, which simply delegates to cl.call().

The client stub function generated by Sun's rpcgen have protype as the following

return_type func ( ARG, CLIENT );

One easily identifies this as a method func() of a class derived from CLIENT.

The Server and other classes

The same mapping rules apply to the server side, we are not going to repeat the discussion but merely list the mappings in the following table.

C Java(tm)
struct AUTH Auth class
Authunix.c AuthUnix class
struct rpc_err rpc_err.java, rpc_err exception class
Svc.C file Svc.java
Svc_tcp.C file SvcTCP.java, TCPServer.java
svc_udp.C file SvcUDP.java, UDPServer.java
svc_run.c svc_run() method in Svc class
pmap_cln.c Pmap class
pmap_rmt.c rmt_call() in Pmap class

Copyright(C) Netbula, LLC 1997-1999. All rights reserved