}
}
private void realRun() {
// Send Accepted
Message accepted = DMT.createFNPSSKAccepted(uid, pubKey == null);
try {
source.sendAsync(accepted, null, this);
} catch (NotConnectedException e1) {
if(logMINOR) Logger.minor(this, "Lost connection to source");
return;
}
if(tag.shouldSlowDown()) {
try {
source.sendAsync(DMT.createFNPRejectedOverload(uid, false, false, realTimeFlag), null, this);
} catch (NotConnectedException e) {
// Ignore.
}
}
while(headers == null || data == null || pubKey == null) {
MessageFilter mfDataInsertRejected = MessageFilter.create().setType(DMT.FNPDataInsertRejected).setField(DMT.UID, uid).setSource(source).setTimeout(DATA_INSERT_TIMEOUT);
MessageFilter mf = mfDataInsertRejected;
if(headers == null) {
MessageFilter m = MessageFilter.create().setType(DMT.FNPSSKInsertRequestHeaders).setField(DMT.UID, uid).setSource(source).setTimeout(DATA_INSERT_TIMEOUT);
mf = m.or(mf);
}
if(data == null) {
MessageFilter m = MessageFilter.create().setType(DMT.FNPSSKInsertRequestData).setField(DMT.UID, uid).setSource(source).setTimeout(DATA_INSERT_TIMEOUT);
mf = m.or(mf);
}
if(pubKey == null) {
MessageFilter m = MessageFilter.create().setType(DMT.FNPSSKPubKey).setField(DMT.UID, uid).setSource(source).setTimeout(DATA_INSERT_TIMEOUT);
mf = m.or(mf);
}
Message msg;
try {
msg = node.usm.waitFor(mf, this);
} catch (DisconnectedException e) {
if(logMINOR) Logger.minor(this, "Lost connection to source on "+uid);
return;
}
if(msg == null) {
Logger.normal(this, "Failed to receive all parts (data="+(data==null?"null":"ok")+" headers="+(headers==null?"null":"ok")+" pk="+pubKey+") for "+uid);
Message failed = DMT.createFNPDataInsertRejected(uid, DMT.DATA_INSERT_REJECTED_RECEIVE_FAILED);
try {
source.sendSync(failed, this, realTimeFlag);
} catch (NotConnectedException e) {
// Ignore
} catch (SyncSendWaitedTooLongException e) {
// Ignore
}
return;
} else if(msg.getSpec() == DMT.FNPSSKInsertRequestHeaders) {
headers = ((ShortBuffer)msg.getObject(DMT.BLOCK_HEADERS)).getData();
} else if(msg.getSpec() == DMT.FNPSSKInsertRequestData) {
data = ((ShortBuffer)msg.getObject(DMT.DATA)).getData();
} else if(msg.getSpec() == DMT.FNPSSKPubKey) {
byte[] pubkeyAsBytes = ((ShortBuffer)msg.getObject(DMT.PUBKEY_AS_BYTES)).getData();
try {
pubKey = DSAPublicKey.create(pubkeyAsBytes);
if(logMINOR) Logger.minor(this, "Got pubkey on "+uid+" : "+pubKey);
Message confirm = DMT.createFNPSSKPubKeyAccepted(uid);
try {
source.sendAsync(confirm, null, this);
} catch (NotConnectedException e) {
if(logMINOR) Logger.minor(this, "Lost connection to source on "+uid);
return;
}
} catch (CryptFormatException e) {
Logger.error(this, "Invalid pubkey from "+source+" on "+uid);
msg = DMT.createFNPDataInsertRejected(uid, DMT.DATA_INSERT_REJECTED_SSK_ERROR);
try {
source.sendSync(msg, this, realTimeFlag);
} catch (NotConnectedException ee) {
// Ignore
} catch (SyncSendWaitedTooLongException ee) {
// Ignore
}
return;
}
} else if(msg.getSpec() == DMT.FNPDataInsertRejected) {
try {
source.sendAsync(DMT.createFNPDataInsertRejected(uid, msg.getShort(DMT.DATA_INSERT_REJECTED_REASON)), null, this);
} catch (NotConnectedException e) {
// Ignore.
}
return;
} else {
Logger.error(this, "Unexpected message? "+msg+" on "+this);
}
}
try {
key.setPubKey(pubKey);
block = new SSKBlock(data, headers, key, false);
} catch (SSKVerifyException e1) {
Logger.error(this, "Invalid SSK from "+source, e1);
Message msg = DMT.createFNPDataInsertRejected(uid, DMT.DATA_INSERT_REJECTED_SSK_ERROR);
try {
source.sendSync(msg, this, realTimeFlag);
} catch (NotConnectedException e) {
// Ignore
} catch (SyncSendWaitedTooLongException e) {
// Ignore
}
return;
}
SSKBlock storedBlock = node.fetch(key, false, false, false, canWriteDatastore, false, null);
if((storedBlock != null) && !storedBlock.equals(block)) {
try {
RequestHandler.sendSSK(storedBlock.getRawHeaders(), storedBlock.getRawData(), false, pubKey, source, uid, this, realTimeFlag);
} catch (NotConnectedException e1) {
if(logMINOR) Logger.minor(this, "Lost connection to source on "+uid);
return;
} catch (WaitedTooLongException e1) {
Logger.error(this, "Took too long to send ssk datareply to "+uid+" (because of throttling)");
return;
} catch (PeerRestartedException e) {
if(logMINOR) Logger.minor(this, "Source restarted on "+uid);
return;
} catch (SyncSendWaitedTooLongException e) {
Logger.error(this, "Took too long to send ssk datareply to "+uid);
return;
}
block = storedBlock;
}
if(logMINOR) Logger.minor(this, "Got block for "+key+" for "+uid);
if(htl > 0)
sender = node.makeInsertSender(block, htl, uid, tag, source, false, false, canWriteDatastore, forkOnCacheable, preferInsert, ignoreLowBackoff, realTimeFlag);
boolean receivedRejectedOverload = false;
while(true) {
synchronized(sender) {
try {
if(sender.getStatus() == SSKInsertSender.NOT_FINISHED)
sender.wait(5000);
} catch (InterruptedException e) {
// Ignore
}
}
if((!receivedRejectedOverload) && sender.receivedRejectedOverload()) {
receivedRejectedOverload = true;
// Forward it
// Does not need to be sent synchronously since is non-terminal.
Message m = DMT.createFNPRejectedOverload(uid, false, true, realTimeFlag);
try {
source.sendAsync(m, null, this);
} catch (NotConnectedException e) {
if(logMINOR) Logger.minor(this, "Lost connection to source");
return;
}
}
if(sender.hasRecentlyCollided()) {
// Forward collision
data = sender.getData();
headers = sender.getHeaders();
collided = true;
try {
block = new SSKBlock(data, headers, key, true);
} catch (SSKVerifyException e1) {
// Is verified elsewhere...
throw new Error("Impossible: " + e1, e1);
}
try {
RequestHandler.sendSSK(headers, data, false, pubKey, source, uid, this, realTimeFlag);
} catch (NotConnectedException e1) {
if(logMINOR) Logger.minor(this, "Lost connection to source on "+uid);
return;
} catch (WaitedTooLongException e1) {
Logger.error(this, "Took too long to send ssk datareply to "+uid+" because of bwlimiting");
return;
} catch (PeerRestartedException e) {
Logger.error(this, "Peer restarted on "+uid);
return;
} catch (SyncSendWaitedTooLongException e) {
Logger.error(this, "Took too long to send ssk datareply to "+uid);
return;
}
}
int status = sender.getStatus();
if(status == SSKInsertSender.NOT_FINISHED) {
continue;
}
// Local RejectedOverload's (fatal).
// Internal error counts as overload. It'd only create a timeout otherwise, which is the same thing anyway.
// We *really* need a good way to deal with nodes that constantly R_O!
if((status == SSKInsertSender.TIMED_OUT) ||
(status == SSKInsertSender.GENERATED_REJECTED_OVERLOAD) ||
(status == SSKInsertSender.INTERNAL_ERROR)) {
// Unlock early for originator, late for target; see UIDTag comments.
tag.unlockHandler();
Message msg = DMT.createFNPRejectedOverload(uid, true, true, realTimeFlag);
try {
source.sendSync(msg, this, realTimeFlag);
} catch (NotConnectedException e) {
if(logMINOR) Logger.minor(this, "Lost connection to source");
return;
} catch (SyncSendWaitedTooLongException e) {
Logger.error(this, "Took too long to send "+msg+" to "+source);
return;
}
// Might as well store it anyway.
if((status == SSKInsertSender.TIMED_OUT) ||
(status == SSKInsertSender.GENERATED_REJECTED_OVERLOAD))
canCommit = true;
finish(status);
return;
}
if((status == SSKInsertSender.ROUTE_NOT_FOUND) || (status == SSKInsertSender.ROUTE_REALLY_NOT_FOUND)) {
// Unlock early for originator, late for target; see UIDTag comments.
tag.unlockHandler();
Message msg = DMT.createFNPRouteNotFound(uid, sender.getHTL());
try {
source.sendSync(msg, this, realTimeFlag);
} catch (NotConnectedException e) {
if(logMINOR) Logger.minor(this, "Lost connection to source");
return;
} catch (SyncSendWaitedTooLongException e) {
Logger.error(this, "Took too long to send "+msg+" to source");
}
canCommit = true;
finish(status);
return;
}
if(status == SSKInsertSender.SUCCESS) {
// Unlock early for originator, late for target; see UIDTag comments.
tag.unlockHandler();
Message msg = DMT.createFNPInsertReply(uid);
try {
source.sendSync(msg, this, realTimeFlag);
} catch (NotConnectedException e) {
if(logMINOR) Logger.minor(this, "Lost connection to source");
return;
} catch (SyncSendWaitedTooLongException e) {
Logger.error(this, "Took too long to send "+msg+" to "+source);
}
canCommit = true;
finish(status);
return;
}
// Otherwise...?
Logger.error(this, "Unknown status code: "+sender.getStatusString());
// Unlock early for originator, late for target; see UIDTag comments.
tag.unlockHandler();
Message msg = DMT.createFNPRejectedOverload(uid, true, true, realTimeFlag);
try {
source.sendSync(msg, this, realTimeFlag);
} catch (NotConnectedException e) {
// Ignore
} catch (SyncSendWaitedTooLongException e) {