Author: nextgens
Date: 2006-05-21 13:29:03 +0000 (Sun, 21 May 2006)
New Revision: 8817
Added:
trunk/freenet/src/freenet/node/NodeUpdater.java
Modified:
trunk/freenet/src/freenet/node/Node.java
Log:
First version of the NodeUpdater (disabled for now)
We just advertize on the welcome toadlet that a new version is out.
Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java 2006-05-21 13:17:35 UTC (rev
8816)
+++ trunk/freenet/src/freenet/node/Node.java 2006-05-21 13:29:03 UTC (rev
8817)
@@ -43,6 +43,7 @@
import freenet.client.async.USKManager;
import freenet.clients.http.FproxyToadlet;
import freenet.clients.http.SimpleToadletServer;
+import freenet.config.BooleanCallback;
import freenet.config.Config;
import freenet.config.FilePersistentConfig;
import freenet.config.IntCallback;
@@ -507,6 +508,7 @@
static final int EXIT_COULD_NOT_START_FPROXY = 18;
static final int EXIT_COULD_NOT_START_TMCI = 19;
public static final int EXIT_DATABASE_REQUIRES_RESTART = 20;
+ public static final int EXIT_COULD_NOT_START_UPDATER = 21;
public final long bootID;
public final long startupTime;
@@ -539,6 +541,9 @@
FproxyToadlet fproxyServlet;
SimpleToadletServer toadletContainer;
+ /** NodeUpdater **/
+ public NodeUpdater nodeUpdater;
+
// Persistent temporary buckets
public final PersistentTempBucketFactory persistentTempBucketFactory;
@@ -786,7 +791,7 @@
static class NodeInitException extends Exception {
// One of the exit codes from above
public final int exitCode;
- private static final long serialVersionUID = 0;
+ private static final long serialVersionUID = -1;
NodeInitException(int exitCode, String msg) {
super(msg+" ("+exitCode+")");
@@ -1250,7 +1255,7 @@
new NodeNameCallback(this));
nodeNameUserAlert = new MeaningfulNodeNameUserAlert();
myName = nodeConfig.getString("name");
-
+
nodeConfig.finishedInitialization();
writeNodeFile();
@@ -1340,6 +1345,16 @@
throw new
NodeInitException(EXIT_COULD_NOT_START_FPROXY, "Could not start fproxy: "+e);
}
+
+ // Node Updater
+ try{
+ nodeUpdater = NodeUpdater.maybeCreate(this, config);
+ Logger.normal(this, "Starting the node updater");
+ }catch (NodeInitException e) {
+ e.printStackTrace();
+ throw new
NodeInitException(EXIT_COULD_NOT_START_UPDATER, "Could not start Updater: "+e);
+ }
+
/*
SimpleToadletServer server = new SimpleToadletServer(port+2000);
FproxyToadlet fproxy = new
FproxyToadlet(n.makeClient(RequestStarter.INTERACTIVE_PRIORITY_CLASS));
@@ -2572,6 +2587,10 @@
System.exit(0);
}
+ public NodeUpdater getNodeUpdater(){
+ return nodeUpdater;
+ }
+
public void setTMCI(TextModeClientInterfaceServer server) {
this.tmci = server;
}
Added: trunk/freenet/src/freenet/node/NodeUpdater.java
===================================================================
--- trunk/freenet/src/freenet/node/NodeUpdater.java 2006-05-21 13:17:35 UTC
(rev 8816)
+++ trunk/freenet/src/freenet/node/NodeUpdater.java 2006-05-21 13:29:03 UTC
(rev 8817)
@@ -0,0 +1,291 @@
+package freenet.node;
+
+import java.net.MalformedURLException;
+
+import freenet.client.FetchException;
+import freenet.client.FetchResult;
+import freenet.client.FetcherContext;
+import freenet.client.InserterException;
+import freenet.client.async.BaseClientPutter;
+import freenet.client.async.ClientCallback;
+import freenet.client.async.ClientGetter;
+import freenet.client.async.USKCallback;
+import freenet.config.BooleanCallback;
+import freenet.config.Config;
+import freenet.config.InvalidConfigValueException;
+import freenet.config.StringCallback;
+import freenet.config.SubConfig;
+import freenet.keys.FreenetURI;
+import freenet.keys.USK;
+import freenet.node.Node.NodeInitException;
+import freenet.support.Logger;
+
+class PrivkeyHasBeenBlownException extends Exception{
+ private static final long serialVersionUID = -1;
+
+ PrivkeyHasBeenBlownException(String msg) {
+ super("The project's private key has been blown, meaning that
it has been compromized"+
+ "and shouldn't be trusted anymore. Please get a new
build by hand and verify CAREFULLY"+
+ "its signature and CRC. Here is the revocation
message: "+msg);
+ }
+}
+
+class UpdaterEnabledCallback implements BooleanCallback {
+
+ final Node node;
+
+ UpdaterEnabledCallback(Node n) {
+ this.node = n;
+ }
+
+ public boolean get() {
+ return node.getNodeUpdater() != null;
+ }
+
+ public void set(boolean val) throws InvalidConfigValueException {
+ if(val == get()) return;
+ // FIXME implement
+ throw new InvalidConfigValueException("Cannot be updated on the
fly");
+ }
+}
+
+class AutoUpdateAllowedCallback implements BooleanCallback {
+
+ final Node node;
+
+ AutoUpdateAllowedCallback(Node n) {
+ this.node = n;
+ }
+
+ public boolean get() {
+ NodeUpdater nu = node.getNodeUpdater();
+ return nu.isAutoUpdateAllowed;
+ }
+
+ public void set(boolean val) throws InvalidConfigValueException {
+ if(val == get()) return;
+ // Good idea to prevent it ?
+ throw new InvalidConfigValueException("Cannot be updated on the
fly for security concerns");
+ }
+}
+
+class UpdateURICallback implements StringCallback{
+
+ private final Node node;
+ private final String baseURI="freenet:USK at
XC-ntr3FcUblbYWjLkV9ci6BwnXqvIuKKWcWQHDjlFw,YcCSs5lraAMOKx5VMbrvL-28Waf4elHpz~lvVL~hEDk,AQABAAE/update/";
+
+ public UpdateURICallback(Node node) {
+ this.node = node;
+ }
+
+ public String get() {
+ NodeUpdater nu = node.getNodeUpdater();
+ if (nu != null)
+ return nu.getUpdateKey().toString(true);
+ else
+ return baseURI+Version.buildNumber()+"/";
+ }
+
+ public void set(String val) {
+ if(val == get()) return;
+ // Good idea to prevent it ?
+ //
+ // Maybe it NEEDS to be implemented
+ Logger.error(this, "Node's updater URI can't be updated on the
fly");
+ return;
+ }
+}
+
+class UpdatedVersionAviableUserAlert implements UserAlert {
+ private boolean isValid=true;
+ private int version;
+
+ UpdatedVersionAviableUserAlert(int version){
+ this.version=version;
+ }
+
+ public boolean userCanDismiss() {
+ return false;
+ }
+
+ public String getTitle() {
+ return "A new stable version of Freenet is aviable";
+ }
+
+ public String getText() {
+ return "It seems that your node isn't running the latest
version of the software. "+
+ "Updating to "+version+" is advised.";
+ }
+
+ public short getPriorityClass() {
+ return UserAlert.MINOR;
+ }
+
+ public boolean isValid() {
+ return isValid;
+ }
+
+ public void isValid(boolean b){
+ if(userCanDismiss()) isValid=b;
+ }
+}
+
+
+public class NodeUpdater implements ClientCallback, USKCallback {
+ private FetcherContext ctx;
+ private final FreenetURI URI;
+ private final Node node;
+
+ private final int currentVersion;
+ private int aviableVersion;
+
+ private String revocationMessage;
+ private boolean hasBeenBlown;
+
+ private boolean isRunning = false;
+
+ public final boolean isAutoUpdateAllowed;
+
+ private UpdatedVersionAviableUserAlert alert;
+
+ public NodeUpdater(Node n, boolean isAutoUpdateAllowed, FreenetURI URI)
{
+ super();
+ this.URI = URI;
+ this.node = n;
+ this.currentVersion = Version.buildNumber();
+ this.aviableVersion = Version.buildNumber();
+ this.hasBeenBlown = false;
+ this.isRunning = true;
+ this.isAutoUpdateAllowed = isAutoUpdateAllowed;
+ this.alert=null;
+
+ FetcherContext ctx =
n.makeClient((short)0).getFetcherContext();
+ ctx.allowSplitfiles = true;
+ ctx.dontEnterImplicitArchives = false;
+ ctx.maxArchiveRestarts = 0;
+ ctx.maxMetadataSize = 256;
+ ctx.maxNonSplitfileRetries = 10;
+ ctx.maxOutputLength = 4096;
+ ctx.maxRecursionLevel = 2;
+ ctx.maxTempLength = 4096;
+ this.ctx = ctx;
+
+ try{
+ ctx.uskManager.subscribe(USK.create(URI), this, true);
+ }catch(MalformedURLException e){
+ Logger.error(this,"The auto-update URI isn't valid and
can't be used");
+ this.hasBeenBlown=true;
+ this.revocationMessage = new String("The auto-update
URI isn't valid and can't be used");
+ }
+ }
+
+ public void onFoundEdition(long l, USK key){
+ // FIXME : Check if it has been blown
+ int found = (int)key.suggestedEdition;
+
+ if(found > aviableVersion){
+ this.aviableVersion = found;
+
+ synchronized(this){
+ Logger.normal(this, "Found a new version!,
setting up a new UpdatedVersionAviableUserAlert");
+
+ if(alert != null){
+ System.out.println("unregistering
"+alert.hashCode()+":"+alert);
+ node.alerts.unregister(alert);
+ }
+ alert = new
UpdatedVersionAviableUserAlert(aviableVersion);
+ System.out.println("registering
"+alert.hashCode()+":"+alert);
+ node.alerts.register(new
UpdatedVersionAviableUserAlert(aviableVersion));
+ }
+
+ maybeUpdate();
+ }
+ }
+
+ public synchronized void maybeUpdate(){
+ try{
+ if(isRunning || !isUpdatable()) return;
+ }catch (PrivkeyHasBeenBlownException e){
+ // how to handle it ? a new UserAlert or an imediate
exit?
+ Logger.error(this, "Private key has been blown!");
+ node.exit();
+ }
+
+ //TODO maybe a UpdateInProgress alert ?
+
+ if(isAutoUpdateAllowed){
+ Logger.normal(this,"Starting the update process");
+ }else{
+ Logger.normal(this,"Not starting the update process as
it's not allowed");
+ }
+ }
+
+ public void onSuccess(FetchResult result, ClientGetter state) {
+ }
+
+ public void onFailure(FetchException e, ClientGetter state) {
+ }
+
+ public void onSuccess(BaseClientPutter state) {
+ // Impossible
+ }
+
+ public void onFailure(InserterException e, BaseClientPutter state) {
+ // Impossible
+ }
+
+ public void onGeneratedURI(FreenetURI uri, BaseClientPutter state) {
+ // Impossible
+ }
+
+ public boolean isUpdatable() throws PrivkeyHasBeenBlownException{
+ if(hasBeenBlown)
+ throw new
PrivkeyHasBeenBlownException(revocationMessage);
+ else
+ return (currentVersion<aviableVersion);
+ }
+
+ public boolean isRunning(){
+ return isRunning;
+ }
+
+ public FreenetURI getUpdateKey(){
+ return URI;
+ }
+
+ public static NodeUpdater maybeCreate(Node node, Config config) throws
NodeInitException {
+ SubConfig updaterConfig = new SubConfig("node.updater", config);
+
+ updaterConfig.register("enabled", false, 1, false, "Enable Node's
updater?",
+ "Whether to enable the node's updater. It won't
auto-update unless node.updater.autoupdate is true, it will just warn",
+ new UpdaterEnabledCallback(node));
+
+ boolean enabled = updaterConfig.getBoolean("enabled");
+
+ if(enabled) {
+ // is the auto-update allowed ?
+ updaterConfig.register("autoupdate", false, 2, false, "Is the
node allowed to auto-update?", "Is the node allowed to auto-update?",
+ new AutoUpdateAllowedCallback(node));
+ boolean autoUpdateAllowed =
updaterConfig.getBoolean("autoupdate");
+
+ updaterConfig.register("URI",
+ "freenet:USK at
XC-ntr3FcUblbYWjLkV9ci6BwnXqvIuKKWcWQHDjlFw,YcCSs5lraAMOKx5VMbrvL-28Waf4elHpz~lvVL~hEDk,AQABAAE/update/"+Version.buildNumber()+"/",
+ 3, true, "Where should the node look for
updates?",
+ "Where should the node look for updates?",
+ new UpdateURICallback(node));
+
+ String URI = updaterConfig.getString("URI");
+
+ updaterConfig.finishedInitialization();
+ try{
+ return new NodeUpdater(node , autoUpdateAllowed, new
FreenetURI(URI));
+ }catch(Exception e){
+ Logger.error(node, "Error starting the NodeUpdater:
"+e);
+ throw new
NodeInitException(node.EXIT_COULD_NOT_START_UPDATER,"Unable to start the
NodeUpdater up");
+ }
+ } else {
+ updaterConfig.finishedInitialization();
+ return null;
+ }
+ }
+}