/*
* 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:
*
* - The specific FTPConnector implementation. Every FTPConnector could
* choose a different default value for the property. It should declare the
* default value in its own documentation.
* - The value of the
* "ftp4j.passiveDataTransfer.useSuggestedAddress" system
* property. Regardless the connector's default value, the flag will be
* true if the system property value is "true",
* "yes" or "1". Viceversa, it is false if the
* system property value is "false", "no" or
* "0".
*
*
* @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;
}