client/ftpd/src/se/lu/thep/coreftpd/ftp_server/FTPDataConnection.java

Code
Comments
Other
Rev Date Author Line
741 10 Oct 06 olle 1 /*
1652 22 May 07 gregory 2  $Id$
741 10 Oct 06 olle 3
1916 31 Aug 07 jari 4  Copyright (C) 2006 Olle Mansson
1916 31 Aug 07 jari 5  Copyright (C) 2007 Gregory Vincic, Olle Mansson
741 10 Oct 06 olle 6
1652 22 May 07 gregory 7  This file is part of Proteios.
1652 22 May 07 gregory 8  Available at http://www.proteios.org/
741 10 Oct 06 olle 9
1652 22 May 07 gregory 10  Proteios is free software; you can redistribute it and/or modify it
1652 22 May 07 gregory 11  under the terms of the GNU General Public License as published by
1652 22 May 07 gregory 12  the Free Software Foundation; either version 2 of the License, or
1652 22 May 07 gregory 13  (at your option) any later version.
741 10 Oct 06 olle 14
1652 22 May 07 gregory 15  Proteios is distributed in the hope that it will be useful, but
1652 22 May 07 gregory 16  WITHOUT ANY WARRANTY; without even the implied warranty of
1652 22 May 07 gregory 17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1652 22 May 07 gregory 18  General Public License for more details.
741 10 Oct 06 olle 19
1652 22 May 07 gregory 20  You should have received a copy of the GNU General Public License
1652 22 May 07 gregory 21  along with this program; if not, write to the Free Software
1652 22 May 07 gregory 22  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1652 22 May 07 gregory 23  02111-1307, USA.
1652 22 May 07 gregory 24  */
741 10 Oct 06 olle 25
741 10 Oct 06 olle 26 //  Xerver Free Web Server
741 10 Oct 06 olle 27 //  Copyright (C) 2002-2005 Omid Rouhani
741 10 Oct 06 olle 28 //
741 10 Oct 06 olle 29 //
741 10 Oct 06 olle 30 //  This program is free software; you can redistribute it and/or
741 10 Oct 06 olle 31 //  modify it under the terms of the GNU General Public License
741 10 Oct 06 olle 32 //  as published by the Free Software Foundation; either version 2
741 10 Oct 06 olle 33 //  of the License, or (at your option) any later version.
741 10 Oct 06 olle 34 //
741 10 Oct 06 olle 35 //  This program is distributed in the hope that it will be useful,
741 10 Oct 06 olle 36 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
741 10 Oct 06 olle 37 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
741 10 Oct 06 olle 38 //  GNU General Public License for more details.
741 10 Oct 06 olle 39 //
741 10 Oct 06 olle 40 //  You should have received a copy of the GNU General Public License
741 10 Oct 06 olle 41 //  along with this program; if not, write to the Free Software
741 10 Oct 06 olle 42 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
741 10 Oct 06 olle 43 //
741 10 Oct 06 olle 44 //
741 10 Oct 06 olle 45 //  #############################################################
741 10 Oct 06 olle 46 //  ##  YOU CAN CONTACT THE AUTHOR (OMID ROUHANI) AT:          ##
741 10 Oct 06 olle 47 //  ##  HTTP://WWW.JAVASCRIPT.NU/XERVER/                       ##
741 10 Oct 06 olle 48 //  ##                                                         ##
741 10 Oct 06 olle 49 //  ##  IF YOUR SOFTWARE IS NOT RELEASED UNDER THE             ##
741 10 Oct 06 olle 50 //  ##  GNU GENERAL PUBLIC LICENSE (GPL),                      ##
741 10 Oct 06 olle 51 //  ##  PLEASE DO NOT COPY ANYTHING FROM THIS SOURCE CODE!!!   ##
741 10 Oct 06 olle 52 //  ##                                                         ##
741 10 Oct 06 olle 53 //  ##  FOR FULL LICENSE, PLEASE READ "XERVER LICENSE".        ##
741 10 Oct 06 olle 54 //  #############################################################
741 10 Oct 06 olle 55
1652 22 May 07 gregory 56 package se.lu.thep.coreftpd.ftp_server;
741 10 Oct 06 olle 57
1676 25 May 07 olle 58 import org.proteios.core.SessionControl;
791 23 Oct 06 olle 59 import se.lu.thep.coreftpd.common.DataInputStreamWithReadLine;
791 23 Oct 06 olle 60 import se.lu.thep.coreftpd.common.StreamIO;
741 10 Oct 06 olle 61 import java.io.BufferedInputStream;
741 10 Oct 06 olle 62 import java.io.BufferedOutputStream;
741 10 Oct 06 olle 63 import java.io.DataOutputStream;
741 10 Oct 06 olle 64 import java.io.File;
741 10 Oct 06 olle 65 import java.io.IOException;
741 10 Oct 06 olle 66 import java.net.BindException;
741 10 Oct 06 olle 67 import java.net.InetAddress;
741 10 Oct 06 olle 68 import java.net.ServerSocket;
741 10 Oct 06 olle 69 import java.net.Socket;
741 10 Oct 06 olle 70
741 10 Oct 06 olle 71 /**
1652 22 May 07 gregory 72  * 
1652 22 May 07 gregory 73  * <B>About this class:</B> <BR>
1652 22 May 07 gregory 74  * This is the FTP data connection. <BR>
1652 22 May 07 gregory 75  * There are two different constructors. One if you want use passive mode
1652 22 May 07 gregory 76  * ("PASV") and one if you want use active mode ("PORT").
1652 22 May 07 gregory 77  * 
741 10 Oct 06 olle 78  * @author <a href="http://www.JavaScript.nu/xerver/" TARGET="_top">Omid Rouhani</a>
741 10 Oct 06 olle 79  * @version 1.0
741 10 Oct 06 olle 80  */
741 10 Oct 06 olle 81
1652 22 May 07 gregory 82 final public class FTPDataConnection extends Thread {
1652 22 May 07 gregory 83   private static final boolean b_showErrors = false;
741 10 Oct 06 olle 84
741 10 Oct 06 olle 85   private ServerSocket ss_dataConnection;
1652 22 May 07 gregory 86
2703 16 May 08 olle 87   private int i_portNr;
1652 22 May 07 gregory 88
741 10 Oct 06 olle 89   private Socket so_userConnection;
1652 22 May 07 gregory 90
741 10 Oct 06 olle 91   private DataOutputStream bos;
1652 22 May 07 gregory 92
741 10 Oct 06 olle 93   private DataInputStreamWithReadLine bis;
1652 22 May 07 gregory 94
1652 22 May 07 gregory 95   // NOTE: change this from 10000 to 30000 later on
1652 22 May 07 gregory 96   private static int i_timeToWaitForDataConnection = 30000; // Note, this
1652 22 May 07 gregory 97                                 // can be almost
1652 22 May 07 gregory 98                                 // anything,
1652 22 May 07 gregory 99                                 // after
1652 22 May 07 gregory 100                                 // i_timeToWaitForDataConnection
1652 22 May 07 gregory 101                                 // milliseconds
1652 22 May 07 gregory 102                                 // an error will
1652 22 May 07 gregory 103                                 // be thrown
1652 22 May 07 gregory 104                                 // from
1652 22 May 07 gregory 105                                 // ".accept()"
1652 22 May 07 gregory 106                                 // and we then
1652 22 May 07 gregory 107                                 // immediately
1652 22 May 07 gregory 108                                 // make a new
1652 22 May 07 gregory 109                                 // ".accept()"
1652 22 May 07 gregory 110                                 // and listen
1652 22 May 07 gregory 111                                 // again (unless
1652 22 May 07 gregory 112                                 // we have set
1652 22 May 07 gregory 113                                 // ss_dataConnection==null
1652 22 May 07 gregory 114                                 // (so the
1652 22 May 07 gregory 115                                 // while-loop
1652 22 May 07 gregory 116                                 // stops and we
1652 22 May 07 gregory 117                                 // don't listen
1652 22 May 07 gregory 118                                 // to the port
1652 22 May 07 gregory 119                                 // anymore))
1652 22 May 07 gregory 120
741 10 Oct 06 olle 121   private boolean b_isPASV;
1652 22 May 07 gregory 122
1652 22 May 07 gregory 123   private boolean b_couldConnectInPORTmode = true; // This MUST be true
1652 22 May 07 gregory 124                             // here, and will be set
1652 22 May 07 gregory 125                             // to false if port nr
1652 22 May 07 gregory 126                             // "i_dataPortNr" is
1652 22 May 07 gregory 127                             // already in use or
1652 22 May 07 gregory 128                             // banned (or another
1652 22 May 07 gregory 129                             // error occur so the
1652 22 May 07 gregory 130                             // connection fails).
1652 22 May 07 gregory 131
741 10 Oct 06 olle 132   public static int i_dataPortNr;
1652 22 May 07 gregory 133
741 10 Oct 06 olle 134   private String s_hostUsedForPORT;
1652 22 May 07 gregory 135
741 10 Oct 06 olle 136   private int i_portUsedForPORT;
741 10 Oct 06 olle 137
1652 22 May 07 gregory 138   // Save this for future use?: private int raknare=0;
1652 22 May 07 gregory 139
2703 16 May 08 olle 140   // Which port range shall we use? See the construction comment below.
2703 16 May 08 olle 141   public static int [] ai_portRange = null;
2703 16 May 08 olle 142   // Which port shall we use next? (For PASV only, when we want ports in a particular range)
2703 16 May 08 olle 143   private static int i_nextPortToUse = -1;
2703 16 May 08 olle 144   
1676 25 May 07 olle 145   /*
2703 16 May 08 olle 146    * This only matters if the size of the range of ports
2703 16 May 08 olle 147    * is greater than this value. Normally we try to open
2703 16 May 08 olle 148    * every single port in the specified interval to be
2703 16 May 08 olle 149    * able to find if any port works. However, if the
2703 16 May 08 olle 150    * interval is too big that would take too long time,
2703 16 May 08 olle 151    * instead we have this to have a maximum number
2703 16 May 08 olle 152    * of ports that we will try to open. If the range
2703 16 May 08 olle 153    * for example is 25-35 and this value is
2703 16 May 08 olle 154    * for example 50, we will still only try to open
2703 16 May 08 olle 155    * 10 ports, not 50.
2703 16 May 08 olle 156    */
2703 16 May 08 olle 157   private static int MAX_NR_GET_FREE_PORT_ATTEMPTS = 100;
2703 16 May 08 olle 158   /*
2703 16 May 08 olle 159    * This is how many times we should retry to call
2703 16 May 08 olle 160    * ".accept()" if it throws exceptions (other than
2703 16 May 08 olle 161    * the SocketTimeoutException exception which is thrown
2703 16 May 08 olle 162    * if the client never takes the connection
2703 16 May 08 olle 163    * - if SocketTimeoutException is thrown we will not
2703 16 May 08 olle 164    * retry to listen to the port).
2703 16 May 08 olle 165    */
2703 16 May 08 olle 166   private static int MAX_NR_PASV_RETRY_ATTEMPTS = 10;
2703 16 May 08 olle 167
2703 16 May 08 olle 168   /*
1676 25 May 07 olle 169    * Instance variables not in original Xerver code.
1676 25 May 07 olle 170    */
1676 25 May 07 olle 171   private SessionControl sc = null;
3469 02 Nov 09 olle 172   private boolean inSharedProjectsFolder = false;
4047 01 Dec 10 olle 173   private boolean textBasedFTPClientType = false;
1676 25 May 07 olle 174
741 10 Oct 06 olle 175   /**
790 23 Oct 06 olle 176    * Logger used. Used to log specific events.
790 23 Oct 06 olle 177    */
790 23 Oct 06 olle 178   private static final org.apache.log4j.Logger log = org.apache.log4j.LogManager
1652 22 May 07 gregory 179       .getLogger("se.lu.thep.coreftpd.ftp_server");
790 23 Oct 06 olle 180
790 23 Oct 06 olle 181   /**
1676 25 May 07 olle 182    * Get the SessionControl object.
1676 25 May 07 olle 183    * 
1676 25 May 07 olle 184    * @return the SessionControl object
1676 25 May 07 olle 185    */
1676 25 May 07 olle 186   public SessionControl getSessionControl() {
1676 25 May 07 olle 187     return this.sc;
1676 25 May 07 olle 188   }
1676 25 May 07 olle 189
1676 25 May 07 olle 190
1676 25 May 07 olle 191   /**
1676 25 May 07 olle 192    * Set the SessionControl object.
1676 25 May 07 olle 193    * 
1676 25 May 07 olle 194    * @param sc the SessionControl object to set.
1676 25 May 07 olle 195    */
1676 25 May 07 olle 196   public void setSessionControl(SessionControl sc) {
1676 25 May 07 olle 197     this.sc = sc;
1676 25 May 07 olle 198   }
1676 25 May 07 olle 199
1676 25 May 07 olle 200
1676 25 May 07 olle 201   /**
3469 02 Nov 09 olle 202    * Get inSharedProjectsFolder flag.
3469 02 Nov 09 olle 203    * 
3469 02 Nov 09 olle 204    * @return boolean True if in shared projects folder, else false.
3469 02 Nov 09 olle 205    */
3469 02 Nov 09 olle 206   public boolean isInSharedProjectsFolder()
3469 02 Nov 09 olle 207   {
3469 02 Nov 09 olle 208     return this.inSharedProjectsFolder;
3469 02 Nov 09 olle 209   }
3469 02 Nov 09 olle 210
3469 02 Nov 09 olle 211
3469 02 Nov 09 olle 212   /**
3469 02 Nov 09 olle 213    * Set inSharedProjectsFolder flag.
3469 02 Nov 09 olle 214    * 
3469 02 Nov 09 olle 215    * @param inSharedProjectsFolder The inSharedProjectsFolder flag to set.
3469 02 Nov 09 olle 216    */
3469 02 Nov 09 olle 217   public void setInSharedProjectsFolder(boolean inSharedProjectsFolder)
3469 02 Nov 09 olle 218   {
3469 02 Nov 09 olle 219     this.inSharedProjectsFolder = inSharedProjectsFolder;
3469 02 Nov 09 olle 220   }
3469 02 Nov 09 olle 221
3469 02 Nov 09 olle 222
3469 02 Nov 09 olle 223   /**
4047 01 Dec 10 olle 224    * Get flag indicating a text-based FTP client type.
4047 01 Dec 10 olle 225    * 
4047 01 Dec 10 olle 226    * @return textBasedFTPClientType boolean Flag indicating a text-based FTP client type.
4047 01 Dec 10 olle 227    */
4047 01 Dec 10 olle 228   public boolean isTextBasedFTPClientType()
4047 01 Dec 10 olle 229   {
4047 01 Dec 10 olle 230     return this.textBasedFTPClientType;
4047 01 Dec 10 olle 231   }
4047 01 Dec 10 olle 232   
4047 01 Dec 10 olle 233
4047 01 Dec 10 olle 234   /**
4047 01 Dec 10 olle 235    * Set flag indicating a text-based FTP client type.
4047 01 Dec 10 olle 236    * 
4047 01 Dec 10 olle 237    * @param textBasedFTPClientType boolean Flag to set indicating a text-based FTP client type.
4047 01 Dec 10 olle 238    */
4047 01 Dec 10 olle 239   public void setTextBasedFTPClientType(boolean textBasedFTPClientType)
4047 01 Dec 10 olle 240   {
4047 01 Dec 10 olle 241     this.textBasedFTPClientType = textBasedFTPClientType;
4047 01 Dec 10 olle 242     log.info("FTPDataConnection::setTextBasedFTPClientType(): textBasedFTPClientType set to " + this.textBasedFTPClientType);
4047 01 Dec 10 olle 243   }
4047 01 Dec 10 olle 244
4047 01 Dec 10 olle 245   
4047 01 Dec 10 olle 246   /**
2703 16 May 08 olle 247    * Create DataConnection for passive mode (PASV).
1652 22 May 07 gregory 248    */
1652 22 May 07 gregory 249   public FTPDataConnection() {
1652 22 May 07 gregory 250     // Save this for future use?: raknare=(int)(Math.random()*1000);
741 10 Oct 06 olle 251     try {
1652 22 May 07 gregory 252       b_isPASV = true;
2703 16 May 08 olle 253       ss_dataConnection = getFreePortServerSocket();
2703 16 May 08 olle 254       // Wait i_timeToWaitForDataConnection milliseconds
2703 16 May 08 olle 255       ss_dataConnection.setSoTimeout(i_timeToWaitForDataConnection);
2703 16 May 08 olle 256       i_portNr = ss_dataConnection.getLocalPort();
1652 22 May 07 gregory 257     } catch (Exception e) {
1652 22 May 07 gregory 258       showError(e);
1652 22 May 07 gregory 259     }
741 10 Oct 06 olle 260   }
741 10 Oct 06 olle 261
741 10 Oct 06 olle 262   /**
2703 16 May 08 olle 263    * Returns a ServerSocket bound to a port.
2703 16 May 08 olle 264    * We will try to pick a port in the range specified in "ai_portRange",
2703 16 May 08 olle 265    * but if not possible, we will just pick any port, so there are no guarantees
2703 16 May 08 olle 266    * that we will be connected to a port in the specified range.
2703 16 May 08 olle 267    */
2703 16 May 08 olle 268   private static ServerSocket getFreePortServerSocket()
2703 16 May 08 olle 269     throws Exception
2703 16 May 08 olle 270   {
2703 16 May 08 olle 271     if (ai_portRange == null)
2703 16 May 08 olle 272     {
2703 16 May 08 olle 273       log.info("FTPDataConnection::getFreePortServerSocket(): Start - ai_portRange == null");
2703 16 May 08 olle 274     }
2703 16 May 08 olle 275     else
2703 16 May 08 olle 276     {
2703 16 May 08 olle 277       log.info("FTPDataConnection::getFreePortServerSocket(): Start - ai_portRange = [" + ai_portRange[0] + "," + ai_portRange[1] + "]");
2703 16 May 08 olle 278     }
2703 16 May 08 olle 279     // We will only look for a specific port number if a range is specified
2703 16 May 08 olle 280     if (ai_portRange != null)
2703 16 May 08 olle 281     {
2703 16 May 08 olle 282       if (i_nextPortToUse == -1 || i_nextPortToUse > ai_portRange[1])
2703 16 May 08 olle 283       {
2703 16 May 08 olle 284         // The first port we should look for is ai_portRange[0]
2703 16 May 08 olle 285         i_nextPortToUse = ai_portRange[0];
2703 16 May 08 olle 286       }
2703 16 May 08 olle 287       int i_startPos = i_nextPortToUse;
2703 16 May 08 olle 288       int i_nrFailures = 0;
2703 16 May 08 olle 289       /*
2703 16 May 08 olle 290        * When we have looped through all ports in the range,
2703 16 May 08 olle 291        * and neither one worked, stop looping.
2703 16 May 08 olle 292        */
2703 16 May 08 olle 293       do
2703 16 May 08 olle 294       {
2703 16 May 08 olle 295         try
2703 16 May 08 olle 296         {
2703 16 May 08 olle 297           log.info("FTPDataConnection::getFreePortServerSocket(): Trying to use port i_nextPortToUse = " + i_nextPortToUse);
2703 16 May 08 olle 298           /*
2703 16 May 08 olle 299            * Try to open this port. If it throws an exception,
2703 16 May 08 olle 300            * we will loop and try next port.
2703 16 May 08 olle 301            */
2703 16 May 08 olle 302           return new ServerSocket(i_nextPortToUse++);
2703 16 May 08 olle 303         }
2703 16 May 08 olle 304         catch (Exception e)
2703 16 May 08 olle 305         {
2703 16 May 08 olle 306           /*
2703 16 May 08 olle 307            * We could not open the port.
2703 16 May 08 olle 308            * This can be due to that the port is already used,
2703 16 May 08 olle 309            * or due to that some security restriction which
2703 16 May 08 olle 310            * does not allow us to connect to that port.
2703 16 May 08 olle 311            * It could also happen that two threads
2703 16 May 08 olle 312            * starts at approximately the same time and
2703 16 May 08 olle 313            * they would both try to open the same port,
2703 16 May 08 olle 314            * but only one would succeed and the other
2703 16 May 08 olle 315            * one would loop one more time and get the
2703 16 May 08 olle 316            * next port in the range.
2703 16 May 08 olle 317            */
2703 16 May 08 olle 318           i_nrFailures++;
2703 16 May 08 olle 319           i_nextPortToUse++;
2703 16 May 08 olle 320           if (i_nextPortToUse > ai_portRange[1])
2703 16 May 08 olle 321           {
2703 16 May 08 olle 322             i_nextPortToUse = ai_portRange[0];
2703 16 May 08 olle 323           }
2703 16 May 08 olle 324         }
2703 16 May 08 olle 325       } while (i_startPos != i_nextPortToUse && i_nrFailures < MAX_NR_GET_FREE_PORT_ATTEMPTS);
2703 16 May 08 olle 326     }
2703 16 May 08 olle 327     /*
2703 16 May 08 olle 328      * We failed to find any port in the correct range
2703 16 May 08 olle 329      * (or we didn't specify any interval), so just
2703 16 May 08 olle 330      * open any port.
2703 16 May 08 olle 331      */
2703 16 May 08 olle 332     return new ServerSocket(0); //Just open any port
2703 16 May 08 olle 333   }
2703 16 May 08 olle 334
2703 16 May 08 olle 335   
2703 16 May 08 olle 336   /**
1652 22 May 07 gregory 337    * Create DataConnection for active mode (PORT). When we call
1652 22 May 07 gregory 338    * waitForDataConnectionToBeTaken we will connect to port <CODE>port</CODE>
1652 22 May 07 gregory 339    * at host <CODE>host</CODE>.
1652 22 May 07 gregory 340    */
1652 22 May 07 gregory 341   public FTPDataConnection(String host, int port) {
1652 22 May 07 gregory 342     b_isPASV = false;
1652 22 May 07 gregory 343     s_hostUsedForPORT = host;
1652 22 May 07 gregory 344     i_portUsedForPORT = port;
741 10 Oct 06 olle 345   }
741 10 Oct 06 olle 346
741 10 Oct 06 olle 347   /**
1652 22 May 07 gregory 348    * This is set when we use passive mode (PASV) and returns what port we are
1652 22 May 07 gregory 349    * listening to.
1652 22 May 07 gregory 350    */
1652 22 May 07 gregory 351   public int getPortNr() {
2703 16 May 08 olle 352     return i_portNr;
741 10 Oct 06 olle 353   }
741 10 Oct 06 olle 354
741 10 Oct 06 olle 355   /**
1652 22 May 07 gregory 356    * This returns true iff we use active mode (PORT) and if the local port was
1652 22 May 07 gregory 357    * blocked or already in use. <BR>
1652 22 May 07 gregory 358    * By defult we will try to use port 20, but this can be changed at setup.
1652 22 May 07 gregory 359    * <BR>
1652 22 May 07 gregory 360    * In all other cases this will return false.
1652 22 May 07 gregory 361    */
1652 22 May 07 gregory 362   public boolean portNumberOccupiedWithPORT() {
741 10 Oct 06 olle 363     return !b_isPASV && !b_couldConnectInPORTmode;
741 10 Oct 06 olle 364   }
741 10 Oct 06 olle 365
2386 14 Nov 07 gregory 366   @Override
1652 22 May 07 gregory 367   public void run() {
741 10 Oct 06 olle 368     try {
1652 22 May 07 gregory 369       if (b_isPASV) {
741 10 Oct 06 olle 370         getSocket();
1652 22 May 07 gregory 371       } else {
741 10 Oct 06 olle 372       }
1652 22 May 07 gregory 373     } catch (Exception e) {
1652 22 May 07 gregory 374       showError(e);
1652 22 May 07 gregory 375     }
741 10 Oct 06 olle 376   }
741 10 Oct 06 olle 377
741 10 Oct 06 olle 378   /**
1652 22 May 07 gregory 379    * This is only used when we use passive mode (PASV). <BR>
1652 22 May 07 gregory 380    * This will be called when we call "start()" ("run()") and starts listening
1652 22 May 07 gregory 381    * for incoming connections.
1652 22 May 07 gregory 382    */
1652 22 May 07 gregory 383   private void getSocket() {
741 10 Oct 06 olle 384     try {
1652 22 May 07 gregory 385       // To stop listen to the port, set ss_dataConnection to null.
1652 22 May 07 gregory 386       while (ss_dataConnection != null) // IMPORTANT!!! make sure this
1652 22 May 07 gregory 387                         // loop won't go around too many
1652 22 May 07 gregory 388                         // times without doing anything
1652 22 May 07 gregory 389                         // or java will use up to 100%
1652 22 May 07 gregory 390                         // CPU. Instead let the loop be
1652 22 May 07 gregory 391                         // halted by for example an
1652 22 May 07 gregory 392                         // accept call which will wait
1652 22 May 07 gregory 393                         // for a network connection to
1652 22 May 07 gregory 394                         // be established...
741 10 Oct 06 olle 395       {
1652 22 May 07 gregory 396         so_userConnection = ss_dataConnection.accept(); // Wait until a
1652 22 May 07 gregory 397                                 // request is
1652 22 May 07 gregory 398                                 // sent to the
1652 22 May 07 gregory 399                                 // server (with
1652 22 May 07 gregory 400                                 // "myServerSocket.setSoTimeout()"
1652 22 May 07 gregory 401                                 // we can limit
1652 22 May 07 gregory 402                                 // the time we
1652 22 May 07 gregory 403                                 // wait for
1652 22 May 07 gregory 404                                 // "accept")
1652 22 May 07 gregory 405         ss_dataConnection.close(); // We only come to this line if no
1652 22 May 07 gregory 406                       // Exceptions are thrown from
1652 22 May 07 gregory 407                       // accept. If the client has taken
1652 22 May 07 gregory 408                       // the dataconnection once (has
1652 22 May 07 gregory 409                       // taken accept), then don't listen
1652 22 May 07 gregory 410                       // to the same port again...
1652 22 May 07 gregory 411         ss_dataConnection = null; // We only come to this line if no
1652 22 May 07 gregory 412                       // Exceptions are thrown from
1652 22 May 07 gregory 413                       // accept. If the client has taken
1652 22 May 07 gregory 414                       // the dataconnection once (has
1652 22 May 07 gregory 415                       // taken accept), then don't listen
1652 22 May 07 gregory 416                       // to the same port again...
1652 22 May 07 gregory 417         bos = new DataOutputStream(new BufferedOutputStream(
1652 22 May 07 gregory 418             so_userConnection.getOutputStream()));
1652 22 May 07 gregory 419         bis = new DataInputStreamWithReadLine(new BufferedInputStream(
1652 22 May 07 gregory 420             so_userConnection.getInputStream()));
741 10 Oct 06 olle 421       }
1652 22 May 07 gregory 422     } // Try...
1652 22 May 07 gregory 423     catch (IOException e) {
1652 22 May 07 gregory 424       if (so_userConnection == null) // If the connection was not
1652 22 May 07 gregory 425                       // taken...
741 10 Oct 06 olle 426       {
741 10 Oct 06 olle 427         getSocket();
741 10 Oct 06 olle 428       }
1652 22 May 07 gregory 429       // else //if the connection was taken, do not take it again...
1652 22 May 07 gregory 430     } // After i_timeToWaitForDataConnection milliseconds an exception
1652 22 May 07 gregory 431       // will be thrown from ".accept()", which will result in that this
1652 22 May 07 gregory 432       // line will be executed.
1652 22 May 07 gregory 433     catch (Exception e) {
741 10 Oct 06 olle 434       showError(e);
741 10 Oct 06 olle 435     }
741 10 Oct 06 olle 436   }
741 10 Oct 06 olle 437
1652 22 May 07 gregory 438   private void showError(Exception e) {
1652 22 May 07 gregory 439     if (b_showErrors) {
741 10 Oct 06 olle 440       System.out.println("Error: " + e);
741 10 Oct 06 olle 441       e.printStackTrace();
741 10 Oct 06 olle 442     }
741 10 Oct 06 olle 443   }
741 10 Oct 06 olle 444
741 10 Oct 06 olle 445   /**
1652 22 May 07 gregory 446    * Close the socket and stop listening for incoming connections.
1652 22 May 07 gregory 447    */
1652 22 May 07 gregory 448   public void killConnection() {
741 10 Oct 06 olle 449     try {
1652 22 May 07 gregory 450       if (so_userConnection != null)
741 10 Oct 06 olle 451         so_userConnection.close();
1652 22 May 07 gregory 452       if (bis != null)
741 10 Oct 06 olle 453         bis.close();
1652 22 May 07 gregory 454       if (bos != null)
741 10 Oct 06 olle 455         bos.close();
1652 22 May 07 gregory 456       // if (ss_dataConnection!=null)
1652 22 May 07 gregory 457       // ss_dataConnection.close();
741 10 Oct 06 olle 458
1652 22 May 07 gregory 459       // ss_dataConnection=null;
1652 22 May 07 gregory 460       so_userConnection = null;
1652 22 May 07 gregory 461       bis = null;
1652 22 May 07 gregory 462       bos = null;
1652 22 May 07 gregory 463     } catch (Exception e) {
1652 22 May 07 gregory 464       showError(e);
1652 22 May 07 gregory 465     }
741 10 Oct 06 olle 466   }
741 10 Oct 06 olle 467
741 10 Oct 06 olle 468   /**
1652 22 May 07 gregory 469    * If we use active mode (PORT) we will always just return true. <BR>
1652 22 May 07 gregory 470    * If we use passive mode (PASV) we will see if the connection we are
1652 22 May 07 gregory 471    * listening to is taken or not. <BR>
1652 22 May 07 gregory 472    * If not taken we will see if it becomes taken within maxWaitTimeInMillis
1652 22 May 07 gregory 473    * milli seconds. <BR>
1652 22 May 07 gregory 474    * If it's taken, we return true. Otherwise false.
1652 22 May 07 gregory 475    */
1652 22 May 07 gregory 476   public boolean waitForDataConnectionToBeTaken(long maxWaitTimeInMillis) // Returns
1652 22 May 07 gregory 477                                       // true
1652 22 May 07 gregory 478                                       // iff
1652 22 May 07 gregory 479                                       // the
1652 22 May 07 gregory 480                                       // dataconnection
1652 22 May 07 gregory 481                                       // is
1652 22 May 07 gregory 482                                       // taken
1652 22 May 07 gregory 483                                       // within
1652 22 May 07 gregory 484                                       // the
1652 22 May 07 gregory 485                                       // time
1652 22 May 07 gregory 486                                       // given
1652 22 May 07 gregory 487                                       // (returns
1652 22 May 07 gregory 488                                       // false
1652 22 May 07 gregory 489                                       // if
1652 22 May 07 gregory 490                                       // the
1652 22 May 07 gregory 491                                       // connection
1652 22 May 07 gregory 492                                       // is
1652 22 May 07 gregory 493                                       // never
1652 22 May 07 gregory 494                                       // taken
1652 22 May 07 gregory 495                                       // and
1652 22 May 07 gregory 496                                       // if
1652 22 May 07 gregory 497                                       // it
1652 22 May 07 gregory 498                                       // has
1652 22 May 07 gregory 499                                       // not
1652 22 May 07 gregory 500                                       // been
1652 22 May 07 gregory 501                                       // taken
1652 22 May 07 gregory 502                                       // earlier
1652 22 May 07 gregory 503                                       // either)
741 10 Oct 06 olle 504   {
1652 22 May 07 gregory 505     if (b_isPASV) {
1652 22 May 07 gregory 506       long l_startTime = System.currentTimeMillis();
1652 22 May 07 gregory 507       while (bos == null
1652 22 May 07 gregory 508           && l_startTime + maxWaitTimeInMillis > System
1652 22 May 07 gregory 509               .currentTimeMillis()) {
741 10 Oct 06 olle 510         yield();
741 10 Oct 06 olle 511       }
741 10 Oct 06 olle 512
1652 22 May 07 gregory 513       if (bos == null)
1652 22 May 07 gregory 514         return false; // Data connection never taken
741 10 Oct 06 olle 515       else
1652 22 May 07 gregory 516         return true; // Data connection taken
1652 22 May 07 gregory 517     } else
741 10 Oct 06 olle 518       return true;
741 10 Oct 06 olle 519   }
741 10 Oct 06 olle 520
741 10 Oct 06 olle 521   /**
1652 22 May 07 gregory 522    * We only use this in active mode (PORT). <BR>
1652 22 May 07 gregory 523    * When we call this we will try to connect to the client.
1652 22 May 07 gregory 524    */
1652 22 May 07 gregory 525   private void connectPORTconnection() throws Exception {
1652 22 May 07 gregory 526     if (so_userConnection == null) {
741 10 Oct 06 olle 527       try {
1652 22 May 07 gregory 528         so_userConnection = new Socket(s_hostUsedForPORT,
1652 22 May 07 gregory 529             i_portUsedForPORT, InetAddress.getLocalHost(),
1652 22 May 07 gregory 530             i_dataPortNr);
1652 22 May 07 gregory 531       } catch (BindException e) {
1652 22 May 07 gregory 532         b_couldConnectInPORTmode = false; // this must be set here so
1652 22 May 07 gregory 533                           // we know if the connection
1652 22 May 07 gregory 534                           // was successful or failed
741 10 Oct 06 olle 535         throw e;
741 10 Oct 06 olle 536       }
741 10 Oct 06 olle 537
1652 22 May 07 gregory 538       bos = new DataOutputStream(new BufferedOutputStream(
1652 22 May 07 gregory 539           so_userConnection.getOutputStream()));
1652 22 May 07 gregory 540       bis = new DataInputStreamWithReadLine(new BufferedInputStream(
1652 22 May 07 gregory 541           so_userConnection.getInputStream()));
741 10 Oct 06 olle 542     }
741 10 Oct 06 olle 543   }
741 10 Oct 06 olle 544
741 10 Oct 06 olle 545   /**
1652 22 May 07 gregory 546    * In passive mode (PASV) we will stop listening for incoming connections.
1652 22 May 07 gregory 547    * <BR>
1652 22 May 07 gregory 548    * In active mode (PORT) we will close the ServerSocket we have created.
1652 22 May 07 gregory 549    */
1652 22 May 07 gregory 550   public void stopListenToPort() {
741 10 Oct 06 olle 551     try {
741 10 Oct 06 olle 552       killConnection();
1652 22 May 07 gregory 553       if (ss_dataConnection != null)
741 10 Oct 06 olle 554         ss_dataConnection.close();
1652 22 May 07 gregory 555       ss_dataConnection = null;
1652 22 May 07 gregory 556     } catch (Exception e) {
1652 22 May 07 gregory 557       showError(e);
1652 22 May 07 gregory 558     }
741 10 Oct 06 olle 559   }
741 10 Oct 06 olle 560
741 10 Oct 06 olle 561   /**
1652 22 May 07 gregory 562    * Send a directory listing. Does not include removed core files.
931 16 Nov 06 olle 563    * 
1652 22 May 07 gregory 564    * @param path
1652 22 May 07 gregory 565    *            String path of directory to be listed.
931 16 Nov 06 olle 566    */
1652 22 May 07 gregory 567   public void sendListing(String path) throws Exception {
790 23 Oct 06 olle 568     // *** Debug Info
1652 22 May 07 gregory 569     log.info("FTPDataConnection::sendListing(): Start - path = \"" + path
1652 22 May 07 gregory 570         + "\"");
931 16 Nov 06 olle 571     boolean includeRemoved = false;
931 16 Nov 06 olle 572     sendListing(path, includeRemoved);
931 16 Nov 06 olle 573   }
931 16 Nov 06 olle 574
931 16 Nov 06 olle 575   /**
931 16 Nov 06 olle 576    * Send a directory listing.
931 16 Nov 06 olle 577    * 
1652 22 May 07 gregory 578    * @param path
1652 22 May 07 gregory 579    *            String path of directory to be listed.
1652 22 May 07 gregory 580    * @param includeRemoved
1652 22 May 07 gregory 581    *            boolean flag indicating if removed core files should be
1652 22 May 07 gregory 582    *            included.
931 16 Nov 06 olle 583    */
1652 22 May 07 gregory 584   public void sendListing(String path, boolean includeRemoved)
1652 22 May 07 gregory 585       throws Exception {
931 16 Nov 06 olle 586     // *** Debug Info
1652 22 May 07 gregory 587     log.info("FTPDataConnection::sendListing(): Start - path = \"" + path
3469 02 Nov 09 olle 588         + "\" includeRemoved = " + includeRemoved + " isInSharedProjectsFolder() = " + isInSharedProjectsFolder());
1652 22 May 07 gregory 589     if (!b_isPASV) // PORT shall make the connection AFTER the first
1652 22 May 07 gregory 590             // response. So we most connect here.
741 10 Oct 06 olle 591       connectPORTconnection();
741 10 Oct 06 olle 592
1676 25 May 07 olle 593     //(new MyLS(path)).sendListing(bos, includeRemoved, null);
3469 02 Nov 09 olle 594     //(new MyLS(path, getSessionControl())).sendListing(bos, includeRemoved, null);
4047 01 Dec 10 olle 595     MyLS myLS = new MyLS(path, getSessionControl(), isTextBasedFTPClientType());
3469 02 Nov 09 olle 596     myLS.setInSharedProjectsFolder(isInSharedProjectsFolder());
3469 02 Nov 09 olle 597     myLS.sendListing(bos, includeRemoved, null);
3469 02 Nov 09 olle 598     myLS.setInSharedProjectsFolder(false);
741 10 Oct 06 olle 599   }
741 10 Oct 06 olle 600
741 10 Oct 06 olle 601   /**
1652 22 May 07 gregory 602    * Send a alias listing as if the aliases where directories.
1652 22 May 07 gregory 603    */
1652 22 May 07 gregory 604   public void sendAliaslisting(String[] aliases) throws Exception {
1652 22 May 07 gregory 605     if (!b_isPASV) // PORT shall make the connection AFTER the first
1652 22 May 07 gregory 606             // response. So we most connect here.
741 10 Oct 06 olle 607       connectPORTconnection();
741 10 Oct 06 olle 608
741 10 Oct 06 olle 609     MyLS.sendAliaslisting(bos, aliases);
741 10 Oct 06 olle 610   }
741 10 Oct 06 olle 611
741 10 Oct 06 olle 612   /**
1652 22 May 07 gregory 613    * Send the line that is related to this file when we do a normal folder
1652 22 May 07 gregory 614    * listing. Does not include removed core files.
931 16 Nov 06 olle 615    * 
1652 22 May 07 gregory 616    * @param path
1652 22 May 07 gregory 617    *            String path of directory to be listed.
931 16 Nov 06 olle 618    */
1652 22 May 07 gregory 619   public void sendFileInfo(String path) throws Exception {
790 23 Oct 06 olle 620     // *** Debug Info
1652 22 May 07 gregory 621     log.info("FTPDataConnection::sendFileInfo(): Start - path = \"" + path
1652 22 May 07 gregory 622         + "\"");
931 16 Nov 06 olle 623     boolean includeRemoved = false;
931 16 Nov 06 olle 624     sendFileInfo(path, includeRemoved);
931 16 Nov 06 olle 625   }
931 16 Nov 06 olle 626
931 16 Nov 06 olle 627   /**
1652 22 May 07 gregory 628    * Send the line that is related to this file when we do a normal folder
1652 22 May 07 gregory 629    * listing.
931 16 Nov 06 olle 630    * 
1652 22 May 07 gregory 631    * @param path
1652 22 May 07 gregory 632    *            String path of directory to be listed.
1652 22 May 07 gregory 633    * @param includeRemoved
1652 22 May 07 gregory 634    *            boolean flag indicating if removed core files should be
1652 22 May 07 gregory 635    *            included.
931 16 Nov 06 olle 636    */
1652 22 May 07 gregory 637   public void sendFileInfo(String path, boolean includeRemoved)
1652 22 May 07 gregory 638       throws Exception {
931 16 Nov 06 olle 639     // *** Debug Info
1652 22 May 07 gregory 640     log.info("FTPDataConnection::sendFileInfo(): Start - path = \"" + path
3469 02 Nov 09 olle 641         + "\" includeRemoved = " + includeRemoved + " isInSharedProjectsFolder() = " + isInSharedProjectsFolder());
1652 22 May 07 gregory 642     if (!b_isPASV) // PORT shall make the connection AFTER the first
1652 22 May 07 gregory 643             // response. So we most connect here.
741 10 Oct 06 olle 644       connectPORTconnection();
741 10 Oct 06 olle 645
1676 25 May 07 olle 646     //(new MyLS(path)).sendFileInfo(bos, includeRemoved);
3469 02 Nov 09 olle 647     //(new MyLS(path, getSessionControl())).sendFileInfo(bos, includeRemoved);
4047 01 Dec 10 olle 648     MyLS myLS = new MyLS(path, getSessionControl(), isTextBasedFTPClientType());
3469 02 Nov 09 olle 649     myLS.setInSharedProjectsFolder(isInSharedProjectsFolder());
3469 02 Nov 09 olle 650     myLS.sendFileInfo(bos, includeRemoved);
3469 02 Nov 09 olle 651     myLS.setInSharedProjectsFolder(false);
741 10 Oct 06 olle 652   }
741 10 Oct 06 olle 653
741 10 Oct 06 olle 654   /**
1652 22 May 07 gregory 655    * Read this file, skip i_startPosition bytes.
1652 22 May 07 gregory 656    */
1652 22 May 07 gregory 657   public void sendFileContentBinary(String s_file, int i_startPosition)
1652 22 May 07 gregory 658       throws Exception {
1652 22 May 07 gregory 659     if (!b_isPASV) // PORT shall make the connection AFTER the first
1652 22 May 07 gregory 660             // response. So we most connect here.
741 10 Oct 06 olle 661       connectPORTconnection();
741 10 Oct 06 olle 662
741 10 Oct 06 olle 663     /*
1652 22 May 07 gregory 664      * File f_theFile=new File(s_file); if (f_theFile.isDirectory())
1652 22 May 07 gregory 665      * //Firefox for example asks for the content of a file when it { (new
1652 22 May 07 gregory 666      * MyLS(s_file)).sendListing(bos); } else {
1652 22 May 07 gregory 667      * StreamIO.writeFileToStream(f_theFile, bos, i_startPosition); }
1652 22 May 07 gregory 668      */
1676 25 May 07 olle 669     StreamIO.writeFileToStream(new File(s_file), bos, i_startPosition, getSessionControl());
741 10 Oct 06 olle 670   }
741 10 Oct 06 olle 671
741 10 Oct 06 olle 672   /**
1652 22 May 07 gregory 673    * Read this file.
1652 22 May 07 gregory 674    */
1652 22 May 07 gregory 675   public void sendFileContentASCII(String s_file) throws Exception {
1652 22 May 07 gregory 676     if (!b_isPASV) // PORT shall make the connection AFTER the first
1652 22 May 07 gregory 677             // response. So we most connect here.
741 10 Oct 06 olle 678       connectPORTconnection();
741 10 Oct 06 olle 679
1676 25 May 07 olle 680     StreamIO.writeASCIIFileToStream(new File(s_file), bos, getSessionControl());
741 10 Oct 06 olle 681   }
741 10 Oct 06 olle 682
741 10 Oct 06 olle 683   /**
1652 22 May 07 gregory 684    * Write data to this file.
1652 22 May 07 gregory 685    */
1652 22 May 07 gregory 686   public void writeFile(String s_file, boolean b_append) throws Exception {
1652 22 May 07 gregory 687     if (!b_isPASV) // PORT shall make the connection AFTER the first
1652 22 May 07 gregory 688             // response. So we most connect here.
741 10 Oct 06 olle 689       connectPORTconnection();
741 10 Oct 06 olle 690
1676 25 May 07 olle 691     StreamIO.writeFile(s_file, bis, b_append, getSessionControl());
741 10 Oct 06 olle 692   }
741 10 Oct 06 olle 693 }