package org.fnppl.opensdx.ftp_bridge; /* * Copyright (C) 2010-2015 * fine people e.V. <opensdx@fnppl.org> * Henning Thieß <ht@fnppl.org> * * http://fnppl.org */ /* * Software license * * As far as this file or parts of this file is/are software, rather than documentation, this software-license applies / shall be applied. * * This file is part of openSDX * openSDX is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * openSDX 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 General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * and GNU General Public License along with openSDX. * If not, see <http://www.gnu.org/licenses/>. * */ /* * Documentation license * * As far as this file or parts of this file is/are documentation, rather than software, this documentation-license applies / shall be applied. * * This file is part of openSDX. * Permission is granted to copy, distribute and/or modify this document * under the terms of the GNU Free Documentation License, Version 1.3 * or any later version published by the Free Software Foundation; * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. * A copy of the license is included in the section entitled "GNU * Free Documentation License" resp. in the file called "FDL.txt". * */ import java.awt.BorderLayout; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Vector; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.table.DefaultTableModel; import org.fnppl.opensdx.file_transfer.CommandResponseListener; import org.fnppl.opensdx.file_transfer.OSDXFileTransferClient; import org.fnppl.opensdx.file_transfer.commands.OSDXFileTransferCommand; import org.fnppl.opensdx.file_transfer.commands.OSDXFileTransferDeleteCommand; import org.fnppl.opensdx.file_transfer.commands.OSDXFileTransferDownloadStreamCommand; import org.fnppl.opensdx.file_transfer.commands.OSDXFileTransferListCommand; import org.fnppl.opensdx.file_transfer.commands.OSDXFileTransferMkDirCommand; import org.fnppl.opensdx.file_transfer.commands.OSDXFileTransferRenameCommand; import org.fnppl.opensdx.file_transfer.commands.OSDXFileTransferUploadOldStyleCommand; import org.fnppl.opensdx.file_transfer.model.RemoteFile; import org.fnppl.opensdx.file_transfer.model.Transfer; import org.fnppl.opensdx.helper.QueueWaiting; import org.fnppl.opensdx.security.OSDXKey; import org.fnppl.opensdx.xml.Document; import org.fnppl.opensdx.xml.Element; public class FTP_OSDX_Bridge implements CommandResponseListener { public final static String VERSION = "v.2012-07-20"; private File configFile = new File("ftp_bridge_config.xml"); private File alterConfigFile = new File("src/org/fnppl/opensdx/ftp_bridge/resources/ftp_bridge_config.xml"); private int port = 2221; private HashMap<String, FTP_OSDX_BridgeUser> users = new HashMap<String, FTP_OSDX_BridgeUser>(); public FTP_OSDX_Bridge() { readConfig(); } public FTP_OSDX_Bridge(File configFile) { this.configFile = configFile; readConfig(); } public void readConfig() { users = new HashMap<String, FTP_OSDX_BridgeUser>(); try { if (!configFile.exists()) { configFile = alterConfigFile; } if (!configFile.exists()) { System.out.println("Sorry, ftp_bridge_config.xml not found."); System.exit(0); } Element root = Document.fromFile(configFile).getRootElement(); String sPort = root.getChildText("ftp_server_port"); if (sPort!=null) { try { port = Integer.parseInt(sPort); } catch (Exception ex) { System.out.println("error in config: could not parse ftp_server_port: "+sPort); } } Vector<Element> userConfig = root.getChildren("user"); if (userConfig == null) return; for (Element e : userConfig) { try { String ftp_username = e.getChildTextNN("ftp_username"); String ftp_password = e.getChildTextNN("ftp_password"); OSDXKey mysigning = OSDXKey.fromElement(e.getChild("keypair")); mysigning.unlockPrivateKey(e.getChildTextNN("password")); String username = e.getChildTextNN("username"); FTP_OSDX_BridgeUser c = new FTP_OSDX_BridgeUser(); c.ftpusername = ftp_username; c.ftppassword = ftp_password; c.host = e.getChildTextNN("host"); c.port = Integer.parseInt(e.getChildTextNN("port")); c.prepath = e.getChildTextNN("prepath"); c.signingKey = mysigning; c.username = username; System.out.println("adding user: "+ftp_username+" -> "+username+"::"+mysigning.getKeyID()); users.put(ftp_username, c); } catch (Exception exIn) { exIn.printStackTrace(); } } } catch (Exception ex) { ex.printStackTrace(); } } public void startService() { try { System.out.println("Starting FTP-to-OSDXFiletransfer-Bridge "+VERSION+" on port "+port); osdxclient = new OSDXFileTransferClient(); osdxclient.addResponseListener(this); try { if (users.isEmpty()) { System.out.println("No osdx user configured. Please check your config file."); return; } user = users.values().iterator().next(); osdxclient.connect(user.host, user.port, user.prepath, user.signingKey, user.username); } catch (Exception e) { System.out.println("Error connecting to osdx fileserver. Please check your config file."); } uploadThread = new Thread() { public void run() { while (true) { Transfer t = waitingUploads.get(); if (t==null) { System.out.println("Upload Thread: NULL"); return; //queue of waiting uploads has stopped } System.out.println("Upload Thread: "+t.originalFilename); try { long id = osdxclient.upload(t.file, t.originalFilename); transfersInProgress.put(id, t); } catch (Exception ex) { ex.printStackTrace(); } } } }; uploadThread.start(); ServerSocket s = new ServerSocket(port); while(true) { Socket incoming = s.accept(); new FTP_OSDX_BridgeThread(incoming, this).start(); } } catch (Exception e) { e.printStackTrace(); } } public FTP_OSDX_BridgeUser getUser(String username) { return users.get(username); } public static void main(String[] args) { if (args.length>0) { File f = new File(args[0]); if (f.exists()) { System.out.println("Using config file "+f.getAbsolutePath()); new FTP_OSDX_Bridge(f).startService(); } else { System.out.println("Error: config file "+f.getAbsolutePath()+" does not exist!"); } } else { new FTP_OSDX_Bridge().startService(); } } public OSDXFileTransferClient osdxclient = null; public FTP_OSDX_BridgeUser user = null; public PrintWriter lastOut = null; public HashMap<Long,Transfer> transfersInProgress = new HashMap<Long, Transfer>(); public HashMap<Long,FTP_OSDX_BridgeThread> commandThread = new HashMap<Long, FTP_OSDX_BridgeThread>(); public String pwd = "/"; public QueueWaiting<Transfer> waitingUploads = new QueueWaiting<Transfer>(); private Thread uploadThread = null; public void onSuccess(OSDXFileTransferCommand command) { //System.out.println("Command "+command.getID()+" successful :: "+command.getClass().getSimpleName()); Transfer transfer = transfersInProgress.get(command.getID()); FTP_OSDX_BridgeThread thread = commandThread.get(command.getID()); //if (thread==null) { // System.out.println("NO THREAD TO COMMAND "+command.getID()+" FOUND"); //} //if (transfer==null) { // System.out.println("no transfer type"); //} if (transfer!=null) { if (transfer.type.equals("upload")) { if (command instanceof OSDXFileTransferUploadOldStyleCommand) { System.out.println("upload succeeded\n"); waitingUploads.readyForNext(); transfersInProgress.remove(command.getID()); updateFileTransfers(); } } else { //download if (thread!=null) { // try { // File tmpFile = transfer.file; // if (tmpFile.exists()) { // thread.out.println("150 Binary data connection"); // // //transfer downloaded file to ftp client // FileInputStream fin = new FileInputStream(tmpFile); // // Socket t = thread.getDataSocket(); // if (t==null) { // return; // } // OutputStream out2 = t.getOutputStream(); // byte buffer[] = new byte[1024]; // int read; // try { // while ((read = fin.read(buffer)) != -1) { // out2.write(buffer, 0, read); // } // out2.close(); // thread.out.println("226 transfer complete"); // fin.close(); // tmpFile.delete(); // t.close(); // } catch (IOException e) { // e.printStackTrace(); // } // } else { // thread.out.println("550 Requested action not taken. File unavailable (e.g., file not found, no access)."); // } // } catch (Exception ex) { // ex.printStackTrace(); // } thread.out.println("226 transfer complete"); } else { System.out.println("Connection to FTP Client lost"); } } } else { if (command instanceof OSDXFileTransferDownloadStreamCommand) { System.out.println("streamed download succeeded."); if (thread!=null) { thread.out.println("226 transfer complete"); } else { System.out.println("Connection to FTP Client lost"); } } else if (command instanceof OSDXFileTransferDeleteCommand) { if (command.getID() == thread.lastRMDCommandID) { thread.out.println("250 RMD command succesful"); } else { thread.out.println("250 DELE command succesful"); } } else if (command instanceof OSDXFileTransferRenameCommand) { thread.out.println("250 Rename command succesful"); } else if (command instanceof OSDXFileTransferListCommand) { try { thread.out.println("150 ASCII data"); Socket t = thread.getDataSocket(); if (t==null) { return; } PrintWriter out2 = new PrintWriter(t.getOutputStream(), true); Vector<RemoteFile> list = ((OSDXFileTransferListCommand)command).getList(); for (RemoteFile f : list) { //System.out.println("LIST::"+f.getName()); String di; if (f.isDirectory()) { di = "drwxr-xr-x "; } else { di = "-rw-r--r--"; } String name = f.getName(); //name = name.replace(' ', '_'); String e = di+"1 user group "+f.getLength()+" Jul 04 20:00 "+name+""; out2.println(e); } t.close(); thread.out.println("226 transfer complete"); } catch (Exception ex) { ex.printStackTrace(); } } else if (command instanceof OSDXFileTransferMkDirCommand) { thread.out.println("250 MKD command succesful"); } } //command not longer needed in commandThread map commandThread.remove(command.getID()); } public void onError(OSDXFileTransferCommand command, String msg) { System.out.println("ERROR: "+msg); Transfer transfer = transfersInProgress.get(command.getID()); FTP_OSDX_BridgeThread thread = commandThread.get(command.getID()); if (transfer!=null) { if (transfer.type.equals("upload")) { if (command instanceof OSDXFileTransferUploadOldStyleCommand) { System.out.println("ERROR upload failed!!!\n"); waitingUploads.readyForNext(); transfersInProgress.remove(command.getID()); updateFileTransfers(); } } } else if (command instanceof OSDXFileTransferDownloadStreamCommand) { System.out.println("streamed download failed."); if (thread!=null) { thread.out.println("550 Requested action not taken. File unavailable (e.g., file not found, no access)."); } else { System.out.println("Connection to FTP Client lost"); } } else { if (thread!=null) thread.out.println("550 Requested action not taken. File unavailable (e.g., file not found, no access)."); } // if (command instanceof OSDXFileTransferListCommand) { // out.println("550 Requested action not taken. File unavailable (e.g., file not found, no access)."); // } // else if (command instanceof OSDXFileTransferMkDirCommand) { // out.println("550 Requested action not taken. File unavailable (e.g., file not found, no access)."); // } // if (command instanceof OSDXFileTransferRenameCommand) { // out.println("550 Requested action not taken. File unavailable (e.g., file not found, no access)."); // } // else { // } } public synchronized void onStatusUpdate(OSDXFileTransferCommand command, long progress,long maxProgress, String msg) { Transfer transfer = transfersInProgress.get(command.getID()); if (transfer!=null) { if (transfer.type.equals("upload")) { transfer.pos = (int)progress; transfer.fileLen = maxProgress; //System.out.println("STATUS UPDATE: "+transfer.file.getName()+" :: "+progress+" of "+maxProgress); updateFileTransfers(); } } } // private JFrame progressWnd = null; // private JTable tableProgress = null; // private synchronized void updateFileTransfers() { // if (progressWnd==null) { // progressWnd = new JFrame("FTP to OSDX Bridge :: Uploads"); // progressWnd.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); // progressWnd.setSize(400, 400); // // tableProgress = new JTable(); // progressWnd.setLayout(new BorderLayout()); // progressWnd.add("Center",new JScrollPane(tableProgress)); // progressWnd.setAlwaysOnTop(true); // progressWnd.setVisible(true); // } // // // Collection<Transfer> trans = transfersInProgress.values(); // int countInProgress = trans.size(); // List<Transfer> transWaiting = waitingUploads.list(); // int countWaiting = transWaiting.size(); // int count = countInProgress + countWaiting; // String[] head = new String[] {"filename","transferred","length"}; // String[][] data = new String[count][3]; // int row = 0; // for (Transfer t : trans) { // data[row][0] = t.originalFilename; // //data[row][1] = t.type; // data[row][1] = (t.pos/1024)+" kB"; // data[row][2] = (t.fileLen/1024)+" kB"; // row++; // } // for (Transfer t : transWaiting) { // data[row][0] = t.originalFilename; // //data[row][1] = t.type; // data[row][1] = " waiting..."; // data[row][2] = (t.fileLen/1024)+" kB"; // row++; // } // tableProgress.setModel(new DefaultTableModel(data, head)); // } private long minUpdateDuration = 5000; //update view every 5 seconds or when upload finished private long lastProgressTime = 0; private long lastProgress = -1L; private synchronized void updateFileTransfers() { Collection<Transfer> trans = transfersInProgress.values(); int countInProgress = trans.size(); int countWaiting = waitingUploads.countWaiting(); long now = System.currentTimeMillis(); for (Transfer t : trans) { if (lastProgressTime + minUpdateDuration < now || t.pos == t.fileLen) { String speed = ""; if (lastProgress>0 && (now-lastProgressTime)>0) { long bytePerMS = (t.pos-lastProgress)/(now-lastProgressTime); speed = "\t"+bytePerMS+" kB/s"; // byte/ms nearly kB/s } lastProgressTime = now; lastProgress = t.pos; if (t.pos == t.fileLen) { lastProgress = -1L; } // if ("upload".equals(t.type)) { // String msg = "Upload progress "+t.originalFilename // + "\t"+(t.pos/1024)+" kB of "+(t.fileLen/1024)+" kB"+speed+"\t\t " // +countWaiting+" file(s) in queue" ; // System.out.println(msg); // } if ("upload".equals(t.type)) { String msg = "Upload progress "+t.originalFilename + "\t"+(t.pos/1024)+" kB transferred "+speed+"\t\t " +countWaiting+" file(s) in queue" ; System.out.println(msg); } } } } }