OpenNapDownloadRunner.java
| Index Score | ||
|---|---|---|
![]() |
![]() |
org.xnap.plugin.opennap.net |
![]() |
![]() |
XNap 3 |
View: Reasons, Metrics, Source Code
These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.
/*
* XNap - A P2P framework and client.
*
* See the file AUTHORS for copyright information.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.xnap.plugin.opennap.net;
import java.io.BufferedInputStream;
import java.io.EOFException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.*;
import java.io.RandomAccessFile;
import java.net.*;
import org.apache.log4j.Logger;
import org.xnap.XNap;
import org.xnap.net.NetHelper;
import org.xnap.plugin.opennap.net.msg.MessageHandler;
import org.xnap.plugin.opennap.net.msg.client.*;
import org.xnap.plugin.opennap.net.msg.client.DownloadingFileMessage;
import org.xnap.plugin.opennap.user.OpenNapUser;
import org.xnap.util.IllegalOperationException;
import org.xnap.util.State;
/**
* Takes care of the socket communication to the other peer. Spawned
* by {@link OpenNapDownload} once an incoming socket was received (for
* firewalled downloads) or a DownloadAckMessage was received.
*/
public class OpenNapDownloadRunner implements Runnable {
//--- Constant(s) ---
/**
* Socket timeout during connect.
*/
public static final int CONNECT_TIMEOUT = 1 * 30 * 1000;
/**
* Abort transfer if stalled for this long.
*/
public static final int TRANSFER_TIMEOUT = 2 * 60 * 1000;
/**
* Maximum time to wait for segment.
*/
public static final int SEGMENT_MAX_WAIT = 3 * 60 * 1000;
//--- Data field(s) ---
private static Logger logger = Logger.getLogger(OpenNapDownloadRunner.class);
private OpenNapDownload parent;
private boolean die;
private Socket socket;
private InputStream in;
private OutputStream out;
private OpenNapSegment segment;
//--- Constructor(s) ---
public OpenNapDownloadRunner(OpenNapDownload parent, DownloadSocket d)
{
this.parent = parent;
if (d != null) {
this.socket = d.socket;
this.in = d.in;
}
}
//--- Method(s) ---
public void run()
{
try {
try {
try {
download();
parent.setState(State.SUCCEEDED);
}
finally {
parent.getParent().done(parent);
}
}
catch (FileNotFoundException e) {
logger.debug("download failed", e);
parent.setState(State.FAILED,
XNap.tr("Could not create incomplete file"));
}
catch (IOException e) {
logger.debug("download failed", e);
parent.setState(State.FAILED, NetHelper.getErrorMessage(e));
}
catch (InterruptedException e) {
logger.debug("download aborted");
parent.setState(State.NOT_STARTED, parent.getStatus());
}
}
catch (IllegalOperationException e) {
logger.error("unexpected state", e);
}
}
public void stop()
{
die = true;
}
private void close()
{
try {
if (socket != null)
socket.close();
if (in != null)
in.close();
if (out != null)
out.close();
}
catch (IOException e) {
}
}
/**
* Opens socket and requests file.
*/
private void connect(String ip, int port)
throws IOException, InterruptedException
{
logger.debug("opening socket to " + ip + ":" + port);
//socket = new Socket(ip, port);
try {
socket = NetHelper.connect(ip, port, CONNECT_TIMEOUT);
}
catch (SocketException e) {
MessageHandler.send
(parent.getServer(),
new DataPortErrorMessage(parent.getPeer().getName()));
throw e;
}
socket.setSoTimeout(CONNECT_TIMEOUT);
out = socket.getOutputStream();
in = new BufferedInputStream(socket.getInputStream());
parent.setStateDescription(XNap.tr("Negotiating") + "...");
// read magic number '1'
logger.debug("reading magic number");
char c = (char)in.read();
if (c != '1') {
throw new IOException(XNap.tr("Invalid request"));
}
parent.setStateDescription(XNap.tr("Sending get request") + "...");
// get request needs to be split over 2 packets
String message = "GET";
out.write(message.getBytes());
out.flush();
parent.setStateDescription(XNap.tr("Waiting for segment") + "...");
requestSegment();
parent.setStateDescription(XNap.tr("Sending file request") + "...");
message = parent.getServer().getLocalPeer().getName() + " "
+ "\"" + parent.getResult().getFilename() + "\"" + " "
+ segment.getDownloadOffset();
logger.debug("sending request: " + message);
out.write(message.getBytes());
out.flush();
String expected = segment.getTotal() + "";
StringBuffer sb = new StringBuffer();
while (sb.length() < expected.length()) {
int b = in.read();
if (b == -1) {
throw new IOException(XNap.tr("Socket error"));
}
c = (char)b;
if (Character.isDigit(c)) {
// ignore leading zeros
if (segment.getTotal() == 0 || sb.length() != 0
|| c != '0') {
sb.append(c);
}
}
else if (c == 'F') {
throw new IOException(XNap.tr("File not shared"));
}
else {
throw new IOException(XNap.tr("Invalid request"));
}
}
logger.debug("file length: " + sb.toString());
if (Long.parseLong(sb.toString()) != segment.getTotal()) {
throw new IOException(XNap.tr("Filesizes did not match"));
}
}
private void connect() throws IOException, InterruptedException
{
socket.setSoTimeout(CONNECT_TIMEOUT);
out = socket.getOutputStream();
requestSegment();
// write offset
Long offset = new Long(segment.getDownloadOffset());
out.write(offset.toString().getBytes());
out.flush();
}
private void requestSegment() throws IOException, InterruptedException
{
// spin lock for segment
socket.setSoTimeout(SEGMENT_MAX_WAIT + 30 * 1000);
long startTime = System.currentTimeMillis();
while (segment == null
&& System.currentTimeMillis() - startTime < SEGMENT_MAX_WAIT) {
// request segment for offset
segment = parent.requestSegment();
if (segment != null) {
return;
}
Thread.sleep(500);
}
throw new IOException(XNap.tr("No segment available"));
}
private void download() throws IOException, InterruptedException
{
boolean messageSent = false;
try {
if (socket == null) {
OpenNapUser user = (OpenNapUser)parent.getPeer();
connect(user.getHost(), user.getPort());
}
else {
connect();
}
if (segment.getFile() == null) {
segment.setFile(parent.createIncompleteFile());
}
parent.setState(State.DOWNLOADING);
MessageHandler.send(new DownloadingFileMessage());
messageSent = true;
// compare a few bytes
int byteCount = segment.getOverlap();
if (byteCount > 0) {
match(segment.getFileOffset(), byteCount);
}
downloadToFile();
}
catch (IOException e) {
try {
if (segment != null) {
parent.returnSegment(segment);
}
}
catch (IOException e2) {
logger.debug("segment merge failed", e2);
}
// we propagate the first exception
throw e;
}
catch (InterruptedException e) {
try {
if (segment != null) {
parent.returnSegment(segment);
}
}
catch (IOException e2) {
logger.debug("segment merge failed", e2);
}
// we propagate the first exception
throw e;
}
finally {
close();
if (messageSent) {
MessageHandler.send(new DownloadCompleteMessage());
}
}
parent.returnSegment(segment);
}
private void match(long offset, int byteCount)
throws IOException, InterruptedException
{
RandomAccessFile fileIn = null;
try {
fileIn = new RandomAccessFile(segment.getFile(), "r");
byte[] fileData = new byte[byteCount];
fileIn.seek(offset);
fileIn.readFully(fileData);
byte[] downloadData = new byte[byteCount];
readFully(downloadData, downloadData.length);
for (int i = 0; i < byteCount; i++) {
if (fileData[i] != downloadData[i]) {
throw new IOException(XNap.tr("resume failed at {0}",
new Integer(byteCount)));
}
}
}
finally {
if (fileIn != null) {
try {
fileIn.close();
}
catch (IOException e) {
}
}
}
}
/**
*
* <p>PRECONDITION<br>
* socket != null, in != null, out != null
*/
private void downloadToFile() throws IOException, InterruptedException
{
FileOutputStream fileOut = null;
try {
fileOut = new FileOutputStream
(segment.getFile().getAbsolutePath(), true);
// we need to catch aborts for slow connects quickly
byte[] data = new byte[512];
long transferred = 0;
long toTransfer = segment.getEnd() - segment.getStart();
while (toTransfer > 0) {
int len = (int)Math.min(toTransfer, data.length);
readFully(data, len);
len = segment.commitToFile(len);
parent.commit(len);
try {
fileOut.write(data, 0, len);
}
catch (IOException e) {
// FIX: how many bytes were acctually written?
segment.commitToFile(-len);
throw e;
}
toTransfer = segment.getRemaining();
}
}
finally {
if (fileOut != null) {
try {
fileOut.close();
}
catch (IOException e) {
}
}
}
}
private void readFully(byte[] data, int len)
throws IOException, InterruptedException
{
int byteCount = 0;
long startTime = System.currentTimeMillis();
while (byteCount < len) {
if (die) {
throw new InterruptedException();
}
else if (byteCount == 0 && (System.currentTimeMillis() - startTime
> TRANSFER_TIMEOUT)) {
throw (new IOException(XNap.tr("socket timeout")));
}
try {
// blocks for at most SOCKET_TIMEOUT
int read = in.read(data, byteCount, len - byteCount);
if (read == -1) {
throw new EOFException();
}
byteCount += read;
}
catch (InterruptedIOException e) {
}
}
}
}
The table below shows all metrics for OpenNapDownloadRunner.java.



