Author: toad
Date: 2007-05-25 00:40:17 +0000 (Fri, 25 May 2007)
New Revision: 13369

Added:
   trunk/freenet/src/freenet/client/async/BinaryBlobFormatException.java
   trunk/freenet/src/freenet/client/async/BinaryBlobInserter.java
Modified:
   trunk/freenet/src/freenet/client/async/BinaryBlob.java
   trunk/freenet/src/freenet/crypt/DSAPublicKey.java
   trunk/freenet/src/freenet/keys/Key.java
   trunk/freenet/src/freenet/keys/NodeSSK.java
   trunk/freenet/src/freenet/node/NodeClientCore.java
   trunk/freenet/src/freenet/node/SimpleSendableInsert.java
Log:
BinaryBlobInserter - not wired in yet, and various issues e.g. it keeps all the 
keys in RAM (will file bugs; this one for example depends on making 
SendableInsert work for multiple keys per object)

Modified: trunk/freenet/src/freenet/client/async/BinaryBlob.java
===================================================================
--- trunk/freenet/src/freenet/client/async/BinaryBlob.java      2007-05-24 
23:07:19 UTC (rev 13368)
+++ trunk/freenet/src/freenet/client/async/BinaryBlob.java      2007-05-25 
00:40:17 UTC (rev 13369)
@@ -15,7 +15,7 @@
                
binaryBlobStream.writeShort(BinaryBlob.BINARY_BLOB_OVERALL_VERSION);
        }
        public static void writeKey(DataOutputStream binaryBlobStream, KeyBlock 
block, Key key) throws IOException {
-               byte[] keyData = key.getRoutingKey();
+               byte[] keyData = key.getKeyBytes();
                byte[] headers = block.getRawHeaders();
                byte[] data = block.getRawData();
                byte[] pubkey = block.getPubkeyBytes();

Added: trunk/freenet/src/freenet/client/async/BinaryBlobFormatException.java
===================================================================
--- trunk/freenet/src/freenet/client/async/BinaryBlobFormatException.java       
                        (rev 0)
+++ trunk/freenet/src/freenet/client/async/BinaryBlobFormatException.java       
2007-05-25 00:40:17 UTC (rev 13369)
@@ -0,0 +1,15 @@
+package freenet.client.async;
+
+import freenet.keys.KeyVerifyException;
+
+public class BinaryBlobFormatException extends Exception {
+
+       public BinaryBlobFormatException(String message) {
+               super(message);
+       }
+
+       public BinaryBlobFormatException(String message, KeyVerifyException e) {
+               super(message, e);
+       }
+
+}

Added: trunk/freenet/src/freenet/client/async/BinaryBlobInserter.java
===================================================================
--- trunk/freenet/src/freenet/client/async/BinaryBlobInserter.java              
                (rev 0)
+++ trunk/freenet/src/freenet/client/async/BinaryBlobInserter.java      
2007-05-25 00:40:17 UTC (rev 13369)
@@ -0,0 +1,247 @@
+package freenet.client.async;
+
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.util.Vector;
+
+import com.onionnetworks.util.FileUtil;
+
+import freenet.client.FailureCodeTracker;
+import freenet.client.InsertException;
+import freenet.keys.Key;
+import freenet.keys.KeyBlock;
+import freenet.keys.KeyVerifyException;
+import freenet.node.LowLevelPutException;
+import freenet.node.NodeClientCore;
+import freenet.node.SimpleSendableInsert;
+import freenet.support.Logger;
+import freenet.support.SimpleFieldSet;
+import freenet.support.api.Bucket;
+import freenet.support.api.BucketFactory;
+
+public class BinaryBlobInserter implements ClientPutState {
+
+       final ClientPutter parent;
+       final Object clientContext;
+       final MySendableInsert[] inserters;
+       final FailureCodeTracker errors;
+       final short maxRetries;
+       final short consecutiveRNFsCountAsSuccess;
+       private boolean logMINOR;
+       private int completedBlocks;
+       private int succeededBlocks;
+       private boolean fatal;
+       
+       BinaryBlobInserter(Bucket blob, ClientPutter parent, BucketFactory bf, 
Object clientContext, boolean tolerant, NodeClientCore core, 
+                       short prioClass, short maxRetries, short 
consecutiveRNFsCountAsSuccess) 
+       throws IOException, BinaryBlobFormatException {
+               logMINOR = Logger.shouldLog(Logger.MINOR, this);
+               this.maxRetries = maxRetries;
+               this.consecutiveRNFsCountAsSuccess = 
consecutiveRNFsCountAsSuccess;
+               this.parent = parent;
+               this.clientContext = clientContext;
+               this.errors = new FailureCodeTracker(true);
+               Vector myInserters = new Vector();
+               DataInputStream dis = new 
DataInputStream(blob.getInputStream());
+               long magic = dis.readLong();
+               if(magic != BinaryBlob.BINARY_BLOB_MAGIC)
+                       throw new BinaryBlobFormatException("Bad magic");
+               short version = dis.readShort();
+               if(version != BinaryBlob.BINARY_BLOB_OVERALL_VERSION)
+                       throw new BinaryBlobFormatException("Unknown overall 
version");
+               
+               int i=0;
+               while(true) {
+                       long blobLength;
+                       try {
+                               blobLength = dis.readInt() & 0xFFFFFFFFL;
+                       } catch (EOFException e) {
+                               // End of file
+                               dis.close();
+                               break;
+                       }
+                       short blobType = dis.readShort();
+                       short blobVer = dis.readShort();
+                       
+                       if(blobType == BinaryBlob.BLOB_END) {
+                               dis.close();
+                               break;
+                       } else if(blobType == BinaryBlob.BLOB_BLOCK) {
+                               if(blobVer != BinaryBlob.BLOB_BLOCK_VERSION)
+                                       // Even if tolerant, if we can't read a 
blob there probably isn't much we can do.
+                                       throw new 
BinaryBlobFormatException("Unknown block blob version");
+                               if(blobLength < 9)
+                                       throw new 
BinaryBlobFormatException("Block blob too short");
+                               short keyType = dis.readShort();
+                               int keyLen = dis.readUnsignedByte();
+                               short headersLen = dis.readShort();
+                               short dataLen = dis.readShort();
+                               short pubkeyLen = dis.readShort();
+                               if(blobLength != 9 + keyLen + headersLen + 
dataLen + pubkeyLen)
+                                       throw new 
BinaryBlobFormatException("Binary blob too short for data lengths");
+                               byte[] keyBytes = new byte[keyLen];
+                               byte[] headersBytes = new byte[headersLen];
+                               byte[] dataBytes = new byte[dataLen];
+                               byte[] pubkeyBytes = new byte[pubkeyLen];
+                               dis.readFully(keyBytes);
+                               dis.readFully(headersBytes);
+                               dis.readFully(dataBytes);
+                               dis.readFully(pubkeyBytes);
+                               KeyBlock block;
+                               try {
+                                       block = Key.createBlock(keyType, 
keyBytes, headersBytes, dataBytes, pubkeyBytes);
+                               } catch (KeyVerifyException e) {
+                                       throw new 
BinaryBlobFormatException("Invalid key: "+e.getMessage(), e);
+                               }
+                               
+                               MySendableInsert inserter =
+                                       new MySendableInsert(i, core, block, 
prioClass);
+                               
+                               myInserters.add(inserter);
+                               
+                       } else {
+                               if(tolerant) {
+                                       FileUtil.skipFully(dis, blobLength);
+                               } else {
+                                       throw new 
BinaryBlobFormatException("Unknown blob type: "+blobType);
+                               }
+                       }
+                       i++;
+               }
+               inserters = (MySendableInsert[]) myInserters.toArray(new 
MySendableInsert[myInserters.size()]);
+               parent.addMustSucceedBlocks(inserters.length);
+       }
+       
+       public void cancel() {
+               for(int i=0;i<inserters.length;i++) {
+                       if(inserters[i] != null)
+                               inserters[i].cancel();
+               }
+               parent.onFailure(new 
InsertException(InsertException.CANCELLED), this);
+       }
+
+       public BaseClientPutter getParent() {
+               return parent;
+       }
+
+       public SimpleFieldSet getProgressFieldset() {
+               // FIXME not supported
+               return null;
+       }
+
+       public Object getToken() {
+               return clientContext;
+       }
+
+       public void schedule() throws InsertException {
+               for(int i=0;i<inserters.length;i++) {
+                       inserters[i].schedule();
+               }
+       }
+       
+       class MySendableInsert extends SimpleSendableInsert {
+
+               final int blockNum;
+               private int consecutiveRNFs;
+               private int retries;
+               
+               public MySendableInsert(int i, NodeClientCore core, KeyBlock 
block, short prioClass) {
+                       super(core, block, prioClass);
+                       this.blockNum = i;
+               }
+               
+               public void onSuccess() {
+                       synchronized(this) {
+                               if(inserters[blockNum] == null) return;
+                               inserters[blockNum] = null;
+                               completedBlocks++;
+                               succeededBlocks++;
+                       }
+                       parent.completedBlock(false);
+                       maybeFinish();
+               }
+
+               // FIXME duplicated code from SingleBlockInserter
+               // FIXME combine it somehow
+               public void onFailure(LowLevelPutException e) {
+                       synchronized(BinaryBlobInserter.this) {
+                               if(inserters[blockNum] == null) return;
+                       }
+                       if(parent.isCancelled()) {
+                               fail(new 
InsertException(InsertException.CANCELLED), true);
+                               return;
+                       }
+                       logMINOR = Logger.shouldLog(Logger.MINOR, 
BinaryBlobInserter.this);
+                       switch(e.code) {
+                       case LowLevelPutException.COLLISION:
+                               fail(new 
InsertException(InsertException.COLLISION), false);
+                               break;
+                       case LowLevelPutException.INTERNAL_ERROR:
+                               errors.inc(InsertException.INTERNAL_ERROR);
+                               break;
+                       case LowLevelPutException.REJECTED_OVERLOAD:
+                               errors.inc(InsertException.REJECTED_OVERLOAD);
+                               break;
+                       case LowLevelPutException.ROUTE_NOT_FOUND:
+                               errors.inc(InsertException.ROUTE_NOT_FOUND);
+                               break;
+                       case LowLevelPutException.ROUTE_REALLY_NOT_FOUND:
+                               
errors.inc(InsertException.ROUTE_REALLY_NOT_FOUND);
+                               break;
+                       default:
+                               Logger.error(this, "Unknown 
LowLevelPutException code: "+e.code);
+                               errors.inc(InsertException.INTERNAL_ERROR);
+                       }
+                       if(e.code == LowLevelPutException.ROUTE_NOT_FOUND) {
+                               consecutiveRNFs++;
+                               if(logMINOR) Logger.minor(this, "Consecutive 
RNFs: "+consecutiveRNFs+" / "+consecutiveRNFsCountAsSuccess);
+                               if(consecutiveRNFs == 
consecutiveRNFsCountAsSuccess) {
+                                       if(logMINOR) Logger.minor(this, 
"Consecutive RNFs: "+consecutiveRNFs+" - counting as success");
+                                       onSuccess();
+                                       return;
+                               }
+                       } else
+                               consecutiveRNFs = 0;
+                       if(logMINOR) Logger.minor(this, "Failed: "+e);
+                       retries++;
+                       if((retries > maxRetries) && (maxRetries != -1)) {
+                               fail(InsertException.construct(errors), false);
+                               return;
+                       }
+                       schedule();
+               }
+
+               private void fail(InsertException e, boolean fatal) {
+                       synchronized(BinaryBlobInserter.this) {
+                               if(inserters[blockNum] == null) return;
+                               inserters[blockNum] = null;
+                               completedBlocks++;
+                               if(fatal) BinaryBlobInserter.this.fatal = true;
+                       }
+                       if(fatal)
+                               parent.fatallyFailedBlock();
+                       else
+                               parent.failedBlock();
+                       maybeFinish();
+               }
+       }
+
+       public void maybeFinish() {
+               boolean success;
+               boolean wasFatal;
+               synchronized(this) {
+                       if(completedBlocks != inserters.length)
+                               return;
+                       success = completedBlocks == succeededBlocks;
+                       wasFatal = fatal;
+               }
+               if(success) {
+                       parent.onSuccess(this);
+               } else if(wasFatal)
+                       parent.onFailure(new 
InsertException(InsertException.FATAL_ERRORS_IN_BLOCKS, errors, null), this);
+               else
+                       parent.onFailure(new 
InsertException(InsertException.TOO_MANY_RETRIES_IN_BLOCKS, errors, null), 
this);
+       }
+       
+}

Modified: trunk/freenet/src/freenet/crypt/DSAPublicKey.java
===================================================================
--- trunk/freenet/src/freenet/crypt/DSAPublicKey.java   2007-05-24 23:07:19 UTC 
(rev 13368)
+++ trunk/freenet/src/freenet/crypt/DSAPublicKey.java   2007-05-25 00:40:17 UTC 
(rev 13369)
@@ -54,7 +54,11 @@
                        throw new IllegalArgumentException("y must be < p but 
y="+y+" p="+group.getP());
     }

-    public static DSAPublicKey create(byte[] pubkeyAsBytes) throws 
CryptFormatException {
+    public DSAPublicKey(byte[] pubkeyBytes) throws IOException, 
CryptFormatException {
+       this(new ByteArrayInputStream(pubkeyBytes));
+       }
+
+       public static DSAPublicKey create(byte[] pubkeyAsBytes) throws 
CryptFormatException {
        try {
                        return new DSAPublicKey(new 
ByteArrayInputStream(pubkeyAsBytes));
                } catch (IOException e) {

Modified: trunk/freenet/src/freenet/keys/Key.java
===================================================================
--- trunk/freenet/src/freenet/keys/Key.java     2007-05-24 23:07:19 UTC (rev 
13368)
+++ trunk/freenet/src/freenet/keys/Key.java     2007-05-25 00:40:17 UTC (rev 
13369)
@@ -9,6 +9,8 @@
 import java.security.MessageDigest;
 import java.util.Arrays;

+import freenet.crypt.CryptFormatException;
+import freenet.crypt.DSAPublicKey;
 import freenet.crypt.SHA256;
 import freenet.io.WritableToDataOutputStream;
 import freenet.support.Fields;
@@ -72,6 +74,26 @@
         throw new IOException("Unrecognized format: "+type);
     }

+       public static KeyBlock createBlock(short keyType, byte[] keyBytes, 
byte[] headersBytes, byte[] dataBytes, byte[] pubkeyBytes) throws 
KeyVerifyException {
+               byte type = (byte)(keyType >> 8);
+               byte subtype = (byte)(keyType & 0xFF);
+               if(type == NodeCHK.BASE_TYPE) {
+                       return CHKBlock.construct(headersBytes, dataBytes);
+               } else if(type == NodeSSK.BASE_TYPE) {
+                       DSAPublicKey pubKey;
+                       try {
+                               pubKey = new DSAPublicKey(pubkeyBytes);
+                       } catch (IOException e) {
+                               throw new KeyVerifyException("Failed to 
construct pubkey: "+e, e);
+                       } catch (CryptFormatException e) {
+                               throw new KeyVerifyException("Failed to 
construct pubkey: "+e, e);
+                       }
+                       NodeSSK key = new NodeSSK(pubKey.asBytesHash(), 
keyBytes, pubKey, subtype);
+                       return new SSKBlock(dataBytes, headersBytes, key, 
false);
+               } else {
+                       throw new KeyVerifyException("No such key type 
"+Integer.toHexString(type));
+               }
+       }

     /**
      * Convert the key to a double between 0.0 and 1.0.
@@ -222,5 +244,9 @@
     public byte[] getRoutingKey() {
        return routingKey;
     }
-    
+
+    // Not just the routing key, enough data to reconstruct the key (excluding 
any pubkey needed)
+    public byte[] getKeyBytes() {
+       return routingKey;
+    }
 }

Modified: trunk/freenet/src/freenet/keys/NodeSSK.java
===================================================================
--- trunk/freenet/src/freenet/keys/NodeSSK.java 2007-05-24 23:07:19 UTC (rev 
13368)
+++ trunk/freenet/src/freenet/keys/NodeSSK.java 2007-05-25 00:40:17 UTC (rev 
13369)
@@ -157,4 +157,9 @@
                return hashCode;
        }

+    // Not just the routing key, enough data to reconstruct the key (excluding 
any pubkey needed)
+    public byte[] getKeyBytes() {
+       return encryptedHashedDocname;
+    }
+       
 }

Modified: trunk/freenet/src/freenet/node/NodeClientCore.java
===================================================================
--- trunk/freenet/src/freenet/node/NodeClientCore.java  2007-05-24 23:07:19 UTC 
(rev 13368)
+++ trunk/freenet/src/freenet/node/NodeClientCore.java  2007-05-25 00:40:17 UTC 
(rev 13369)
@@ -995,12 +995,7 @@
        public void queueRandomReinsert(KeyBlock block) {
                SimpleSendableInsert ssi = new SimpleSendableInsert(this, 
block, RequestStarter.MAXIMUM_PRIORITY_CLASS);
                if(logMINOR) Logger.minor(this, "Queueing random reinsert for 
"+block+" : "+ssi);
-               if(block instanceof CHKBlock)
-                       requestStarters.chkPutScheduler.register(ssi);
-               else if(block instanceof SSKBlock)
-                       requestStarters.sskPutScheduler.register(ssi);
-               else
-                       Logger.error(this, "Don't know what to do with 
"+block+" should be queued for reinsert");
+               ssi.schedule();
        }

        public void storeConfig() {

Modified: trunk/freenet/src/freenet/node/SimpleSendableInsert.java
===================================================================
--- trunk/freenet/src/freenet/node/SimpleSendableInsert.java    2007-05-24 
23:07:19 UTC (rev 13368)
+++ trunk/freenet/src/freenet/node/SimpleSendableInsert.java    2007-05-25 
00:40:17 UTC (rev 13369)
@@ -3,9 +3,13 @@
  * http://www.gnu.org/ for further details of the GPL. */
 package freenet.node;

+import freenet.client.InsertException;
 import freenet.client.async.ClientRequester;
+import freenet.keys.CHKBlock;
 import freenet.keys.KeyBlock;
+import freenet.keys.SSKBlock;
 import freenet.support.Logger;
+import freenet.support.RandomGrabArray;

 /**
  * Simple SendableInsert implementation. No feedback, no retries, just insert 
the
@@ -78,4 +82,23 @@
                return true;
        }

+       public void schedule() {
+               finished = false; // can reschedule
+               if(block instanceof CHKBlock)
+                       node.requestStarters.chkPutScheduler.register(this);
+               else if(block instanceof SSKBlock)
+                       node.requestStarters.sskPutScheduler.register(this);
+               else
+                       Logger.error(this, "Don't know what to do with "+block, 
new Exception());
+       }
+
+       public void cancel() {
+               synchronized(this) {
+                       if(finished) return;
+                       finished = true;
+               }
+               RandomGrabArray arr = getParentGrabArray();
+               if(arr != null) arr.remove(this);
+       }
+
 }


Reply via email to