org.acplt.oncrpc.server.package.html Maven / Gradle / Ivy
Show all versions of remotetea-oncrpc Show documentation
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.
© 2015 - 2024 Weber Informatics LLC | Privacy Policy