View Javadoc

1   /*
2    *  XNap - A P2P framework and client.
3    *
4    *  See the file AUTHORS for copyright information.
5    *
6    *  This program 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.
9    *
10   *  This program is distributed in the hope that it will be useful,
11   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   *  GNU General Public License for more details.
14   *
15   *  You should have received a copy of the GNU General Public License
16   *  along with this program; if not, write to the Free Software
17   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   */
19  
20  package org.xnap.plugin.opennap.net;
21  
22  import java.io.BufferedInputStream;
23  import java.io.FileInputStream;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.io.OutputStream;
27  import java.net.Socket;
28  
29  import org.apache.log4j.Logger;
30  import org.xnap.XNap;
31  import org.xnap.io.ThrottledOutputStream;
32  import org.xnap.net.NetHelper;
33  import org.xnap.plugin.opennap.net.msg.MessageHandler;
34  import org.xnap.plugin.opennap.net.msg.client.DownloadCompleteMessage;
35  import org.xnap.plugin.opennap.net.msg.client.DownloadingFileMessage;
36  import org.xnap.plugin.opennap.user.OpenNapUser;
37  import org.xnap.util.State;
38  
39  /***
40   * Uploads a file.
41   */
42  public class OpenNapUploadRunner implements Runnable {
43  
44  	//--- Constant(s) ---
45  
46      /***
47       * Socket timeout during connect.
48       */
49      public static final int CONNECT_TIMEOUT = 1 * 60 * 1000;
50  
51      /***
52       * Abort transfer if stalled for this long.
53       */
54      public static final int TRANSFER_TIMEOUT = 2 * 60 * 1000;
55  
56  	//--- Data field(s) ---
57  
58  	private static Logger logger = Logger.getLogger(OpenNapUploadRunner.class);
59  
60  	private OpenNapUpload parent;
61  	private boolean die;
62  
63      private Socket socket;
64      private InputStream in;
65      private OutputStream out;
66  	private long offset;
67  
68  	//--- Constructor(s) ---
69  	
70  	public OpenNapUploadRunner(OpenNapUpload parent, UploadSocket u)
71  	{
72  		this.parent = parent;
73  
74  		if (u != null) {
75  			this.socket = u.socket;
76  			this.in = u.in;
77  			this.offset = u.offset;
78  		}
79  	}
80  
81  	//--- Method(s) ---
82  
83  	public void run()
84  	{
85  		boolean messageSent = false;
86  		try {
87  			if (socket == null) {
88  				OpenNapUser user = (OpenNapUser)parent.getPeer();
89  				connect(user.getHost(), user.getPort());
90  			}
91  			else {
92  				connect();
93  			}
94  
95  			MessageHandler.send(new DownloadingFileMessage());
96  			messageSent = true;
97  
98  			parent.setState(State.UPLOADING);
99  
100 			upload();
101 
102 			parent.setState(State.SUCCEEDED);
103 		}
104 		catch (IOException e) {
105 			logger.debug("upload failed", e);
106 			parent.setState(State.STOPPED, NetHelper.getErrorMessage(e));
107 		}
108 		catch (InterruptedException e) {
109 			logger.debug("upload aborted");
110 			parent.setState(State.STOPPED);
111 		}
112 		finally {
113 			close();
114 
115 			if (messageSent) {
116 				MessageHandler.send(new DownloadCompleteMessage());
117 			}
118 		}
119 	}
120 
121 	public void stop()
122 	{
123 		die = true;
124 	}
125 
126     private void close() 
127     {
128         try {
129 			if (socket != null)
130 				socket.close();
131 			if (in != null)
132 				in.close();
133 			if (out != null)
134 				out.close();
135         } 
136 		catch (IOException e) {
137         }
138     }
139 
140     /***
141      * Opens socket and requests file.
142      */
143     private void connect(String ip, int port) throws IOException
144     {
145 		logger.debug("opening socket to " + ip + ":" + port);
146 
147 		//socket = new Socket(ip, port);
148 		socket = NetHelper.connect(ip, port, CONNECT_TIMEOUT);
149 		socket.setSoTimeout(CONNECT_TIMEOUT);
150 
151 		out = socket.getOutputStream();
152 		in = new BufferedInputStream(socket.getInputStream());
153 
154 		String message;
155 
156 		// read magic number '1'
157 		char c = (char)in.read();
158 		if (c != '1') {
159 			throw new IOException(XNap.tr("invalid request"));
160 		}
161 	
162 		message = "SEND";
163 		out.write(message.getBytes());
164 		out.flush();
165 	
166 		message = parent.getServer().getLocalPeer().getName() + " \"" 
167 			+ parent.getRequestFilename() + "\" " + parent.getFilesize();
168 		logger.debug("> " + message);
169 		out.write(message.getBytes());
170 		out.flush();
171 
172 		byte data[] = new byte[1000];
173 		int j = in.read(data);
174 	
175 		if (j <= 0) {
176 			throw new IOException(XNap.tr("Socket error"));
177 		}
178 
179 		String response = new String(data, 0, j);
180 		logger.debug("< " + response);
181 		try {
182 			offset = Long.parseLong(response);
183 		}
184 		catch (NumberFormatException e) {
185 			throw new IOException(XNap.tr("invalid request"));
186 		}		
187 	
188 		logger.debug("offset: " + response);
189     }
190 
191 	private void connect() throws IOException
192 	{
193 		out = socket.getOutputStream();
194 		socket.setSoTimeout(CONNECT_TIMEOUT);
195 		
196 		// write filesize
197 		long size = parent.getFile().length();
198 		out.write((new Long(size)).toString().getBytes());
199 		out.flush();
200 	}
201 
202 	/***
203 	 *
204 	 * <p>PRECONDITION<br>
205 	 * socket != null, in != null, out != null
206 	 */
207 	private void upload() throws IOException, InterruptedException
208 	{
209 		byte[] buf = new byte[512];
210 		//byte[] buf = new byte[ThrottledOutputStream.getBlocksize()];
211 
212 		out = new ThrottledOutputStream(out);
213 		
214 		BufferedInputStream inFile = new BufferedInputStream
215 			(new FileInputStream(parent.getFile()));
216 		
217 		if (inFile.skip(offset) != offset) {
218 			throw new IOException(XNap.tr("invalid offset"));
219 		}
220 		parent.setTotalBytesTransferred(offset);
221 		
222 		while (!die) {
223 			int len = inFile.read(buf, 0, buf.length);
224 			if (len <= 0) {
225 				break;
226 			}
227 			
228 			out.write(buf, 0, len);
229 			
230 			parent.commit(len);
231 		}
232 
233 		if (die) {
234 			throw new InterruptedException();
235 		}
236     }
237 
238 }
239