Package org.apache.ftpserver

Source Code of org.apache.ftpserver.IODataConnectionFactory

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/ 

package org.apache.ftpserver;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.GeneralSecurityException;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

import org.apache.ftpserver.ftplet.DataConnection;
import org.apache.ftpserver.ftplet.FtpException;
import org.apache.ftpserver.interfaces.DataConnectionConfiguration;
import org.apache.ftpserver.interfaces.FtpIoSession;
import org.apache.ftpserver.interfaces.FtpServerContext;
import org.apache.ftpserver.ssl.ClientAuth;
import org.apache.ftpserver.ssl.SslConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
* We can get the ftp data connection using this class.
* It uses either PORT or PASV command.
*/
public class IODataConnectionFactory implements ServerDataConnectionFactory {
   
    private final Logger LOG = LoggerFactory.getLogger(IODataConnectionFactory.class);
   
    private FtpServerContext    serverContext;
    private Socket        dataSoc;
    ServerSocket  servSoc;
   
    InetAddress  address;
    int          port    = 0;
   
    long requestTime = 0L;
   
    boolean passive   = false;
   
    boolean secure   = false;
    private boolean isZip    = false;

    InetAddress serverControlAddress;

    FtpIoSession session;
   
    public IODataConnectionFactory(final FtpServerContext serverContext, final FtpIoSession session) {
        this.session = session;
        this.serverContext = serverContext;
       
    }

   
    /**
     * Close data socket.
     */
    public synchronized void closeDataConnection() {
       
        // close client socket if any
        if(dataSoc != null) {
            try {
                dataSoc.close();
            }
            catch(Exception ex) {
                LOG.warn("FtpDataConnection.closeDataSocket()", ex);
            }
            dataSoc = null;
        }
       
        // close server socket if any
        if (servSoc != null) {
            try {
               servSoc.close();
            }
            catch(Exception ex) {
                LOG.warn("FtpDataConnection.closeDataSocket()", ex);
            }
           
            FtpServerContext ctx = serverContext;
           
            if(ctx != null) {
                DataConnectionConfiguration dcc = session.getListener().getDataConnectionConfiguration();
                if(dcc != null) {
                    dcc.releasePassivePort(port);
                }
            }
           
            servSoc = null;
        }
       
        // reset request time
        requestTime = 0L;
    }
    
    /**
     * Port command.
     */
    public synchronized void initActiveDataConnection(final InetSocketAddress address) {
       
        // close old sockets if any
        closeDataConnection();
       
        // set variables
        passive = false;
        this.address = address.getAddress();
        port = address.getPort();
        requestTime = System.currentTimeMillis();
    }
   
    /**
     * Initiate a data connection in passive mode (server listening).
     * It returns the success flag.
     */
    public synchronized InetSocketAddress initPassiveDataConnection() throws DataConnectionException {
        LOG.debug("Initiating passive data connection");
        // close old sockets if any
        closeDataConnection();
       
        // get the passive port
        int passivePort = session.getListener().getDataConnectionConfiguration().requestPassivePort();
        if(passivePort == -1) {
            servSoc = null;
            throw new DataConnectionException("Cannot find an available passive port.");
        }
       
        // open passive server socket and get parameters
        try {
            DataConnectionConfiguration dataCfg = session.getListener().getDataConnectionConfiguration();
            address = dataCfg.getPassiveAddress();

            if(address == null) {
                address = serverControlAddress;
            }

            if(secure) {
                LOG.debug("Opening SSL passive data connection on address \"{}\" and port {}", address, passivePort);
                SslConfiguration ssl = dataCfg.getSslConfiguration();
                if(ssl == null) {
                    throw new DataConnectionException("Data connection SSL required but not configured.");
                }
                servSoc = createServerSocket(ssl, address, passivePort);
                port = servSoc.getLocalPort();
                LOG.debug("SSL Passive data connection created on address \"{}\" and port {}", address, passivePort);
            }
            else {
                LOG.debug("Opening passive data connection on address \"{}\" and port {}", address, passivePort);
                servSoc = new ServerSocket(passivePort, 0, address);
                port = servSoc.getLocalPort();
                LOG.debug("Passive data connection created on address \"{}\" and port {}", address, passivePort);
            }
            servSoc.setSoTimeout(dataCfg.getIdleTime() * 1000);

            // set different state variables
            passive = true;
            requestTime = System.currentTimeMillis();
           
            return new InetSocketAddress(address, port);
        }
        catch(Exception ex) {
            servSoc = null;
            closeDataConnection();
            throw new DataConnectionException("Failed to initate passive data connection: " + ex.getMessage(), ex);
        }
    }
    
    private ServerSocket createServerSocket(final SslConfiguration ssl, final InetAddress address2, final int passivePort) throws IOException, GeneralSecurityException {
        // get server socket factory
        SSLContext ctx = ssl.getSSLContext();
        SSLServerSocketFactory ssocketFactory = ctx.getServerSocketFactory();
       
        // create server socket
        SSLServerSocket sslServerSocket = null;
        if(address2 == null) {
            sslServerSocket = (SSLServerSocket) ssocketFactory.createServerSocket(passivePort, 100);
        } else {
            sslServerSocket = (SSLServerSocket) ssocketFactory.createServerSocket(passivePort, 100, address2);
        }
       
        // initialize server socket
        if(ssl.getClientAuth() == ClientAuth.NEED) {
            sslServerSocket.setNeedClientAuth(true);
        } else if(ssl.getClientAuth() == ClientAuth.WANT) {
            sslServerSocket.setWantClientAuth(true);
        }

       
        if(ssl.getEnabledCipherSuites() != null) {
            sslServerSocket.setEnabledCipherSuites(ssl.getEnabledCipherSuites());
        }
        return sslServerSocket;
    }


    /* (non-Javadoc)
     * @see org.apache.ftpserver.FtpDataConnectionFactory2#getInetAddress()
     */
    public InetAddress getInetAddress() {
        return address;
    }
    
    /* (non-Javadoc)
     * @see org.apache.ftpserver.FtpDataConnectionFactory2#getPort()
     */
    public int getPort() {
        return port;
    }

    /* (non-Javadoc)
     * @see org.apache.ftpserver.FtpDataConnectionFactory2#openConnection()
     */
    public DataConnection openConnection() throws Exception {
        return new IODataConnection(createDataSocket(), session, this);
    }
   
    /**
     * Get the data socket. In case of error returns null.
     */
    private synchronized Socket createDataSocket() throws Exception {

        // get socket depending on the selection
        dataSoc = null;
        DataConnectionConfiguration dataConfig = session.getListener().getDataConnectionConfiguration();
        try {
            if(!passive) {
                int localPort = dataConfig.getActiveLocalPort();
                if(secure) {
                    SslConfiguration ssl = dataConfig.getSslConfiguration();
                    if(ssl == null) {
                        throw new FtpException("Data connection SSL not configured");
                    }
                    if(localPort == 0) {
                        dataSoc = createSocket(ssl, address, port, null, localPort, false);
                    }
                    else {
                        InetAddress localAddr = dataConfig.getActiveLocalAddress();
                        dataSoc = createSocket(ssl, address, port, localAddr, localPort, false);
                    }
                }
                else {
                    if(localPort == 0) {
                        dataSoc = new Socket(address, port)
                    }
                    else {
                        InetAddress localAddr = dataConfig.getActiveLocalAddress();
                        dataSoc = new Socket(address, port, localAddr, localPort);
                    }
                }
            } else {
                LOG.debug("Opening passive data connection");
                dataSoc = servSoc.accept();
                LOG.debug("Passive data connection opened");
            }
        }
        catch(Exception ex) {
            closeDataConnection();
            LOG.warn("FtpDataConnection.getDataSocket()", ex);
            throw ex;
        }
       
        // Make sure we initate the SSL handshake, or we'll
        // get an error if we turn out not to send any data
        // e.g. during the listing of an empty dir
        if(dataSoc instanceof SSLSocket) {
            ((SSLSocket)dataSoc).startHandshake();
        }
       
        return dataSoc;
    }
   
    private Socket createSocket(final SslConfiguration ssl, final InetAddress address2,
            final int port2, final InetAddress localAddress, final int localPort, final boolean clientMode) throws IOException, GeneralSecurityException {
       
        // get socket factory
        SSLContext ctx = ssl.getSSLContext();
        SSLSocketFactory socFactory = ctx.getSocketFactory();
       
        // create socket
        SSLSocket ssoc;
        if(localPort != 0) {
            ssoc = (SSLSocket)socFactory.createSocket(address2, port2);
        } else {
            ssoc = (SSLSocket)socFactory.createSocket(address2, port2, localAddress, localPort);
        }
        ssoc.setUseClientMode(clientMode);
       
       
        // initialize socket
        if(ssl.getEnabledCipherSuites() != null) {
            ssoc.setEnabledCipherSuites(ssl.getEnabledCipherSuites());
        }
        return ssoc;
    }


    /* (non-Javadoc)
     * @see org.apache.ftpserver.FtpDataConnectionFactory2#isSecure()
     */
    public boolean isSecure() {
        return secure;
    }
   
    /**
     * Set the security protocol.
     */
    public void setSecure(final boolean secure) {
        this.secure = secure;
    }
   
    /* (non-Javadoc)
     * @see org.apache.ftpserver.FtpDataConnectionFactory2#isZipMode()
     */
    public boolean isZipMode() {
        return isZip;
    }
   
    /**
     * Set zip mode.
     */
    public void setZipMode(final boolean zip) {
        isZip = zip;
    }
   
    /**
     * Check the data connection idle status.
     */
    public synchronized boolean isTimeout(final long currTime) {
       
        // data connection not requested - not a timeout
        if(requestTime == 0L) {
            return false;
        }
       
        // data connection active - not a timeout
        if(dataSoc != null) {
            return false;
        }
       
        // no idle time limit - not a timeout
        int maxIdleTime = session.getListener().getDataConnectionConfiguration().getIdleTime() * 1000;
        if(maxIdleTime == 0) {
            return false;
        }
       
        // idle time is within limit - not a timeout
        if( (currTime - requestTime) < maxIdleTime ) {
            return false;
        }
       
        return true;
    }
   
    /**
     * Dispose data connection - close all the sockets.
     */
    public void dispose() {
        closeDataConnection();
    }

    /**
     * Sets the server's control address.
     */
    public void setServerControlAddress(final InetAddress serverControlAddress) {
        this.serverControlAddress = serverControlAddress;
    }
}
    
TOP

Related Classes of org.apache.ftpserver.IODataConnectionFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.