I'm transferring files using FTP with JAVA. I'm using FTPClient and FTPServer from Apache. But in a specific environment, sometimes the file isn't transferred. I call the enterLocalPassiveMode method from FTPClient before the login method call and yet sometimes the files aren't transferred.
When the file is transferred successfully:
Client code:
this.getFtpClientUtil().connect(settingsService.getServer(), settingsService.getFtpServerCommandChannelPort());
int reply = this.getFtpClientUtil().getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
logger.error("Fail to connect to FTP Server");
this.getFtpClientUtil().disconnect();
isConnect = false;
return false;
}
logger.info("FTP Server connected successfully");
this.getFtpClientUtil().enterLocalPassiveMode();
isConnect = this.getFtpClientUtil().login(settingsService.getftpUsername(), settingsService.getftpPassword());
Server Code:
// Data Configuration
this.dataConfigurationFactory = new DataConnectionConfigurationFactory();
dataConfigurationFactory.setPassiveAddress(this.ipAddress);
dataConfigurationFactory.setPassiveExternalAddress(this.ipAddress);
dataConfigurationFactory.setPassivePorts(this.settingsService.getFtpServerTransferChannelPort());
// Listener
listenerFactory = new ListenerFactory();
listenerFactory.setPort(this.settingsService.getFtpServerCommandChannelPort());
listenerFactory.setDataConnectionConfiguration(dataConfigurationFactory.createDataConnectionConfiguration());
// Desliga SSL
listenerFactory.setImplicitSsl(false);
// User
PropertiesUserManagerFactory userManagerFactory = new PropertiesUserManagerFactory();
UserManager um = userManagerFactory.createUserManager();
this.serverFactory = new FtpServerFactory();
serverFactory.addListener("default", listenerFactory.createListener());
serverFactory.setUserManager(um);
UserFactory userFactory = new UserFactory();
userFactory.setName(this.settingsService.getftpUsername());
userFactory.setPassword(this.settingsService.getftpPassword());
userFactory.setMaxIdleTime(60);
final String absolutePath = this.settingsService.getftpHomeDirectory();
userFactory.setHomeDirectory(absolutePath);
userFactory.setAuthorities(Arrays.asList((Authority) new WritePermission()));
User user = userFactory.createUser();
um.save(user);
// Connection Config
connectionConfigFactory = new ConnectionConfigFactory();
connectionConfigFactory.setAnonymousLoginEnabled(false);
connectionConfigFactory.setMaxLogins(100);
serverFactory.setConnectionConfig(connectionConfigFactory.createConnectionConfig());
Is this a firewall problem?
I tried set passive port ranges on the server side using the setPassivePorts method from DataConnectionConfigurationFactory class, but the problem continues.
Is there any form to set port ranges on the Client side? How can I check if the connection is really using passive mode?
Thanks in advance.
Is this a firewall problem?
In these cases, the correct way would be turn off the firewall to test or set a range of ports that the application can to connect. But in the production environment this wasn't an option. So, the only thing I know is that in the development environment works fine and in the production environment the problem arise. My assumption is that the firewall is blocking the ports.
Is there any form to set port ranges on the Client side? How can I check if the connection is really using passive mode?
The local port can be set on connect() method from FTPClient:
this.getFtpClientUtil().connect(settingsService.getServer(), settingsService.getFtpServerCommandChannelPort(),
InetAddress.getLocalHost(), getLocalPort());
It's possible to verify if the connection is using the passive mode in two ways:
Setting local port didn't resolve the problem. Perhaps because the local port that I'm configuring is only for the command channel. The transfer channel still uses random ports on client side. The solution is trying to transfer the file again. If the transfer fails, I disconnect the client, then I connect the client again using other ports and then I try to transfer the file again. In all my tests, the files was transferred successfully in the second time. I put 3 attempts if the transferring fails.
When connecting the client again, if the same port was used, the java could throw "java.net.BindException: Address already in use". Even after disconnect the client, the port continues locked for a few moments. In this case, I verify if the port is available before trying to connect, if necessary I try to connect the client in another port.