1 /* ActiveModeDTP.java --
2    Copyright (C) 2003, 2004  Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package gnu.java.net.protocol.ftp;
40 
41 import java.io.IOException;
42 import java.io.InputStream;
43 import java.io.OutputStream;
44 import java.net.InetAddress;
45 import java.net.ServerSocket;
46 import java.net.Socket;
47 
48 /**
49  * An active mode FTP data transfer process.
50  * This starts a server on the specified port listening for a data
51  * connection. It converts the socket input into a file stream for reading.
52  *
53  * @author Chris Burdess (dog@gnu.org)
54  */
55 final class ActiveModeDTP
56   implements DTP, Runnable
57 {
58 
59   ServerSocket server;
60   Socket socket;
61   DTPInputStream in;
62   DTPOutputStream out;
63   boolean completed;
64   boolean inProgress;
65   int transferMode;
66   IOException exception;
67   Thread acceptThread;
68   int connectionTimeout;
69 
ActiveModeDTP(InetAddress localhost, int port, int connectionTimeout, int timeout)70   ActiveModeDTP(InetAddress localhost, int port,
71                 int connectionTimeout, int timeout)
72     throws IOException
73   {
74     completed = false;
75     inProgress = false;
76     server = new ServerSocket(port, 1, localhost);
77     if (timeout > 0)
78       {
79         server.setSoTimeout(timeout);
80       }
81     if (connectionTimeout <= 0)
82       {
83         connectionTimeout = 20000;
84       }
85     this.connectionTimeout = connectionTimeout;
86     acceptThread = new Thread(this, "ActiveModeDTP");
87     acceptThread.setDaemon(true);
88     acceptThread.start();
89   }
90 
91   /**
92    * Start listening.
93    */
run()94   public void run()
95   {
96     try
97       {
98         socket = server.accept();
99         //System.err.println("Accepted connection from "+socket.getInetAddress()+":"+socket.getPort());
100       }
101     catch (IOException e)
102       {
103         exception = e;
104       }
105   }
106 
107   /**
108    * Waits until a client has connected.
109    */
waitFor()110   public void waitFor()
111     throws IOException
112   {
113     try
114       {
115         acceptThread.join(connectionTimeout);
116       }
117     catch (InterruptedException e)
118       {
119       }
120     if (exception != null)
121       {
122         throw exception;
123       }
124     if (socket == null)
125       {
126         server.close();
127         throw new IOException("client did not connect before timeout");
128       }
129     acceptThread = null;
130   }
131 
132   /**
133    * Returns an input stream from which a remote file can be read.
134    */
getInputStream()135   public InputStream getInputStream()
136     throws IOException
137   {
138     if (inProgress)
139       {
140         throw new IOException("Transfer in progress");
141       }
142     if (acceptThread != null)
143       {
144         waitFor();
145       }
146     switch (transferMode)
147       {
148       case FTPConnection.MODE_STREAM:
149         in = new StreamInputStream(this, socket.getInputStream());
150         break;
151       case FTPConnection.MODE_BLOCK:
152         in = new BlockInputStream(this, socket.getInputStream());
153         break;
154       case FTPConnection.MODE_COMPRESSED:
155         in = new CompressedInputStream(this, socket.getInputStream());
156         break;
157       default:
158         throw new IllegalStateException("invalid transfer mode");
159       }
160     in.setTransferComplete(false);
161     return in;
162   }
163 
164   /**
165    * Returns an output stream to which a local file can be written for
166    * upload.
167    */
getOutputStream()168   public OutputStream getOutputStream() throws IOException
169   {
170     if (inProgress)
171       {
172         throw new IOException("Transfer in progress");
173       }
174     if (acceptThread != null)
175       {
176         waitFor();
177       }
178     switch (transferMode)
179       {
180       case FTPConnection.MODE_STREAM:
181         out = new StreamOutputStream(this, socket.getOutputStream());
182         break;
183       case FTPConnection.MODE_BLOCK:
184         out = new BlockOutputStream(this, socket.getOutputStream());
185         break;
186       case FTPConnection.MODE_COMPRESSED:
187         out = new CompressedOutputStream(this, socket.getOutputStream());
188         break;
189       default:
190         throw new IllegalStateException("invalid transfer mode");
191       }
192     out.setTransferComplete(false);
193     return out;
194   }
195 
setTransferMode(int mode)196   public void setTransferMode(int mode)
197   {
198     transferMode = mode;
199   }
200 
complete()201   public void complete()
202   {
203     completed = true;
204     if (!inProgress)
205       {
206         transferComplete();
207       }
208   }
209 
abort()210   public boolean abort()
211   {
212     completed = true;
213     transferComplete();
214     return inProgress;
215   }
216 
transferComplete()217   public void transferComplete()
218   {
219     if (socket == null)
220       {
221         return;
222       }
223     if (in != null)
224       {
225         in.setTransferComplete(true);
226       }
227     if (out != null)
228       {
229         out.setTransferComplete(true);
230       }
231     completed = completed || (transferMode == FTPConnection.MODE_STREAM);
232     if (completed && socket != null)
233       {
234         try
235           {
236             socket.close();
237           }
238         catch (IOException e)
239           {
240           }
241         try
242           {
243             server.close();
244           }
245         catch (IOException e)
246           {
247           }
248       }
249   }
250 
251 }
252