View Javadoc

1   // ActivePutter.java
2   // $Id: ActivePutter.java,v 1.6 2007/02/21 00:07:50 sjardine Exp $
3   //
4   // Copyright 2000, Joe Phillips <jaiger@innovationsw.com>
5   // Copyright 2001, 2002 Innovation Software Group, LLC - http://www.innovationsw.com
6   //
7   // This library is free software; you can redistribute it and/or
8   // modify it under the terms of the GNU Library General Public
9   // License as published by the Free Software Foundation; either
10  // version 2 of the License, or (at your option) any later version.
11  //
12  // This library is distributed in the hope that it will be useful,
13  // but WITHOUT ANY WARRANTY; without even the implied warranty of
14  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  // Library General Public License for more details.
16  //
17  // You should have received a copy of the GNU Library General Public
18  // License along with this library; if not, write to the Free
19  // Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  package gnu.inet.ftp;
21  
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.InterruptedIOException;
25  import java.io.OutputStream;
26  import java.net.InetAddress;
27  import java.net.ServerSocket;
28  import java.net.Socket;
29  import java.net.SocketException;
30  import java.util.zip.DeflaterOutputStream;
31  
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  
35  /***
36   * This class implements an FTP-style data connection server thread for PUTing
37   * in a non-passive files/data.
38   * <P>
39   * This class is used internally to the FtpClient class.
40   */
41  public class ActivePutter extends Putter {
42  
43      private final static Log log = LogFactory.getLog(ActivePutter.class);
44  
45      private InetAddress address;
46  
47      private int port;
48  
49      private ServerSocket server;
50  
51      private int timeout;
52  
53      /***
54       * Create a new ActivePutter thread given the InputStream data source.
55       * 
56       * @param in
57       *                data source
58       * @exception IOException
59       *                    io error with the ServerSocket
60       */
61      public ActivePutter(InputStream in) throws IOException {
62  	super();
63  
64  	// create server socket
65  	this.server = new ServerSocket(0);
66  	this.timeout = 30 * 1000; // 30s timeout
67  	// store the port that the server is listening on
68  	this.port = server.getLocalPort();
69  	this.address = this.server.getInetAddress();
70  
71  	this.istream = in;
72      }// end of default constructor
73  
74      //
75      // public methods
76      //
77  
78      /***
79       * get address that this Putter is listening on
80       * 
81       * @return server socket IP address
82       */
83      public InetAddress getInetAddress() {
84  	return address;
85      }// getInetAddress
86  
87      /***
88       * get the port this ActivePutter is listening on
89       * 
90       * @return port number
91       */
92      public synchronized int getPort() {
93  	return port;
94      }// getPort
95  
96      /***
97       * implements thread behavior. Put data to server using given parameters.
98       */
99      public void run() {
100 	boolean signalClosure = false;
101 	Socket sock = null;
102 	OutputStream ostream = null;
103 	long amount = 0;
104 	int buffer_size = 0;
105 	byte buffer[] = new byte[BUFFER_SIZE];
106 	// this.cancelled= false; // reset cancelled flag
107 
108 	try {
109 	    // wait for connection
110 	    server.setSoTimeout(timeout); // can only wait so long
111 	    if (cancelled)
112 		throw new InterruptedIOException("Transfer cancelled"); // small
113 	    // race
114 	    // condition
115 	    // here
116 	    sock = server.accept();
117 	    signalConnectionOpened(new ConnectionEvent(sock.getInetAddress(),
118 		    sock.getPort()));
119 	    signalTransferStarted();
120 
121 	    try {
122 
123 		// handle different type settings
124 		switch (type) {
125 		case FtpClientProtocol.TYPE_ASCII:
126 		    ostream = new AsciiOutputStream(sock.getOutputStream());
127 		    break;
128 		default:
129 		    ostream = sock.getOutputStream();
130 		    break;
131 		}// switch
132 
133 		// handle different mode settings
134 		switch (mode) {
135 		case FtpClientProtocol.MODE_ZLIB:
136 		    ostream = new DeflaterOutputStream(ostream);
137 		    break;
138 		case FtpClientProtocol.MODE_STREAM:
139 		default:
140 		    break;
141 		}// switch
142 
143 		int len;
144 		while ((len = istream.read(buffer)) != -1) {
145 		    ostream.write(buffer, 0, len);
146 		    amount += len;
147 		    buffer_size += len;
148 		    if (buffer_size >= BUFFER_SIZE) {
149 			buffer_size = buffer_size % BUFFER_SIZE;
150 			signalTransfered(amount);
151 		    }
152 		    yield();
153 		}
154 	    } catch (InterruptedIOException iioe) {
155 		if (!cancelled) {
156 		    log.error(iioe.getMessage(), iioe);
157 		}
158 	    } catch (Exception e) {
159 		log.error(e.getMessage(), e);
160 	    } finally {
161 		log.debug("Closing inputstream");
162 		if (ostream != null) {
163 		    ostream.close();
164 		}
165 		if (!sock.isClosed()) {
166 		    try {
167 			log.debug("Setting socket to 0 lingering");
168 			sock.setSoLinger(true, 0);
169 			sock.close();
170 		    } catch (SocketException e) {
171 			// Don't care.
172 		    }
173 		}
174 		signalTransferCompleted();
175 	    }
176 	} catch (Exception ee) {
177 	    signalConnectionFailed(ee);
178 	    log.error(ee.getMessage(), ee);
179 	} finally {
180 	    try {
181 		log.debug("Closing server socket");
182 		server.close();
183 	    } catch (IOException ex) {
184 		// don't care
185 	    }
186 	}
187 
188 	if (signalClosure == true && sock != null) {
189 	    signalConnectionClosed(new ConnectionEvent(sock.getInetAddress(),
190 		    sock.getPort()));
191 	}
192     }// run
193 
194     /***
195      * set connection timeout in milliseconds. must be called before
196      * start()/run()
197      * 
198      * @param milliseconds
199      *                the number of milliseconds the server socket should wait
200      *                for a connection before timing-out. the default timeout is
201      *                30s
202      */
203     public void setTimeout(int milliseconds) {
204 	timeout = milliseconds;
205     }// setTimeout
206 
207 }// ActivePutter
208 
209 // ActivePutter.java