All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.acplt.oncrpc.server.package.html Maven / Gradle / Ivy

There is a newer version: 1.1.6
Show newest version


ONC/RPC Server for Java package



ONC/RPC Server support package.

This package implements classes needed to write ONC/RPC servers according to Sun's ONC/RPC Remote Procedure Call specification (see RFC 1831, RFC 1832, RFC 1833).

Here is a short introduction to writing ONC/RPC servers. However, at the moment this might be not as convenient as you would like it to be, but rather low-level. Nevertheless, here are the basic steps to write a simple ONC/RPC server. Please also take a look at src/tests/org/acplt/oncrpc/ServerTest.java.

To implement an ONC/RPC server, you need to implement the OncRpcDispatchable interface. This requires implementing the dispatchOncRpcCall method, which handles incoming ONC/RPC calls. In the following code snippet we show how to handle the ping request (ONC/RPC procedure number 0):

public void dispatchOncRpcCall(OncRpcCallInformation call,
                               int program, int version, int procedure)
       throws OncRpcException, IOException {
    System.out.println("Incomming call for program "
                       + Integer.toHexString(program)
                       + "; version " + version
                       + "; procedure " + Integer.toHexString(procedure));
    switch ( procedure ) {
    //
    // Implement ping call...
    //
    case 0:
        call.retrieveCall(XdrVoid.XDR_VOID);
        call.reply(XdrVoid.XDR_VOID);
        break;
    //
    // For all unknown calls, send back an error reply.
    //
    default:
        call.failProcedureUnavailable();
    }
}

For every incoming ONC/RPC call, you'll receive some information about the call through the call parameter (of class OncRpcCallInformation). The call object is necessary to retrieve the parameters of the call as well as to sent back the reply. For the ping call (procedure number 0), the ONC/RPC dispatcher shown above simply retrieves the parameters using retrieveCall(XdrAble). Because the call expects no parameters, we supply the static void object XdrVoid.XDR_VOID to the retrieveCall method.

To send back the reply for the ping call, we use OncRpcCallInformation(XdrAble). Again, the caller does not expect any reply, so we specify the static void object XdrVoid.XDR_VOID once more. Then, we simply return and let the ONC/RPC magic sending back the reply.

In case we receive an ONC/RPC call for an unknown procedure (and / or version) we simply call the failProcedureUnavailable() method of the call object.

Now that we have solved the handling of ONC/RPC calls, we can now set up the stage, also known as an ONC/RPC server. To receive incoming calls, you first need to create so-called ONC/RPC server transports. In our example we will create one transport for each the UDP/IP and TCP/IP protocols. When creating a server transport, you need to specify in the call to the constructor:

  • the object which will handle incoming ONC/RPC calls,
  • the port number where to wait for incoming calls (if you do not need to listen at a specific port number, just specify 0, so the system will choose the next free port number for you),
  • the program number to handle through the transport,
  • the program's version number,
  • and finally an optional buffer size. This buffer size is especially important for UDP/IP-based transports, as they are only able to receive calls and send back replies not larger than the buffer size. For TCP/IP-based transport the buffer size only affects how efficient the network communication will be, for instance, how often the buffer needs to be flushed and data transmitted over the network. Especially with large calls or replies, larger buffer sizes can improve communication speed.
OncRpcUdpServerTransport udpTrans =
    new OncRpcUdpServerTransport(this, 55555, 0x49679, 1, 8192);
OncRpcTcpServerTransport tcpTrans =
    new OncRpcTcpServerTransport(this, 55555, 0x49679, 1, 8192);

When you're ready, you should first register your ONC/RPC server with the (local) portmapper by calling the register() method on all server transports you created during the previous step. Then start listening on these transports by calling their listen() methods.

udpTrans.register();
tcpTrans.register();

tcpTrans.listen();
udpTrans.listen();

System.out.println("Server started.");

Note that the listen() methods will create new threads, which then will be responsible for handling incoming ONC/RPC calls. Note that you may need to make your ONC/RPC dispatch handler (OncRpcDispatchable) synchronized if you can not handle simultaneous calls from multiple threads at the same time.

The tricky part is stopping the server somehow. Unfortunately, this is not an easy issue on Java platforms and up to you. For an example, look at the source of the src/tests/org/acplt/oncrpc/ServerTest.java example. Basically, this example uses the ONC/RPC call 42 to shut down a server.

After you have received the shutdown notification you can shut down the server transports (for instance) from your main thread using the close() method:

tcpTrans.unregister();
tcpTrans.close();

udpTrans.unregister();
udpTrans.close();

System.out.println("Server shut down.");

You should also deregister your server from the portmapper at the same time you're closing the transports. Note that the OncRpcTcpServerTransport.close() method also closes all currently open TCP/IP transports which have been created to handle individual TCP/IP connections from individual clients.

Now that's basically all you need to know to write ONC/RPC servers. However, if you plan to mess with authentication, read on...

ONC/RPC authentication on the server side is done within the call dispatcher. Before executing an ONC/RPC call, first check the authentication object for kosher information:

public void dispatchOncRpcCall(OncRpcCallInformation call,
                               int program, int version, int procedure)
       throws OncRpcException, IOException {
    switch ( call.callMessage.auth.getAuthenticationType() )
    case OncRpcAuthType.ONCRPC_AUTH_UNIX:
        ...
        break;
    case OncRpcAuthType.ONCRPC_AUTH_SHORT:
        ...
        break;
    case OncRpcAuthType.ONCRPC_AUTH_NONE:
    default:
        throw(new OncRpcAuthenticationException(
                      OncRpcAuthStatus.ONCRPC_AUTH_BADCRED));
    }

The example above is a very restrictive one in that it even forbids ONC/RPC clients to ping the server without proper authentication.

In a more elaborate example below you can see how to handle authentication of type AUTH_UNIX. It also shows how to use shorthand credentials, if you like.

public void dispatchOncRpcCall(OncRpcCallInformation call,
                               int program, int version, int procedure)
       throws OncRpcException, IOException {
    switch ( call.callMessage.auth.getAuthenticationType() )
    case OncRpcAuthType.ONCRPC_AUTH_UNIX:
        OncRpcServerAuthUnix auth = (OncRpcServerAuthUnix) call.callMessage.auth;
        if ( (auth.uid != 42)
             && (auth.gid != 815) ) {
            throw(new OncRpcAuthenticationException(
                          OncRpcAuthStatus.ONCRPC_AUTH_BADCRED));
        }
        //
        // Suggest shorthand authentication...
        //
        XdrBufferEncodingStream xdr = new XdrBufferEncodingStream(8);
        xdr.beginEncoding(null, 0);
        xdr.xdrEncodeInt(42);
        xdr.xdrEncodeInt(~42);
        xdr.endEncoding();
        //
        // ATTENTION: this will return the *whole* buffer created by the
        // constructor of XdrBufferEncodingStream(len) above. So make sure
        // that you really want to return the whole buffer!
        //
        auth.setShorthandVerifier(xdr.getXdrData());
        break;

    case OncRpcAuthType.ONCRPC_AUTH_SHORT:
        //
        // Check shorthand credentials.
        //
        OncRpcServerAuthShort auth = (OncRpcServerAuthShort) call.callMessage.auth;
        XdrBufferDecodingStream xdr =
            new XdrBufferDecodingStream(auth.getShorthandCred());
        xdr.beginDecoding();
        int credv1 = xdr.xdrDecodeInt();
        int credv2 = xdr.xdrDecodeInt();
        xdr.endDecoding();
        if ( credv1 != ~credv2 ) {
            throw(new OncRpcAuthenticationException(
                          OncRpcAuthStatus.ONCRPC_AUTH_REJECTEDCRED));
        }
        if ( (++shorthandCredCounter % 3) == 0 ) {
            throw(new OncRpcAuthenticationException(
                          OncRpcAuthStatus.ONCRPC_AUTH_REJECTEDCRED));
        }
        break;

    case OncRpcAuthType.ONCRPC_AUTH_NONE:
        if ( procedure != 0 ) {
            throw(new OncRpcAuthenticationException(
                          OncRpcAuthStatus.ONCRPC_AUTH_BADCRED));
        }

    default:
        throw(new OncRpcAuthenticationException(
                      OncRpcAuthStatus.ONCRPC_AUTH_BADCRED));
    }
    
    switch ( procedure ) {
        ...
    }
}

This package is part of the ACPLT/KS ACPLTea Java Library package.

(c) 1999, 2006 Harald Albrecht.
(c) 1999 Lehrstuhl für Prozeßleittechnik, Aachen University of Technology, Germany.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details.

You should have received a copy of the GNU Library General Public License along with this program (see the file LICENSE.txt for more details); if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.