Author: toad
Date: 2006-01-12 18:39:32 +0000 (Thu, 12 Jan 2006)
New Revision: 7845

Modified:
   trunk/freenet/src/freenet/crypt/DSAPublicKey.java
   trunk/freenet/src/freenet/io/comm/UdpSocketManager.java
   trunk/freenet/src/freenet/keys/InsertableClientSSK.java
   trunk/freenet/src/freenet/keys/NodeSSK.java
   trunk/freenet/src/freenet/keys/SSKBlock.java
   trunk/freenet/src/freenet/node/Node.java
   trunk/freenet/src/freenet/node/RequestHandler.java
   trunk/freenet/src/freenet/node/RequestSender.java
   trunk/freenet/src/freenet/node/Version.java
   trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java
   trunk/freenet/src/freenet/store/FreenetStore.java
Log:
343: (mandatory)
SSKs *sometimes* work. :)

Modified: trunk/freenet/src/freenet/crypt/DSAPublicKey.java
===================================================================
--- trunk/freenet/src/freenet/crypt/DSAPublicKey.java   2006-01-12 18:33:28 UTC 
(rev 7844)
+++ trunk/freenet/src/freenet/crypt/DSAPublicKey.java   2006-01-12 18:39:32 UTC 
(rev 7845)
@@ -13,6 +13,8 @@
     private final BigInteger y;
        /** A cache of the hexadecimal string representation of y */
     private final String yAsHexString; 
+    
+    public static final int PADDED_SIZE = 660;

     private final DSAGroup group;

@@ -131,6 +133,17 @@
                return bytes;
     }

+    public byte[] asPaddedBytes() {
+       byte[] asBytes = asBytes();
+       if(asBytes.length == PADDED_SIZE)
+               return asBytes;
+       if(asBytes.length > PADDED_SIZE)
+               throw new Error("Cannot fit key in "+PADDED_SIZE+" - real size 
is "+asBytes.length);
+       byte[] padded = new byte[PADDED_SIZE];
+       System.arraycopy(asBytes, 0, padded, 0, asBytes.length);
+       return padded;
+    }
+    
     public byte[] fingerprint() {
                synchronized(this) {
                        if(fingerprint == null)

Modified: trunk/freenet/src/freenet/io/comm/UdpSocketManager.java
===================================================================
--- trunk/freenet/src/freenet/io/comm/UdpSocketManager.java     2006-01-12 
18:33:28 UTC (rev 7844)
+++ trunk/freenet/src/freenet/io/comm/UdpSocketManager.java     2006-01-12 
18:39:32 UTC (rev 7845)
@@ -322,10 +322,11 @@
                                        i.remove();
                                        ret = m;
                                        Logger.debug(this, "Matching from 
_unclaimed");
+                                       break;
                                }
                        }
-                       Logger.minor(this, "Not in _unclaimed");
                        if (ret == null) {
+                               Logger.minor(this, "Not in _unclaimed");
                            // Insert filter into filter list in order of 
timeout
                                ListIterator i = _filters.listIterator();
                                while (true) {
@@ -354,7 +355,7 @@
                                        // Precaution against filter getting 
matched between being added to _filters and
                                        // here - bug discovered by Mason
                                    boolean fmatched = false;
-                                   while(!(fmatched = filter.matched() || 
filter.droppedConnection() != null)) {
+                                   while(!(fmatched = (filter.matched() || 
filter.droppedConnection() != null))) {
                                        long wait = 
filter.getTimeout()-System.currentTimeMillis();
                                        if(wait > 0)
                                            filter.wait(wait);

Modified: trunk/freenet/src/freenet/keys/InsertableClientSSK.java
===================================================================
--- trunk/freenet/src/freenet/keys/InsertableClientSSK.java     2006-01-12 
18:33:28 UTC (rev 7844)
+++ trunk/freenet/src/freenet/keys/InsertableClientSSK.java     2006-01-12 
18:39:32 UTC (rev 7845)
@@ -97,6 +97,7 @@

                aes.initialize(origDataHash);
                PCFBMode pcfb = new PCFBMode(aes);
+               pcfb.reset(origDataHash);

                pcfb.blockEncipher(data, 0, data.length);


Modified: trunk/freenet/src/freenet/keys/NodeSSK.java
===================================================================
--- trunk/freenet/src/freenet/keys/NodeSSK.java 2006-01-12 18:33:28 UTC (rev 
7844)
+++ trunk/freenet/src/freenet/keys/NodeSSK.java 2006-01-12 18:39:32 UTC (rev 
7845)
@@ -99,7 +99,7 @@

        public void setPubKey(DSAPublicKey pubKey2) {
                if(pubKey == pubKey2) return;
-               if(pubKey != null) throw new IllegalStateException("Already 
assigned pubkey to different value! Old="+pubKey.writeAsField()+", 
new="+pubKey2.writeAsField());
+               if(pubKey != null && !pubKey.equals(pubKey2)) throw new 
IllegalStateException("Already assigned pubkey to different value! 
Old="+pubKey.writeAsField()+", new="+pubKey2.writeAsField());
                this.pubKey = pubKey2;
        }


Modified: trunk/freenet/src/freenet/keys/SSKBlock.java
===================================================================
--- trunk/freenet/src/freenet/keys/SSKBlock.java        2006-01-12 18:33:28 UTC 
(rev 7844)
+++ trunk/freenet/src/freenet/keys/SSKBlock.java        2006-01-12 18:39:32 UTC 
(rev 7845)
@@ -132,4 +132,8 @@
                return data;
        }

+       public DSAPublicKey getPubKey() {
+               return pubKey;
+       }
+
 }

Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java    2006-01-12 18:33:28 UTC (rev 
7844)
+++ trunk/freenet/src/freenet/node/Node.java    2006-01-12 18:39:32 UTC (rev 
7845)
@@ -129,6 +129,8 @@
     private final FreenetStore chkDatastore;
     /** The SSK datastore */
     private final FreenetStore sskDatastore;
+    /** The store of DSAPublicKeys (by hash) */
+    private final FreenetStore pubKeyDatastore;
     /** RequestSender's currently running, by KeyHTLPair */
     private final HashMap requestSenders;
     /** RequestSender's currently transferring, by key */
@@ -357,6 +359,7 @@
         try {
             chkDatastore = new 
BerkeleyDBFreenetStore(prefix+"store-"+portNumber, maxStoreKeys, 32768, 
CHKBlock.TOTAL_HEADERS_LENGTH);
             sskDatastore = new 
BerkeleyDBFreenetStore(prefix+"sskstore-"+portNumber, maxStoreKeys, 1024, 
SSKBlock.TOTAL_HEADERS_LENGTH);
+            pubKeyDatastore = new 
BerkeleyDBFreenetStore(prefix+"pubkeystore-"+portNumber, maxStoreKeys, 
DSAPublicKey.PADDED_SIZE, 0);
         } catch (FileNotFoundException e1) {
             Logger.error(this, "Could not open datastore: "+e1, e1);
             System.err.println("Could not open datastore: "+e1);
@@ -548,6 +551,7 @@
                        case RequestSender.GENERATED_REJECTED_OVERLOAD:
                        case RequestSender.TIMED_OUT:
                                throw new 
LowLevelGetException(LowLevelGetException.REJECTED_OVERLOAD);
+                       case RequestSender.INTERNAL_ERROR:
                        default:
                                Logger.error(this, "Unknown RequestSender code 
in getCHK: "+rs.getStatus()+" on "+rs);
                                throw new 
LowLevelGetException(LowLevelGetException.INTERNAL_ERROR);
@@ -570,7 +574,9 @@
         Object o = makeRequestSender(key.getNodeKey(), MAX_HTL, uid, null, 
lm.loc.getValue(), localOnly, cache);
         if(o instanceof SSKBlock) {
             try {
-                return new ClientSSKBlock((SSKBlock)o, key);
+               SSKBlock block = (SSKBlock)o;
+               key.setPublicKey(block.getPubKey());
+                return new ClientSSKBlock(block, key);
             } catch (SSKVerifyException e) {
                 Logger.error(this, "Does not verify: "+e, e);
                 throw new 
LowLevelGetException(LowLevelGetException.DECODE_FAILED);
@@ -610,7 +616,9 @@

                if(rs.getStatus() == RequestSender.SUCCESS) {
                        try {
-                               return new ClientSSKBlock(rs.getSSKBlock(), 
key);
+                               SSKBlock block = rs.getSSKBlock();
+                               key.setPublicKey(block.getPubKey());
+                               return new ClientSSKBlock(block, key);
                        } catch (SSKVerifyException e) {
                                Logger.error(this, "Does not verify: "+e, e);
                                throw new 
LowLevelGetException(LowLevelGetException.DECODE_FAILED);                
@@ -632,6 +640,7 @@
                        case RequestSender.GENERATED_REJECTED_OVERLOAD:
                        case RequestSender.TIMED_OUT:
                                throw new 
LowLevelGetException(LowLevelGetException.REJECTED_OVERLOAD);
+                       case RequestSender.INTERNAL_ERROR:
                        default:
                                Logger.error(this, "Unknown RequestSender code 
in getCHK: "+rs.getStatus()+" on "+rs);
                                throw new 
LowLevelGetException(LowLevelGetException.INTERNAL_ERROR);
@@ -958,9 +967,16 @@
         try {
                if(key instanceof NodeCHK)
                        chk = chkDatastore.fetch((NodeCHK)key, !cache);
-               else if(key instanceof NodeSSK)
-                       chk = sskDatastore.fetch((NodeSSK)key, !cache);
-               else
+               else if(key instanceof NodeSSK) {
+                       NodeSSK k = (NodeSSK)key;
+                       DSAPublicKey pubKey = k.getPubKey();
+                       if(pubKey == null) {
+                               pubKey = getKey(k.getPubKeyHash());
+                               k.setPubKey(pubKey);
+                       }
+                       if(pubKey != null)
+                               chk = sskDatastore.fetch((NodeSSK)key, !cache);
+               } else
                        throw new IllegalStateException("Unknown key type: 
"+key.getClass());
         } catch (IOException e) {
             Logger.error(this, "Error accessing store: "+e, e);
@@ -1049,6 +1065,7 @@
     public synchronized void store(SSKBlock block) {
        try {
                sskDatastore.put(block);
+               cacheKey(((NodeSSK)block.getKey()).getPubKeyHash(), 
((NodeSSK)block.getKey()).getPubKey());
        } catch (IOException e) {
                Logger.error(this, "Cannot store data: "+e, e);
        }
@@ -1153,6 +1170,10 @@
     public synchronized SSKInsertSender makeInsertSender(SSKBlock block, short 
htl, long uid, PeerNode source,
             boolean fromStore, double closestLoc, boolean cache) {
        NodeSSK key = (NodeSSK) block.getKey();
+       if(key.getPubKey() == null) {
+               throw new IllegalArgumentException("No pub key when inserting");
+       }
+       cacheKey(key.getPubKeyHash(), key.getPubKey());
         Logger.minor(this, 
"makeInsertSender("+key+","+htl+","+uid+","+source+",...,"+fromStore);
         KeyHTLPair kh = new KeyHTLPair(key, htl);
         SSKInsertSender is = (SSKInsertSender) insertSenders.get(kh);
@@ -1335,9 +1356,21 @@
                ImmutableByteArrayWrapper w = new 
ImmutableByteArrayWrapper(hash);
                synchronized(cachedPubKeys) {
                        DSAPublicKey key = (DSAPublicKey) cachedPubKeys.get(w);
-                       if(key != null)
+                       if(key != null) {
                                cachedPubKeys.push(w, key);
+                               return key;
+                       }
+               }
+               try {
+                       DSAPublicKey key = pubKeyDatastore.fetchPubKey(hash, 
false);
+                       if(key != null) {
+                               cacheKey(hash, key);
+                       }
                        return key;
+               } catch (IOException e) {
+                       // FIXME deal with disk full, access perms etc; tell 
user about it.
+                       Logger.error(this, "Error accessing pubkey store: "+e, 
e);
+                       return null;
                }
        }

@@ -1354,5 +1387,11 @@
                        while(cachedPubKeys.size() > MAX_CACHED_KEYS)
                                cachedPubKeys.popKey();
                }
+               try {
+                       pubKeyDatastore.put(hash, key);
+               } catch (IOException e) {
+                       // FIXME deal with disk full, access perms etc; tell 
user about it.
+                       Logger.error(this, "Error accessing pubkey store: "+e, 
e);
+               }
        }
 }

Modified: trunk/freenet/src/freenet/node/RequestHandler.java
===================================================================
--- trunk/freenet/src/freenet/node/RequestHandler.java  2006-01-12 18:33:28 UTC 
(rev 7844)
+++ trunk/freenet/src/freenet/node/RequestHandler.java  2006-01-12 18:39:32 UTC 
(rev 7845)
@@ -25,6 +25,7 @@
     private short htl;
     final PeerNode source;
     private double closestLoc;
+    private boolean needsPubKey;
     final Key key;

     public String toString() {
@@ -44,6 +45,8 @@
         double keyLoc = key.toNormalizedDouble();
         if(Math.abs(keyLoc - myLoc) < Math.abs(keyLoc - closestLoc))
             closestLoc = myLoc;
+        if(key instanceof NodeSSK)
+               needsPubKey = m.getBoolean(DMT.NEED_PUB_KEY);
     }

     public void run() {
@@ -59,6 +62,12 @@
             KeyBlock block = (KeyBlock) o;
             Message df = createDataFound(block);
             source.send(df);
+            if(key instanceof NodeSSK) {
+                if(needsPubKey) {
+                       Message pk = DMT.createFNPSSKPubKey(uid, 
((NodeSSK)block.getKey()).getPubKey().asBytes());
+                       source.send(pk);
+                }
+            }
             if(block instanceof CHKBlock) {
                PartiallyReceivedBlock prb =
                        new PartiallyReceivedBlock(Node.PACKETS_IN_BLOCK, 
Node.PACKET_SIZE, block.getRawData());
@@ -108,6 +117,7 @@
                        return;
                case RequestSender.GENERATED_REJECTED_OVERLOAD:
                case RequestSender.TIMED_OUT:
+               case RequestSender.INTERNAL_ERROR:
                        // Locally generated.
                    // Propagate back to source who needs to reduce send rate
                    Message reject = DMT.createFNPRejectedOverload(uid, true);
@@ -122,10 +132,14 @@
                        if(key instanceof NodeSSK) {
                         Message df = DMT.createFNPSSKDataFound(uid, 
rs.getHeaders(), rs.getSSKData());
                         source.send(df);
+                        if(needsPubKey) {
+                               Message pk = DMT.createFNPSSKPubKey(uid, 
((NodeSSK)rs.getSSKBlock().getKey()).getPubKey().asBytes());
+                               source.send(df);
+                        }
                        } else if(!rs.transferStarted()) {
                                Logger.error(this, "Status is SUCCESS but we 
never started a transfer on "+uid);
                        }
-               case RequestSender.TRANSFER_FAILED:
+                       return;
                case RequestSender.VERIFY_FAILURE:
                        if(key instanceof NodeCHK) {
                                if(shouldHaveStartedTransfer)
@@ -133,6 +147,18 @@
                                shouldHaveStartedTransfer = true;
                                continue; // should have started transfer
                        }
+                   reject = DMT.createFNPRejectedOverload(uid, true);
+                       source.sendAsync(reject, null);
+                       return;
+               case RequestSender.TRANSFER_FAILED:
+                       if(key instanceof NodeCHK) {
+                               if(shouldHaveStartedTransfer)
+                                       throw new IllegalStateException("Got 
status code "+status+" but transfer not started");
+                               shouldHaveStartedTransfer = true;
+                               continue; // should have started transfer
+                       }
+                       // Other side knows, right?
+                       return;
                default:
                    throw new IllegalStateException("Unknown status code 
"+status);
             }

Modified: trunk/freenet/src/freenet/node/RequestSender.java
===================================================================
--- trunk/freenet/src/freenet/node/RequestSender.java   2006-01-12 18:33:28 UTC 
(rev 7844)
+++ trunk/freenet/src/freenet/node/RequestSender.java   2006-01-12 18:39:32 UTC 
(rev 7845)
@@ -8,12 +8,10 @@
 import freenet.io.comm.DisconnectedException;
 import freenet.io.comm.Message;
 import freenet.io.comm.MessageFilter;
-import freenet.io.comm.NotConnectedException;
 import freenet.io.comm.RetrievalException;
 import freenet.io.xfer.BlockReceiver;
 import freenet.io.xfer.PartiallyReceivedBlock;
 import freenet.keys.CHKBlock;
-import freenet.keys.CHKVerifyException;
 import freenet.keys.Key;
 import freenet.keys.KeyVerifyException;
 import freenet.keys.NodeCHK;
@@ -69,6 +67,7 @@
     static final int VERIFY_FAILURE = 5;
     static final int TIMED_OUT = 6;
     static final int GENERATED_REJECTED_OVERLOAD = 7;
+    static final int INTERNAL_ERROR = 8;



@@ -225,8 +224,12 @@
                 MessageFilter mfDF = makeDataFoundFilter(next);
                 MessageFilter mfRouteNotFound = 
MessageFilter.create().setSource(next).setField(DMT.UID, 
uid).setTimeout(FETCH_TIMEOUT).setType(DMT.FNPRouteNotFound);
                 MessageFilter mfRejectedOverload = 
MessageFilter.create().setSource(next).setField(DMT.UID, 
uid).setTimeout(FETCH_TIMEOUT).setType(DMT.FNPRejectedOverload);
-                MessageFilter mf = 
mfDNF.or(mfDF.or(mfRouteNotFound.or(mfRejectedOverload)));
+                MessageFilter mfPubKey = 
MessageFilter.create().setSource(next).setField(DMT.UID, 
uid).setTimeout(FETCH_TIMEOUT).setType(DMT.FNPSSKPubKey);
+               MessageFilter mfRealDFCHK = 
MessageFilter.create().setSource(next).setField(DMT.UID, 
uid).setTimeout(FETCH_TIMEOUT).setType(DMT.FNPCHKDataFound);
+               MessageFilter mfRealDFSSK = 
MessageFilter.create().setSource(next).setField(DMT.UID, 
uid).setTimeout(FETCH_TIMEOUT).setType(DMT.FNPSSKDataFound);
+                MessageFilter mf = 
mfDNF.or(mfRouteNotFound.or(mfRejectedOverload.or(mfDF.or(mfPubKey.or(mfRealDFCHK.or(mfRealDFSSK))))));

+                
                try {
                        msg = node.usm.waitFor(mf);
                } catch (DisconnectedException e) {
@@ -333,6 +336,7 @@
                                byte[] pubkeyAsBytes = 
((ShortBuffer)msg.getObject(DMT.PUBKEY_AS_BYTES)).getData();
                                try {
                                        pubKey = new 
DSAPublicKey(pubkeyAsBytes);
+                                       ((NodeSSK)key).setPubKey(pubKey);
                                } catch (IOException e) {
                                        Logger.error(this, "Invalid pubkey from 
"+source+" on "+uid);
                                        finish(VERIFY_FAILURE, next);
@@ -349,7 +353,7 @@

                        Logger.minor(this, "Got data on "+uid);

-                       if(!(key instanceof NodeCHK)) {
+                       if(!(key instanceof NodeSSK)) {
                                Logger.error(this, "Got "+msg+" but expected a 
different key type from "+next);
                                break;
                        }
@@ -371,6 +375,7 @@
         }
         } catch (Throwable t) {
             Logger.error(this, "Caught "+t, t);
+            finish(INTERNAL_ERROR, null);
         } finally {
                Logger.minor(this, "Leaving RequestSender.run() for "+uid);
             node.completed(uid);
@@ -384,17 +389,21 @@
                        node.store(block);
                        finish(SUCCESS, next);
                } catch (SSKVerifyException e) {
-                       Logger.error(this, "Failed to verify: "+e+" from 
"+next);
+                       Logger.error(this, "Failed to verify: "+e+" from 
"+next, e);
                        finish(VERIFY_FAILURE, next);
                        return;
                }
        }

+    /**
+     * Note that this must be first on the list.
+     */
        private MessageFilter makeDataFoundFilter(PeerNode next) {
        if(key instanceof NodeCHK)
                return MessageFilter.create().setSource(next).setField(DMT.UID, 
uid).setTimeout(FETCH_TIMEOUT).setType(DMT.FNPCHKDataFound);
-       else if(key instanceof NodeSSK)
+       else if(key instanceof NodeSSK) {
                return MessageFilter.create().setSource(next).setField(DMT.UID, 
uid).setTimeout(FETCH_TIMEOUT).setType(DMT.FNPSSKDataFound);
+       }
        else throw new IllegalStateException("Unknown keytype: "+key);
        }


Modified: trunk/freenet/src/freenet/node/Version.java
===================================================================
--- trunk/freenet/src/freenet/node/Version.java 2006-01-12 18:33:28 UTC (rev 
7844)
+++ trunk/freenet/src/freenet/node/Version.java 2006-01-12 18:39:32 UTC (rev 
7845)
@@ -20,10 +20,10 @@
        public static final String protocolVersion = "1.0";

        /** The build number of the current revision */
-       public static final int buildNumber = 342;
+       public static final int buildNumber = 343;

        /** Oldest build of Fred we will talk to */
-       public static final int lastGoodBuild = 342;
+       public static final int lastGoodBuild = 343;

        /** The highest reported build of fred */
        public static int highestSeenBuild = buildNumber;

Modified: trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java
===================================================================
--- trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java 2006-01-12 
18:33:28 UTC (rev 7844)
+++ trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java 2006-01-12 
18:39:32 UTC (rev 7845)
@@ -23,6 +23,7 @@
 import com.sleepycat.je.SecondaryKeyCreator;
 import com.sleepycat.je.Transaction;

+import freenet.crypt.DSAPublicKey;
 import freenet.keys.CHKBlock;
 import freenet.keys.CHKVerifyException;
 import freenet.keys.KeyBlock;
@@ -31,6 +32,7 @@
 import freenet.keys.SSKBlock;
 import freenet.keys.SSKVerifyException;
 import freenet.support.Fields;
+import freenet.support.HexUtil;
 import freenet.support.Logger;

 /** 
@@ -264,7 +266,7 @@
                    Logger.minor(this, "Data: "+data.length+" bytes, hash 
"+data);

                }catch(SSKVerifyException ex){
-                       Logger.normal(this, "Does not verify, setting 
accessTime to 0 for : "+chk);
+                       Logger.normal(this, "Does not verify, setting 
accessTime to 0 for : "+chk, ex);
                        storeBlock.setRecentlyUsedToZero();
                        DatabaseEntry updateDBE = new DatabaseEntry();
                        storeBlockTupleBinding.objectToEntry(storeBlock, 
updateDBE);
@@ -286,6 +288,78 @@
 //     return null;
     }

+    // FIXME do this with interfaces etc.
+    
+       /**
+     * Retrieve a block.
+     * @param dontPromote If true, don't promote data if fetched.
+     * @return null if there is no such block stored, otherwise the block.
+     */
+    public DSAPublicKey fetchPubKey(byte[] hash, boolean dontPromote) throws 
IOException
+    {
+       if(closed)
+               return null;
+       
+       DatabaseEntry routingkeyDBE = new DatabaseEntry(hash);
+       DatabaseEntry blockDBE = new DatabaseEntry();
+       Cursor c = null;
+       try{
+               Transaction t = environment.beginTransaction(null,null);
+               c = chkDB.openCursor(t,null);
+               
+               if(c.getSearchKey(routingkeyDBE,blockDBE,LockMode.DEFAULT)
+                               !=OperationStatus.SUCCESS) {
+                       c.close();
+                       t.abort();
+                       return null;
+               }
+
+               StoreBlock storeBlock = (StoreBlock) 
storeBlockTupleBinding.entryToObject(blockDBE);
+                               
+               DSAPublicKey block = null;
+               
+                       byte[] data = new byte[dataBlockSize];
+                       synchronized(chkStore) {
+                               
chkStore.seek(storeBlock.offset*(long)(dataBlockSize+headerBlockSize));
+                               chkStore.read(data);
+                       }
+                       
+                       try {
+                               block = new DSAPublicKey(data);
+                       } catch (IOException e) {
+                               Logger.error(this, "Could not read key");
+                               return null;
+                       }
+                       
+                       if(!dontPromote)
+                       {
+                               storeBlock.updateRecentlyUsed();
+                               DatabaseEntry updateDBE = new DatabaseEntry();
+                               
storeBlockTupleBinding.objectToEntry(storeBlock, updateDBE);
+                               c.putCurrent(updateDBE);
+                               c.close();
+                               t.commit();
+                       }else{
+                               c.close();
+                               t.abort();
+                       }
+                       
+                       Logger.minor(this, "Get key: 
"+HexUtil.bytesToHex(hash));
+                   Logger.minor(this, "Data: "+data.length+" bytes, hash 
"+data);
+                       
+               return block;
+       }catch(Exception ex) {  // FIXME: ugly  
+               if(c!=null) {
+                       try{c.close();}catch(DatabaseException ex2){}
+               }
+               Logger.error(this, "Caught "+ex, ex);
+               ex.printStackTrace();
+               throw new IOException(ex.getMessage());
+        }
+       
+//     return null;
+    }
+
     /**
      * Store a block.
      */
@@ -360,6 +434,72 @@
         }
     }

+    /**
+     * Store a block.
+     */
+    public void put(byte[] hash, DSAPublicKey key) throws IOException
+    {          
+       if(closed)
+               return;
+               
+       byte[] routingkey = hash;
+        byte[] data = key.asBytes();
+        
+        if(data.length!=dataBlockSize) {
+               Logger.minor(this, "This data is "+data.length+" bytes. Should 
be "+dataBlockSize);
+               return;
+        }
+        
+        Transaction t = null;
+        
+        try{
+               t = environment.beginTransaction(null,null);
+               DatabaseEntry routingkeyDBE = new DatabaseEntry(routingkey);
+               
+               synchronized(chkStore) {
+                       if(chkBlocksInStore<maxChkBlocks) {
+                               // Expand the store file
+                               int byteOffset = 
chkBlocksInStore*(dataBlockSize+headerBlockSize);
+                               StoreBlock storeBlock = new 
StoreBlock(chkBlocksInStore);
+                               DatabaseEntry blockDBE = new DatabaseEntry();
+                       storeBlockTupleBinding.objectToEntry(storeBlock, 
blockDBE);
+                       chkDB.put(t,routingkeyDBE,blockDBE);
+                       chkStore.seek(byteOffset);
+                       chkStore.write(data);
+                       t.commit();
+                       chkBlocksInStore++;
+                       }else{
+                               // Overwrite an other block
+                               Cursor c = chkDB_accessTime.openCursor(t,null);
+                               DatabaseEntry keyDBE = new DatabaseEntry();
+                               DatabaseEntry dataDBE = new DatabaseEntry();
+                               c.getFirst(keyDBE,dataDBE,null);
+                               StoreBlock oldStoreBlock = (StoreBlock) 
storeBlockTupleBinding.entryToObject(dataDBE);
+                               c.delete();
+                               c.close();
+                               StoreBlock storeBlock = new 
StoreBlock(oldStoreBlock.getOffset());
+                               DatabaseEntry blockDBE = new DatabaseEntry();
+                               
storeBlockTupleBinding.objectToEntry(storeBlock, blockDBE);
+                               chkDB.put(t,routingkeyDBE,blockDBE);
+                       
chkStore.seek(storeBlock.getOffset()*(long)(dataBlockSize+headerBlockSize));
+                       chkStore.write(data);
+                               t.commit();
+                       }
+               }
+               
+               Logger.minor(this, "Put key: "+HexUtil.bytesToHex(hash));
+               Logger.minor(this, "Data: "+data.length+" bytes, hash 
"+Fields.hashCode(data));
+                
+        }catch(Exception ex) {  // FIXME: ugly  
+               if(t!=null){
+                       try{t.abort();}catch(DatabaseException ex2){};
+               }
+               Logger.error(this, "Caught "+ex, ex);
+               ex.printStackTrace();
+               throw new IOException(ex.getMessage());
+        }
+    }
+    
     private class StoreBlock
     {
        private long recentlyUsed;

Modified: trunk/freenet/src/freenet/store/FreenetStore.java
===================================================================
--- trunk/freenet/src/freenet/store/FreenetStore.java   2006-01-12 18:33:28 UTC 
(rev 7844)
+++ trunk/freenet/src/freenet/store/FreenetStore.java   2006-01-12 18:39:32 UTC 
(rev 7845)
@@ -2,6 +2,7 @@

 import java.io.IOException;

+import freenet.crypt.DSAPublicKey;
 import freenet.keys.CHKBlock;
 import freenet.keys.Key;
 import freenet.keys.KeyBlock;
@@ -29,7 +30,17 @@
     public SSKBlock fetch(NodeSSK key, boolean dontPromote) throws IOException;

     /**
+     * Fetch a public key.
+     */
+    public DSAPublicKey fetchPubKey(byte[] hash, boolean dontPromote) throws 
IOException;
+    
+    /**
      * Store a block.
      */
     public void put(KeyBlock block) throws IOException;
-}
\ No newline at end of file
+    
+    /**
+     * Store a public key.
+     */
+    public void put(byte[] hash, DSAPublicKey key) throws IOException;
+}


Reply via email to