Author: toad
Date: 2006-01-13 18:09:01 +0000 (Fri, 13 Jan 2006)
New Revision: 7852
Modified:
trunk/freenet/src/freenet/client/FileInserter.java
trunk/freenet/src/freenet/client/InserterException.java
trunk/freenet/src/freenet/keys/NodeSSK.java
trunk/freenet/src/freenet/keys/SSKBlock.java
trunk/freenet/src/freenet/node/LowLevelPutException.java
trunk/freenet/src/freenet/node/Node.java
trunk/freenet/src/freenet/node/SSKInsertHandler.java
trunk/freenet/src/freenet/node/SSKInsertSender.java
trunk/freenet/src/freenet/node/Version.java
Log:
348: (mandatory) Working SSK collision detection.
Modified: trunk/freenet/src/freenet/client/FileInserter.java
===================================================================
--- trunk/freenet/src/freenet/client/FileInserter.java 2006-01-13 17:17:44 UTC
(rev 7851)
+++ trunk/freenet/src/freenet/client/FileInserter.java 2006-01-13 18:09:01 UTC
(rev 7852)
@@ -263,6 +263,8 @@
break;
}
}
+ if(le.code == LowLevelPutException.COLLISION)
+ break;
}
}
@@ -284,6 +286,8 @@
throw new
InserterException(InserterException.ROUTE_NOT_FOUND, uri);
case LowLevelPutException.ROUTE_REALLY_NOT_FOUND:
throw new
InserterException(InserterException.ROUTE_REALLY_NOT_FOUND, uri);
+ case LowLevelPutException.COLLISION:
+ throw new
InserterException(InserterException.COLLISION, uri);
default:
Logger.error(this, "Unknown LowLevelPutException code:
"+e.code+" on "+this);
throw new
InserterException(InserterException.INTERNAL_ERROR, e, null);
Modified: trunk/freenet/src/freenet/client/InserterException.java
===================================================================
--- trunk/freenet/src/freenet/client/InserterException.java 2006-01-13
17:17:44 UTC (rev 7851)
+++ trunk/freenet/src/freenet/client/InserterException.java 2006-01-13
18:09:01 UTC (rev 7852)
@@ -72,6 +72,8 @@
public static final int TOO_MANY_RETRIES_IN_BLOCKS = 7;
/** Not able to leave the node at all */
public static final int ROUTE_REALLY_NOT_FOUND = 8;
+ /** Collided with pre-existing content */
+ public static final int COLLISION = 9;
public static String getMessage(int mode) {
switch(mode) {
@@ -91,6 +93,8 @@
return "Could not propagate the insert to enough nodes
(normal on small networks, try fetching it anyway)";
case ROUTE_REALLY_NOT_FOUND:
return "Insert could not leave the node at all";
+ case COLLISION:
+ return "Insert collided with different, pre-existing
data at the same key";
default:
return "Unknown error "+mode;
}
Modified: trunk/freenet/src/freenet/keys/NodeSSK.java
===================================================================
--- trunk/freenet/src/freenet/keys/NodeSSK.java 2006-01-13 17:17:44 UTC (rev
7851)
+++ trunk/freenet/src/freenet/keys/NodeSSK.java 2006-01-13 18:09:01 UTC (rev
7852)
@@ -6,6 +6,7 @@
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
import freenet.crypt.DSAPublicKey;
@@ -103,4 +104,14 @@
this.pubKey = pubKey2;
}
+ public boolean equals(Object o) {
+ if(!(o instanceof NodeSSK)) return false;
+ NodeSSK key = (NodeSSK)o;
+ if(!Arrays.equals(key.encryptedHashedDocname,
encryptedHashedDocname)) return false;
+ if(!Arrays.equals(key.pubKeyHash, pubKeyHash)) return false;
+ if(!Arrays.equals(key.routingKey, routingKey)) return false;
+ // cachedNormalizedDouble and pubKey could be negative/null.
+ return true;
+ }
+
}
Modified: trunk/freenet/src/freenet/keys/SSKBlock.java
===================================================================
--- trunk/freenet/src/freenet/keys/SSKBlock.java 2006-01-13 17:17:44 UTC
(rev 7851)
+++ trunk/freenet/src/freenet/keys/SSKBlock.java 2006-01-13 18:09:01 UTC
(rev 7852)
@@ -54,6 +54,20 @@
static final short ENCRYPTED_HEADERS_LENGTH = 36;
+ public boolean equals(Object o) {
+ if(!(o instanceof SSKBlock)) return false;
+ SSKBlock block = (SSKBlock)o;
+
+ if(!block.pubKey.equals(pubKey)) return false;
+ if(!block.nodeKey.equals(nodeKey)) return false;
+ if(block.headersOffset != headersOffset) return false;
+ if(block.hashIdentifier != hashIdentifier) return false;
+ if(block.symCipherIdentifier != symCipherIdentifier) return false;
+ if(!Arrays.equals(block.headers, headers)) return false;
+ if(!Arrays.equals(block.data, data)) return false;
+ return true;
+ }
+
/**
* Initialize, and verify data, headers against key. Provided
* key must have a pubkey, or we throw.
Modified: trunk/freenet/src/freenet/node/LowLevelPutException.java
===================================================================
--- trunk/freenet/src/freenet/node/LowLevelPutException.java 2006-01-13
17:17:44 UTC (rev 7851)
+++ trunk/freenet/src/freenet/node/LowLevelPutException.java 2006-01-13
18:09:01 UTC (rev 7852)
@@ -11,6 +11,8 @@
public static final int REJECTED_OVERLOAD = 3;
/** Insert could not get off the node at all */
public static final int ROUTE_REALLY_NOT_FOUND = 4;
+ /** Insert collided with pre-existing, different content. Can only
happen with KSKs and SSKs. */
+ public static final int COLLISION = 5;
/** Failure code */
public final int code;
@@ -25,6 +27,8 @@
return "A node downstream either timed out or was
overloaded (retry)";
case ROUTE_REALLY_NOT_FOUND:
return "The insert could not get off the node at all";
+ case COLLISION:
+ return "The insert collided with different data of the
same key already on the network";
default:
return "Unknown error code: "+reason;
}
Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java 2006-01-13 17:17:44 UTC (rev
7851)
+++ trunk/freenet/src/freenet/node/Node.java 2006-01-13 18:09:01 UTC (rev
7852)
@@ -830,6 +830,12 @@
insertThrottle.requestCompleted(len);
}
}
+
+ if(is.hasCollided()) {
+ // Store it locally so it can be fetched immediately, and
overwrites any locally inserted.
+ store(is.getBlock());
+ throw new LowLevelPutException(LowLevelPutException.COLLISION);
+ }
if(is.getStatus() == SSKInsertSender.SUCCESS) {
Logger.normal(this, "Succeeded inserting "+block);
@@ -1054,6 +1060,24 @@
transferringRequestSenders.put(key, sender);
}
+ public synchronized SSKBlock fetch(NodeSSK key) {
+ try {
+ return sskDatastore.fetch(key, false);
+ } catch (IOException e) {
+ Logger.error(this, "Cannot fetch data: "+e, e);
+ return null;
+ }
+ }
+
+ public synchronized CHKBlock fetch(NodeCHK key) {
+ try {
+ return chkDatastore.fetch(key, false);
+ } catch (IOException e) {
+ Logger.error(this, "Cannot fetch data: "+e, e);
+ return null;
+ }
+ }
+
/**
* Store a datum.
*/
Modified: trunk/freenet/src/freenet/node/SSKInsertHandler.java
===================================================================
--- trunk/freenet/src/freenet/node/SSKInsertHandler.java 2006-01-13
17:17:44 UTC (rev 7851)
+++ trunk/freenet/src/freenet/node/SSKInsertHandler.java 2006-01-13
18:09:01 UTC (rev 7852)
@@ -40,6 +40,7 @@
private Thread runThread;
private boolean sentSuccess;
private boolean canCommit;
+ private boolean collided;
SSKInsertHandler(Message req, long id, Node node, long startTime) {
this.req = req;
@@ -128,8 +129,6 @@
}
}
- // Now we have the data, the headers and the pubkey. Commit it.
-
try {
key.setPubKey(pubKey);
block = new SSKBlock(data, headers, key, false);
@@ -143,8 +142,21 @@
}
return;
}
- Logger.minor(this, "Committed SSK "+key+" for "+uid);
+ SSKBlock storedBlock = node.fetch(key);
+
+ if(storedBlock != null && !storedBlock.equals(block)) {
+ Message msg = DMT.createFNPSSKDataFound(uid,
storedBlock.getRawHeaders(), storedBlock.getRawData());
+ try {
+ source.send(msg);
+ } catch (NotConnectedException e) {
+ Logger.minor(this, "Lost connection to source
on "+uid);
+ }
+ block = storedBlock;
+ }
+
+ Logger.minor(this, "Got block for "+key+" for "+uid);
+
if(htl == 0) {
Message msg = DMT.createFNPInsertReply(uid);
sentSuccess = true;
Modified: trunk/freenet/src/freenet/node/SSKInsertSender.java
===================================================================
--- trunk/freenet/src/freenet/node/SSKInsertSender.java 2006-01-13 17:17:44 UTC
(rev 7851)
+++ trunk/freenet/src/freenet/node/SSKInsertSender.java 2006-01-13 18:09:01 UTC
(rev 7852)
@@ -11,6 +11,7 @@
import freenet.io.comm.Message;
import freenet.io.comm.MessageFilter;
import freenet.io.comm.NotConnectedException;
+import freenet.keys.CHKBlock;
import freenet.keys.NodeSSK;
import freenet.keys.SSKBlock;
import freenet.keys.SSKVerifyException;
@@ -51,6 +52,7 @@
private boolean sentRequest;
private boolean hasCollided;
private boolean hasRecentlyCollided;
+ private SSKBlock block;
/** Time at which we set status to a value other than NOT_FINISHED */
private long setStatusTime = -1;
@@ -93,7 +95,7 @@
} catch (NoSuchAlgorithmException e) {
throw new Error("SHA-256 not supported by system!: "+e);
}
-
+ this.block = block;
startTime = System.currentTimeMillis();
Thread t = new Thread(this, "SSKInsertSender for UID "+uid+" on
"+node.portNumber+" at "+System.currentTimeMillis());
t.setDaemon(true);
@@ -391,7 +393,7 @@
}
try {
- SSKBlock newBlock = new
SSKBlock(newData, newHeaders, myKey, false);
+ block = new SSKBlock(newData,
newHeaders, myKey, false);
} catch (SSKVerifyException e) {
Logger.error(this, "Node sent
us collision but got corrupt SSK!! from "+next+" on "+uid);
// Try next node, no way to
tell this one about its mistake as it's stopped listening. FIXME should it?
@@ -405,6 +407,7 @@
hasCollided = true;
notifyAll();
}
+ break; // go to next node
}
if (msg.getSpec() != DMT.FNPInsertReply) {
@@ -510,4 +513,8 @@
return data;
}
+ public SSKBlock getBlock() {
+ return block;
+ }
+
}
Modified: trunk/freenet/src/freenet/node/Version.java
===================================================================
--- trunk/freenet/src/freenet/node/Version.java 2006-01-13 17:17:44 UTC (rev
7851)
+++ trunk/freenet/src/freenet/node/Version.java 2006-01-13 18:09:01 UTC (rev
7852)
@@ -20,10 +20,10 @@
public static final String protocolVersion = "1.0";
/** The build number of the current revision */
- public static final int buildNumber = 347;
+ public static final int buildNumber = 348;
/** Oldest build of Fred we will talk to */
- public static final int lastGoodBuild = 344;
+ public static final int lastGoodBuild = 348;
/** The highest reported build of fred */
public static int highestSeenBuild = buildNumber;