KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > drftpd > slave > TransferImpl


1 /*
2  * This file is part of DrFTPD, Distributed FTP Daemon.
3  *
4  * DrFTPD is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * DrFTPD is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with DrFTPD; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */

18 package net.sf.drftpd.slave;
19
20 import java.io.File JavaDoc;
21 import java.io.FileInputStream JavaDoc;
22 import java.io.FileNotFoundException JavaDoc;
23 import java.io.FileOutputStream JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.InputStream JavaDoc;
26 import java.io.OutputStream JavaDoc;
27 import java.net.Socket JavaDoc;
28 import java.rmi.RemoteException JavaDoc;
29 import java.rmi.server.UnicastRemoteObject JavaDoc;
30 import java.util.zip.CRC32 JavaDoc;
31 import java.util.zip.CheckedInputStream JavaDoc;
32 import java.util.zip.CheckedOutputStream JavaDoc;
33
34 import net.sf.drftpd.FileExistsException;
35 import net.sf.drftpd.util.AddAsciiOutputStream;
36
37 import org.apache.log4j.Logger;
38
39 /**
40  * @author mog
41  * @version $Id: TransferImpl.java,v 1.48 2004/05/12 00:45:11 mog Exp $
42  */

43 public class TransferImpl extends UnicastRemoteObject JavaDoc implements Transfer {
44     private static final Logger logger = Logger.getLogger(TransferImpl.class);
45     private boolean _abort = false;
46     private CRC32 JavaDoc _checksum = null;
47     private Connection _conn;
48     private char _direction;
49
50     private InputStream JavaDoc _in;
51     private OutputStream JavaDoc _out;
52     private char _mode = 'I';
53     private Socket JavaDoc _sock;
54
55     private long _started = 0;
56     private long _finished = 0;
57
58     private long _transfered = 0;
59     private SlaveImpl _slave;
60     /**
61      * Start undefined transfer.
62      */

63     public TransferImpl(Connection conn, SlaveImpl slave)
64         throws RemoteException JavaDoc {
65         super(0);
66         _slave = slave;
67         _direction = Transfer.TRANSFER_UNKNOWN;
68         _conn = conn;
69     }
70
71     public void abort() throws RemoteException JavaDoc {
72         _abort = true;
73         if (_conn != null)
74             _conn.abort();
75         if (_sock == null )
76             // already closed
77
return;
78         try {
79             _sock.close();
80         } catch (IOException JavaDoc e) {
81             logger.warn("abort() failed to close() the socket", e);
82         }
83     }
84
85     public TransferStatus sendFile(
86         String JavaDoc path,
87         char type,
88         long resumePosition)
89         throws IOException JavaDoc {
90         _direction = TRANSFER_SENDING_DOWNLOAD;
91
92         _in = new FileInputStream JavaDoc(_slave.getRoots().getFile(path));
93         if (_slave.getDownloadChecksums()) {
94             _checksum = new CRC32 JavaDoc();
95             _in = new CheckedInputStream JavaDoc(_in, _checksum);
96         }
97         _in.skip(resumePosition);
98
99         System.out.println("DL:" + path);
100         transfer();
101         return getStatus();
102     }
103
104     public long getChecksum() {
105         if (_checksum == null)
106             return 0;
107         return _checksum.getValue();
108     }
109
110     public char getDirection() {
111         return _direction;
112     }
113
114     public int getLocalPort() throws RemoteException JavaDoc {
115         if (_conn instanceof PassiveConnection) {
116             return ((PassiveConnection) _conn).getLocalPort();
117         } else {
118             throw new IllegalStateException JavaDoc("getLocalPort() called on a non-passive transfer");
119         }
120     }
121
122     public long getTransfered() {
123         return _transfered;
124     }
125
126     public long getElapsed() {
127         if (_finished == 0) {
128             return System.currentTimeMillis() - _started;
129         } else {
130             return _finished - _started;
131         }
132     }
133
134     public int getXferSpeed() {
135         long elapsed = getElapsed();
136
137         if (_transfered == 0) {
138             return 0;
139         }
140
141         if (elapsed == 0) {
142             return 0;
143         }
144         return (int) (_transfered / ((float) elapsed / (float) 1000));
145     }
146
147     public TransferStatus getStatus() {
148         return new TransferStatus(getElapsed(), getTransfered(), getChecksum(), _sock.getInetAddress());
149     }
150
151     public boolean isReceivingUploading() {
152         return _direction == TRANSFER_RECEIVING_UPLOAD;
153     }
154
155     public boolean isSendingUploading() {
156         return _direction == Transfer.TRANSFER_SENDING_DOWNLOAD;
157     }
158
159     /**
160      * Call sock.connect() and start sending.
161      *
162      * Read about buffers here:
163      * http://groups.google.com/groups?hl=sv&lr=&ie=UTF-8&oe=UTF-8&threadm=9eomqe%24rtr%241%40to-gate.itd.utech.de&rnum=22&prev=/groups%3Fq%3Dtcp%2Bgood%2Bbuffer%2Bsize%26start%3D20%26hl%3Dsv%26lr%3D%26ie%3DUTF-8%26oe%3DUTF-8%26selm%3D9eomqe%2524rtr%25241%2540to-gate.itd.utech.de%26rnum%3D22
164      *
165      * Quote:
166      * Short answer is: if memory is not limited make your buffer big; TCP will flow
167      * control itself and only use what it needs.
168      *
169      *Longer answer: for optimal throughput (assuming TCP is not flow controlling itself
170      * for other reasons) you want your buffer size to at least be
171      *
172      * channel bandwidth * channel round-trip-delay.
173      *
174      * So on a long slow link, if you can get 100K bps throughput,
175      * but your delay -s 8 seconds, you want:
176      *
177      * 100Kbps * / bits-per-byte * 8 seconds
178      * = 100 Kbytes
179      *
180      * That way TCP can keep transmitting data for 8 seconds before it
181      * would have to stop and wait for an ack (to clear space in the
182      * buffer for new data so it can put new TX data in there and
183      * on the line). (The idea is to get the ack before you have to stop
184      * transmitting.)
185      */

186     private TransferStatus transfer() throws IOException JavaDoc {
187         _started = System.currentTimeMillis();
188         _sock = _conn.connect();
189         _conn = null;
190         int bufsize = _slave.getBufferSize();
191         if (_in == null) {
192             if(bufsize > 0) _sock.setReceiveBufferSize(bufsize);
193             _in = _sock.getInputStream();
194         } else if (_out == null) {
195             if(bufsize > 0) _sock.setSendBufferSize(bufsize);
196             _out = _sock.getOutputStream();
197         } else {
198             throw new IllegalStateException JavaDoc("neither in or out was null");
199         }
200         if (_mode == 'A') {
201             _out = new AddAsciiOutputStream(_out);
202         }
203
204         _slave.addTransfer(this);
205         TransferStatus status;
206         try {
207             byte[] buff = new byte[Math.max(_slave.getBufferSize(), 65535)];
208             int count;
209             try {
210                 while ((count = _in.read(buff)) != -1 && !_abort) {
211                     _transfered += count;
212                     _out.write(buff, 0, count);
213                 }
214                 _out.flush();
215             } catch (IOException JavaDoc e) {
216                 throw new TransferFailedException(e, getStatus());
217             }
218         } finally {
219             _finished = System.currentTimeMillis();
220             status = getStatus();
221             _slave.removeTransfer(this);
222
223             _in.close();
224             _out.close();
225             _sock.close();
226
227             _in = null;
228             _out = null;
229             //_sock = null;
230
}
231         if (_abort)
232             throw new TransferFailedException("Transfer was aborted", getStatus());
233         return status;
234     }
235
236     public TransferStatus receiveFile(
237         String JavaDoc dirname,
238         char mode,
239         String JavaDoc filename,
240         long offset)
241         throws IOException JavaDoc {
242         _direction = TRANSFER_RECEIVING_UPLOAD;
243         try {
244             _slave.getRoots().getFile(dirname + File.separator + filename);
245             throw new FileExistsException("File exists");
246         } catch (FileNotFoundException JavaDoc ex) {
247         }
248
249         String JavaDoc root = _slave.getRoots().getARootFileDir(dirname).getPath();
250
251         _out = new FileOutputStream JavaDoc(root + File.separator + filename);
252
253         if (_slave.getUploadChecksums()) {
254             _checksum = new CRC32 JavaDoc();
255             _out = new CheckedOutputStream JavaDoc(_out, _checksum);
256         }
257         System.out.println("UL:" + dirname + File.separator + filename);
258         try {
259             return transfer();
260         } catch (IOException JavaDoc e) {
261             // TODO really delete on IOException ?
262
//_slave.delete(root + File.separator + filename);
263
throw e; // so the Master can still handle the exception
264
}
265     }
266 }
267
Popular Tags