start();
}
private boolean maybeFetch() {
boolean tryEverything = false;
PeerNode chosen = null;
while(true) {
synchronized(this) {
if(peersFetching.size() >= MAX_NODES_SENDING_JAR) {
if(logMINOR) Logger.minor(this, "Already fetching jar from 2 peers "+peersFetching);
return false;
}
if(completed) return false;
}
HashSet<PeerNode> uomPeers;
synchronized(UpdateOverMandatoryManager.this) {
uomPeers = new HashSet<PeerNode>(nodesSentMainJar);
}
chosen = chooseRandomPeer(uomPeers);
if(chosen != null) break;
synchronized(UpdateOverMandatoryManager.this) {
uomPeers = new HashSet<PeerNode>(nodesSendingMainJar);
}
chosen = chooseRandomPeer(uomPeers);
if(chosen != null) break;
synchronized(UpdateOverMandatoryManager.this) {
uomPeers = new HashSet<PeerNode>(allNodesOfferedMainJar);
}
chosen = chooseRandomPeer(uomPeers);
if(chosen != null) break;
if(tryEverything) {
Logger.minor(this, "Could not find a peer to send request to for "+saveTo);
return false;
}
synchronized(this) {
if(peersFailed.size() != 0) {
System.out.println("UOM trying peers which have failed downloads for "+saveTo.getName()+" because nowhere else to go ...");
peersFailed.clear();
tryEverything = true;
}
}
if(!tryEverything) {
Logger.minor(this, "Could not find a peer to send request to for "+saveTo);
return false;
}
}
if(chosen == null) return false;
final PeerNode fetchFrom = chosen;
updateManager.node.executor.execute(new Runnable() {
@Override
public void run() {
boolean failed = false;
File tmp = null;
FileRandomAccessBuffer raf = null;
try {
System.out.println("Fetching "+saveTo+" from "+fetchFrom);
long uid = updateManager.node.fastWeakRandom.nextLong();
fetchFrom.sendAsync(DMT.createUOMFetchDependency(uid, expectedHash, size), null, updateManager.ctr);
tmp = FileUtil.createTempFile(saveTo.getName(), NodeUpdateManager.TEMP_FILE_SUFFIX, saveTo.getParentFile());
raf = new FileRandomAccessBuffer(tmp, size, false);
PartiallyReceivedBulk prb =
new PartiallyReceivedBulk(updateManager.node.getUSM(), size,
Node.PACKET_SIZE, raf, false);
BulkReceiver br = new BulkReceiver(prb, fetchFrom, uid, updateManager.ctr);
failed = !br.receive();
raf.close();
raf = null;
if(!failed) {
// Check the hash.
if(MainJarDependenciesChecker.validFile(tmp, expectedHash, size, executable)) {
if(FileUtil.renameTo(tmp, saveTo)) {
synchronized(UOMDependencyFetcher.this) {
if(completed) return;
completed = true;
}
synchronized(UpdateOverMandatoryManager.this) {
dependencyFetchers.remove(expectedHashBuffer);
}
cb.onSuccess();
} else {
synchronized(UOMDependencyFetcher.this) {
if(completed) return;
}
failed = true;
System.err.println("Update failing: Saved dependency to "+tmp+" for "+saveTo+" but cannot rename it! Permissions problems?");
}
peerMaybeFreeAllSlots(fetchFrom);
} else {
synchronized(UOMDependencyFetcher.this) {
if(completed) return;
}
failed = true;
System.err.println("Update failing: Downloaded file "+saveTo+" from "+fetchFrom+" but file does not match expected hash.");
// Wrong length -> transfer would have failed.
}
} else {
System.out.println("Download failed: "+saveTo+" from "+fetchFrom);
failed = true;
}
} catch (NotConnectedException e) {
// Not counting this as a failure.
System.out.println("Disconnected while downloading "+saveTo+" from "+fetchFrom);
} catch (IOException e) {
// This isn't their fault either.
// User might be able to understand and fix this.
System.out.println("IOException while downloading "+saveTo+" from "+fetchFrom+" : "+e);
Logger.error(this, "IOException while downloading "+saveTo+" from "+fetchFrom+" : "+e, e);
} catch (RuntimeException e) {
Logger.error(this, "Caught fetching "+saveTo+" from "+fetchFrom +" : "+e, e);
System.err.println("Fetch failed due to internal error (bug or severe local problem?): "+e);
e.printStackTrace();
} catch (Error e) {
Logger.error(this, "Caught fetching "+saveTo+" from "+fetchFrom +" : "+e, e);
System.err.println("Fetch failed due to internal error (bug or severe local problem?): "+e);
e.printStackTrace();
} finally {
boolean connected = fetchFrom.isConnected();
boolean addFailed = failed && connected;
synchronized(UOMDependencyFetcher.this) {
if(addFailed)
peersFailed.add(fetchFrom);
peersFetching.remove(fetchFrom);
}
Closer.close(raf);
if(tmp != null)
tmp.delete();
if(failed) {
start();
if(fetchFrom.isConnected() && fetchFrom.isDarknet()) {
// Darknet peers only: Try again in an hour.
// On opennet we'll just keep announcing until we succeed.
updateManager.node.getTicker().queueTimedJob(new Runnable() {
@Override