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

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

There is a newer version: 1.1.6
Show newest version
/*
 * $Header: /home/harald/repos/remotetea.sf.net/remotetea/src/org/acplt/oncrpc/server/OncRpcTcpServerTransport.java,v 1.3 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 LICENSE.txt 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;
import java.net.ServerSocket;
import java.net.InetAddress;

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

    /**
     * Create a new instance of a OncRpcTcpServerTransport which
     * encapsulates TCP/IP-based XDR streams of an ONC/RPC server. This
     * particular server transport only waits for incoming connection requests
     * and then creates {@link OncRpcTcpConnectionServerTransport} server transports
     * to handle individual connections.
     * 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 port Number of port where the server will wait for incoming
     *   calls.
     * @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.
     * 
     * @throws OncRpcException if an RPC error occurs.
     * @throws IOException if an IO error occurs.
     */
    public OncRpcTcpServerTransport(OncRpcDispatchable dispatcher,
                                    int port,
                                    int program, int version,
                                    int bufferSize)
           throws OncRpcException, IOException {
        this(dispatcher, port,
             new OncRpcServerTransportRegistrationInfo[] {
                new OncRpcServerTransportRegistrationInfo(program, version)
             },
             bufferSize);
    }

    /**
     * Create a new instance of a OncRpcTcpServerTransport which
     * encapsulates TCP/IP-based XDR streams of an ONC/RPC server. This
     * particular server transport only waits for incoming connection requests
     * and then creates {@link OncRpcTcpConnectionServerTransport} server transports
     * to handle individual connections.
     *
     * @param dispatcher Reference to interface of an object capable of
     *   dispatching (handling) ONC/RPC calls.
     * @param port Number of port where the server will wait for incoming
     *   calls.
     * @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.
     * 
     * @throws OncRpcException if an RPC error occurs.
     * @throws IOException if an IO error occurs.
     */
    public OncRpcTcpServerTransport(OncRpcDispatchable dispatcher,
                                    int port,
                                    OncRpcServerTransportRegistrationInfo [] info,
                                    int bufferSize)
           throws OncRpcException, IOException {
        this(dispatcher, null, port, info, bufferSize);
    }

    /**
     * Create a new instance of a OncRpcTcpServerTransport which
     * encapsulates TCP/IP-based XDR streams of an ONC/RPC server. This
     * particular server transport only waits for incoming connection requests
     * and then creates {@link OncRpcTcpConnectionServerTransport} server transports
     * to handle individual connections.
     *
     * @param dispatcher Reference to interface of an object capable of
     *   dispatching (handling) ONC/RPC calls.
     * @param bindAddr The local Internet Address the server will bind to.
     * @param port Number of port where the server will wait for incoming
     *   calls.
     * @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.
     * 
     * @throws OncRpcException if an RPC error occurs.
     * @throws IOException if an IO error occurs.
     */
    public OncRpcTcpServerTransport(OncRpcDispatchable dispatcher,
                                    InetAddress bindAddr,
                                    int port,
                                    OncRpcServerTransportRegistrationInfo [] info,
                                    int bufferSize)
           throws OncRpcException, IOException {
        super(dispatcher, port, info);
        //
        // Make sure the buffer is large enough and resize system buffers
        // accordingly, if possible.
        //
        if ( bufferSize < 1024 ) {
            bufferSize = 1024;
        }
        this.bufferSize = bufferSize;
        socket = new ServerSocket(port, 0, bindAddr);
        if ( port == 0 ) {
            this.port = socket.getLocalPort();
        }
    }

    /**
     * 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. * In addition, all server transports handling the individual TCP/IP * connections will also be closed. The handler threads will therefore * either terminate directly or when they try 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 connections: it is // possible that that 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. // ServerSocket deadSocket = socket; socket = null; try { deadSocket.close(); } catch ( IOException e ) { } } // // Now close all per-connection transports currently open... // synchronized ( openTransports ) { while ( openTransports.size() > 0 ) { OncRpcTcpConnectionServerTransport transport = (OncRpcTcpConnectionServerTransport) openTransports.removeFirst(); transport.close(); } } } /** * Removes a TCP/IP server transport from the list of currently open * transports. * * @param transport Server transport to remove from the list of currently * open transports for this listening transport. */ protected void removeTransport(OncRpcTcpConnectionServerTransport transport) { synchronized ( openTransports ) { openTransports.remove((Object)transport); } } /** * Register the TCP/IP port where this server transport waits for incoming * requests with the ONC/RPC portmapper. * * @throws OncRpcException if the portmapper could not be contacted * successfully of if the portmapper rejected port registration(s). */ public void register() throws OncRpcException { try { OncRpcPortmapClient portmapper = new OncRpcPortmapClient(InetAddress.getByName("127.0.0.1")); int size = info.length; for ( int idx = 0; idx < size; ++idx ) { // // Try to register the port for our transport with the local ONC/RPC // portmapper. If this fails, bail out with an exception. // if ( !portmapper.setPort(info[idx].program, info[idx].version, OncRpcProtocols.ONCRPC_TCP, port) ) { throw(new OncRpcException(OncRpcException.RPC_CANNOTREGISTER)); } } } catch ( IOException e ) { throw(new OncRpcException(OncRpcException.RPC_FAILED)); } } /** * Do not call. * * @throws Error because this method must not be called for a listening * server transport. */ public void retrieveCall(XdrAble call) throws OncRpcException, IOException { throw(new Error("OncRpcTcpServerTransport.retrieveCall() is abstract " +"and can not be called.")); } /** * Do not call. * * @throws Error because this method must not be called for a listening * server transport. */ protected XdrDecodingStream getXdrDecodingStream() { throw(new Error("OncRpcTcpServerTransport.getXdrDecodingStream() is abstract " +"and can not be called.")); } /** * Do not call. * * @throws Error because this method must not be called for a listening * server transport. */ protected void endDecoding() throws OncRpcException, IOException { throw(new Error("OncRpcTcpServerTransport.endDecoding() is abstract " +"and can not be called.")); } /** * Do not call. * * @throws Error because this method must not be called for a listening * server transport. */ protected XdrEncodingStream getXdrEncodingStream() { throw(new Error("OncRpcTcpServerTransport.getXdrEncodingStream() is abstract " +"and can not be called.")); } /** * Do not call. * * @throws Error because this method must not be called for a listening * server transport. */ protected void beginEncoding(OncRpcCallInformation callInfo, OncRpcServerReplyMessage state) throws OncRpcException, IOException { throw(new Error("OncRpcTcpServerTransport.beginEncoding() is abstract " +"and can not be called.")); } /** * Do not call. * * @throws Error because this method must not be called for a listening * server transport. */ protected void endEncoding() throws OncRpcException, IOException { throw(new Error("OncRpcTcpServerTransport.endEncoding() is abstract " +"and can not be called.")); } /** * Do not call. * * @throws Error because this method must not be called for a listening * server transport. */ protected void reply(OncRpcCallInformation callInfo, OncRpcServerReplyMessage state, XdrAble reply) throws OncRpcException, IOException { throw(new Error("OncRpcTcpServerTransport.reply() is abstract " +"and can not be called.")); } /** * Creates a new thread and uses this thread to listen to incoming * ONC/RPC requests, then dispatches them and finally sends back the * appropriate reply messages. Control in the calling thread immediately * returns after the handler thread has been created. * *

For every incomming TCP/IP connection a handler thread is created * to handle ONC/RPC calls on this particular connection. */ public void listen() { // // Create a new (daemon) thread which will handle incoming connection // requests. // Thread listenThread = new Thread("TCP server transport listener thread") { public void run() { for ( ;; ) { try { // // Now wait for (new) connection requests to come in. // ServerSocket myServerSocket = socket; if ( myServerSocket == null ) { break; } Socket newSocket = myServerSocket.accept(); OncRpcTcpConnectionServerTransport transport = new OncRpcTcpConnectionServerTransport( dispatcher, newSocket, info, bufferSize, OncRpcTcpServerTransport.this, transmissionTimeout); synchronized ( openTransports ) { openTransports.add((Object)transport); } // // Let the newly created transport object handle this // connection. Note that it will create its own // thread for handling. // Before, we pass the provided authentication schemes. // transport.setAuthenticationSchemes(getAuthenticationSchemes()); transport.listen(); } catch ( OncRpcException e ) { } catch ( IOException e ) { // // We are just ignoring most of the IOExceptions as // they might be thrown, for instance, if a client // attempts a connection and resets it before it is // pulled off by accept(). If the socket has been // gone away after an IOException this means that the // transport has been closed, so we end this thread // gracefully. // if ( socket == null ) { break; } } } } }; // // Now make the new handling thread a deamon and start it, so it // sits there waiting for incoming TCP/IP connection requests. // listenThread.setDaemon(true); listenThread.start(); } /** * Set the timeout used during transmission of data. If the flow of data * when sending calls or receiving replies blocks longer than the given * timeout, an exception is thrown. The timeout must be > 0. * * @param milliseconds Transmission timeout in milliseconds. */ public void setTransmissionTimeout(int milliseconds) { if ( milliseconds <= 0 ) { throw(new IllegalArgumentException("transmission timeout must be > 0")); } transmissionTimeout = milliseconds; } /** * Retrieve the current timeout used during transmission phases (call and * reply phases). * * @return Current transmission timeout. */ public int getTransmissionTimeout() { return transmissionTimeout; } /** * 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) { this.characterEncoding = 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 characterEncoding; } /** * TCP socket used for stream-based communication with ONC/RPC * clients. */ private ServerSocket socket; /** * Size of send/receive buffers to use when encoding/decoding XDR data. */ private int bufferSize; /** * Collection containing currently open transports. */ private TransportList openTransports = new TransportList(); /** * Timeout during the phase where data is received within calls, or data is * sent within replies. */ protected int transmissionTimeout = 30000; /** * Encoding to use when deserializing strings or null if * the system's default encoding should be used. */ private String characterEncoding = null; /** * Minumum implementation of a double linked list which notices which * transports are currently open and have to be shut down when this * listening transport is shut down. The only reason why we have this * code here instead of using java.util.LinkedList is due to JDK 1.1 * compatibility. * *

Note that the methods are not synchronized as we leave this up * to the caller, who can thus optimize access during critical sections. */ private class TransportList { /** * Create a new instance of a list of open transports. */ public TransportList() { // // Link header node with itself, so it is its own successor // and predecessor. Using a header node excuses us from checking // for the special cases of first and last node (or both at // the same time). // head.next = head; head.prev = head; } /** * Add new transport to list of open transports. The new transport * is always added immediately after the head of the linked list. * * @param o The transport which will be associated with new list node. */ public void add(Object o) { Node node = new Node(o); node.next = head.next; head.next = node; node.prev = head; node.next.prev = node; ++size; } /** * Remove given transport from list of open transports. * * @param o The transport to remove. * * @return True if an entry with the given transport has been found and removed, false otherwise. */ public boolean remove(Object o) { Node node = head.next; while ( node != head ) { if ( node.item == o ) { node.prev.next = node.next; node.next.prev = node.prev; --size; return true; } node = node.next; } return false; } /** * Removes and returns the first open transport from list. * * @return The first transport of the actual list. */ public Object removeFirst() { // // Do not remove the header node. // if ( size == 0 ) { throw(new java.util.NoSuchElementException()); } Node node = head.next; head.next = node.next; node.next.prev = head; --size; return node.item; } /** * Returns the number of (open) transports in this list. * * @return the number of (open) transports. */ public int size() { return size; } /** * Head node for list of open transports which does not represent * an open transport but instead excuses us of dealing with all * the special cases of real nodes at the begin or end of the list. */ private Node head = new Node(null); /** * Number of (real) open transports currently registered in this * list. */ private int size = 0; /** * Node class referencing an individual open transport and holding * references to the previous and next open transports. */ private class Node { /** * Create a new instance of a node object and let it reference * an open transport. The creator of this object is then * responsible for adding this node to the circular list itself. * * @param item The transport to associate with the new node instance. */ public Node(Object item) { this.item = item; } /** * Next item node (in other words: next open transport) * in the list. This will never be null for the * first item, but instead reference the last item. Thus, the * list is circular. */ Node next; /** * Previous item node (in other words: previous open transport) * in the list. This will never be null for the * last item, but instead reference the first item. Thus, the * list is circular. */ Node prev; /** * The item/object placed at this position in the list. This * currently always references an open transport. */ Object item; } } } // End of OncRpcTcpServerTransport.java





© 2015 - 2024 Weber Informatics LLC | Privacy Policy