FtpClient storeFile always return False - java

Please figure this out. The code runs properly without any exception.
try
{
FTPClient ftp = new FTPClient();
ftp.connect(server);
if(!ftp.login(username, password))
{
ftp.logout();
return false;
}
int reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply))
{
ftp.disconnect();
return false;
}
InputStream in = new FileInputStream(localfile);
ftp.setFileType(ftp.BINARY_FILE_TYPE, ftp.BINARY_FILE_TYPE);
ftp.setFileTransferMode(ftp.BINARY_FILE_TYPE);
Store = ftp.storeFile(destinationfile, in);
in.close();
ftp.logout();
ftp.disconnect();
}
catch (Exception ex)
{
ex.printStackTrace();
return false;
}
return Store;
Butm the return statement always returns false and the file is not uploaded on the server. Someone please help on this.
For your information, I am in an office network. ---> do we need to add any proxies?
File file = new File("C:\\Users\\sg0214273\\Desktop\\seagate\\seagate.txt");
FileInputStream input = new FileInputStream(file);
client.setFileType(FTP.BINARY_FILE_TYPE);
if (!client.storeFile(file.getName(), input)) {
System.out.println("upload failed!");
}
reply = client.getReplyCode();
if(!FTPReply.isPositiveCompletion(reply)) {
System.out.println("upload failed!");
}
Login success...
230 User ******** logged in.
upload failed!-----> is form boolean return value of storefile
upload failed!---------> is from replycode...
Logout from FTP server...
Please help out.

The exact failure message can be found by calling FtpClient#getReplyCode(). From that page (my emphasis):
Immediately after connecting is the only real time you need to check
the reply code (because connect is of type void). The convention for
all the FTP command methods in FTPClient is such that they either
return a boolean value or some other value. The boolean methods return
true on a successful completion reply from the FTP server and false on
a reply resulting in an error condition or failure. The methods
returning a value other than boolean return a value containing the
higher level data produced by the FTP command, or null if a reply
resulted in an error condition or failure. If you want to access the
exact FTP reply code causing a success or failure, you must call
getReplyCode after a success or failure.
To see what a return code means, you can see Wikipedia: List of FTP server return codes.

Topic is quite old but maybe I will help to any other. I compared what FileZilla sends to FTP server and my program did. I needed to use ftp.enterLocalPassiveMode() to make it work, ftp.pasv() no good :)
And for debugging is better to use getReplyString() than only getReplyCode().

Modify you code to switch to passive mode before you transfer the file with storeFile() as follows:
...
ftp.setFileTransferMode(ftp.BINARY_FILE_TYPE);
ftp.enterLocalPassiveMode();//Switch to passive mode
Store = ftp.storeFile(destinationfile, in);
in.close();
...
Hope that helps.

please add the apache library for this code
this are the impoted class
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
rest import class is from java.io or java.net
public boolean upload(String server,String username,String password,File localfile ){
boolean Store=false;
try{
FTPClient ftp = new FTPClient();
// ftp.connect(server);
/* you can use either code which is written above above or below code as ftp port 20 is used for the data transfer and port 21 is used for command and controlls */
ftp.connect(InetAddress.getByName(server),21);
//here 'server' is your domain name of ftp server or url
if(!ftp.login(username, password))
{
ftp.logout();
return false;
}
ftp.sendNoOp();//used so server timeout exception will not rise
int reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply))
{
ftp.disconnect();
return false;
}
ftp.enterLocalPassiveMode(); /* just include this line here and your code will work fine */
InputStream in = new FileInputStream(localfile);
// ftp.setFileType(ftp.BINARY_FILE_TYPE, ftp.BINARY_FILE_TYPE);
ftp.setFileType(FTP.BINARY_FILE_TYPE);
// ftp.setFileTransferMode(ftp.BINARY_FILE_TYPE);
Store = ftp.storeFile(destinationfile, in);
in.close();
//ftp.disconnect();
//here logout will close the connection for you
ftp.logout();
}
catch (Exception ex)
{
ex.printStackTrace();
return false;
}
return Store;
}

Try to use ftp.enterLocalPassiveMode(); before ftp.storeFile(destinationfile, in);

Related

Java - CopyStreamException due to SSLProtocolException when storing file's contents in FTP server

I'm facing an issue when trying to store a file in an FTP server. When trying to upload a file to the FTP server, the file is created but its contents are not copied.
Context
We use the following configuration to access the FTP server using lftp. I cannot change this configuration, and don't know why do we use FTPS with verify-certificates disabled.
# FTPS_OPTIONS:
set ssl:verify-certificate/testhostname no;
set ftp:ssl-protect-data yes;
set ftp:passive-mode on;
I need to store certain files from a Java application. I'm using apache-commons library. The implemented code looks like this:
#Autowired
public FtpService() {
ftpsClient = new FTPSClient();
ftpsClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));
}
public void uploadFile(String ftpHost, File tempFile, String destination, String filename)
throws UploadException {
ftpsClient.connect(ftpHost, 990);
ftpsClient.execPBSZ(0);
ftpsClient.execPROT("P");
ftpsClient.enterLocalPassiveMode();
ftpsClient.setKeepAlive(true);
ftpsClient.setControlKeepAliveTimeout(3000);
if(ftpsClient.login("user", "password")) {
try (InputStream fileStream = new FileInputStream(tempFile)) {
if (!ftpsClient.changeWorkingDirectory(destination)) {
throwUploadException("Destination directory not available in FTP server");
}
boolean saved = ftpsClient.storeFile(filename, fileStream);
// Following code is not executed since the exception is thrown in the previous line
if (!saved) {
throwUploadException("Unable to save file in FTP server");
}
log.info("Saved FTP file: {}/{}", destination, filename);
}
catch (UploadException | IOException e)
{
throwUploadException(e.getMessage());
}
finally
{
ftpsClient.disconnect();
if (!tempFile.delete()) {
log.warn("Unable to delete '{}' file", tempFile.getAbsolutePath());
}
}
}
}
Problem
I started with a FTPClient (non FTPSClient) but this way I wasn't able to login.
Currently (FTPSClient), I can:
change the working directory
create directories in the FTP server
I cannot:
storeFile: this method throws the following exception, and creates the file in the FTP server, but this is empty
org.apache.commons.net.io.CopyStreamException: IOException caught while copying.
Cause: javax.net.ssl.SSLProtocolException: Software caused connection abort: socket write error
listFiles()/listDirectories(): when executing this command, the obtained list is always empty. The logged user has all the required permissions in the whole FTP server
Following is the FTP's log (note that I have translated the commands to English between parenthesis), corresponding to the code shown before, that raises the exception mentioned before:
er: testhostname:990
USER *******
331 Usuario testuser OK. Clave requerida ( = User testuser OK. Password required)
PASS *******
230 OK. El directorio restringido actual es / ( = OK. The current restricted directory is /)
CWD /test/upload
250 OK. El directorio actual es /test/upload ( = Ok. The current directory is /test/upload)
PASV
227 Entering Passive Mode (<numbers...>)
[Replacing PASV mode reply address <ip_address> with testhostname]
STOR dummyfile.txt
150 Conexi├│n de datos aceptada ( = Data connection accepted)
If there is anything else I can include to improve the description, please let me know. Thanks for your help!
I had a similar problem from python connecting to an FTPS server. The error was that the server required the data channel session to be the same as the control channel session(reuse the session). The solution was to override one of the methods to do that.
You can test extending FTPClient.java and overriding the next method:
#Override
protected void _prepareDataSocket_(final Socket socket) {
if(preferences.getBoolean("ftp.tls.session.requirereuse")) {
if(socket instanceof SSLSocket) {
// Control socket is SSL
final SSLSession session = ((SSLSocket) _socket_).getSession();
if(session.isValid()) {
final SSLSessionContext context = session.getSessionContext();
context.setSessionCacheSize(preferences.getInteger("ftp.ssl.session.cache.size"));
try {
final Field sessionHostPortCache = context.getClass().getDeclaredField("sessionHostPortCache");
sessionHostPortCache.setAccessible(true);
final Object cache = sessionHostPortCache.get(context);
final Method putMethod = cache.getClass().getDeclaredMethod("put", Object.class, Object.class);
putMethod.setAccessible(true);
Method getHostMethod;
try {
getHostMethod = socket.getClass().getMethod("getPeerHost");
}
catch(NoSuchMethodException e) {
// Running in IKVM
getHostMethod = socket.getClass().getDeclaredMethod("getHost");
}
getHostMethod.setAccessible(true);
Object peerHost = getHostMethod.invoke(socket);
putMethod.invoke(cache, String.format("%s:%s", peerHost, socket.getPort()).toLowerCase(Locale.ROOT), session);
}
catch(NoSuchFieldException e) {
// Not running in expected JRE
log.warn("No field sessionHostPortCache in SSLSessionContext", e);
}
catch(Exception e) {
// Not running in expected JRE
log.warn(e.getMessage());
}
}
else {
log.warn(String.format("SSL session %s for socket %s is not rejoinable", session, socket));
}
}
}
}
I found this Java solution here: https://stackoverflow.com/a/32404418/19599290

Apache Commons Net FTP does not throw any exception on wrong credentials

I just managed to upload some files to an FTP server using Apache Commons Net FTP. When I use everything as it should be it works fine, I mean, the file uploading is working, but when I use, for example, a wrong password for the FTP account, obviously the files don't get uploaded to the server, but I don't get an error message either. In other words: I don't know how to show the error. I tried to show with a toast the e.getMessage() from the Exception but nothing is shown. Is there any documentation that would help me? Or am I missing something you could help me with? thank you!
This is my code:
#Override
protected Void doInBackground(Void... voids) {
FTPClient ftpClient=new FTPClient();
try {
ftpClient.connect(fserver);
ftpClient.login(fusername,fpassword);
ftpClient.enterLocalPassiveMode();
dirArch = new ArrayList<>();
for (int k=0;k<adapter.getSelected().size();k++){
dirArch.add(adapter.getSelected().get(k).getArch());
}
for (String archTXT : dirArch){
File fileX =new File(stringFolder,archTXT);
InputStream inputStream=new FileInputStream(fileX);
ftpClient.storeFile(archTXT,inputStream);
inputStream.close();
pbPorc=pbPorc+pbSum;
pb1.setProgress(pbPorc);
pb2.setProgress(pbPorc);
}
ftpClient.logout();
ftpClient.disconnect();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(ExportTracks.this,e.getMessage(),Toast.LENGTH_LONG).show();
}
return null;
}
Your error handling is wrong.
The FTPClient.login does not throw an exception, when the credentials are wrong. It returns a false. You do not test for that. Your code carries on, trying to work with not authorized session instead, all of which will obviously fail too.
But as the same is true for FTPClient.storeFile, which also just returns false, your code basically does not notice any errors.

Connection Reset when attempting to list all files from a Sharefolder

I am trying to recursively check for a specific file in my company sharefolder using SmbFile and NtlmPasswordAuthentication.
As I am not very knowledgeable in Java I followed examples found in the internet but I keep getting the following error whenever I try to do a root.listFiles() :
jcifs.smb.SmbException: Failed to connect: foldername/xx.xx.xx.xxx
jcifs.util.transport.TransportException
java.net.SocketException: Connection reset
I do have access rights to the sharefolder so my initial thought is that something is missing from my code but instead an authentication or proxy error. I am using the url in the following format: smb://foldername/something/somethingelse/anothersomething/
My code:
public static Boolean checkDiretory(String location, String docName){
Boolean result = false;
try {
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("", Consts.username, Consts.password);
SmbFile root = new SmbFile(location, auth);
List<SmbFile> files = Arrays.asList(root.listFiles());
for(SmbFile file : files){
if(file.isDirectory()){
result = checkDiretory(file.getPath(), docName);
if(result)
return result;
}
else{
if(file.exists() && file.getName().contains(docName)){
return true;
}else{
result = false;
}
}
}
} catch (SmbException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
}
return result;
}
Like Eliad Cohen suggested, you might have to change to SMBJ due to incompatibility of SMBv2 in jcifs.
I've found a similar issue here which may help you to solve this matter.
Keep in mind that the host is just your path!
Happy coding!

Handling a Biometric Fingerprint Attendance Device by using socket

I am trying to connect with a Biometric Fingerprint Attendance Device using a Java program. The device I am using is a Biocom Fingerprint attendance system. However, I am search and reading about that and I see the SDK could used which based on device type (which hard, not logical, moreover, it is not global solution!)
I research for a global standard on how to connect, send and retrieve data with a Fingerprint Device which again I wasn't lucky enough to find a clear solution. Currently, I tried to connect with the device by creating a Socket object (through Ethernet port) but also not executed with me. This open infinite loop problems on my head.
Is there any general, standard way to connect, send and retrieve data from such device using Java?
Can a Socket be considered as a solution for such problem?
If yes, what is wrong in my code below? What additional things more than the host IP and port number are needed to connect with the device?
The Socket code that used:
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class Requester {
Socket requestSocket;
ObjectOutputStream out;
ObjectInputStream in;
String message;
Requester() {
}
void run() throws IOException {
try {
// 1. creating a socket to connect to the server
requestSocket = new Socket("192.168.0.19", 4370);
System.out.println("Connected to given host in port 4370");
// 2. get Input and Output streams
in = new ObjectInputStream(requestSocket.getInputStream());
// 3: Communicating with the server
String line;
while (true) {
line = in.readLine();
if (line != null) {
System.out.println(line);
}
}
} catch (UnknownHostException unknownHost) {
System.err.println("You are trying to connect to an unknown host!");
} catch (IOException ioException) {
ioException.printStackTrace();
} catch (Exception Exception) {
Exception.printStackTrace();
} finally {
in.close();
requestSocket.close();
}
}
void sendMessage(String msg) {
try {
out.writeObject(msg);
out.flush();
System.out.println("client: " + msg);
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
public static void main(String args[]) throws IOException {
Requester client = new Requester();
client.run();
}
}
This image may give more details:
You don't need the ObjectInputStream. Just use the InputStream you get from requestSocket.getInputStream().
Alternatively use a terminal programm like putty to connect to your device. This requires no coding.
Biocom Biometrics are ZKTeco devices. ZkTeco devices are launched only with windows SDK. You can download the SDK from https://www.zkteco.com/en/download_catgory.html and use the DLL in java which can run only on Windows platorm. For HTTP communication, to work in any platform through any language, refer http://camsunit.com/application/zk-teco-essl-api-integration.html

java: FTP in multi threaded, multi user web application

I'm developing an application using Spring MVC. In a business process, an image file is generated which needs to retrieved to web server from the application server. I'm using the commons-net api to do it the simple way.
public class FtpUtility{
private FTPClient ftpClient = new FTPClient();
public boolean retriveFileFromApp(String srcFile, String destFile){
boolean flag = false;
try{
connectToFtp()
File dest = new File(destFile);
if(!dest.exists())
dest.mkdirs();
if(dest.exists())
dest.delete();
FileOutputStream destStream = new FileOutputStream(dest);
ftpClient.retrieveFile(srcFile, destStream);
}
catch(Exception e){
//exception handling
}
finally{
disconnect();
}
return flag;
}
private boolean connectToFtp(){
boolean flag = false;
try{
ftpClient.connect(appserverip); // connect to ftp
flag = ftpClient.login(ftpUserId, ftpPassword);
}
catch(Exception e){
//exception handling
}
return flag;
}
private void disconnect(){
try{
ftpClient.logout();
ftpClient.disconnect();
}
catch(Exception e){
//some exception handling
}
}
}
Now while multiple users are using this application, they are simultaneously connecting using an instance of this class and then disconnecting. Even a single user is connecting and disconnecting for each file transfer.
How can I effectively do this like connecting once, then doing the all transfer and then disconnecting, not opening and closing the connection for each transfer.
Will use of static help? If yes how?
This isn't going to work. Either the FTP client is static and you connect it once and use it serially via synchronization, or it is per-session and each session creates and connects and uses its own concurrently. Your present mixture of both can't work.

Categories

Resources