/** Abort the current transfer */ private void abortTransfer() { // logger.debug("Will abort transfer and write: ", write); FtpFile file = null; FtpTransfer current = null; try { current = getExecutingFtpTransfer(); file = current.getFtpFile(); file.abortFile(); } catch (FtpNoTransferException e) { logger.warn("Abort problem", e); } catch (FtpNoFileException e) { } catch (CommandAbstractException e) { logger.warn("Abort problem", e); } if (current != null) { current.setStatus(false); } endDataConnection(); session.setReplyCode( ReplyCode.REPLY_426_CONNECTION_CLOSED_TRANSFER_ABORTED, "Transfer aborted for " + (current == null ? "Unknown command" : current.toString())); if (current != null) { if (!FtpCommandCode.isListLikeCommand(current.getCommand())) { try { session.getBusinessHandler().afterTransferDoneBeforeAnswer(current); } catch (CommandAbstractException e) { session.setReplyCode(e); } } } finalizeExecution(); }
/** Run the command from an executor */ private void runExecutor() { // Unlock Mode Codec try { session.getDataConn().getDataNetworkHandler().unlockModeCodec(); } catch (FtpNoConnectionException e) { setTransferAbortedFromInternal(false); return; } // Run the command if (executorService == null) { executorService = Executors.newSingleThreadExecutor(); } endOfCommand = new WaarpFuture(true); final ArrayList<Callable<Object>> tasks = new ArrayList<Callable<Object>>(1); tasks.add(Executors.callable(new FtpTransferExecutor(session, executingCommand))); try { executorService.invokeAll(tasks); } catch (InterruptedException e1) { } // XXX TRY FIX TO IMPROVE /* executorService.execute(new FtpTransferExecutor(session, executingCommand)); */ try { commandFinishing.await(); } catch (InterruptedException e) { } }
/** * To enable abort from internal error * * @param write True means the message is write back to the control command, false it is only * prepared */ public void setTransferAbortedFromInternal(boolean write) { // logger.debug("Set transfer aborted internal {}", write); abortTransfer(); if (write) { session.getNetworkHandler().writeIntermediateAnswer(); } if (endOfCommand != null) { endOfCommand.cancel(); } }
/** * Set the new opened Channel (from channelConnected of {@link DataNetworkHandler}) * * @param channel * @param dataNetworkHandler */ public void setOpenedDataChannel(Channel channel, DataNetworkHandler dataNetworkHandler) { logger.debug( "SetOpenedDataChannel: " + (channel != null ? channel.getRemoteAddress() : "no channel")); if (channel != null) { session.getDataConn().setDataNetworkHandler(dataNetworkHandler); waitForOpenedDataChannel.setChannel(channel); waitForOpenedDataChannel.setSuccess(); } else { waitForOpenedDataChannel.cancel(); } }
/** Finish correctly a transfer */ private void closeTransfer() { // logger.debug("Will close transfer and write: {}", write); FtpFile file = null; FtpTransfer current = null; try { current = getExecutingFtpTransfer(); file = current.getFtpFile(); file.closeFile(); } catch (FtpNoTransferException e) { logger.warn("Close problem", e); } catch (FtpNoFileException e) { } catch (CommandAbstractException e) { logger.warn("Close problem", e); } if (current != null) { current.setStatus(true); } if (session.getDataConn().isStreamFile()) { endDataConnection(); } session.setReplyCode( ReplyCode.REPLY_226_CLOSING_DATA_CONNECTION, "Transfer complete for " + (current == null ? "Unknown command" : current.toString())); if (current != null) { if (!FtpCommandCode.isListLikeCommand(current.getCommand())) { try { session.getBusinessHandler().afterTransferDoneBeforeAnswer(current); } catch (CommandAbstractException e) { session.setReplyCode(e); } } else { // Special wait to prevent fast LIST following by STOR or RETR command try { Thread.sleep(FtpInternalConfiguration.RETRYINMS); } catch (InterruptedException e) { } } } finalizeExecution(); }
/** * Wait that the new opened connection is ready (same method in {@link FtpDataAsyncConn} from * openConnection) * * @return the new opened Channel * @throws InterruptedException */ public Channel waitForOpenedDataChannel() throws InterruptedException { Channel channel = null; if (waitForOpenedDataChannel.await( session.getConfiguration().TIMEOUTCON + 1000, TimeUnit.MILLISECONDS)) { if (waitForOpenedDataChannel.isSuccess()) { channel = waitForOpenedDataChannel.getChannel(); } else { logger.warn("data connection is in error"); } } else { logger.warn("Timeout occurs during data connection"); } waitForOpenedDataChannel = new WaarpChannelFuture(true); return channel; }
/** * Wait for the client to be connected (Passive) or Wait for the server to be connected to the * client (Active) * * @return True if the connection is OK * @throws Reply425Exception */ public boolean openDataConnection() throws Reply425Exception { // Prepare this Data channel to be closed ;-) // In fact, prepare the future close op which should occur since it is // now opened closedDataChannel = new WaarpFuture(true); FtpDataAsyncConn dataAsyncConn = session.getDataConn(); if (!dataAsyncConn.isStreamFile()) { // FIXME isConnected or isDNHReady ? if (dataAsyncConn.isConnected()) { // Already connected // logger.debug("Connection already open"); session.setReplyCode( ReplyCode.REPLY_125_DATA_CONNECTION_ALREADY_OPEN, dataAsyncConn.getType().name() + " mode data connection already open"); return true; } } else { // Stream, Data Connection should not be opened if (dataAsyncConn.isConnected()) { logger.error("Connection already open but should not since in Stream mode"); setTransferAbortedFromInternal(false); throw new Reply425Exception("Connection already open but should not since in Stream mode"); } } // Need to open connection session.setReplyCode( ReplyCode.REPLY_150_FILE_STATUS_OKAY, "Opening " + dataAsyncConn.getType().name() + " mode data connection"); if (dataAsyncConn.isPassiveMode()) { if (!dataAsyncConn.isBind()) { // No passive connection prepared throw new Reply425Exception("No passive data connection prepared"); } // Wait for the connection to be done by the client // logger.debug("Passive mode standby"); try { dataChannel = waitForOpenedDataChannel(); dataAsyncConn.setNewOpenedDataChannel(dataChannel); } catch (InterruptedException e) { logger.warn("Connection abort in passive mode", e); // Cannot open connection throw new Reply425Exception("Cannot open passive data connection"); } // logger.debug("Passive mode connected"); } else { // Wait for the server to be connected to the client InetAddress inetAddress = dataAsyncConn.getLocalAddress().getAddress(); InetSocketAddress inetSocketAddress = dataAsyncConn.getRemoteAddress(); if (session .getConfiguration() .getFtpInternalConfiguration() .hasFtpSession(inetAddress, inetSocketAddress)) { throw new Reply425Exception( "Cannot open active data connection since remote address is already in use: " + inetSocketAddress); } // logger.debug("Active mode standby"); ClientBootstrap clientBootstrap = session .getConfiguration() .getFtpInternalConfiguration() .getActiveBootstrap(session.isDataSsl()); session.getConfiguration().setNewFtpSession(inetAddress, inetSocketAddress, session); // Set the session for the future dataChannel String mylog = session.toString(); logger.debug( "DataConn for: " + session.getCurrentCommand().getCommand() + " to " + inetSocketAddress.toString()); ChannelFuture future = clientBootstrap.connect(inetSocketAddress, dataAsyncConn.getLocalAddress()); try { future.await(); } catch (InterruptedException e1) { } if (!future.isSuccess()) { logger.warn( "Connection abort in active mode from future while session: " + session.toString() + "\nTrying connect to: " + inetSocketAddress.toString() + "\nWas: " + mylog, future.getCause()); // Cannot open connection session.getConfiguration().delFtpSession(inetAddress, inetSocketAddress); throw new Reply425Exception("Cannot open active data connection"); } try { dataChannel = waitForOpenedDataChannel(); dataAsyncConn.setNewOpenedDataChannel(dataChannel); } catch (InterruptedException e) { logger.warn("Connection abort in active mode", e); // Cannot open connection session.getConfiguration().delFtpSession(inetAddress, inetSocketAddress); throw new Reply425Exception("Cannot open active data connection"); } // logger.debug("Active mode connected"); } if (dataChannel == null) { // Cannot have a new Data connection since shutdown if (!dataAsyncConn.isPassiveMode()) { session .getConfiguration() .getFtpInternalConfiguration() .delFtpSession( dataAsyncConn.getLocalAddress().getAddress(), dataAsyncConn.getRemoteAddress()); } throw new Reply425Exception("Cannot open data connection, shuting down"); } return true; }