/* * ftp4j - A pure Java FTP client library * * Copyright (C) 2008-2010 Carlo Pelliccia (www.sauronsoftware.it) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1, as published by the Free Software Foundation. * * This program 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 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this program. * If not, see . */ package it.sauronsoftware.ftp4j; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; /** * This abstract class is the base for creating a connector. Connectors are used * by the client to establish connections with remote servers. * * @author Carlo Pelliccia */ public abstract class FTPConnector { /** * Timeout in seconds for connection enstablishing. * * @since 1.7 */ protected int connectionTimeout = 10; /** * Timeout in seconds for read operations. * * @since 1.7 */ protected int readTimeout = 10; /** * Timeout in seconds for connection regular closing. * * @since 1.7 */ protected int closeTimeout = 10; /** * This flag determines the behavior of the connector when it has to open a * connection toward the server to perform a passive data transfer. * * @see FTPConnector#setUseSuggestedAddressForDataConnections(boolean) * @since 1.7.1 */ private boolean useSuggestedAddressForDataConnections; /** * The socket of an ongoing connection attempt for a communication channel. * * @since 1.7 */ private Socket connectingCommunicationChannelSocket; /** * Builds the connector. * * @param useSuggestedAddressForDataConnectionsDefValue * The connector's default value for the * useSuggestedAddressForDataConnections flag. * * @see FTPConnector#setUseSuggestedAddressForDataConnections(boolean) */ protected FTPConnector(boolean useSuggestedAddressForDataConnectionsDefValue) { String sysprop = System.getProperty(FTPKeys.PASSIVE_DT_USE_SUGGESTED_ADDRESS); if ("true".equalsIgnoreCase(sysprop) || "yes".equalsIgnoreCase(sysprop) || "1".equals(sysprop)) { useSuggestedAddressForDataConnections = true; } else if ("false".equalsIgnoreCase(sysprop) || "no".equalsIgnoreCase(sysprop) || "0".equals(sysprop)) { useSuggestedAddressForDataConnections = false; } else { useSuggestedAddressForDataConnections = useSuggestedAddressForDataConnectionsDefValue; } } /** * Builds the connector. * * By calling this constructor, the connector's default value for the * useSuggestedAddressForDataConnections flag is false. */ protected FTPConnector() { this(false); } /** * Sets the timeout for connection operations. * * @param connectionTimeout * The timeout value in seconds. * @since 1.7 */ public void setConnectionTimeout(int connectionTimeout) { this.connectionTimeout = connectionTimeout; } /** * Sets the timeout for read operations. * * @param readTimeout * The timeout value in seconds. * @since 1.7 */ public void setReadTimeout(int readTimeout) { this.readTimeout = readTimeout; } /** * Sets the timeout for close operations. * * @param closeTimeout * The timeout value in seconds. * @since 1.7 */ public void setCloseTimeout(int closeTimeout) { this.closeTimeout = closeTimeout; } /** * This flag determines the behavior of the connector when it has to open a * connection toward the server to perform a passive data transfer. * * If the flag is true, the client connects to the IP address * returned as a reply of the PASV command. * * If the flag is false, the client ignores the IP address * suggested by the server, and it connects to the same host used for the * communication connection (the same host supplied in the * {@link FTPClient#connect(String)} and * {@link FTPClient#connect(String, int)} methods). In this case, the * response to the PASV command is used only to determinate the port for the * connection. * * The default value for this flag (the one used if you never the method is * never called) depends on: * * * @param value * The value for the flag. */ public void setUseSuggestedAddressForDataConnections(boolean value) { this.useSuggestedAddressForDataConnections = value; } /** * Returns the value for the useSuggestedAddressForDataConnections * flag. * * @return The value for the useSuggestedAddressForDataConnections * flag. */ boolean getUseSuggestedAddressForDataConnections() { return useSuggestedAddressForDataConnections; } /** * Creates a socket and connects it to the given host for a communication * channel. Socket timeouts are automatically set according to the values of * {@link FTPConnector#connectionTimeout}, {@link FTPConnector#readTimeout} * and {@link FTPConnector#closeTimeout}. * * If you are extending FTPConnector, consider using this method to * establish your socket connection for the communication channel, instead * of creating Socket objects, since it is already aware of the timeout * values possibly given by the caller. Moreover the caller can abort * connection calling {@link FTPClient#abortCurrentConnectionAttempt()}. * * @param host * The host for the connection. * @param port * The port for the connection. * @return The connected socket. * @throws IOException * If connection fails. * @since 1.7 */ protected Socket tcpConnectForCommunicationChannel(String host, int port) throws IOException { try { connectingCommunicationChannelSocket = new Socket(); connectingCommunicationChannelSocket.setKeepAlive(true); connectingCommunicationChannelSocket.setSoTimeout(readTimeout * 1000); connectingCommunicationChannelSocket.setSoLinger(true, closeTimeout); connectingCommunicationChannelSocket.connect(new InetSocketAddress(host, port), connectionTimeout * 1000); return connectingCommunicationChannelSocket; } finally { connectingCommunicationChannelSocket = null; } } /** * Creates a socket and connects it to the given host for a data transfer * channel. Socket timeouts are automatically set according to the values of * {@link FTPConnector#connectionTimeout}, {@link FTPConnector#readTimeout} * and {@link FTPConnector#closeTimeout}. * * If you are extending FTPConnector, consider using this method to * establish your socket connection for the communication channel, instead * of creating Socket objects, since it is already aware of the timeout * values possibly given by the caller. * * @param host * The host for the connection. * @param port * The port for the connection. * @return The connected socket. * @throws IOException * If connection fails. * @since 1.7 */ protected Socket tcpConnectForDataTransferChannel(String host, int port) throws IOException { Socket socket = new Socket(); socket.setSoTimeout(readTimeout * 1000); socket.setSoLinger(true, closeTimeout); socket.setReceiveBufferSize(512 * 1024); socket.setSendBufferSize(512 * 1024); socket.connect(new InetSocketAddress(host, port), connectionTimeout * 1000); return socket; } /** * Aborts an ongoing connection attempt for a communication channel. * * @since 1.7 */ public void abortConnectForCommunicationChannel() { if (connectingCommunicationChannelSocket != null) { try { connectingCommunicationChannelSocket.close(); } catch (Throwable t) { } } } /** * This methods returns an established connection to a remote host, suitable * for a FTP communication channel. * * @param host * The remote host name or address. * @param port * The remote port. * @return The connection with the remote host. * @throws IOException * If the connection cannot be established. */ public abstract Socket connectForCommunicationChannel(String host, int port) throws IOException; /** * This methods returns an established connection to a remote host, suitable * for a FTP data transfer channel. * * @param host * The remote host name or address. * @param port * The remote port. * @return The connection with the remote host. * @throws IOException * If the connection cannot be established. */ public abstract Socket connectForDataTransferChannel(String host, int port) throws IOException; }