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

org.filesys.oncrpc.portmap.PortMapperServer Maven / Gradle / Ivy

Go to download

Java file server with SMB, FTP/FTPS and NFS support, virtual filesystems, database filesystems

There is a newer version: 1.4.0
Show newest version
/*
 * Copyright (C) 2006-2010 Alfresco Software Limited.
 *
 * This file is part of Alfresco
 *
 * Alfresco is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Alfresco 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Alfresco. If not, see .
 */

package org.filesys.oncrpc.portmap;

import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;

import org.filesys.debug.Debug;
import org.filesys.oncrpc.PortMapping;
import org.filesys.oncrpc.Rpc;
import org.filesys.oncrpc.RpcPacket;
import org.filesys.oncrpc.RpcProcessor;
import org.filesys.oncrpc.TcpRpcSessionHandler;
import org.filesys.oncrpc.UdpRpcDatagramHandler;
import org.filesys.oncrpc.nfs.NFSConfigSection;
import org.filesys.server.NetworkServer;
import org.filesys.server.ServerListener;
import org.filesys.server.Version;
import org.filesys.server.config.ServerConfiguration;

/**
 * Port Mapper Server Class
 *
 * @author gkspencer
 */
public class PortMapperServer extends NetworkServer implements RpcProcessor {

    //	Constants
    //
    //	Server version
    private static final String ServerVersion = Version.PortMapServerVersion;

    //	Default port mapper port
    public final static int DefaultPort = 111;

    //	Maximum request size to accept
    public final static int MaxRequestSize = 1024;

    //  Configuration sections
    private NFSConfigSection m_nfsConfig;

    //	Incoming datagram handler for UDP requests
    private UdpRpcDatagramHandler m_udpHandler;

    //	Incoming session handler for TCP requests
    private TcpRpcSessionHandler m_tcpHandler;

    //	Portmapper port
    private int m_port;

    //	Table of active port mappings
    private Hashtable m_mappings;
    private Hashtable m_noVerMappings;

    /**
     * Class constructor
     *
     * @param config ServerConfiguration
     */
    public PortMapperServer(ServerConfiguration config) {
        super("Portmap", config);

        //	Set the server version
        setVersion(ServerVersion);

        //  Get the NFS configuration
        m_nfsConfig = (NFSConfigSection) config.getConfigSection(NFSConfigSection.SectionName);

        if (m_nfsConfig != null) {

            //	Enable/disable debug output
            setDebug(getNFSConfiguration().hasPortMapperDebug());

            //	Set the port to use
            if (getNFSConfiguration().getPortMapperPort() != 0)
                setPort(getNFSConfiguration().getPortMapperPort());
            else
                setPort(DefaultPort);

            //	Create the mappings tables
            m_mappings = new Hashtable();
            m_noVerMappings = new Hashtable();
        } else
            setEnabled(false);
    }

    /**
     * Return the server port
     *
     * @return int
     */
    public final int getPort() {
        return m_port;
    }

    /**
     * Return the NFS configuration section
     *
     * @return NFSConfigSection
     */
    private final NFSConfigSection getNFSConfiguration() {
        return m_nfsConfig;
    }

    /**
     * Start the portmapper server
     */
    public void startServer() {

        try {

            //	Create the UDP RPC handler to accept incoming requests
            m_udpHandler = new UdpRpcDatagramHandler("PortMap", "Port", this, this, null, getPort(), MaxRequestSize);
            m_udpHandler.initializeSessionHandler(this);

            //	Start the UDP request listener is a seperate thread
            Thread udpThread = new Thread(m_udpHandler);
            udpThread.setName("PortMap_UDP");
            udpThread.start();

            //	Create the TCP RPC handler to accept incoming requests
            m_tcpHandler = new TcpRpcSessionHandler("PortMap", "Port", this, this, null, getPort(), MaxRequestSize);
            m_tcpHandler.initializeSessionHandler(this);

            //	Start the UDP request listener is a seperate thread
            Thread tcpThread = new Thread(m_tcpHandler);
            tcpThread.setName("PortMap_TCP");
            tcpThread.start();

            //	Add port mapper entries for the portmapper service
            PortMapping portMap = new PortMapping(PortMapper.ProgramId, PortMapper.VersionId, Rpc.ProtocolId.UDP, getPort());
            addPortMapping(portMap);

            portMap = new PortMapping(PortMapper.ProgramId, PortMapper.VersionId, Rpc.ProtocolId.TCP, getPort());
            addPortMapping(portMap);
        }
        catch (Exception ex) {
            Debug.println(ex);
        }
    }

    /**
     * Shutdown the server
     *
     * @param immediate boolean
     */
    public void shutdownServer(boolean immediate) {

        //	Stop the RPC handlers
        if (m_udpHandler != null) {
            m_udpHandler.closeSessionHandler(this);
            m_udpHandler = null;
        }

        if (m_tcpHandler != null) {
            m_tcpHandler.closeSessionHandler(this);
            m_tcpHandler = null;
        }

        //	Fire a shutdown notification event
        fireServerEvent(ServerListener.ServerShutdown);
    }

    /**
     * Set the server port
     *
     * @param port int
     */
    public final void setPort(int port) {
        m_port = port;
    }

    /**
     * Process an RPC request
     *
     * @param rpc RpcPacket
     * @return RpcPacket
     * @exception IOException Socket error
     */
    public RpcPacket processRpc(RpcPacket rpc)
            throws IOException {

        //	Validate the request
        if (rpc.getProgramId() != PortMapper.ProgramId) {

            //	Request is not for us
            rpc.buildAcceptErrorResponse(Rpc.AcceptSts.ProgUnavail);
            return rpc;
        } else if (rpc.getProgramVersion() != PortMapper.VersionId) {

            //	Request is not for this version of portmapper
            rpc.buildProgramMismatchResponse(PortMapper.VersionId, PortMapper.VersionId);
            return rpc;
        }

        //	Position the RPC buffer pointer at the start of the call parameters
        rpc.positionAtParameters();

        //	Process the RPC request
        RpcPacket response = null;
        PortMapper.ProcedureId procId = PortMapper.ProcedureId.fromInt( rpc.getProcedureId());

        switch ( procId) {

            //	Null request
            case Null:
                response = procNull(rpc);
                break;

            //	Set a port
            case Set:
                response = procSet(rpc);
                break;

            //	Release a port
            case UnSet:
                response = procUnSet(rpc);
                break;

            //	Get the port for a service
            case GetPort:
                response = procGetPort(rpc);
                break;

            //	Dump ports request
            case Dump:
                response = procDump(rpc);
                break;
        }

        //	Return the RPC response
        return response;
    }

    /**
     * Process the null request
     *
     * @param rpc RpcPacket
     * @return RpcPacket
     */
    private final RpcPacket procNull(RpcPacket rpc) {

        //	Build the response
        rpc.buildResponseHeader();
        return rpc;
    }

    /**
     * Process the set request
     *
     * @param rpc RpcPacket
     * @return RpcPacket
     */
    private final RpcPacket procSet(RpcPacket rpc) {

        //	Get the call parameters
        int progId = rpc.unpackInt();
        int verId = rpc.unpackInt();
        Rpc.ProtocolId proto = Rpc.ProtocolId.fromInt(rpc.unpackInt());
        int port = rpc.unpackInt();

        //	DEBUG
        if (Debug.EnableInfo && hasDebug())
            Debug.println("[PortMap] Set port program=" + Rpc.getServiceName(progId) + ", version=" + verId +
                    ", protocol=" + proto.name() + ", port=" + port);

        //	Check if the port is already mapped
        PortMapping portMap = findPortMapping(progId, verId, proto);
        int portAdded = Rpc.False;

        if (portMap == null) {

            //	Add a mapping for the new service
            portMap = new PortMapping(progId, verId, proto, port);
            if (addPortMapping(portMap) == true)
                portAdded = Rpc.True;
        }

        //	Check if the service is on the same port as the current port mapping, and it is not
        //	an attempt to set the port mapper service port.
        else if (progId != PortMapper.ProgramId && portMap.getPort() == port) {

            //	Settings are the same as the existing service settings so accept it
            portAdded = Rpc.True;
        }

        //	Build the response header
        rpc.buildResponseHeader();

        //	Pack a boolean indicating if the port was added, or not
        rpc.packInt(portAdded);
        rpc.setLength();

        //	Return the response
        return rpc;
    }

    /**
     * Process the unset request
     *
     * @param rpc RpcPacket
     * @return RpcPacket
     */
    private final RpcPacket procUnSet(RpcPacket rpc) {

        //	Get the call parameters
        int progId = rpc.unpackInt();
        int verId = rpc.unpackInt();
        Rpc.ProtocolId proto = Rpc.ProtocolId.fromInt(rpc.unpackInt());
        int port = rpc.unpackInt();

        //	DEBUG
        if (Debug.EnableInfo && hasDebug())
            Debug.println("[PortMap] UnSet port program=" + Rpc.getServiceName(progId) + ", version=" + verId +
                    ", protocol=" + proto.name() + ", port=" + port);

        //	Check if the port is mapped, and it is not an attempt to remove a portmapper portt
        PortMapping portMap = findPortMapping(progId, verId, proto);
        int portRemoved = Rpc.False;

        if (portMap != null && progId != PortMapper.ProgramId) {

            //	Remove the port mapping
            if (removePortMapping(portMap) == true)
                portRemoved = Rpc.True;
        }

        //	Build the response header
        rpc.buildResponseHeader();

        //	Pack a boolean indicating if the port was removed, or not
        rpc.packInt(portRemoved);
        rpc.setLength();

        //	Return the response
        return rpc;
    }

    /**
     * Process the get port request
     *
     * @param rpc RpcPacket
     * @return RpcPacket
     */
    private final RpcPacket procGetPort(RpcPacket rpc) {

        //	Get the call parameters
        int progId = rpc.unpackInt();
        int verId = rpc.unpackInt();
        Rpc.ProtocolId proto = Rpc.ProtocolId.fromInt(rpc.unpackInt());

        //	Find the required port mapping
        PortMapping portMap = findPortMapping(progId, verId, proto);

        //	DEBUG
        if (Debug.EnableInfo && hasDebug())
            Debug.println("[PortMap] Get port program=" + Rpc.getServiceName(progId) + ", version=" + verId +
                    ", protocol=" + proto.name() +
                    ", port=" + (portMap != null ? portMap.getPort() : 0));

        //	Build the response header
        rpc.buildResponseHeader();

        //	Pack the port number of the requested RPC service, or zero if not found
        rpc.packInt(portMap != null ? portMap.getPort() : 0);
        rpc.setLength();

        //	Return the response
        return rpc;
    }

    /**
     * Process the dump request
     *
     * @param rpc RpcPacket
     * @return RpcPacket
     */
    private final RpcPacket procDump(RpcPacket rpc) {

        //	DEBUG
        if (Debug.EnableInfo && hasDebug())
            Debug.println("[PortMap] Dump ports request from " + rpc.getClientDetails());

        //	Build the response
        rpc.buildResponseHeader();

        //	Pack the active port mappings structures
        Enumeration enm = m_mappings.elements();

        while (enm.hasMoreElements()) {

            //	Get the current port mapping
            PortMapping portMap = (PortMapping) enm.nextElement();

            //	Pack the port mapping structure
            rpc.packInt(Rpc.True);
            rpc.packPortMapping(portMap);
        }

        //	Pack the end of list structure, set the response length
        rpc.packInt(Rpc.False);
        rpc.setLength();

        //	Return the response
        return rpc;
    }

    /**
     * Add a port mapping to the active list
     *
     * @param portMap PortMapping
     * @return boolean
     */
    private final boolean addPortMapping(PortMapping portMap) {

        //	Check if there is an existing port mapping that matches the new port
        Integer key = new Integer(portMap.hashCode());
        if (m_mappings.get(key) != null)
            return false;

        //	Add the port mapping
        m_mappings.put(key, portMap);

        //	Add a port mapping with a version id of zero
        key = new Integer(PortMapping.generateHashCode(portMap.getProgramId(), 0, portMap.getProtocol().intValue()));
        m_noVerMappings.put(key, portMap);

        //	Indicate that the mapping was added
        return true;
    }

    /**
     * Remove a port mapping from the active list
     *
     * @param portMap PortMapping
     * @return boolean
     */
    private final boolean removePortMapping(PortMapping portMap) {

        //	Remove the port mapping from the active lists
        Integer key = new Integer(portMap.hashCode());
        Object removedObj = m_mappings.remove(key);

        key = new Integer(PortMapping.generateHashCode(portMap.getProgramId(), 0, portMap.getProtocol().intValue()));
        m_noVerMappings.remove(key);

        //	Return a status indicating if the mapping was removed
        return removedObj != null ? true : false;
    }

    /**
     * Search for a port mapping
     *
     * @param progId int
     * @param verId  int
     * @param proto  Rpc.ProtocolId
     * @return PortMapping
     */
    private final PortMapping findPortMapping(int progId, int verId, Rpc.ProtocolId proto) {

        //	Create a key for the RPC service
        Integer key = new Integer(PortMapping.generateHashCode(progId, verId, proto.intValue()));

        //	Search for the required port mapping, including the version id
        PortMapping portMap = m_mappings.get(key);
        if (portMap == null && verId == 0) {

            //	Search for the port mapping without the version id
            portMap = m_noVerMappings.get(key);
        }

        //	Return the port mapping, or null if not found
        return portMap;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy