Author: toad
Date: 2006-03-04 16:49:51 +0000 (Sat, 04 Mar 2006)
New Revision: 8156
Added:
trunk/freenet/src/freenet/node/fcp/PersistenceParseException.java
Modified:
trunk/freenet/src/freenet/node/Node.java
trunk/freenet/src/freenet/node/Version.java
trunk/freenet/src/freenet/node/fcp/AllDataMessage.java
trunk/freenet/src/freenet/node/fcp/ClientGet.java
trunk/freenet/src/freenet/node/fcp/ClientPut.java
trunk/freenet/src/freenet/node/fcp/ClientPutMessage.java
trunk/freenet/src/freenet/node/fcp/ClientRequest.java
trunk/freenet/src/freenet/node/fcp/DataCarryingMessage.java
trunk/freenet/src/freenet/node/fcp/FCPConnectionInputHandler.java
trunk/freenet/src/freenet/node/fcp/ProtocolErrorMessage.java
trunk/freenet/src/freenet/support/PaddedEphemerallyEncryptedBucket.java
trunk/freenet/src/freenet/support/io/PersistentTempBucketFactory.java
Log:
490:
Fix persistent buckets.
Make ClientPut { Persistence=forever, UploadFrom=direct } work.
Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java 2006-03-04 15:14:22 UTC (rev
8155)
+++ trunk/freenet/src/freenet/node/Node.java 2006-03-04 16:49:51 UTC (rev
8156)
@@ -836,7 +836,6 @@
writeNodeFile();
nodeConfig.finishedInitialization();
- persistentTempBucketFactory.completedInit();
// FIXME make all the below arbitrary constants configurable!
@@ -928,6 +927,8 @@
if(testnetHandler != null)
testnetHandler.start();
+ persistentTempBucketFactory.completedInit();
+
Thread t = new Thread(ipDetector, "IP address re-detector");
t.setDaemon(true);
t.start();
Modified: trunk/freenet/src/freenet/node/Version.java
===================================================================
--- trunk/freenet/src/freenet/node/Version.java 2006-03-04 15:14:22 UTC (rev
8155)
+++ trunk/freenet/src/freenet/node/Version.java 2006-03-04 16:49:51 UTC (rev
8156)
@@ -20,7 +20,7 @@
public static final String protocolVersion = "1.0";
/** The build number of the current revision */
- private static final int buildNumber = 489;
+ private static final int buildNumber = 490;
/** Oldest build of Fred we will talk to */
private static final int lastGoodBuild = 475;
Modified: trunk/freenet/src/freenet/node/fcp/AllDataMessage.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/AllDataMessage.java 2006-03-04
15:14:22 UTC (rev 8155)
+++ trunk/freenet/src/freenet/node/fcp/AllDataMessage.java 2006-03-04
16:49:51 UTC (rev 8156)
@@ -39,4 +39,8 @@
throw new
MessageInvalidException(ProtocolErrorMessage.INVALID_MESSAGE, "AllData goes
from server to client not the other way around", identifier);
}
+ String getIdentifier() {
+ return identifier;
+ }
+
}
Modified: trunk/freenet/src/freenet/node/fcp/ClientGet.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientGet.java 2006-03-04 15:14:22 UTC
(rev 8155)
+++ trunk/freenet/src/freenet/node/fcp/ClientGet.java 2006-03-04 16:49:51 UTC
(rev 8156)
@@ -130,9 +130,9 @@
* Create a ClientGet from a request serialized to a SimpleFieldSet.
* Can throw, and does minimal verification, as is dealing with data
* supposedly serialized out by the node.
- * @throws MalformedURLException
+ * @throws IOException
*/
- public ClientGet(SimpleFieldSet fs, FCPClient client2) throws
MalformedURLException {
+ public ClientGet(SimpleFieldSet fs, FCPClient client2) throws
IOException {
uri = new FreenetURI(fs.get("URI"));
identifier = fs.get("Identifier");
verbosity = Integer.parseInt(fs.get("Verbosity"));
@@ -187,7 +187,7 @@
} else if(returnType == ClientGetMessage.RETURN_TYPE_DIRECT) {
byte[] key =
HexUtil.hexToBytes(fs.get("ReturnBucket.DecryptKey"));
String fnam = fs.get("ReturnBucket.Filename");
- ret =
client.server.node.persistentTempBucketFactory.registerEncryptedBucket(fnam,
key);
+ ret =
client.server.node.persistentTempBucketFactory.registerEncryptedBucket(fnam,
key, succeeded ? foundDataLength : 0);
} else {
throw new IllegalArgumentException();
}
Modified: trunk/freenet/src/freenet/node/fcp/ClientPut.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientPut.java 2006-03-04 15:14:22 UTC
(rev 8155)
+++ trunk/freenet/src/freenet/node/fcp/ClientPut.java 2006-03-04 16:49:51 UTC
(rev 8156)
@@ -24,7 +24,9 @@
import freenet.keys.FreenetURI;
import freenet.support.Bucket;
import freenet.support.Fields;
+import freenet.support.HexUtil;
import freenet.support.Logger;
+import freenet.support.PaddedEphemerallyEncryptedBucket;
import freenet.support.SimpleFieldSet;
import freenet.support.io.FileBucket;
@@ -100,9 +102,10 @@
* Create from a persisted SimpleFieldSet.
* Not very tolerant of errors, as the input was generated
* by the node.
- * @throws MalformedURLException
+ * @throws PersistenceParseException
+ * @throws IOException
*/
- public ClientPut(SimpleFieldSet fs, FCPClient client2) throws
MalformedURLException {
+ public ClientPut(SimpleFieldSet fs, FCPClient client2) throws
PersistenceParseException, IOException {
uri = new FreenetURI(fs.get("URI"));
identifier = fs.get("Identifier");
verbosity = Integer.parseInt(fs.get("Verbosity"));
@@ -118,15 +121,28 @@
boolean dontCompress =
Fields.stringToBool(fs.get("DontCompress"), false);
int maxRetries = Integer.parseInt(fs.get("MaxRetries"));
clientToken = fs.get("ClientToken");
- fromDisk = true;
- origFilename = new File(fs.get("Filename"));
- Bucket data = new FileBucket(origFilename, true, false, false,
false);
+ fromDisk = Fields.stringToBool(fs.get("FromDisk"), false);
+ Bucket data;
+ if(fromDisk) {
+ origFilename = new File(fs.get("Filename"));
+ data = new FileBucket(origFilename, true, false, false,
false);
+ } else {
+ origFilename = null;
+ byte[] key =
HexUtil.hexToBytes(fs.get("TempBucket.DecryptKey"));
+ String fnam = fs.get("TempBucket.Filename");
+ long sz = Long.parseLong(fs.get("TempBucket.Size"));
+ data =
client.server.node.persistentTempBucketFactory.registerEncryptedBucket(fnam,
key, sz);
+ if(data.size() != sz)
+ throw new PersistenceParseException("Size of
bucket is wrong: "+data.size()+" should be "+sz);
+ }
ctx = new InserterContext(client.defaultInsertContext, new
SimpleEventProducer());
ctx.dontCompress = dontCompress;
ctx.eventProducer.addEventListener(this);
ctx.maxInsertRetries = maxRetries;
block = new InsertBlock(data, new ClientMetadata(mimeType),
uri);
+ // FIXME uncomment after testing
finished = Fields.stringToBool(fs.get("Finished"), false);
+ //finished = false;
succeeded = Fields.stringToBool(fs.get("Succeeded"), false);
String genURI = fs.get("GeneratedURI");
if(genURI != null)
@@ -313,8 +329,16 @@
// finished => persistence of completion state, pending messages
//fs.put("Finished", Boolean.toString(finished));
fs.put("ClientToken", clientToken);
- if(!fromDisk) throw new
UnsupportedOperationException("Persistent insert not from disk - NOT
SUPPORTED");
- fs.put("Filename", origFilename.getPath());
+ fs.put("FromDisk", Boolean.toString(fromDisk));
+ if(fromDisk) {
+ fs.put("Filename", origFilename.getPath());
+ } else {
+ // the bucket is a persistent encrypted temp bucket
+ PaddedEphemerallyEncryptedBucket bucket =
(PaddedEphemerallyEncryptedBucket) block.getData();
+ fs.put("TempBucket.DecryptKey",
HexUtil.bytesToHex(bucket.getKey()));
+ fs.put("TempBucket.Filename",
((FileBucket)(bucket.getUnderlying())).getName());
+ fs.put("TempBucket.Size", Long.toString(bucket.size()));
+ }
fs.put("DontCompress", Boolean.toString(ctx.dontCompress));
fs.put("MaxRetries", Integer.toString(ctx.maxInsertRetries));
fs.put("Finished", Boolean.toString(finished));
Modified: trunk/freenet/src/freenet/node/fcp/ClientPutMessage.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientPutMessage.java 2006-03-04
15:14:22 UTC (rev 8155)
+++ trunk/freenet/src/freenet/node/fcp/ClientPutMessage.java 2006-03-04
16:49:51 UTC (rev 8156)
@@ -1,13 +1,15 @@
package freenet.node.fcp;
import java.io.File;
+import java.io.IOException;
import java.net.MalformedURLException;
import freenet.keys.FreenetURI;
import freenet.node.Node;
import freenet.node.RequestStarter;
+import freenet.support.Bucket;
+import freenet.support.BucketFactory;
import freenet.support.Fields;
-import freenet.support.Logger;
import freenet.support.SimpleFieldSet;
import freenet.support.io.FileBucket;
@@ -136,9 +138,6 @@
} else {
throw new
MessageInvalidException(ProtocolErrorMessage.ERROR_PARSING_NUMBER, "Error
parsing Persistence field: "+persistenceString, identifier);
}
- if(persistenceType == ClientRequest.PERSIST_FOREVER &&
!fromDisk) {
- throw new
MessageInvalidException(ProtocolErrorMessage.NOT_SUPPORTED,
"Persistence=forever AND UploadFrom=direct unsupported!", identifier);
- }
clientToken = fs.get("ClientToken");
}
@@ -167,4 +166,16 @@
return dataLength;
}
-}
+ String getIdentifier() {
+ return identifier;
+ }
+
+ Bucket createBucket(BucketFactory bf, long length, FCPServer server)
throws IOException {
+ if(persistenceType == ClientRequest.PERSIST_FOREVER) {
+ return
server.node.persistentTempBucketFactory.makeEncryptedBucket();
+ } else {
+ return super.createBucket(bf, length, server);
+ }
+ }
+
+}
\ No newline at end of file
Modified: trunk/freenet/src/freenet/node/fcp/ClientRequest.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientRequest.java 2006-03-04
15:14:22 UTC (rev 8155)
+++ trunk/freenet/src/freenet/node/fcp/ClientRequest.java 2006-03-04
16:49:51 UTC (rev 8156)
@@ -67,17 +67,22 @@
SimpleFieldSet fs = new SimpleFieldSet(br, true);
String clientName = fs.get("ClientName");
FCPClient client = server.registerClient(clientName,
server.node, null);
- String type = fs.get("Type");
- if(type.equals("GET")) {
- ClientGet cg = new ClientGet(fs, client);
- client.register(cg);
- return cg;
- } else if(type.equals("PUT")) {
- ClientPut cp = new ClientPut(fs, client);
- client.register(cp);
- return cp;
- } else {
- Logger.error(ClientRequest.class, "Unrecognized type:
"+type);
+ try {
+ String type = fs.get("Type");
+ if(type.equals("GET")) {
+ ClientGet cg = new ClientGet(fs, client);
+ client.register(cg);
+ return cg;
+ } else if(type.equals("PUT")) {
+ ClientPut cp = new ClientPut(fs, client);
+ client.register(cp);
+ return cp;
+ } else {
+ Logger.error(ClientRequest.class, "Unrecognized
type: "+type);
+ return null;
+ }
+ } catch (Throwable t) {
+ Logger.error(ClientRequest.class, "Failed to parse:
"+t, t);
return null;
}
}
Modified: trunk/freenet/src/freenet/node/fcp/DataCarryingMessage.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/DataCarryingMessage.java 2006-03-04
15:14:22 UTC (rev 8155)
+++ trunk/freenet/src/freenet/node/fcp/DataCarryingMessage.java 2006-03-04
16:49:51 UTC (rev 8156)
@@ -7,6 +7,7 @@
import freenet.support.Bucket;
import freenet.support.BucketFactory;
import freenet.support.BucketTools;
+import freenet.support.Logger;
public abstract class DataCarryingMessage extends FCPMessage {
@@ -15,18 +16,30 @@
abstract long dataLength();
+ Bucket createBucket(BucketFactory bf, long length, FCPServer server)
throws IOException {
+ return bf.makeBucket(length);
+ }
+
+ abstract String getIdentifier();
+
protected boolean freeOnSent;
void setFreeOnSent() {
freeOnSent = true;
}
- public void readFrom(InputStream is, BucketFactory bf) throws
IOException {
+ public void readFrom(InputStream is, BucketFactory bf, FCPServer
server) throws IOException, MessageInvalidException {
long len = dataLength();
if(len < 0)
throw new IllegalArgumentException("Invalid length:
"+len);
if(len == 0) return;
- Bucket bucket = bf.makeBucket(len);
+ Bucket bucket;
+ try {
+ bucket = createBucket(bf, len, server);
+ } catch (IOException e) {
+ Logger.error(this, "Bucket error: "+e, e);
+ throw new
MessageInvalidException(ProtocolErrorMessage.INTERNAL_ERROR, e.toString(),
getIdentifier());
+ }
BucketTools.copyFrom(bucket, is, len);
this.bucket = bucket;
}
Modified: trunk/freenet/src/freenet/node/fcp/FCPConnectionInputHandler.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/FCPConnectionInputHandler.java
2006-03-04 15:14:22 UTC (rev 8155)
+++ trunk/freenet/src/freenet/node/fcp/FCPConnectionInputHandler.java
2006-03-04 16:49:51 UTC (rev 8156)
@@ -66,7 +66,14 @@
continue;
}
if(msg instanceof DataCarryingMessage) {
- ((DataCarryingMessage)msg).readFrom(lis,
handler.bf);
+ // FIXME tidy up - coalesce with above and
below try { } catch (MIE) {}'s?
+ try {
+
((DataCarryingMessage)msg).readFrom(lis, handler.bf, handler.server);
+ } catch (MessageInvalidException e) {
+ FCPMessage err = new
ProtocolErrorMessage(e.protocolCode, false, e.getMessage(), e.ident);
+ handler.outputHandler.queue(err);
+ continue;
+ }
}
if((!firstMessage) && msg instanceof
ClientHelloMessage) {
FCPMessage err = new
ProtocolErrorMessage(ProtocolErrorMessage.NO_LATE_CLIENT_HELLOS, false, null,
null);
Added: trunk/freenet/src/freenet/node/fcp/PersistenceParseException.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/PersistenceParseException.java
2006-03-04 15:14:22 UTC (rev 8155)
+++ trunk/freenet/src/freenet/node/fcp/PersistenceParseException.java
2006-03-04 16:49:51 UTC (rev 8156)
@@ -0,0 +1,12 @@
+package freenet.node.fcp;
+
+/**
+ * Thrown when a persistent request cannot be parsed.
+ */
+public class PersistenceParseException extends Exception {
+
+ public PersistenceParseException(String string) {
+ super(string);
+ }
+
+}
Modified: trunk/freenet/src/freenet/node/fcp/ProtocolErrorMessage.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ProtocolErrorMessage.java
2006-03-04 15:14:22 UTC (rev 8155)
+++ trunk/freenet/src/freenet/node/fcp/ProtocolErrorMessage.java
2006-03-04 16:49:51 UTC (rev 8156)
@@ -35,6 +35,7 @@
static final int COULD_NOT_RENAME_FILE = 14;
static final int NO_SUCH_IDENTIFIER = 15;
static final int NOT_SUPPORTED = 16;
+ static final int INTERNAL_ERROR = 17;
final int code;
final String extra;
@@ -75,6 +76,8 @@
return "No such identifier";
case NOT_SUPPORTED:
return "Not supported";
+ case INTERNAL_ERROR:
+ return "Internal error";
default:
Logger.error(this, "Unknown error code: "+code, new
Exception("debug"));
return "(Unknown)";
Modified:
trunk/freenet/src/freenet/support/PaddedEphemerallyEncryptedBucket.java
===================================================================
--- trunk/freenet/src/freenet/support/PaddedEphemerallyEncryptedBucket.java
2006-03-04 15:14:22 UTC (rev 8155)
+++ trunk/freenet/src/freenet/support/PaddedEphemerallyEncryptedBucket.java
2006-03-04 16:49:51 UTC (rev 8156)
@@ -60,16 +60,28 @@
lastOutputStream = 0;
}
- public PaddedEphemerallyEncryptedBucket(Bucket bucket, int minSize,
byte[] key, RandomSource origRandom) {
+ /**
+ * Load an existing PaddedEphemerallyEncryptedBucket, with a key.
+ * The bucket can and should already exist.
+ * @param bucket
+ * @param minSize
+ * @param knownSize The size of the data. This cannot be deduced from
the bucket
+ * alone and must be specified. If the bucket is smaller than this, we
throw.
+ * @param key
+ * @param origRandom
+ * @throws IOException
+ */
+ public PaddedEphemerallyEncryptedBucket(Bucket bucket, int minSize,
long knownSize, byte[] key, RandomSource origRandom) throws IOException {
+ if(bucket.size() < knownSize)
+ throw new IOException("Bucket is too small on disk");
+ this.dataLength = knownSize;
this.origRandom = origRandom;
this.bucket = bucket;
- if(bucket.size() != 0) throw new
IllegalArgumentException("Bucket must be empty");
try {
aes = new Rijndael(256, 256);
} catch (UnsupportedCipherException e) {
throw new Error(e);
}
- origRandom.nextBytes(key);
aes.initialize(key);
this.key = key;
this.minPaddedSize = minSize;
Modified: trunk/freenet/src/freenet/support/io/PersistentTempBucketFactory.java
===================================================================
--- trunk/freenet/src/freenet/support/io/PersistentTempBucketFactory.java
2006-03-04 15:14:22 UTC (rev 8155)
+++ trunk/freenet/src/freenet/support/io/PersistentTempBucketFactory.java
2006-03-04 16:49:51 UTC (rev 8156)
@@ -72,7 +72,7 @@
* and to register this fact so that it is not deleted on startup
completion.
*/
public Bucket register(String filename) {
- File f = new File(filename);
+ File f = new File(dir, filename);
Bucket b = new FileBucket(f, false, false, false, true);
originalFiles.remove(f);
return b;
@@ -99,9 +99,9 @@
return new PaddedEphemerallyEncryptedBucket(b, 1024, rand,
false);
}
- public Bucket registerEncryptedBucket(String filename, byte[] key) {
+ public Bucket registerEncryptedBucket(String filename, byte[] key, long
len) throws IOException {
Bucket fileBucket = register(filename);
- return new PaddedEphemerallyEncryptedBucket(fileBucket, 1024,
key, rand);
+ return new PaddedEphemerallyEncryptedBucket(fileBucket, 1024,
len, key, rand);
}
public void freeBucket(Bucket b) throws IOException {