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

org.acplt.oncrpc.server.OncRpcTcpConnectionServerTransport Maven / Gradle / Ivy

/*
 * $Header: /cvsroot/remotetea/remotetea/src/org/acplt/oncrpc/server/OncRpcTcpConnectionServerTransport.java,v 1.5 2008/01/02 15:13:35 haraldalbrecht Exp $
 *
 * Copyright (c) 1999, 2000
 * Lehrstuhl fuer Prozessleittechnik (PLT), RWTH Aachen
 * D-52064 Aachen, Germany.
 * All rights reserved.
 *
 * 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 COPYING.LIB for more
 * details); if not, write to the Free Software Foundation, Inc.,
 * 675 Mass Ave, Cambridge, MA 02139, USA.
 */

package org.acplt.oncrpc.server;

import org.acplt.oncrpc.*;
import java.io.IOException;
import java.net.Socket;

/**
 * Instances of class OncRpcTcpServerTransport encapsulate
 * TCP/IP-based XDR streams of ONC/RPC servers. This server transport class
 * is responsible for receiving ONC/RPC calls over TCP/IP.
 *
 * @see OncRpcServerTransport
 * @see OncRpcTcpServerTransport
 * @see OncRpcUdpServerTransport
 *
 * @version $Revision: 1.5 $ $Date: 2008/01/02 15:13:35 $ $State: Exp $ $Locker:  $
 * @author Harald Albrecht
 */
public class OncRpcTcpConnectionServerTransport extends OncRpcServerTransport {

    /**
     * Create a new instance of a OncRpcTcpSConnectionerverTransport
     * which encapsulates TCP/IP-based XDR streams of an ONC/RPC server. This
     * particular server transport handles individual ONC/RPC connections over
     * TCP/IP. This constructor is a convenience constructor for those transports
     * handling only a single ONC/RPC program and version number.
     *
     * @param dispatcher Reference to interface of an object capable of
     *   dispatching (handling) ONC/RPC calls.
     * @param socket TCP/IP-based socket of new connection.
     * @param program Number of ONC/RPC program handled by this server
     *   transport.
     * @param version Version number of ONC/RPC program handled.
     * @param bufferSize Size of buffer used when receiving and sending
     *   chunks of XDR fragments over TCP/IP. The fragments built up to
     *   form ONC/RPC call and reply messages.
     * @param parent Parent server transport which created us.
     * @param transmissionTimeout Inherited transmission timeout.
     */
    public OncRpcTcpConnectionServerTransport(OncRpcDispatchable dispatcher,
                                              Socket socket,
                                              int program, int version,
                                              int bufferSize,
                                              OncRpcTcpServerTransport parent,
                                              int transmissionTimeout)
           throws OncRpcException, IOException {
        this(dispatcher, socket,
             new OncRpcServerTransportRegistrationInfo[] {
                new OncRpcServerTransportRegistrationInfo(program, version)
             },
             bufferSize, parent, transmissionTimeout);
    }

    /**
     * Create a new instance of a OncRpcTcpSConnectionerverTransport
     * which encapsulates TCP/IP-based XDR streams of an ONC/RPC server. This
     * particular server transport handles individual ONC/RPC connections over
     * TCP/IP.
     *
     * @param dispatcher Reference to interface of an object capable of
     *   dispatching (handling) ONC/RPC calls.
     * @param socket TCP/IP-based socket of new connection.
     * @param info Array of program and version number tuples of the ONC/RPC
     *   programs and versions handled by this transport.
     * @param bufferSize Size of buffer used when receiving and sending
     *   chunks of XDR fragments over TCP/IP. The fragments built up to
     *   form ONC/RPC call and reply messages.
     * @param parent Parent server transport which created us.
     * @param transmissionTimeout Inherited transmission timeout.
     */
    public OncRpcTcpConnectionServerTransport(OncRpcDispatchable dispatcher,
                                              Socket socket,
                                              OncRpcServerTransportRegistrationInfo [] info,
                                              int bufferSize,
                                              OncRpcTcpServerTransport parent,
                                              int transmissionTimeout)
           throws OncRpcException, IOException {
        super(dispatcher, 0, info);
        this.parent = parent;
        this.transmissionTimeout = transmissionTimeout;
        //
        // Make sure the buffer is large enough and resize system buffers
        // accordingly, if possible.
        //
        if ( bufferSize < 1024 ) {
            bufferSize = 1024;
        }
        this.socket = socket;
        this.port = socket.getLocalPort();
        socketHelper = new OncRpcTcpSocketHelper(socket);
        if ( socketHelper.getSendBufferSize() < bufferSize ) {
            socketHelper.setSendBufferSize(bufferSize);
        }
        if ( socketHelper.getReceiveBufferSize() < bufferSize ) {
            socketHelper.setReceiveBufferSize(bufferSize);
        }
        //
        // Create the necessary encoding and decoding streams, so we can
        // communicate at all.
        //
        sendingXdr = new XdrTcpEncodingStream(socket, bufferSize);
        receivingXdr = new XdrTcpDecodingStream(socket, bufferSize);
        //
        // Inherit the character encoding setting from the listening
        // transport (parent transport).
        //
        setCharacterEncoding(parent.getCharacterEncoding());
    }

    /**
     * Close the server transport and free any resources associated with it.
     *
     * 

Note that the server transport is not deregistered. You'll * have to do it manually if you need to do so. The reason for this * behaviour is, that the portmapper removes all entries regardless of * the protocol (TCP/IP or UDP/IP) for a given ONC/RPC program number * and version. * *

Calling this method on a OncRpcTcpServerTransport * results in the listening TCP network socket immediately being closed. * The handler thread will therefore either terminate directly or when * it tries to sent back replies. */ public void close() { if ( socket != null ) { // // Since there is a non-zero chance of getting race conditions, // we now first set the socket instance member to null, before // we close the corresponding socket. This avoids null-pointer // exceptions in the method which waits for new requests: it is // possible that this method is awakened because the socket has // been closed before we could set the socket instance member to // null. Many thanks to Michael Smith for tracking down this one. // Socket deadSocket = socket; socket = null; try { deadSocket.close(); } catch ( IOException e ) { } } if ( sendingXdr != null ) { XdrEncodingStream deadXdrStream = sendingXdr; sendingXdr = null; try { deadXdrStream.close(); } catch ( IOException e ) { } catch ( OncRpcException e ) { } } if ( receivingXdr != null ) { XdrDecodingStream deadXdrStream = receivingXdr; receivingXdr = null; try { deadXdrStream.close(); } catch ( IOException e ) { } catch ( OncRpcException e ) { } } if ( parent != null ) { parent.removeTransport(this); parent = null; } } /** * Finalize object by making sure that we're removed from the list * of open transports which our parent transport maintains. */ protected void finalize() { if ( parent != null ) { parent.removeTransport(this); } } /** * Do not call. * * @throws Error because this method must not be called for an * individual TCP/IP-based server transport. */ public void register() throws OncRpcException { throw(new Error("OncRpcTcpServerTransport.register() is abstract " +"and can not be called.")); } /** * Retrieves the parameters sent within an ONC/RPC call message. It also * makes sure that the deserialization process is properly finished after * the call parameters have been retrieved. Under the hood this method * therefore calls {@link XdrDecodingStream#endDecoding} to free any * pending resources from the decoding stage. * * @throws OncRpcException if an ONC/RPC exception occurs, like the data * could not be successfully deserialized. * @throws IOException if an I/O exception occurs, like transmission * failures over the network, etc. */ public void retrieveCall(XdrAble call) throws OncRpcException, IOException { call.xdrDecode(receivingXdr); if ( pendingDecoding ) { pendingDecoding = false; receivingXdr.endDecoding(); } } /** * Returns XDR stream which can be used for deserializing the parameters * of this ONC/RPC call. This method belongs to the lower-level access * pattern when handling ONC/RPC calls. * */ protected XdrDecodingStream getXdrDecodingStream() { return receivingXdr; } /** * Finishes call parameter deserialization. Afterwards the XDR stream * returned by {@link #getXdrDecodingStream} must not be used any more. * This method belongs to the lower-level access pattern when handling * ONC/RPC calls. * * @throws OncRpcException if an ONC/RPC exception occurs, like the data * could not be successfully deserialized. * @throws IOException if an I/O exception occurs, like transmission * failures over the network, etc. */ protected void endDecoding() throws OncRpcException, IOException { if ( pendingDecoding ) { pendingDecoding = false; receivingXdr.endDecoding(); } } /** * Returns XDR stream which can be used for eserializing the reply * to this ONC/RPC call. This method belongs to the lower-level access * pattern when handling ONC/RPC calls. * * @return Reference to enecoding XDR stream. */ protected XdrEncodingStream getXdrEncodingStream() { return sendingXdr; } /** * Begins the sending phase for ONC/RPC replies. * This method belongs to the lower-level access pattern when handling * ONC/RPC calls. * * @param callInfo Information about ONC/RPC call for which we are about * to send back the reply. * @param state ONC/RPC reply header indicating success or failure. * * @throws OncRpcException if an ONC/RPC exception occurs, like the data * could not be successfully serialized. * @throws IOException if an I/O exception occurs, like transmission */ protected void beginEncoding(OncRpcCallInformation callInfo, OncRpcServerReplyMessage state) throws OncRpcException, IOException { // // In case decoding has not been properly finished, do it now to // free up pending resources, etc. // if ( pendingDecoding ) { pendingDecoding = false; receivingXdr.endDecoding(); } // // Now start encoding using the reply message header first... // pendingEncoding = true; sendingXdr.beginEncoding(callInfo.peerAddress, callInfo.peerPort); state.xdrEncode(sendingXdr); } /** * Finishes encoding the reply to this ONC/RPC call. Afterwards you must * not use the XDR stream returned by {@link #getXdrEncodingStream} any * longer. * * @throws OncRpcException if an ONC/RPC exception occurs, like the data * could not be successfully serialized. * @throws IOException if an I/O exception occurs, like transmission * failures over the network, etc. */ protected void endEncoding() throws OncRpcException, IOException { // // Close the case. Finito. // sendingXdr.endEncoding(); pendingEncoding = false; } /** * Send back an ONC/RPC reply to the original caller. This is rather a * low-level method, typically not used by applications. Dispatcher handling * ONC/RPC calls have to use the * {@link OncRpcCallInformation#reply(XdrAble)} method instead on the * call object supplied to the handler. * * @param callInfo information about the original call, which are necessary * to send back the reply to the appropriate caller. * @param state ONC/RPC reply message header indicating success or failure * and containing associated state information. * @param reply If not null, then this parameter references * the reply to be serialized after the reply message header. * * @throws OncRpcException if an ONC/RPC exception occurs, like the data * could not be successfully serialized. * @throws IOException if an I/O exception occurs, like transmission * failures over the network, etc. * * @see OncRpcCallInformation * @see OncRpcDispatchable */ protected void reply(OncRpcCallInformation callInfo, OncRpcServerReplyMessage state, XdrAble reply) throws OncRpcException, IOException { beginEncoding(callInfo, state); if ( reply != null ) { reply.xdrEncode(sendingXdr); } endEncoding(); } /** * Creates a new thread and uses this thread to handle the new connection * to receive ONC/RPC requests, then dispatching them and finally sending * back reply messages. Control in the calling thread immediately * returns after the handler thread has been created. * *

Currently only one call after the other is dispatched, so no * multithreading is done when receiving multiple calls. Instead, later * calls have to wait for the current call to finish before they are * handled. */ public void listen() { Thread listener = new Thread("TCP server transport connection thread") { public void run() { _listen(); } }; listener.setDaemon(true); listener.start(); } /** * The real workhorse handling incoming requests, dispatching them and * sending back replies. */ private void _listen() { OncRpcCallInformation callInfo = new OncRpcCallInformation(this); for ( ;; ) { // // Start decoding the incomming call. This involves remembering // from whom we received the call so we can later send back the // appropriate reply message. // try { socket.setSoTimeout(0); pendingDecoding = true; receivingXdr.beginDecoding(); callInfo.peerAddress = receivingXdr.getSenderAddress(); callInfo.peerPort = receivingXdr.getSenderPort(); socket.setSoTimeout(transmissionTimeout); } catch ( IOException e ) { // // In case of I/O Exceptions (especially socket exceptions) // close the file and leave the stage. There's nothing we can // do anymore. // close(); return; } catch ( OncRpcException e ) { // // In case of ONC/RPC exceptions at this stage kill the // connection. // close(); return; } try { // // Pull off the ONC/RPC call header of the XDR stream. // callInfo.callMessage.xdrDecode(receivingXdr); } catch ( IOException e ) { // // In case of I/O Exceptions (especially socket exceptions) // close the file and leave the stage. There's nothing we can // do anymore. // close(); return; } catch ( OncRpcException e ) { // // In case of ONC/RPC exceptions at this stage we're silently // ignoring that there was some data coming in, as we're not // sure we got enough information to send a matching reply // message back to the caller. // if ( pendingDecoding ) { pendingDecoding = false; try { receivingXdr.endDecoding(); } catch ( IOException e2 ) { close(); return; } catch ( OncRpcException e2 ) { } } continue; } try { // // Let the dispatcher retrieve the call parameters, work on // it and send back the reply. // To make it once again clear: the dispatch called has to // pull off the parameters of the stream! // dispatcher.dispatchOncRpcCall(callInfo, callInfo.callMessage.program, callInfo.callMessage.version, callInfo.callMessage.procedure); } catch ( Exception e ) { // // In case of some other runtime exception, we report back to // the caller a system error. We can not do this if we don't // got the exception when serializing the reply, in this case // all we can do is to drop the connection. If a reply was not // yet started, we can safely send a system error reply. // if ( pendingEncoding ) { close(); // Drop the connection... return; // ...and kill the transport. } // // Looks safe, so we try to send back an error reply. // if ( pendingDecoding ) { pendingDecoding = false; try { receivingXdr.endDecoding(); } catch ( IOException e2 ) { close(); return; } catch ( OncRpcException e2 ) { } } // // Check for authentication exceptions, which are reported back // as is. Otherwise, just report a system error // -- very generic, indeed. // try { if ( e instanceof OncRpcAuthenticationException ) { callInfo.failAuthenticationFailed( ((OncRpcAuthenticationException) e).getAuthStatus()); } else { callInfo.failSystemError(); } } catch ( IOException e2 ) { close(); return; } catch ( OncRpcException e2 ) { } // // Phew. Done with the error reply. So let's wait for new // incoming ONC/RPC calls... // } } } /** * Set the character encoding for (de-)serializing strings. * * @param characterEncoding the encoding to use for (de-)serializing strings. * If null, the system's default encoding is to be used. */ public void setCharacterEncoding(String characterEncoding) { sendingXdr.setCharacterEncoding(characterEncoding); receivingXdr.setCharacterEncoding(characterEncoding); } /** * Get the character encoding for (de-)serializing strings. * * @return the encoding currently used for (de-)serializing strings. * If null, then the system's default encoding is used. */ public String getCharacterEncoding() { return sendingXdr.getCharacterEncoding(); } /** * TCP socket used for stream-based communication with ONC/RPC * clients. */ private Socket socket; /** * Socket helper object supplying missing methods for JDK 1.1 * backwards compatibility. So much for compile once, does not run * everywhere. */ private OncRpcTcpSocketHelper socketHelper; /** * XDR encoding stream used for sending replies via TCP/IP back to an * ONC/RPC client. */ private XdrTcpEncodingStream sendingXdr; /** * XDR decoding stream used when receiving requests via TCP/IP from * ONC/RPC clients. */ private XdrTcpDecodingStream receivingXdr; /** * Indicates that BeginDecoding has been called for the * receiving XDR stream, so that it should be closed later using * EndDecoding. */ private boolean pendingDecoding = false; /** * Indicates that BeginEncoding has been called for the * sending XDR stream, so in face of exceptions we can not send an * error reply to the client but only drop the connection. */ private boolean pendingEncoding = false; /** * Reference to the TCP/IP transport which created us to handle a * new ONC/RPC connection. */ private OncRpcTcpServerTransport parent; /** * Timeout during the phase where data is received within calls, or data is * sent within replies. */ protected int transmissionTimeout; } // End of OncRpcTcpConnectionServerTransport.java





© 2015 - 2024 Weber Informatics LLC | Privacy Policy