gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r29196 - in gnunet-java/src: main/java/org/gnunet/construct


From: gnunet
Subject: [GNUnet-SVN] r29196 - in gnunet-java/src: main/java/org/gnunet/construct main/java/org/gnunet/construct/parsers main/java/org/gnunet/testbed main/java/org/gnunet/testbed/callbacks main/java/org/gnunet/testbed/messages main/java/org/gnunet/util main/java/org/gnunet/voting main/java/org/gnunet/voting/messages main/resources/org/gnunet/construct main/resources/org/gnunet/voting test/java/org/gnunet/testbed test/java/org/gnunet/util
Date: Wed, 11 Sep 2013 13:28:32 +0200

Author: dold
Date: 2013-09-11 13:28:31 +0200 (Wed, 11 Sep 2013)
New Revision: 29196

Added:
   gnunet-java/src/main/java/org/gnunet/testbed/CompressedConfig.java
   gnunet-java/src/main/java/org/gnunet/testbed/callbacks/
   
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/ControllerEventCallback.java
   
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/ControllerStatusCallback.java
   
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/HostRegistrationCompletion.java
   
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/OperationCompletionCallback.java
   gnunet-java/src/main/java/org/gnunet/testbed/callbacks/PeerChurnCallback.java
   
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/PeerCreateCallback.java
   gnunet-java/src/main/java/org/gnunet/testbed/messages/
   
gnunet-java/src/main/java/org/gnunet/testbed/messages/ConnectionEventMessage.java
   
gnunet-java/src/main/java/org/gnunet/testbed/messages/ControllerInitMessage.java
   
gnunet-java/src/main/java/org/gnunet/testbed/messages/CreatePeerSuccessMessage.java
   
gnunet-java/src/main/java/org/gnunet/testbed/messages/GenericOperationSuccessMessage.java
   gnunet-java/src/main/java/org/gnunet/testbed/messages/HelperInitMessage.java
   gnunet-java/src/main/java/org/gnunet/testbed/messages/HelperReplyMessage.java
   
gnunet-java/src/main/java/org/gnunet/testbed/messages/ManagePeerServiceMessage.java
   
gnunet-java/src/main/java/org/gnunet/testbed/messages/OperationFailEventMessage.java
   
gnunet-java/src/main/java/org/gnunet/testbed/messages/OverlayConnectMessage.java
   
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerConfigurationInformationMessage.java
   gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerCreateMessage.java
   
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerCreateSuccessMessage.java
   gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerDestroyMessage.java
   gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerEventMessage.java
   
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerReconfigureMessage.java
   gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerStartMessage.java
   gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerStopMessage.java
   gnunet-java/src/main/java/org/gnunet/voting/BallotTool.java
   gnunet-java/src/main/java/org/gnunet/voting/messages/
   
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterRequestMessage.java
   
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterRespondMessage.java
   
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateRequestMessage.java
   
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateResponseMessage.java
   gnunet-java/src/main/java/org/gnunet/voting/messages/QueryResultMessage.java
   
gnunet-java/src/main/java/org/gnunet/voting/messages/QueryResultResponseMessage.java
   gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitMessage.java
   
gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitResponseMessage.java
Removed:
   gnunet-java/src/main/java/org/gnunet/testbed/ControllerEventCallback.java
   gnunet-java/src/main/java/org/gnunet/testbed/ControllerInitMessage.java
   gnunet-java/src/main/java/org/gnunet/testbed/ControllerStatusCallback.java
   gnunet-java/src/main/java/org/gnunet/testbed/HelperInitMessage.java
   gnunet-java/src/main/java/org/gnunet/testbed/HelperReplyMessage.java
   gnunet-java/src/main/java/org/gnunet/testbed/OperationCompletionCallback.java
   gnunet-java/src/main/java/org/gnunet/testbed/Peer.java
   gnunet-java/src/main/java/org/gnunet/testbed/PeerChurnCallback.java
   gnunet-java/src/main/java/org/gnunet/testbed/PeerCreateCallback.java
   gnunet-java/src/main/java/org/gnunet/voting/ElectionCallTool.java
   gnunet-java/src/main/java/org/gnunet/voting/ElectionSpecification.java
   gnunet-java/src/main/java/org/gnunet/voting/VotingTool.java
Modified:
   
gnunet-java/src/main/java/org/gnunet/construct/MessageIdAnnotationProcessor.java
   gnunet-java/src/main/java/org/gnunet/construct/parsers/StringParser.java
   gnunet-java/src/main/java/org/gnunet/testbed/Controller.java
   gnunet-java/src/main/java/org/gnunet/testbed/ControllerProc.java
   gnunet-java/src/main/java/org/gnunet/testbed/Host.java
   gnunet-java/src/main/java/org/gnunet/util/Configuration.java
   gnunet-java/src/main/java/org/gnunet/util/CryptoECC.java
   gnunet-java/src/main/java/org/gnunet/util/Helper.java
   gnunet-java/src/main/java/org/gnunet/util/Program.java
   gnunet-java/src/main/java/org/gnunet/util/Scheduler.java
   gnunet-java/src/main/java/org/gnunet/voting/CertificateAuthorityService.java
   gnunet-java/src/main/java/org/gnunet/voting/TallyAuthorityService.java
   gnunet-java/src/main/resources/org/gnunet/construct/MsgMap.txt
   gnunet-java/src/main/resources/org/gnunet/voting/template.espec
   gnunet-java/src/test/java/org/gnunet/testbed/TestbedTest.java
   gnunet-java/src/test/java/org/gnunet/util/CryptoECCTest.java
Log:
- fix scheduler
- thread-safe scheduler
- work on voting


Modified: 
gnunet-java/src/main/java/org/gnunet/construct/MessageIdAnnotationProcessor.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/construct/MessageIdAnnotationProcessor.java
    2013-09-11 11:19:59 UTC (rev 29195)
+++ 
gnunet-java/src/main/java/org/gnunet/construct/MessageIdAnnotationProcessor.java
    2013-09-11 11:28:31 UTC (rev 29196)
@@ -105,6 +105,13 @@
                     return false;
                 }
                 String unionName = 
getClassName(types.asElement(unionInterface));
+                if (idToMember.contains(unionName, ann.value())) {
+                    String existingName = idToMember.get(unionName, 
ann.value());
+                    
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, String.format(
+                            "duplicate message id %s for union '%s: '%s' and 
'%s'", ann.value(), unionName,
+                            getClassName(e), existingName));
+                    return false;
+                }
                 idToMember.put(unionName, ann.value(), getClassName(e));
             }
         }

Modified: 
gnunet-java/src/main/java/org/gnunet/construct/parsers/StringParser.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/parsers/StringParser.java    
2013-09-11 11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/java/org/gnunet/construct/parsers/StringParser.java    
2013-09-11 11:28:31 UTC (rev 29196)
@@ -48,7 +48,7 @@
             if (optional) {
                 return 0;
             } else {
-                throw new AssertionError("non-optional string cannot be null");
+                throw new AssertionError("non-optional string in field '" + 
targetField + "' cannot be null");
             }
         }
         try {

Added: gnunet-java/src/main/java/org/gnunet/testbed/CompressedConfig.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/CompressedConfig.java          
                (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/testbed/CompressedConfig.java  
2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,80 @@
+package org.gnunet.testbed;
+
+import com.google.common.base.Charsets;
+import org.gnunet.util.Configuration;
+
+import java.io.ByteArrayOutputStream;
+import java.util.zip.DataFormatException;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+/**
+ * A configuration stored in compressed form.
+ */
+public class CompressedConfig {
+    final public byte[] compressed_data;
+
+    private int uncompressed_size;
+
+    /**
+     * Create a compressed configuration from an uncompressed configuration.
+     * @param cfg the uncompressed configuration
+     */
+    public CompressedConfig(Configuration cfg) {
+        byte[] serialized_config = cfg.serialize().getBytes();
+
+        Deflater compresser = new Deflater();
+        compresser.setInput(serialized_config);
+        compresser.finish();
+
+        ByteArrayOutputStream s = new ByteArrayOutputStream();
+        byte[] buf = new byte[1024];
+        while (!compresser.finished()) {
+            int n = compresser.deflate(buf);
+            s.write(buf, 0, n);
+        }
+        compressed_data = s.toByteArray();
+        uncompressed_size = serialized_config.length;
+    }
+
+    /**
+     * Create a compressed configuration from already compressed data.
+     * @param compressed_data the compressed config data
+     */
+    public CompressedConfig(byte[] compressed_data) {
+        this.compressed_data = compressed_data;
+        this.uncompressed_size = -1;
+    }
+
+    /**
+     * Decompress the configuration.
+     *
+     * @return the decompressed configuration, or null on data format error
+     */
+    public Configuration decompress() {
+        Inflater inflater = new Inflater();
+        inflater.setInput(compressed_data);
+        ByteArrayOutputStream s = new ByteArrayOutputStream();
+        byte[] buf = new byte[1024];
+        while (!inflater.finished()) {
+            int n;
+            try {
+                n = inflater.inflate(buf);
+            } catch (DataFormatException e) {
+                return null;
+            }
+            s.write(buf, 0, n);
+        }
+        String str = new String(s.toByteArray(), Charsets.UTF_8);
+        Configuration cfg = new Configuration();
+        cfg.deserialize(str);
+        return cfg;
+    }
+
+    public int getUncompressedSize() {
+        if (uncompressed_size == -1) {
+            uncompressed_size = decompress().serialize().getBytes().length;
+        }
+        return uncompressed_size;
+    }
+}

Modified: gnunet-java/src/main/java/org/gnunet/testbed/Controller.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/Controller.java        
2013-09-11 11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/java/org/gnunet/testbed/Controller.java        
2013-09-11 11:28:31 UTC (rev 29196)
@@ -1,7 +1,19 @@
 package org.gnunet.testbed;
 
+import org.gnunet.mq.Envelope;
+import org.gnunet.requests.MatchingRequestContainer;
+import org.gnunet.requests.RequestContainer;
+import org.gnunet.requests.SequentialRequestContainer;
+import org.gnunet.testbed.callbacks.*;
+import org.gnunet.testbed.messages.ControllerInitMessage;
+import org.gnunet.testbed.messages.PeerCreateMessage;
+import org.gnunet.testbed.messages.PeerCreateSuccessMessage;
+import org.gnunet.util.Cancelable;
 import org.gnunet.util.Client;
 import org.gnunet.util.Configuration;
+import org.gnunet.util.RunaboutMessageReceiver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Handle to interact with a GNUnet testbed controller.  Each
@@ -13,13 +25,108 @@
  * links are established via TCP/IP on the controller's service port.
  */
 public class Controller {
+private static final Logger logger = LoggerFactory
+        .getLogger(Controller.class);
 
+    public static int ET_PEER_START = 0;
+    public static int ET_PEER_STOP = 1;
+    public static int ET_CONNECT = 2;
+    public static int ET_DISCONNECT = 3;
+    public static int ET_OPERATION_FINISHED = 4;
+
+
     /**
      * Client connecting to the testbed service.
      */
-    Client client;
+    private Client client;
 
     /**
+     * Host that this controller runs on.
+     */
+    private Host host;
+
+    private int operationCounter;
+    private int peerCounter;
+
+    /**
+     * Request queue (called operation queue in the GNUnet C implementation)
+     */
+    private MatchingRequestContainer<Long,RequestContainer.Request> requests;
+
+
+    class PeerCreateRequest extends RequestContainer.Request {
+        private final Host host;
+        private final Configuration cfg;
+        private final PeerCreateCallback cb;
+        public long op_id;
+
+        public PeerCreateRequest(Host host, Configuration cfg, 
PeerCreateCallback cb) {
+            this.host = host;
+            this.cfg = cfg;
+            this.cb = cb;
+            this.op_id = getNextOpId();
+        }
+
+        @Override
+        public Envelope assembleRequest() {
+            CompressedConfig ccfg = new CompressedConfig(cfg);
+            PeerCreateMessage m = new PeerCreateMessage();
+            m.host_id = host.id;
+            m.operation_id = op_id;
+            m.peer_id = peerCounter++;
+            m.compressed_config = ccfg.compressed_data;
+            m.config_size = ccfg.getUncompressedSize();
+            return new Envelope(m);
+        }
+    }
+
+    class PeerStartRequest extends RequestContainer.Request {
+
+        @Override
+        public Envelope assembleRequest() {
+            return null;  //To change body of implemented methods use File | 
Settings | File Templates.
+        }
+    }
+
+    class PeerStopRequest extends RequestContainer.Request {
+
+        @Override
+        public Envelope assembleRequest() {
+            return null;  //To change body of implemented methods use File | 
Settings | File Templates.
+        }
+    }
+
+    class ConnectOverlayRequest extends RequestContainer.Request {
+        @Override
+        public Envelope assembleRequest() {
+            return null;  //To change body of implemented methods use File | 
Settings | File Templates.
+        }
+    }
+
+
+    public class ControllerMessageReceiver extends RunaboutMessageReceiver {
+        public void visit(PeerCreateSuccessMessage m) {
+            RequestContainer.Request r = requests.getRequest(m.operation_id);
+            if (!(r instanceof PeerCreateRequest)) {
+                logger.warn("response to peer create request does not match");
+                return;
+            }
+            PeerCreateRequest pcr = (PeerCreateRequest) r;
+            // FIXME: create peer
+            pcr.cb.onPeerCreated(null);
+        }
+        @Override
+        public void handleError() {
+            throw new AssertionError();
+        }
+    }
+
+    private long getNextOpId() {
+        return (((long) host.id) << 32) | (long) operationCounter++;
+    }
+
+
+    /**
      * Connect to a controller process.  The configuration to use for the 
connection
      * is retreived from the given host where a controller is started using
      * GNUNET_TESTBED_controller_start().
@@ -34,7 +141,16 @@
      * @param cb controller callback to invoke on events
      */
     public Controller(Host host, long event_mask, ControllerEventCallback cb) {
+        this.host = host;
         client = new Client("testbed", host.cfg);
+        client.installReceiver(new ControllerMessageReceiver());
+        requests = new MatchingRequestContainer<Long, 
RequestContainer.Request>(client);
+
+        ControllerInitMessage m = new ControllerInitMessage();
+        m.event_mask = event_mask;
+        m.controler_hostname = (host.hostname == null) ? "127.0.0.1" : 
host.hostname;
+        m.host_id = host.id;
+        client.send(m);
     }
 
     /**
@@ -42,21 +158,21 @@
      * controller.  If the given controller is not running on the target
      * host, it should find or create a controller at the target host and
      * delegate creating the peer.  Explicit delegation paths can be setup
-     * using 'GNUNET_TESTBED_controller_link'.  If no explicit delegation
+     * using 'Controller.link'.  If no explicit delegation
      * path exists, a direct link with a subordinate controller is setup
      * for the first delegated peer to a particular host; the subordinate
      * controller is then destroyed once the last peer that was delegated
      * to the remote host is stopped.
      *
      * Creating the peer only creates the handle to manipulate and further
-     * configure the peer; use "GNUNET_TESTBED_peer_start" and
-     * "GNUNET_TESTBED_peer_stop" to actually start/stop the peer's
+     * configure the peer; use "Peer.start" and
+     * "Peer.stop" to actually start/stop the peer's
      * processes.
      *
      * Note that the given configuration will be adjusted by the
      * controller to avoid port/path conflicts with other peers.
      * The "final" configuration can be obtained using
-     * 'GNUNET_TESTBED_peer_get_information'.
+     * 'Peer.getInformation'.
      *
      * @param host host to run the peer on; cannot be NULL
      * @param cfg Template configuration to use for the peer. Should exist 
until
@@ -64,9 +180,9 @@
      * @param cb the callback to call when the peer has been created
      * @return the operation handle
      */
-
-    public Operation createPeer(Host host, Configuration cfg, 
PeerCreateCallback cb) {
-        return null;
+    public Cancelable createPeer(Host host, Configuration cfg, 
PeerCreateCallback cb) {
+        PeerCreateRequest r = new PeerCreateRequest(host, cfg, cb);
+        return requests.addRequest(r.op_id, r);
     }
 
     /**
@@ -75,8 +191,110 @@
      * blocks until the testbed has been fully terminated (!).
      */
     public void disconnect () {
+        client.disconnect();
+    }
 
+
+    /**
+     * Create a link from slave controller to delegated controller. Whenever 
the
+     * master controller is asked to start a peer at the delegated controller 
the
+     * request will be routed towards slave controller (if a route exists). The
+     * slave controller will then route it to the delegated controller. The
+     * configuration of the delegated controller is given and is used to either
+     * create the delegated controller or to connect to an existing 
controller. Note
+     * that while starting the delegated controller the configuration will be
+     * modified to accommodate available free ports.  the 'is_subordinate' 
specifies
+     * if the given delegated controller should be started and managed by the 
slave
+     * controller, or if the delegated controller already has a master and the 
slave
+     * controller connects to it as a non master controller. The success or 
failure
+     * of this operation will be signalled through the
+     * GNUNET_TESTBED_ControllerCallback() with an event of type
+     * GNUNET_TESTBED_ET_OPERATION_FINISHED
+     *
+     * @param delegated_host requests to which host should be delegated; 
cannot be NULL
+     * @param slave_host which host is used to run the slave controller; use 
NULL to
+     *          make the master controller connect to the delegated host
+     * @param is_subordinate GNUNET_YES if the controller at delegated_host 
should
+     *          be started by the slave controller; GNUNET_NO if the slave
+     *          controller has to connect to the already started delegated
+     *          controller via TCP/IP
+     * @return the operation handle
+     */
+    public Operation link(Host delegated_host, Host slave_host, boolean 
is_subordinate) {
+        // low priority
+        throw new UnsupportedOperationException("not yet implemented");
     }
 
 
+    /**
+     * Register a host with the controller. This makes the controller aware of 
the
+     * host. A host should be registered at the controller before starting a
+     * sub-controller on that host using GNUNET_TESTBED_controller_link().
+     *
+     * @param host the host to register
+     * @param cc the completion callback to call to inform the status of
+     *          registration. After calling this callback the registration 
handle
+     *          will be invalid. Cannot be NULL
+     * @return handle to the host registration which can be used to cancel the
+     *           registration; NULL if another registration handle is present 
and
+     *           is not cancelled
+     */
+    Cancelable registerHost(Host host, HostRegistrationCompletion cc) {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+
+    /**
+     * Opaque handle to a peer controlled by the testbed framework.  A peer 
runs
+     * at a particular host.
+     */
+    public class Peer {
+        public Operation start(PeerChurnCallback peerChurnCallback) {
+            return null;
+        }
+
+        public Operation stop(PeerChurnCallback peerChurnCallback) {
+            return null;
+        }
+
+        public Operation getInformation() {
+            return null;
+        }
+
+        /*
+         * Change peer configuration.  Must only be called while the
+         * peer is stopped.  Ports and paths cannot be changed this
+         * way.
+         */
+        public Operation updateConfiguration(Configuration cfg) {
+            return null;
+        }
+
+        /*
+         * Change peer configuration.  Must only be called while the
+         * peer is stopped.  Ports and paths cannot be changed this
+         * way.
+         */
+        public Operation destroy() {
+            return null;
+        }
+
+        public Operation manageService(String serviceName, boolean start) {
+            return null;
+        }
+
+        /**
+         * Both peers must have been started before calling this function.
+         * This function then obtains a HELLO from this peer, gives it to 
'otherPeer'
+         * and asks 'otherPeer' to connect to this peer..
+         */
+        public Operation connectOverlay(OperationCompletionCallback cb, Peer 
otherPeer) {
+            return null;
+        }
+
+        public Operation getServiceConnection(String serviceName /*,... */) {
+            return null;
+        }
+
+    }
 }

Deleted: 
gnunet-java/src/main/java/org/gnunet/testbed/ControllerEventCallback.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/ControllerEventCallback.java   
2013-09-11 11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/java/org/gnunet/testbed/ControllerEventCallback.java   
2013-09-11 11:28:31 UTC (rev 29196)
@@ -1,21 +0,0 @@
-package org.gnunet.testbed;
-
-
-
-public abstract class ControllerEventCallback {
-    void onPeerStart() {
-        throw new AssertionError("event not handled");
-    }
-    void onPeerStop() {
-        throw new AssertionError("event not handled");
-    }
-    void onPeerConnect() {
-        throw new AssertionError("event not handled");
-    }
-    void onPeerDisconnect() {
-        throw new AssertionError("event not handled");
-    }
-    void onOperationFinished() {
-        throw new AssertionError("event not handled");
-    }
-}

Deleted: gnunet-java/src/main/java/org/gnunet/testbed/ControllerInitMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/ControllerInitMessage.java     
2013-09-11 11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/java/org/gnunet/testbed/ControllerInitMessage.java     
2013-09-11 11:28:31 UTC (rev 29196)
@@ -1,30 +0,0 @@
-package org.gnunet.testbed;
-
-
-import org.gnunet.construct.UInt32;
-import org.gnunet.construct.UInt64;
-import org.gnunet.construct.UnionCase;
-import org.gnunet.construct.ZeroTerminatedString;
-import org.gnunet.util.GnunetMessage;
-
address@hidden(460)
-public class ControllerInitMessage implements GnunetMessage.Body {
-    /**
-     * Host ID that the controller is either given (if this is the
-     * dominating client) or assumed to have (for peer-connections
-     * between controllers).  A controller must check that all
-     * connections make consistent claims...
-     */
-    @UInt32
-    public int host_id;
-
-    /**
-     * Event mask that specifies which events this client is interested in.
-     */
-    @UInt64
-    public long event_mask;
-
-    @ZeroTerminatedString
-    public String controler_hostname;
-
-}

Modified: gnunet-java/src/main/java/org/gnunet/testbed/ControllerProc.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/ControllerProc.java    
2013-09-11 11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/java/org/gnunet/testbed/ControllerProc.java    
2013-09-11 11:28:31 UTC (rev 29196)
@@ -1,10 +1,17 @@
 package org.gnunet.testbed;
 
 import com.google.common.base.Charsets;
+import org.gnunet.testbed.callbacks.ControllerStatusCallback;
+import org.gnunet.testbed.messages.HelperInitMessage;
+import org.gnunet.testbed.messages.HelperReplyMessage;
 import org.gnunet.util.Helper;
 import org.gnunet.util.RunaboutMessageReceiver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.zip.Deflater;
 
 /**
@@ -13,18 +20,23 @@
  * the testbed helper on a remote machine.
  */
 public class ControllerProc {
+    private static final Logger logger = LoggerFactory
+            .getLogger(ControllerProc.class);
     private Helper helper;
+    private ControllerStatusCallback cb;
+    private Host host;
 
-
     public class ControllerProcReceiver extends RunaboutMessageReceiver {
         public void visit(HelperReplyMessage m) {
             System.out.println("got controller proc message");
-
+            CompressedConfig ccfg = new CompressedConfig(m.compressed_config);
+            host.cfg = ccfg.decompress();
+            cb.onStartupSuccess(host.cfg);
         }
 
         @Override
         public void handleError() {
-            throw new AssertionError();
+            cb.onStartupFailure();
         }
     }
 
@@ -32,7 +44,7 @@
      * Create a controller proc. Nothing will hapen until ControllerProc.start 
is called.
      */
     public void ControllerProc() {
-
+        // empty
     }
 
     /**
@@ -57,8 +69,13 @@
      *          parameter cannot be NULL.
      */
     public void start(String trustedIP, Host host, ControllerStatusCallback 
cb) {
+        this.cb = cb;
+        this.host = host;
         if (host.isLocal()) {
-            helper = new Helper(false, "gnunet-helper-testbed", null, new 
ControllerProcReceiver());
+            List<String> args = new ArrayList<String>();
+            args.add("-llog-testbed-helper");
+            args.add("-LDEBUG");
+            helper = new Helper(false, "gnunet-helper-testbed", args, new 
ControllerProcReceiver());
         } else {
             throw new AssertionError("not implemented yet");
         }
@@ -71,14 +88,15 @@
      * been fully terminated (!). The controller status cb will not be called.
      */
     public void stop() {
-        throw new AssertionError("not implemented");
+        logger.debug("stopping controller");
+        helper.kill(false);
     }
 
 
     private HelperInitMessage makeHelperInitMessage(String trustedIP, Host 
host) {
         HelperInitMessage m = new HelperInitMessage();
         if (host.hostname == null) {
-            m.hostname = null;
+            m.hostname = new byte[0];
             m.hostname_size = 0;
         } else {
             m.hostname_size =  host.hostname.length();
@@ -87,22 +105,10 @@
         m.trusted_ip_size = trustedIP.length();
         m.trusted_ip = trustedIP;
 
-        byte[] serialized_config = host.cfg.serialize().getBytes();
+        CompressedConfig ccfg = new CompressedConfig(host.cfg);
+        m.compressed_config = ccfg.compressed_data;
+        m.config_size = ccfg.getUncompressedSize();
 
-        Deflater compresser = new Deflater();
-        compresser.setInput(serialized_config);
-        compresser.finish();
-
-        ByteArrayOutputStream s = new ByteArrayOutputStream();
-        byte[] buf = new byte[1024];
-        while (!compresser.finished()) {
-            int n = compresser.deflate(buf);
-            s.write(buf, 0, n);
-        }
-
-        m.compressed_config = s.toByteArray();
-        m.config_size = serialized_config.length;
-
         return m;
     }
 }

Deleted: 
gnunet-java/src/main/java/org/gnunet/testbed/ControllerStatusCallback.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/ControllerStatusCallback.java  
2013-09-11 11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/java/org/gnunet/testbed/ControllerStatusCallback.java  
2013-09-11 11:28:31 UTC (rev 29196)
@@ -1,9 +0,0 @@
-package org.gnunet.testbed;
-
-
-import org.gnunet.util.Configuration;
-
-public interface ControllerStatusCallback {
-    void onStartupSuccess(Configuration cfg);
-    void onStartupFailure();
-}

Deleted: gnunet-java/src/main/java/org/gnunet/testbed/HelperInitMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/HelperInitMessage.java 
2013-09-11 11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/java/org/gnunet/testbed/HelperInitMessage.java 
2013-09-11 11:28:31 UTC (rev 29196)
@@ -1,37 +0,0 @@
-package org.gnunet.testbed;
-
-import org.gnunet.construct.*;
-import org.gnunet.util.GnunetMessage;
-
-/**
- * Initialization message for gnunet-helper-testbed to start testbed service
- */
address@hidden(495)
-public class HelperInitMessage implements GnunetMessage.Body {
-    /**
-     * The controller hostname size excluding the NULL termination character -
-     * strlen (hostname); cannot be zero
-     */
-    @UInt16
-    int trusted_ip_size;
-    /**
-     * The hostname size excluding the NULL termination character - strlen
-     * (hostname); cannot be zero
-     */
-    @UInt16
-    int hostname_size;
-    /**
-     * The size of the uncompressed configuration
-     */
-    @UInt16
-    public int config_size;
-
-    @ZeroTerminatedString(optional = true)
-    public String trusted_ip;
-
-    @VariableSizeIntegerArray(signed = true, bitSize = 8, lengthField = 
"hostname_size")
-    public byte[] hostname;
-
-    @FillWith @UInt8
-    public byte[] compressed_config;
-}

Deleted: gnunet-java/src/main/java/org/gnunet/testbed/HelperReplyMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/HelperReplyMessage.java        
2013-09-11 11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/java/org/gnunet/testbed/HelperReplyMessage.java        
2013-09-11 11:28:31 UTC (rev 29196)
@@ -1,17 +0,0 @@
-package org.gnunet.testbed;
-
-
-import org.gnunet.construct.FillWith;
-import org.gnunet.construct.UInt16;
-import org.gnunet.construct.UInt8;
-import org.gnunet.construct.UnionCase;
-import org.gnunet.util.GnunetMessage;
-
address@hidden(496)
-public class HelperReplyMessage implements GnunetMessage.Body {
-    @UInt16
-    int uncompressed_config_size;
-
-    @FillWith @UInt8
-    byte[] compressed_config;
-}

Modified: gnunet-java/src/main/java/org/gnunet/testbed/Host.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/Host.java      2013-09-11 
11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/java/org/gnunet/testbed/Host.java      2013-09-11 
11:28:31 UTC (rev 29196)
@@ -9,12 +9,13 @@
  */
 public class Host {
     static int nextUID = 1;
-    final Configuration cfg;
+    Configuration cfg;
     final String hostname;
     final String username;
     final int port;
 
     private boolean controllerStarted;
+    public int id;
 
     /**
      * Create a host to run peers and controllers on.
@@ -28,6 +29,11 @@
      */
     public Host(String hostname, String username, Configuration cfg, int port) 
{
         this.port = (port == 0) ? 22 : port;
+        if (hostname == null) {
+            id = 0;
+        } else {
+            id = nextUID++;
+        }
         this.hostname = hostname;
         this.username = username;
         this.cfg = cfg;

Deleted: 
gnunet-java/src/main/java/org/gnunet/testbed/OperationCompletionCallback.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/OperationCompletionCallback.java   
    2013-09-11 11:19:59 UTC (rev 29195)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/OperationCompletionCallback.java   
    2013-09-11 11:28:31 UTC (rev 29196)
@@ -1,11 +0,0 @@
-package org.gnunet.testbed;
-
-/**
- * Created with IntelliJ IDEA.
- * User: dold
- * Date: 8/25/13
- * Time: 1:35 PM
- * To change this template use File | Settings | File Templates.
- */
-public interface OperationCompletionCallback {
-}

Deleted: gnunet-java/src/main/java/org/gnunet/testbed/Peer.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/Peer.java      2013-09-11 
11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/java/org/gnunet/testbed/Peer.java      2013-09-11 
11:28:31 UTC (rev 29196)
@@ -1,57 +0,0 @@
-package org.gnunet.testbed;
-
-import org.gnunet.util.Configuration;
-
-/**
- * Opaque handle to a peer controlled by the testbed framework.  A peer runs
- * at a particular host.
- */
-public class Peer {
-    public Operation start(PeerChurnCallback peerChurnCallback) {
-        return null;
-    }
-
-    public Operation stop(PeerChurnCallback peerChurnCallback) {
-        return null;
-    }
-
-    public Operation getInformation() {
-        return null;
-    }
-
-    /*
-     * Change peer configuration.  Must only be called while the
-     * peer is stopped.  Ports and paths cannot be changed this
-     * way.
-     */
-    public Operation updateConfiguration(Configuration cfg) {
-        return null;
-    }
-
-    /*
-     * Change peer configuration.  Must only be called while the
-     * peer is stopped.  Ports and paths cannot be changed this
-     * way.
-     */
-    public Operation destroy() {
-        return null;
-    }
-
-    public Operation manageService(String serviceName, boolean start) {
-        return null;
-    }
-
-    /**
-     * Both peers must have been started before calling this function.
-     * This function then obtains a HELLO from this peer, gives it to 
'otherPeer'
-     * and asks 'otherPeer' to connect to this peer..
-     */
-    public Operation connectOverlay(OperationCompletionCallback cb, Peer 
otherPeer) {
-        return null;
-    }
-
-    public Operation getServiceConnection(String serviceName /*,... */) {
-        return null;
-    }
-
-}

Deleted: gnunet-java/src/main/java/org/gnunet/testbed/PeerChurnCallback.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/PeerChurnCallback.java 
2013-09-11 11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/java/org/gnunet/testbed/PeerChurnCallback.java 
2013-09-11 11:28:31 UTC (rev 29196)
@@ -1,7 +0,0 @@
-package org.gnunet.testbed;
-
-
-public interface PeerChurnCallback {
-    void onChurnSuccess();
-    void onChurnError(String emsg);
-}

Deleted: gnunet-java/src/main/java/org/gnunet/testbed/PeerCreateCallback.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/PeerCreateCallback.java        
2013-09-11 11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/java/org/gnunet/testbed/PeerCreateCallback.java        
2013-09-11 11:28:31 UTC (rev 29196)
@@ -1,7 +0,0 @@
-package org.gnunet.testbed;
-
-
-public interface PeerCreateCallback {
-    void onPeerCreated(Peer peer);
-    void onError(String errorMessage);
-}

Copied: 
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/ControllerEventCallback.java
 (from rev 28950, 
gnunet-java/src/main/java/org/gnunet/testbed/ControllerEventCallback.java)
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/ControllerEventCallback.java
                         (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/ControllerEventCallback.java
 2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,21 @@
+package org.gnunet.testbed.callbacks;
+
+
+
+public abstract class ControllerEventCallback {
+    void onPeerStart() {
+        throw new AssertionError("event not handled");
+    }
+    void onPeerStop() {
+        throw new AssertionError("event not handled");
+    }
+    void onPeerConnect() {
+        throw new AssertionError("event not handled");
+    }
+    void onPeerDisconnect() {
+        throw new AssertionError("event not handled");
+    }
+    void onOperationFinished() {
+        throw new AssertionError("event not handled");
+    }
+}

Copied: 
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/ControllerStatusCallback.java
 (from rev 28950, 
gnunet-java/src/main/java/org/gnunet/testbed/ControllerStatusCallback.java)
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/ControllerStatusCallback.java
                                (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/ControllerStatusCallback.java
        2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,9 @@
+package org.gnunet.testbed.callbacks;
+
+
+import org.gnunet.util.Configuration;
+
+public interface ControllerStatusCallback {
+    void onStartupSuccess(Configuration cfg);
+    void onStartupFailure();
+}

Added: 
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/HostRegistrationCompletion.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/HostRegistrationCompletion.java
                              (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/HostRegistrationCompletion.java
      2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,4 @@
+package org.gnunet.testbed.callbacks;
+
+public class HostRegistrationCompletion {
+}

Copied: 
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/OperationCompletionCallback.java
 (from rev 28950, 
gnunet-java/src/main/java/org/gnunet/testbed/OperationCompletionCallback.java)
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/OperationCompletionCallback.java
                             (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/OperationCompletionCallback.java
     2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,11 @@
+package org.gnunet.testbed.callbacks;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: dold
+ * Date: 8/25/13
+ * Time: 1:35 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public interface OperationCompletionCallback {
+}

Copied: 
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/PeerChurnCallback.java 
(from rev 28950, 
gnunet-java/src/main/java/org/gnunet/testbed/PeerChurnCallback.java)
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/PeerChurnCallback.java   
                            (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/PeerChurnCallback.java   
    2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,7 @@
+package org.gnunet.testbed.callbacks;
+
+
+public interface PeerChurnCallback {
+    void onChurnSuccess();
+    void onChurnError(String emsg);
+}

Copied: 
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/PeerCreateCallback.java 
(from rev 28950, 
gnunet-java/src/main/java/org/gnunet/testbed/PeerCreateCallback.java)
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/PeerCreateCallback.java  
                            (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/PeerCreateCallback.java  
    2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,8 @@
+package org.gnunet.testbed.callbacks;
+
+import org.gnunet.testbed.Controller;
+
+public interface PeerCreateCallback {
+    void onPeerCreated(Controller.Peer peer);
+    void onError(String errorMessage);
+}

Added: 
gnunet-java/src/main/java/org/gnunet/testbed/messages/ConnectionEventMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/messages/ConnectionEventMessage.java
                           (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/messages/ConnectionEventMessage.java
   2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,11 @@
+package org.gnunet.testbed.messages;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: dold
+ * Date: 9/10/13
+ * Time: 1:37 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class ConnectionEventMessage {
+}

Copied: 
gnunet-java/src/main/java/org/gnunet/testbed/messages/ControllerInitMessage.java
 (from rev 28950, 
gnunet-java/src/main/java/org/gnunet/testbed/ControllerInitMessage.java)
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/messages/ControllerInitMessage.java
                            (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/messages/ControllerInitMessage.java
    2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,36 @@
+package org.gnunet.testbed.messages;
+
+
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UInt64;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.construct.ZeroTerminatedString;
+import org.gnunet.util.GnunetMessage;
+
+/**
+ * Initial message from a client to a testing control service.
+ */
address@hidden(460)
+public class ControllerInitMessage implements GnunetMessage.Body {
+    /**
+     * Host ID that the controller is either given (if this is the
+     * dominating client) or assumed to have (for peer-connections
+     * between controllers).  A controller must check that all
+     * connections make consistent claims...
+     */
+    @UInt32
+    public int host_id;
+
+    /**
+     * Event mask that specifies which events this client is interested in.
+     */
+    @UInt64
+    public long event_mask;
+
+    /**
+     * 0-terminated hostname of the controller.
+     */
+    @ZeroTerminatedString
+    public String controler_hostname;
+
+}

Added: 
gnunet-java/src/main/java/org/gnunet/testbed/messages/CreatePeerSuccessMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/messages/CreatePeerSuccessMessage.java
                         (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/messages/CreatePeerSuccessMessage.java
 2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,5 @@
+package org.gnunet.testbed.messages;
+
+
+public class CreatePeerSuccessMessage {
+}

Added: 
gnunet-java/src/main/java/org/gnunet/testbed/messages/GenericOperationSuccessMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/messages/GenericOperationSuccessMessage.java
                           (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/messages/GenericOperationSuccessMessage.java
   2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,11 @@
+package org.gnunet.testbed.messages;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: dold
+ * Date: 9/10/13
+ * Time: 2:30 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class GenericOperationSuccessMessage {
+}

Copied: 
gnunet-java/src/main/java/org/gnunet/testbed/messages/HelperInitMessage.java 
(from rev 28950, 
gnunet-java/src/main/java/org/gnunet/testbed/HelperInitMessage.java)
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/messages/HelperInitMessage.java    
                            (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/messages/HelperInitMessage.java    
    2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,37 @@
+package org.gnunet.testbed.messages;
+
+import org.gnunet.construct.*;
+import org.gnunet.util.GnunetMessage;
+
+/**
+ * Initialization message for gnunet-helper-testbed to start testbed service
+ */
address@hidden(495)
+public class HelperInitMessage implements GnunetMessage.Body {
+    /**
+     * The controller hostname size excluding the NULL termination character -
+     * strlen (hostname); cannot be zero
+     */
+    @UInt16
+    public int trusted_ip_size;
+    /**
+     * The hostname size excluding the NULL termination character - strlen
+     * (hostname); cannot be zero
+     */
+    @UInt16
+    public int hostname_size;
+    /**
+     * The size of the uncompressed configuration
+     */
+    @UInt16
+    public int config_size;
+
+    @ZeroTerminatedString(optional = true)
+    public String trusted_ip;
+
+    @VariableSizeIntegerArray(signed = true, bitSize = 8, lengthField = 
"hostname_size")
+    public byte[] hostname;
+
+    @FillWith @UInt8
+    public byte[] compressed_config;
+}

Copied: 
gnunet-java/src/main/java/org/gnunet/testbed/messages/HelperReplyMessage.java 
(from rev 28950, 
gnunet-java/src/main/java/org/gnunet/testbed/HelperReplyMessage.java)
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/messages/HelperReplyMessage.java   
                            (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/messages/HelperReplyMessage.java   
    2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,17 @@
+package org.gnunet.testbed.messages;
+
+
+import org.gnunet.construct.FillWith;
+import org.gnunet.construct.UInt16;
+import org.gnunet.construct.UInt8;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+
address@hidden(496)
+public class HelperReplyMessage implements GnunetMessage.Body {
+    @UInt16
+    public int uncompressed_config_size;
+
+    @FillWith @UInt8
+    public byte[] compressed_config;
+}

Added: 
gnunet-java/src/main/java/org/gnunet/testbed/messages/ManagePeerServiceMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/messages/ManagePeerServiceMessage.java
                         (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/messages/ManagePeerServiceMessage.java
 2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,5 @@
+package org.gnunet.testbed.messages;
+
+
+public class ManagePeerServiceMessage {
+}

Added: 
gnunet-java/src/main/java/org/gnunet/testbed/messages/OperationFailEventMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/messages/OperationFailEventMessage.java
                                (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/messages/OperationFailEventMessage.java
        2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,11 @@
+package org.gnunet.testbed.messages;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: dold
+ * Date: 9/10/13
+ * Time: 2:30 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class OperationFailEventMessage {
+}

Added: 
gnunet-java/src/main/java/org/gnunet/testbed/messages/OverlayConnectMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/messages/OverlayConnectMessage.java
                            (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/messages/OverlayConnectMessage.java
    2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,37 @@
+package org.gnunet.testbed.messages;
+
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UInt64;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+
+/**
+ * Message sent from client to testing service to
+ * connect two peers.
+ */
address@hidden(470)
+public class OverlayConnectMessage implements GnunetMessage.Body {
+    /**
+     * Unique ID for the first peer.
+     */
+    @UInt32
+    public int peer1;
+
+    /**
+     * Operation ID that is used to identify this operation.
+     */
+    @UInt64
+    public int operation_id;
+
+    /**
+     * Unique ID for the second peer.
+     */
+    @UInt32
+    public int peer2;
+
+    /**
+     * The ID of the host which runs peer2
+     */
+    @UInt32
+    public int peer2_host;
+}

Added: 
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerConfigurationInformationMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerConfigurationInformationMessage.java
                              (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerConfigurationInformationMessage.java
      2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,8 @@
+package org.gnunet.testbed.messages;
+
+/**
+ * Peer configuration and identity reply from controller to a client.
+ */
+public class PeerConfigurationInformationMessage {
+
+}

Added: 
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerCreateMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerCreateMessage.java    
                            (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerCreateMessage.java    
    2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,24 @@
+package org.gnunet.testbed.messages;
+
+
+import org.gnunet.construct.*;
+import org.gnunet.util.GnunetMessage;
+
address@hidden(464)
+public class PeerCreateMessage implements GnunetMessage.Body {
+    @UInt32
+    public int host_id;
+    @UInt64
+    public long operation_id;
+    @UInt32
+    public int peer_id;
+
+    /**
+     * The size of the uncompressed configuration
+     */
+    @UInt16
+    public int config_size;
+
+    @FillWith @UInt8
+    public byte[] compressed_config;
+}

Added: 
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerCreateSuccessMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerCreateSuccessMessage.java
                         (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerCreateSuccessMessage.java
 2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,17 @@
+package org.gnunet.testbed.messages;
+
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UInt64;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+
+/**
+ * Event notification from a controller to a client.
+ */
address@hidden(474)
+public class PeerCreateSuccessMessage implements GnunetMessage.Body {
+    @UInt32
+    public int peer_id;
+    @UInt64
+    public long operation_id;
+}

Added: 
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerDestroyMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerDestroyMessage.java   
                            (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerDestroyMessage.java   
    2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,15 @@
+package org.gnunet.testbed.messages;
+
+
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UInt64;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+
address@hidden(468)
+public class PeerDestroyMessage implements GnunetMessage.Body {
+    @UInt32
+    public int peer_id;
+    @UInt64
+    public int operation_id;
+}

Added: 
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerEventMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerEventMessage.java 
                        (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerEventMessage.java 
2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,26 @@
+package org.gnunet.testbed.messages;
+
+
+import org.gnunet.construct.Int32;
+import org.gnunet.construct.Int64;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+
+/**
+ * Event notification from a controller to a client.
+ */
address@hidden(471)
+public class PeerEventMessage implements GnunetMessage.Body {
+    /**
+     * 'enum GNUNET_TESTBED_EventType'
+     * either GNUNET_TESTBED_ET_PEER_START or GNUNET_TESTBED_ET_PEER_STOP.
+     */
+    @Int32
+    int event_type;
+    @Int32
+    int host_id;
+    @Int32
+    int peer_id;
+    @Int64
+    int operation_id;
+}

Added: 
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerReconfigureMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerReconfigureMessage.java
                           (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerReconfigureMessage.java
   2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,8 @@
+package org.gnunet.testbed.messages;
+
+/**
+ * Message sent from client to testing service to
+ * reconfigure a (stopped) a peer.
+ */
+public class PeerReconfigureMessage {
+}

Added: 
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerStartMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerStartMessage.java 
                        (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerStartMessage.java 
2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,15 @@
+package org.gnunet.testbed.messages;
+
+
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UInt64;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+
address@hidden(466)
+public class PeerStartMessage implements GnunetMessage.Body {
+    @UInt32
+    public int peer_id;
+    @UInt64
+    public int operation_id;
+}

Added: 
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerStopMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerStopMessage.java  
                        (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerStopMessage.java  
2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,15 @@
+package org.gnunet.testbed.messages;
+
+
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UInt64;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+
address@hidden(467)
+public class PeerStopMessage implements GnunetMessage.Body {
+    @UInt32
+    public int peer_id;
+    @UInt64
+    public int operation_id;
+}

Modified: gnunet-java/src/main/java/org/gnunet/util/Configuration.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/Configuration.java        
2013-09-11 11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/java/org/gnunet/util/Configuration.java        
2013-09-11 11:28:31 UTC (rev 29196)
@@ -226,28 +226,10 @@
         return sections.contains(section, option);
     }
 
-    /**
-     * Parse a configuration file, add all of the options in the file to the
-     * configuration environment.
-     *
-     * @param filename name of the configuration file
-     */
-    public void parse(String filename) {
-        filename = replaceHome(filename);
 
+    private void parseFromLines(Iterator<String> it, String filename) {
         String current_section = "";
-
-        Iterator<String> it;
-
-        try {
-            List<String> lines = Files.readLines(new File(filename), 
Charset.defaultCharset());
-            it = lines.iterator();
-        } catch (IOException e) {
-            throw new ParsingError("Cannot read configuration file '" + 
filename + "'");
-        }
-
-        int lineNumer = 1;
-
+        int lineNumber = 1;
         while (it.hasNext()) {
             String line = it.next();
             String[] split_line = line.split("#");
@@ -281,14 +263,34 @@
             } else if (whitspace.matcher(line).matches()) {
                 // whitespace is ok
             } else {
-                logger.warn(String.format("skipped unreadable line %s in 
configuration file '%s': '%s'", lineNumer,
+                logger.warn(String.format("skipped unreadable line %s in 
configuration file '%s': '%s'", lineNumber,
                         filename, line));
             }
 
-            lineNumer++;
+            lineNumber++;
         }
     }
 
+    /**
+     * Parse a configuration file, add all of the options in the file to the
+     * configuration environment.
+     *
+     * @param filename name of the configuration file
+     */
+    public void parse(String filename) {
+        filename = replaceHome(filename);
+
+        Iterator<String> it;
+        try {
+            List<String> lines = Files.readLines(new File(filename), 
Charset.defaultCharset());
+            it = lines.iterator();
+        } catch (IOException e) {
+            throw new ParsingError("Cannot read configuration file '" + 
filename + "'");
+        }
+        parseFromLines(it, filename);
+
+    }
+
     private String replaceHome(String filename) {
         String home = System.getenv("HOME");
         return home != null ? filename.replace("~", home) : filename;
@@ -346,6 +348,10 @@
         }
     }
 
+    /**
+     * Serialize the configuration to a string.
+     * @return the serialized configuration
+     */
     public String serialize() {
         StringBuffer buf = new StringBuffer();
         for (Map.Entry<String, Map<String,String>> section : 
sections.rowMap().entrySet()) {
@@ -357,7 +363,24 @@
         return buf.toString();
     }
 
+    /**
+     * Serialize the given configuration sections a string.
+     *
+     * @param sectionNames sections to serialize
+     * @return the serialized sections
+     */
+    public String serialize(String... sectionNames) {
+        StringBuffer buf = new StringBuffer();
+        for (String sectionName : sectionNames) {
+            buf.append("[" + sectionName + "]\n");
+            for (Map.Entry<String, String> option : 
sections.row(sectionName).entrySet()) {
+                buf.append(option.getKey() + " = " + option.getValue() + "\n");
+            }
+        }
+        return buf.toString();
+    }
 
+
     public void loadDefaults() {
         Collection<File> dirs = new ArrayList<File>(5);
         dirs.add(new File("/usr/share/gnunet/config.d/"));
@@ -381,6 +404,11 @@
         }
     }
 
+    public void deserialize(String str) {
+        String[] linesArray = str.split("\\r?\\n");
+        parseFromLines(Arrays.asList(linesArray).iterator(), 
"<serialized-config>");
+    }
+
     public static class ConfigurationException extends RuntimeException {
         public ConfigurationException(String string) {
             super(string);

Modified: gnunet-java/src/main/java/org/gnunet/util/CryptoECC.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/CryptoECC.java    2013-09-11 
11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/java/org/gnunet/util/CryptoECC.java    2013-09-11 
11:28:31 UTC (rev 29196)
@@ -1,3 +1,23 @@
+/*
+ This file is part of GNUnet.
+  (C) 2012, 2013 Christian Grothoff (and other contributing authors)
+
+  GNUnet is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 3, or (at your
+  option) any later version.
+
+  GNUnet is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with GNUnet; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+  Boston, MA 02111-1307, USA.
+ */
+
 package org.gnunet.util;
 
 import org.gnunet.construct.FixedSizeIntegerArray;
@@ -2,7 +22,9 @@
 import org.gnunet.construct.Message;
-import org.gnunet.construct.ProtocolViolationException;
-import org.gnunet.construct.UInt32;
 
+import java.io.File;
+import java.io.IOError;
+import java.io.IOException;
 import java.math.BigInteger;
 import java.nio.ByteBuffer;
+import java.nio.file.Files;
 import java.security.MessageDigest;
@@ -26,6 +48,26 @@
          */
         @FixedSizeIntegerArray(bitSize = 8, signed = false, length = 32)
         public byte[] d;
+
+        /**
+         * Load a private key from the given file.
+         *
+         * @param privKeyFilename the private key file name
+         * @return the private key from the file
+         */
+        public static PrivateKey fromFile(String privKeyFilename) {
+            byte[] data;
+            try {
+                data = Files.readAllBytes(new File(privKeyFilename).toPath());
+            } catch (IOException e) {
+                throw new IOError(e);
+            }
+            if (data.length != 32)
+                return null;
+            PrivateKey privateKey = new PrivateKey();
+            privateKey.d = data;
+            return privateKey;
+        }
     }
 
     /**
@@ -46,6 +88,15 @@
         @FixedSizeIntegerArray(bitSize = 8, signed = false, length = 32)
         public byte[] y;
 
+        @Override
+        public String toString() {
+            byte[] data = encodepoint(asPoint());
+            return Strings.dataToString(data);
+        }
+
+        public BigInteger[] asPoint() {
+            return new BigInteger[]{decodeint(x), decodeint(y)};
+        }
     }
 
     /**
@@ -53,7 +104,7 @@
      */
     public static final class Signature implements Message {
         /**
-         * R-value of the signature.
+         * R value of the signature in compressed form.
          * The number is stored as little endian.
          */
         @FixedSizeIntegerArray(bitSize = 8, signed = false, length = 32)
@@ -65,6 +116,14 @@
          */
         @FixedSizeIntegerArray(bitSize = 8, signed = false, length = 32)
         public byte[] s;
+
+        @Override
+        public String toString() {
+            byte[] data = new byte[r.length + s.length];
+            System.arraycopy(r, 0, data, 0, r.length);
+            System.arraycopy(s, 0, data, r.length, s.length);
+            return Strings.dataToString(data);
+        }
     }
 
     // curve parameter b

Modified: gnunet-java/src/main/java/org/gnunet/util/Helper.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/Helper.java       2013-09-11 
11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/java/org/gnunet/util/Helper.java       2013-09-11 
11:28:31 UTC (rev 29196)
@@ -1,3 +1,22 @@
+/*
+ This file is part of GNUnet.
+  (C) 2012, 2013 Christian Grothoff (and other contributing authors)
+
+  GNUnet is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 3, or (at your
+  option) any later version.
+
+  GNUnet is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with GNUnet; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+  Boston, MA 02111-1307, USA.
+ */
 package org.gnunet.util;
 
 import org.gnunet.construct.Construct;
@@ -22,6 +41,7 @@
 
 /**
  * Process that we can communicate to with standard GNUnet messages over 
stdin/stdout.
+ * The implementation uses threads, as Java does not support async I/O on 
process handles.
  */
 public class Helper extends MessageQueue {
     private static final Logger logger = LoggerFactory
@@ -33,16 +53,22 @@
     private volatile GnunetMessage.Body writeMessage;
     private WriteThread writeThread;
     private ReadThread readThread;
+    /**
+     * Task that guarantees scheduler lifeness while the helper process
+     * is running.
+     */
+    private Cancelable lifenessTask;
 
     private final class WriteThread extends Thread {
         @Override
         public void run() {
+            logger.debug("in write thread");
             GnunetMessage.Body msg;
             while (true) {
                 synchronized (Helper.this) {
                     while (writeMessage == null) {
                         try {
-                            wait();
+                            Helper.this.wait();
                         } catch (InterruptedException e) {
                             // do nothing
                         }
@@ -52,18 +78,23 @@
                     writeMessage = null;
                     // somebody can set the next send message
                 }
-                byte[] data = Construct.toBinary(GnunetMessage.fromBody(msg));
+                logger.debug("helper got message");
+                GnunetMessage gm = GnunetMessage.fromBody(msg);
+                byte[] data = Construct.toBinary(gm);
                 try {
                     process.getOutputStream().write(data);
+                    process.getOutputStream().flush();
                 } catch (IOException e) {
-                    // fixme: what now?
+                    throw new IOError(e);
                 }
+                logger.debug("helper wrote message, size {}, size in header 
{}, adding cont", data.length, gm.header.messageSize);
                 Scheduler.addContinuation(new Scheduler.Task() {
                     @Override
                     public void run(Scheduler.RunContext ctx) {
                         reportMessageSent();
                     }
                 }, EnumSet.noneOf(Scheduler.Reason.class));
+                logger.debug("cont added");
             }
         }
     }
@@ -72,21 +103,33 @@
         private ByteBuffer buffer;
         ReadableByteChannel channel;
 
-        private void fillBuffer() {
+        /**
+         * Read until our buffer is full, or an error occurs.
+         *
+         * @return true on success
+         */
+        private boolean fillBuffer() {
             while (buffer.hasRemaining()) {
                 try {
-                    channel.read(buffer);
+                    int n = channel.read(buffer);
+                    if (n == -1) {
+                        logger.debug("read eof");
+                        return false;
+                    }
                 } catch (IOException e) {
-                    // FIXME
-                    return;
+                    logger.debug("read error");
+                    return false;
                 }
             }
+            logger.debug("filled buffer");
+            return true;
         }
 
         private void scheduleInvokeReceiver(final GnunetMessage.Body body) {
             Scheduler.addContinuation(new Scheduler.Task() {
                 @Override
                 public void run(Scheduler.RunContext ctx) {
+                    logger.debug("calling receiver with message");
                     receiver.process(body);
                 }
             }, EnumSet.noneOf(Scheduler.Reason.class));
@@ -99,11 +142,15 @@
             buffer = ByteBuffer.allocate(4);
             channel = Channels.newChannel(process.getInputStream());
             while (true) {
+                // FIXME: use some more general mechanism for reading messages 
(like a message stream tokenizer)
+                logger.debug("helper ready to receive message");
                 buffer.clear();
                 buffer.limit(4);
-                fillBuffer();
+                if (!fillBuffer())
+                    return;
                 buffer.rewind();
                 GnunetMessage.Header msgh = Construct.parseAs(buffer, 
GnunetMessage.Header.class);
+                logger.debug("helper received header of size {}, type {}", 
msgh.messageSize, msgh.messageType);
                 if (msgh.messageSize > GnunetMessage.Header.SIZE) {
                     if (buffer.capacity() < msgh.messageSize) {
                         ByteBuffer newBuf = 
ByteBuffer.allocate(msgh.messageSize);
@@ -112,29 +159,36 @@
                         buffer = newBuf;
                     }
                     buffer.limit(msgh.messageSize);
-                    fillBuffer();
+                    if (!fillBuffer())
+                        return;
                 }
                 // we now have a complete message
                 // prepare for reading again
                 buffer.flip();
 
                 boolean found = true;
-                Class unionClass = null;
-
                 try {
-                    unionClass = 
MessageLoader.getUnionClass(GnunetMessage.Body.class, msgh.messageType);
+                    MessageLoader.getUnionClass(GnunetMessage.Body.class, 
msgh.messageType);
                 } catch (ProtocolViolationException e) {
                     found = false;
                 }
+                logger.debug("about to parse message");
                 if (found) {
+                    logger.debug("found");
                     GnunetMessage msg;
                     msg = Construct.parseAs(buffer, GnunetMessage.class);
+                    logger.debug("parsed");
                     scheduleInvokeReceiver(msg.body);
+                    logger.debug("scheduled");
                 } else {
+                    logger.debug("not found");
                     UnknownMessageBody b = new UnknownMessageBody();
+                    b.data = buffer.array();
                     b.id = msgh.messageType;
                     scheduleInvokeReceiver(b);
+                    logger.debug("scheduled");
                 }
+                logger.debug("scheduled call to receiver");
             }
         }
     }
@@ -149,8 +203,17 @@
         return prefix + "/lib/" + "gnunet/" + "libexec/" +  binaryName;
     }
 
+    /**
+     * Create and start a new helper process
+     *
+     * @param withControlPipe (not implemented yet)
+     * @param binaryName binary name of the helper process
+     * @param argv arguments to the helper process
+     * @param receiver receiver for messages from the process
+     */
     public Helper(boolean withControlPipe, String binaryName, List<String> 
argv,
                   RunaboutMessageReceiver receiver) {
+        logger.debug("in helper constructor");
         this.receiver = receiver;
         List<String> command = new LinkedList<String>();
         if (binaryName == null) {
@@ -166,9 +229,18 @@
             throw new IOError(e);
         }
 
+        lifenessTask = Scheduler.addDelayed(RelativeTime.FOREVER, new 
Scheduler.Task() {
+            @Override
+            public void run(Scheduler.RunContext ctx) {
+                // do nothing
+            }
+        });
+
         writeThread = new WriteThread();
         readThread = new ReadThread();
 
+        logger.debug("creating helper");
+
         writeThread.start();
         readThread.start();
 
@@ -176,14 +248,14 @@
     }
 
     /**
-     * Sends termination signal to the helper process.  The helper process is 
not
-     * reaped; call GNUNET_HELPER_wait() for reaping the dead helper process.
+     * Sends termination signal to the helper process.
      *
      * @param softkill if GNUNET_YES, signals termination by closing the 
helper's
      *          stdin; GNUNET_NO to signal termination by sending SIGTERM to 
helper
      * @return true on success, false on failure
      */
     public boolean kill(boolean softkill) {
+        lifenessTask.cancel();
         if (softkill) {
             try {
                 process.getInputStream().close();
@@ -206,6 +278,7 @@
     public boolean waitFor() {
         try {
             process.waitFor();
+            process.waitFor();
         } catch (InterruptedException e) {
             return false;
         }

Modified: gnunet-java/src/main/java/org/gnunet/util/Program.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/Program.java      2013-09-11 
11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/java/org/gnunet/util/Program.java      2013-09-11 
11:28:31 UTC (rev 29196)
@@ -45,7 +45,7 @@
     protected final Configuration cfg = new Configuration();
 
     @Argument(shortname = "c", longname = "config",
-            description = "Path of the configuration file",
+            description = "path of the configuration file",
             argumentName = "FILENAME",
             action = ArgumentAction.STORE_STRING)
     public String cfgFileName;
@@ -204,8 +204,6 @@
                 }
             });
         }
-
-        System.exit(returnValue);
     }
 
     /**

Modified: gnunet-java/src/main/java/org/gnunet/util/Scheduler.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/Scheduler.java    2013-09-11 
11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/java/org/gnunet/util/Scheduler.java    2013-09-11 
11:28:31 UTC (rev 29196)
@@ -28,6 +28,7 @@
 import java.nio.channels.*;
 import java.nio.channels.spi.SelectorProvider;
 import java.util.*;
+import java.util.concurrent.locks.ReentrantLock;
 
 /**
  * Schedule computations using continuation passing style.
@@ -38,23 +39,35 @@
     private static final Logger logger = LoggerFactory
             .getLogger(Scheduler.class);
 
-    // only valid while a task is executing
+    private static ReentrantLock lock = new ReentrantLock(true);
+
+    /**
+     * Task that we are currently executing, or null if no task is currently 
running.
+     */
     private static TaskConfiguration activeTask = null;
 
-    // cumulative number of tasks in the ready lists
+    /**
+     * Number of tasks in the ready lists, that is, number of tasks that is 
ready to run
+     * (all prerequisites are fulfilled).
+     */
     private static volatile int readyCount = 0;
 
     /**
-     * Priority for Tasks.
+     * Priority for Tasks, in order if ascending priority.
+     * When two tasks are ready, the one with the higher priority is executed 
first.
      */
     public enum Priority {
         IDLE, BACKGROUND, DEFAULT, HIGH, UI, URGENT, SHUTDOWN;
 
-        // how many different priorities do we have?
+        /**
+         * how many different priorities do we have?
+         */
         private static final int numberOfPriorities = Priority.values().length;
     }
 
-    // for every priority, there is a list of tasks that is definitely ready 
to run
+    /**
+     * For every priority, there is a list of tasks that is definitely ready 
to run.
+     */
     @SuppressWarnings("unchecked")
     final private static LinkedList<TaskConfiguration>[] readyLists = new 
LinkedList[Priority.numberOfPriorities];
 
@@ -92,7 +105,10 @@
     private static boolean scheduler_running = false;
 
 
-    // tasks that are waiting for an event, which are executed anyway after 
the deadline has occurred
+    /**
+     * Pending tasks are waiting for an event. Each pending task has a 
(possibly infinitely long)
+     * deadline after which the task is executed regardless of the 
prerequisites.
+     */
     final private static Queue<TaskConfiguration> pending = new 
PriorityQueue<TaskConfiguration>(5, new Comparator
             <TaskConfiguration>() {
         @Override
@@ -131,10 +147,7 @@
         /**
          * The reason this task has been called by the scheduler.
          */
-        Set<Reason> reasons = EnumSet.noneOf(Reason.class);
-
-        public RunContext() {
-        }
+        public Set<Reason> reasons = EnumSet.noneOf(Reason.class);
     }
 
     /**
@@ -176,6 +189,12 @@
                 this.deadline = delay.toAbsolute();
         }
 
+        /**
+         * Register the task configuration to run once the given event 
completed.
+         *
+         * @param channel channel that we wait for an event on
+         * @param eventType the event we wait on
+         */
         private void addChannelEvent(SelectableChannel channel, int eventType) 
{
             if (channel == null) {
                 throw new AssertionError("channel must be non-null");
@@ -192,6 +211,8 @@
             SelectionKey key = channel.keyFor(selector);
             if (key == null || !key.isValid()) {
                 try {
+                    // tread safety ... avoid deadlock
+                    selector.wakeup();
                     key = channel.register(selector, interestOp, new 
TaskConfiguration[4]);
                 } catch (ClosedChannelException e) {
                     throw new IOError(e);
@@ -237,6 +258,7 @@
         }
 
         public Cancelable schedule() {
+            lock.lock();
             if (this.deadline == null)
                 throw new AssertionError("a task without deadline may not be 
scheduled");
             if (priority == null) {
@@ -247,6 +269,7 @@
                 }
             }
             pending.add(this);
+            lock.unlock();
             return this;
         }
 
@@ -254,6 +277,7 @@
             if (eventChannels == null) {
                 return;
             }
+            lock.lock();
             for (int i = 0; i < eventChannels.size(); ++i) {
                 SelectionKey key = eventChannels.get(i).keyFor(selector);
                 TaskConfiguration[] subscribers = (TaskConfiguration[]) 
key.attachment();
@@ -264,6 +288,8 @@
                 subscribers[eventTypes.get(i)] = null;
                 key.interestOps(key.interestOps() & (~interestOp));
             }
+
+            lock.unlock();
         }
 
         public void selectRead(SelectableChannel channel) {
@@ -287,11 +313,15 @@
      * Run the task regardless of any prerequisites, before any other task of
      * the same priority.
      */
-    public static synchronized void addContinuation(Task task, EnumSet<Reason> 
reasons) {
+    public static void addContinuation(Task task, EnumSet<Reason> reasons) {
+        lock.lock();
         TaskConfiguration t = new TaskConfiguration(null, task);
         t.ctx.reasons = reasons;
         t.priority = Priority.DEFAULT;
         queueReady(t);
+        logger.debug("about to wake up");
+        lock.unlock();
+        selector.wakeup();
     }
 
     /**
@@ -342,11 +372,14 @@
      * @return true to continue the main loop, false to exit
      */
     private static boolean checkLiveness() {
+        lock.lock();
         if (readyCount > 0) {
+            lock.unlock();
             return true;
         }
         for (TaskConfiguration t : pending) {
             if (t.lifeness) {
+                lock.unlock();
                 return true;
             }
         }
@@ -354,9 +387,11 @@
         if (!pending.isEmpty()) {
             logger.debug("tasks pending but not alive -- disconnect");
             shutdown();
+            lock.unlock();
             return true;
         }
 
+        lock.unlock();
         return false;
     }
 
@@ -366,11 +401,13 @@
      *
      * @param tid TaskIdentifier of the ready task
      */
-    private static synchronized void queueReady(TaskConfiguration tid) {
+    private static void queueReady(TaskConfiguration tid) {
+        lock.lock();
         int idx = tid.priority.ordinal();
         readyLists[idx].add(tid);
         readyCount++;
         pending.remove(tid);
+        lock.unlock();
     }
 
 
@@ -381,6 +418,7 @@
      */
     private static RelativeTime handleTimeouts() {
         RelativeTime timeout = RelativeTime.FOREVER;
+        lock.lock();
 
         // check if any timeouts occurred
         while (true) {
@@ -398,16 +436,25 @@
                 break;
             }
         }
+        lock.unlock();
         return timeout;
     }
 
+    /**
+     * If there is a subscribing task for the given event type, add it to the 
set of executable tasks.
+     *
+     * @param executableTasks set of executable tasks
+     * @param subscribers subscriber set, one subscriber for each event type
+     * @param eventType event type we are interested in
+     */
     private static void addSubscriberTask(Collection<TaskConfiguration> 
executableTasks,
                                           TaskConfiguration[] subscribers, int 
eventType) {
-        if (subscribers[eventType] == null) {
+        TaskConfiguration tc = subscribers[eventType];
+        if (tc == null) {
             return;
         }
-        executableTasks.add(subscribers[eventType]);
-        subscribers[eventType].ctx.reasons.add(eventToReason[eventType]);
+        executableTasks.add(tc);
+        tc.ctx.reasons.add(eventToReason[eventType]);
     }
 
     /**
@@ -416,21 +463,30 @@
      * @param timeout timeout for select
      */
     private static void handleSelect(RelativeTime timeout) {
+        if (!lock.isHeldByCurrentThread())
+            throw new AssertionError();
         long timeout_ms = timeout.getMicroseconds() / 1000;
+        lock.unlock();
         try {
             // selector.select(0) would block indefinitely (counter-intuitive, 
java's fault)
             if (timeout_ms == 0) {
                 selector.selectNow();
             } else if (timeout.isForever()) {
+                // fixme: we should only do this if we are sure there are 
tasks that select on something
+                logger.debug("selecting, timeout=forever");
                 selector.select(0);
             } else {
                 selector.select(timeout_ms);
             }
         } catch (IOException e) {
             throw new IOError(e);
+        } finally {
+            lock.lock();
         }
 
-        // we have to do this so we don't execute any task twice
+        logger.debug("select over");
+
+        // we use a set so that we don't execute any task twice
         Collection<TaskConfiguration> executableTasks = new 
HashSet<TaskConfiguration>();
         for (SelectionKey sk : selector.selectedKeys()) {
             TaskConfiguration[] subscribers = (TaskConfiguration[]) 
sk.attachment();
@@ -472,7 +528,7 @@
      * @param initialTask the initial task to run immediately
      */
     public static void run(Task initialTask) {
-        logger.info("running scheduler");
+        logger.debug("running scheduler");
         if (scheduler_running) {
             throw new AssertionError("Scheduler already running");
         }
@@ -480,7 +536,7 @@
         try {
             run_unchecked(initialTask);
         } finally {
-            logger.info("cleaning up after scheduler ran");
+            logger.debug("cleaning up after scheduler ran");
             // ensure that after run returns, the scheduler is in its initial 
state,
             // even though there was an exception (e.g. after a test case that 
expects an exception)
             forceReset();
@@ -501,28 +557,30 @@
 
         // the gnunet main loop
         while (true) {
-            synchronized (Scheduler.class) {
-                if (checkLiveness() == false)
-                    break;
-                RelativeTime nextTimeout = handleTimeouts();
-                if (nextTimeout.getMicroseconds() < 0) {
-                    logger.warn("negative timeout for select");
-                }
+            lock.lock();
+            if (checkLiveness() == false) {
+                lock.unlock();
+                break;
+            }
+            RelativeTime nextTimeout = handleTimeouts();
+            if (nextTimeout.getMicroseconds() < 0) {
+                logger.warn("negative timeout for select");
+            }
 
-                // don't select if there are no tasks; we are done!
-                if (readyCount == 0 && pending.isEmpty()) {
-                    return;
-                }
+            // don't select if there are no tasks; we are done!
+            if (readyCount == 0 && pending.isEmpty()) {
+                lock.unlock();
+                return;
+            }
 
-                // don't block in select if we have tasks ready to run!
-                if (readyCount > 0) {
-                    handleSelect(RelativeTime.ZERO);
-                } else {
-                    handleSelect(nextTimeout);
-                }
-
-                runReady();
+            // don't block in select if we have tasks ready to run!
+            if (readyCount > 0) {
+                handleSelect(RelativeTime.ZERO);
+            } else {
+                handleSelect(nextTimeout);
             }
+            runReady();
+            lock.unlock();
         }
 
         if (readyCount != 0) {
@@ -546,7 +604,7 @@
 
 
     /**
-     * Execute tasks until there either
+     * Execute tasks until either
      * <ul>
      * <li>there are no ready tasks</li>
      * <li>there is a pending task (which may be of higher priority)</li>
@@ -675,4 +733,3 @@
         return new FilePipe(fpt);
     }
 }
-

Copied: gnunet-java/src/main/java/org/gnunet/voting/BallotTool.java (from rev 
28950, gnunet-java/src/main/java/org/gnunet/voting/VotingTool.java)
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/BallotTool.java                 
        (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/voting/BallotTool.java 2013-09-11 
11:28:31 UTC (rev 29196)
@@ -0,0 +1,300 @@
+/*
+ This file is part of GNUnet.
+  (C) 2012, 2013 Christian Grothoff (and other contributing authors)
+
+  GNUnet is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 3, or (at your
+  option) any later version.
+
+  GNUnet is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with GNUnet; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+  Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.voting;
+
+
+import com.google.common.base.Charsets;
+import com.google.common.io.ByteStreams;
+import com.google.common.io.Files;
+import com.google.common.io.OutputSupplier;
+import org.gnunet.mesh.Mesh;
+import org.gnunet.mesh.MeshRunabout;
+import org.gnunet.util.Configuration;
+import org.gnunet.util.CryptoECC;
+import org.gnunet.util.Program;
+import org.gnunet.util.getopt.Argument;
+import org.gnunet.util.getopt.ArgumentAction;
+import org.gnunet.voting.messages.BallotRegisterRequestMessage;
+import org.gnunet.voting.messages.SubmitMessage;
+import org.gnunet.voting.messages.SubmitResponseMessage;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.util.regex.Pattern;
+
+/**
+ * Tool for creating, manipulating and submitting ballot files.
+ */
+public class BallotTool {
+    public static void main(String[] args) {
+        new Program(args) {
+            @Argument(
+                    shortname = "q",
+                    longname = "query",
+                    action = ArgumentAction.SET,
+                    description = "query election result")
+            boolean query = false;
+
+            @Argument(
+                    shortname = "s",
+                    longname = "submit",
+                    action = ArgumentAction.SET,
+                    description = "submit the vote to the authorities")
+            boolean submit = false;
+
+            @Argument(
+                    shortname = "r",
+                    longname = "register",
+                    action = ArgumentAction.SET,
+                    description = "register an election with the authorities")
+            boolean register = false;
+
+            @Argument(
+                    shortname = "x",
+                    longname = "select",
+                    action = ArgumentAction.STORE_STRING,
+                    argumentName = "CHOICE",
+                    description = "select and encrypt a vote option")
+            String select = null;
+
+            @Argument(
+                    shortname = "p",
+                    longname = "permission",
+                    action = ArgumentAction.SET,
+                    description = "request permission to vote from the 
certificate authority")
+             boolean permission = false;
+
+            @Argument(
+                    shortname = "V",
+                    longname = "verify",
+                    action = ArgumentAction.SET,
+                    description = "verify signatures in the ballot and show 
information")
+            boolean verify = false;
+
+            @Argument(
+                    shortname = "t",
+                    longname = "template",
+                    action = ArgumentAction.SET,
+                    description = "write a template ballot to the give ballot 
file")
+            boolean template = false;
+
+            @Override
+            protected String makeHelpText() {
+                return "gnunet-ballot [OPTIONS]... BALLOT [PRIVKEYFILE]\n" +
+                        "Create, modify and execute operation on ballots.";
+            }
+
+            private void runTemplate(String filename) {
+                File f = new File(filename);
+                if (f.exists()) {
+                    System.err.println("file already exists, not overwriting");
+                    return;
+                }
+                InputStream is = 
getClass().getResourceAsStream("template.espec");
+                OutputSupplier<FileOutputStream> oss = 
Files.newOutputStreamSupplier(f);
+                try {
+                    ByteStreams.copy(is, oss);
+                } catch (IOException e) {
+                    System.err.println("could not copy template file: " + 
e.getMessage());
+                }
+            }
+
+            private void runRegister(String ballotFilename, String 
privKeyFilename) {
+                File bf = new File(ballotFilename);
+                if (!bf.exists()) {
+                    System.err.println("ballot file does not exist");
+                    return;
+                }
+                File kf = new File(privKeyFilename);
+                if (!kf.exists()) {
+                    System.err.println("private-key file does not exist");
+                    return;
+                }
+                Configuration ballot = new Configuration();
+                ballot.parse(ballotFilename);
+                CryptoECC.PrivateKey privateKey = 
CryptoECC.PrivateKey.fromFile(privKeyFilename);
+                if (privateKey == null) {
+                    System.err.println("keyfile invalid");
+                    return;
+                }
+                CryptoECC.PublicKey publicKey = 
CryptoECC.computePublicKey(privateKey);
+                ballot.setValueString("election", "ISSUER_PUB", 
publicKey.toString());
+                String sigData = ballot.serialize("election", "authorities");
+                CryptoECC.Signature sig = 
CryptoECC.sign(sigData.getBytes(Charsets.UTF_8), privateKey, publicKey);
+                ballot.setValueString("registration-issuer", "SIGNATURE", 
sig.toString());
+                String b = ballot.serialize();
+                try {
+                    Files.write(b, bf, Charsets.UTF_8);
+                } catch (IOException e) {
+                    System.err.println("can not write to ballot file");
+                    return;
+                }
+                System.out.println("ballot registered");
+            }
+
+            public void runSelect(String ballotFilename, String 
privKeyFilename, String choice) {
+                File bf = new File(ballotFilename);
+                if (!bf.exists()) {
+                    System.err.println("ballot file does not exist");
+                    return;
+                }
+                File kf = new File(privKeyFilename);
+                if (!kf.exists()) {
+                    System.err.println("private-key file does not exist");
+                    return;
+                }
+                Configuration ballot = new Configuration();
+                ballot.parse(ballotFilename);
+                CryptoECC.PrivateKey privateKey = 
CryptoECC.PrivateKey.fromFile(privKeyFilename);
+                if (privateKey == null) {
+                    System.err.println("keyfile invalid");
+                    return;
+                }
+                CryptoECC.PublicKey publicKey = 
CryptoECC.computePublicKey(privateKey);
+                String choicesStr = ballot.getValueString("election", 
"CHOICES").get();
+                String[] choices = 
choicesStr.trim().split(Pattern.quote("//"));
+                choice = choice.trim();
+                boolean found = false;
+                for (String possibleChoice : choices) {
+                    if (possibleChoice.trim().equals(choice))
+                        found = true;
+                }
+                if (!found) {
+                    System.err.println("choice invalid");
+                    return;
+                }
+                CryptoECC.Signature sig = 
CryptoECC.sign(choice.getBytes(Charsets.UTF_8), privateKey, publicKey);
+                ballot.setValueString("vote", "CHOICE_PLAIN", choice);
+                ballot.setValueString("vote", "PUB", publicKey.toString());
+                ballot.setValueString("vote", "SIG", sig.toString());
+                try {
+                    Files.write(ballot.serialize(), bf, Charsets.UTF_8);
+                } catch (IOException e) {
+                    System.err.println("can not write to ballot file");
+                    return;
+                }
+                System.out.println("vote written to ballot file");
+            }
+
+            public void runSubmit(String ballotFilename) {
+                class SubmitMessageReceiver extends MeshRunabout {
+                    public void visit(SubmitResponseMessage m) {
+                        // FIXME ...
+                    }
+                }
+                File bf = new File(ballotFilename);
+                if (!bf.exists()) {
+                    System.err.println("ballot file does not exist");
+                    return;
+                }
+                Configuration ballot = new Configuration();
+                ballot.parse(ballotFilename);
+                Mesh mesh = new Mesh(getConfiguration(), null, null, new 
SubmitMessageReceiver());
+                Mesh.Tunnel<Void> t = mesh.createTunnel(null, 
CertificateAuthorityService.MESH_PORT, true, true, null);
+                SubmitMessage m = new SubmitMessage();
+                m.ballot = ballot.toString();
+                t.send(m);
+                // FIXME ...
+            }
+
+            public void runQuery(String ballotFilename) {
+
+            }
+
+
+            public void runPermission(String ballotFilename, String 
privKeyFilename) {
+
+            }
+
+
+            public void runVerify(String ballotFilename) {
+                System.err.print("not implemented");
+            }
+
+
+            @Override
+            public void run() {
+                if (template) {
+                    if (this.unprocessedArgs.length != 1) {
+                        System.err.println("-t/--template requires exactly one 
positional argument");
+                        return;
+                    }
+                    runTemplate(unprocessedArgs[0]);
+                    return;
+                }
+
+                if (register) {
+                    if (this.unprocessedArgs.length != 2) {
+                        System.err.println("-r/--register requires exactly two 
positional arguments");
+                        return;
+                    }
+                    runRegister(unprocessedArgs[0], unprocessedArgs[1]);
+                    return;
+                }
+                if (select != null) {
+                    if (this.unprocessedArgs.length != 2) {
+                        System.err.println("-x/--select requires exactly two 
positional argument");
+                        return;
+                    }
+                    runSelect(unprocessedArgs[0], unprocessedArgs[1], select);
+                    return;
+                }
+                if (submit) {
+                    if (this.unprocessedArgs.length != 1) {
+                        System.err.println("-s/--submit requires exactly one 
positional argument");
+                        return;
+                    }
+                    runSubmit(unprocessedArgs[0]);
+                    return;
+                }
+                if (verify) {
+                    if (this.unprocessedArgs.length != 1) {
+                        System.err.println("-V/--verify requires exactly one 
positional argument");
+                        return;
+                    }
+                    runVerify(unprocessedArgs[0]);
+                    return;
+                }
+                if (query) {
+                    if (this.unprocessedArgs.length != 1) {
+                        System.err.println("-q/--query requires exactly one 
positional argument");
+                        return;
+                    }
+                    runQuery(unprocessedArgs[0]);
+                    return;
+                }
+                if (permission) {
+                    if (this.unprocessedArgs.length != 2) {
+                        System.err.println("-p/--permission requires exactly 
two positional arguments");
+                        return;
+                    }
+                    runPermission(unprocessedArgs[0], unprocessedArgs[1]);
+                    return;
+                }
+            }
+        }.start();
+
+    }
+
+}

Modified: 
gnunet-java/src/main/java/org/gnunet/voting/CertificateAuthorityService.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/voting/CertificateAuthorityService.java    
    2013-09-11 11:19:59 UTC (rev 29195)
+++ 
gnunet-java/src/main/java/org/gnunet/voting/CertificateAuthorityService.java    
    2013-09-11 11:28:31 UTC (rev 29196)
@@ -1,7 +1,55 @@
+/*
+ This file is part of GNUnet.
+  (C) 2012, 2013 Christian Grothoff (and other contributing authors)
+
+  GNUnet is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 3, or (at your
+  option) any later version.
+
+  GNUnet is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with GNUnet; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+  Boston, MA 02111-1307, USA.
+ */
 package org.gnunet.voting;
 
+import org.gnunet.mesh.Mesh;
+import org.gnunet.mesh.MeshRunabout;
+import org.gnunet.util.RelativeTime;
+import org.gnunet.util.Service;
+import org.gnunet.voting.messages.CertificateRequestMessage;
+
 /**
  * Permits or denies a voter to participate in an election.
  */
-public class CertificateAuthorityService {
+public class CertificateAuthorityService extends Service {
+    public static final int MESH_PORT = 1001;
+    private Mesh mesh;
+
+
+    private class CaMeshReceiver extends MeshRunabout {
+        public void visit(CertificateRequestMessage m) {
+            // TODO: just sign the
+        }
+    }
+
+    public CertificateAuthorityService(String[] args) {
+        super("voting-ca", RelativeTime.FOREVER, true, args);
+    }
+
+    public static void main(String[] args) {
+        CertificateAuthorityService service = new 
CertificateAuthorityService(args);
+        service.start();
+    }
+
+    @Override
+    public void run() {
+        mesh = new Mesh(getConfiguration(), null, null, new CaMeshReceiver(), 
MESH_PORT);
+    }
 }

Deleted: gnunet-java/src/main/java/org/gnunet/voting/ElectionCallTool.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/ElectionCallTool.java   
2013-09-11 11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/java/org/gnunet/voting/ElectionCallTool.java   
2013-09-11 11:28:31 UTC (rev 29196)
@@ -1,50 +0,0 @@
-package org.gnunet.voting;
-
-
-import org.gnunet.util.Program;
-import org.gnunet.util.getopt.Argument;
-import org.gnunet.util.getopt.ArgumentAction;
-
-public class ElectionCallTool {
-
-    public static void main(String[] args) {
-        new Program(args) {
-            @Argument(
-                    shortname = "t",
-                    longname = "template",
-                    action = ArgumentAction.SET,
-                    description = "output election template")
-            boolean template = false;
-            @Argument(
-                    shortname = "o",
-                    longname = "outfile",
-                    argumentName = "FILE",
-                    action = ArgumentAction.STORE_STRING,
-                    description = "write spec to FILE instead of standard 
output")
-            String outfilename = null;
-            @Argument(
-                    shortname = "V",
-                    longname = "verify",
-                    action = ArgumentAction.SET,
-                    description = "verify that the ESPEC is valid")
-            boolean verify = false;
-            @Argument(
-                    shortname = "a",
-                    longname = "authorize",
-                    action = ArgumentAction.SET,
-                    description = "authorize the ESPEC with the authorities")
-            boolean authorize = false;
-
-            @Override
-            protected String makeHelpText() {
-                return "gnunet-vote-call [OPTIONS]... ESPEC\n" +
-                        "Create, authorize and verify an election 
specification";
-            }
-
-            @Override
-            public void run() {
-            }
-
-        }.start();
-    }
-}

Deleted: gnunet-java/src/main/java/org/gnunet/voting/ElectionSpecification.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/ElectionSpecification.java      
2013-09-11 11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/java/org/gnunet/voting/ElectionSpecification.java      
2013-09-11 11:28:31 UTC (rev 29196)
@@ -1,5 +0,0 @@
-package org.gnunet.voting;
-
-public class ElectionSpecification {
-
-}

Modified: gnunet-java/src/main/java/org/gnunet/voting/TallyAuthorityService.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/TallyAuthorityService.java      
2013-09-11 11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/java/org/gnunet/voting/TallyAuthorityService.java      
2013-09-11 11:28:31 UTC (rev 29196)
@@ -1,5 +1,81 @@
+/*
+ This file is part of GNUnet.
+  (C) 2012, 2013 Christian Grothoff (and other contributing authors)
+
+  GNUnet is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 3, or (at your
+  option) any later version.
+
+  GNUnet is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with GNUnet; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+  Boston, MA 02111-1307, USA.
+ */
 package org.gnunet.voting;
 
 
-public class TallyAuthorityService {
+import com.google.common.collect.Maps;
+import org.gnunet.mesh.Mesh;
+import org.gnunet.mesh.MeshRunabout;
+import org.gnunet.util.CryptoECC;
+import org.gnunet.util.RelativeTime;
+import org.gnunet.util.Service;
+import org.gnunet.voting.messages.BallotRegisterRequestMessage;
+import org.gnunet.voting.messages.CertificateRequestMessage;
+import org.gnunet.voting.messages.QueryResultMessage;
+import org.gnunet.voting.messages.SubmitMessage;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class TallyAuthorityService extends Service {
+    public static final int MESH_PORT = 1002;
+    private Mesh mesh;
+
+
+    private class ElectionState {
+        /**
+         * Set of voters that have submitted their ballot.
+         */
+        private Set<CryptoECC.PublicKey> voters = new 
HashSet<CryptoECC.PublicKey>();
+
+        /**
+         * Maping from choice to number of votes for that choice.
+         */
+        private Map<String,Integer> tally = Maps.newHashMap();
+    }
+
+
+    private class TallyMeshReceiver extends MeshRunabout {
+        public void visit(SubmitMessage m) {
+            // TODO: count!
+        }
+        public void visit(BallotRegisterRequestMessage m) {
+            // TODO ...
+        }
+        public void visit(QueryResultMessage m) {
+
+        }
+    }
+
+    public TallyAuthorityService(String[] args) {
+        super("voting-tally", RelativeTime.FOREVER, true, args);
+    }
+
+    public static void main(String[] args) {
+        CertificateAuthorityService service = new 
CertificateAuthorityService(args);
+        service.start();
+    }
+
+    @Override
+    public void run() {
+        mesh = new Mesh(getConfiguration(), null, null, new 
TallyMeshReceiver(), MESH_PORT);
+    }
 }

Deleted: gnunet-java/src/main/java/org/gnunet/voting/VotingTool.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/VotingTool.java 2013-09-11 
11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/java/org/gnunet/voting/VotingTool.java 2013-09-11 
11:28:31 UTC (rev 29196)
@@ -1,49 +0,0 @@
-package org.gnunet.voting;
-
-
-import org.gnunet.util.Program;
-import org.gnunet.util.getopt.Argument;
-import org.gnunet.util.getopt.ArgumentAction;
-
-public class VotingTool {
-    public static void main(String[] args) {
-        new Program(args) {
-            @Argument(
-                    shortname = "q",
-                    longname = "query",
-                    action = ArgumentAction.SET,
-                    description = "query election result")
-            boolean query = false;
-
-            @Argument(
-                    shortname = "s",
-                    longname = "submit",
-                    action = ArgumentAction.STORE_STRING,
-                    argumentName = "CHOICE",
-                    description = "submit vote to the election")
-            String vote = null;
-
-            @Argument(
-                    shortname = "p",
-                    longname = "certificate",
-                    action = ArgumentAction.STORE_STRING,
-                    argumentName = "FILE",
-                    description = "certificate file with the permission to 
vote")
-            String certfile = null;
-
-            @Override
-            protected String makeHelpText() {
-                return "gnunet-vote [OPTIONS]... ESPEC\n" +
-                        "Submit a vote or query an election's result.\n" +
-                        "The election is identified in the ESPEC file.";
-            }
-
-            @Override
-            public void run() {
-
-            }
-        }.start();
-
-    }
-
-}

Added: 
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterRequestMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterRequestMessage.java
                              (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterRequestMessage.java
      2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,6 @@
+package org.gnunet.voting.messages;
+
+import org.gnunet.util.GnunetMessage;
+
+public class BallotRegisterRequestMessage implements GnunetMessage.Body {
+}

Added: 
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterRespondMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterRespondMessage.java
                              (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterRespondMessage.java
      2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,6 @@
+package org.gnunet.voting.messages;
+
+import org.gnunet.util.GnunetMessage;
+
+public class BallotRegisterRespondMessage implements GnunetMessage.Body {
+}

Added: 
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateRequestMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateRequestMessage.java
                         (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateRequestMessage.java
 2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,8 @@
+package org.gnunet.voting.messages;
+
+/**
+ * Request a certificate that allows a voter to submit a ballot.
+ * Sent by the voter to the certificate authority.
+ */
+public class CertificateRequestMessage {
+}

Added: 
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateResponseMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateResponseMessage.java
                                (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateResponseMessage.java
        2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,5 @@
+package org.gnunet.voting.messages;
+
+
+public class CertificateResponseMessage {
+}

Added: 
gnunet-java/src/main/java/org/gnunet/voting/messages/QueryResultMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/voting/messages/QueryResultMessage.java    
                            (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/voting/messages/QueryResultMessage.java    
    2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,5 @@
+package org.gnunet.voting.messages;
+
+public class QueryResultMessage {
+
+}

Added: 
gnunet-java/src/main/java/org/gnunet/voting/messages/QueryResultResponseMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/voting/messages/QueryResultResponseMessage.java
                                (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/voting/messages/QueryResultResponseMessage.java
        2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,5 @@
+package org.gnunet.voting.messages;
+
+
+public class QueryResultResponseMessage {
+}

Added: gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitMessage.java     
                        (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitMessage.java     
2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,12 @@
+package org.gnunet.voting.messages;
+
+import org.gnunet.construct.ZeroTerminatedString;
+import org.gnunet.util.GnunetMessage;
+
+/**
+ * Message send by the voter to the election authority to submit a vote.
+ */
+public class SubmitMessage implements GnunetMessage.Body {
+    @ZeroTerminatedString
+    public String ballot;
+}

Added: 
gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitResponseMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitResponseMessage.java 
                            (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitResponseMessage.java 
    2013-09-11 11:28:31 UTC (rev 29196)
@@ -0,0 +1,5 @@
+package org.gnunet.voting.messages;
+
+
+public class SubmitResponseMessage {
+}

Modified: gnunet-java/src/main/resources/org/gnunet/construct/MsgMap.txt
===================================================================
--- gnunet-java/src/main/resources/org/gnunet/construct/MsgMap.txt      
2013-09-11 11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/resources/org/gnunet/construct/MsgMap.txt      
2013-09-11 11:28:31 UTC (rev 29196)
@@ -30,12 +30,19 @@
 
org.gnunet.util.GnunetMessage$Body|70=org.gnunet.core.NotifyInboundTrafficMessage
 
org.gnunet.util.GnunetMessage$Body|71=org.gnunet.core.NotifyOutboundTrafficMessage
 org.gnunet.util.GnunetMessage$Body|64=org.gnunet.core.InitMessage
+org.gnunet.util.GnunetMessage$Body|474=org.gnunet.testbed.messages.PeerCreateSuccessMessage
 org.gnunet.util.GnunetMessage$Body|65=org.gnunet.core.InitReplyMessage
 org.gnunet.util.GnunetMessage$Body|67=org.gnunet.core.ConnectNotifyMessage
 org.gnunet.util.GnunetMessage$Body|76=org.gnunet.core.SendMessage
+org.gnunet.util.GnunetMessage$Body|470=org.gnunet.testbed.messages.OverlayConnectMessage
+org.gnunet.util.GnunetMessage$Body|471=org.gnunet.testbed.messages.PeerEventMessage
+org.gnunet.util.GnunetMessage$Body|468=org.gnunet.testbed.messages.PeerDestroyMessage
+org.gnunet.util.GnunetMessage$Body|466=org.gnunet.testbed.messages.PeerStartMessage
+org.gnunet.util.GnunetMessage$Body|467=org.gnunet.testbed.messages.PeerStopMessage
+org.gnunet.util.GnunetMessage$Body|464=org.gnunet.testbed.messages.PeerCreateMessage
 org.gnunet.util.GnunetMessage$Body|74=org.gnunet.core.SendMessageRequest
 org.gnunet.util.GnunetMessage$Body|75=org.gnunet.core.SendMessageReady
-org.gnunet.util.GnunetMessage$Body|460=org.gnunet.testbed.ControllerInitMessage
+org.gnunet.util.GnunetMessage$Body|460=org.gnunet.testbed.messages.ControllerInitMessage
 org.gnunet.util.GnunetMessage$Body|323=org.gnunet.nse.UpdateMessage
 org.gnunet.util.GnunetMessage$Body|321=org.gnunet.nse.StartMessage
 org.gnunet.util.GnunetMessage$Body|332=org.gnunet.peerinfo.InfoMessage
@@ -46,8 +53,8 @@
 
org.gnunet.util.GnunetMessage$Body|371=org.gnunet.transport.BlacklistReplyMessage
 
org.gnunet.util.GnunetMessage$Body|370=org.gnunet.transport.BlacklistQueryMessage
 
org.gnunet.util.GnunetMessage$Body|380=org.gnunet.transport.AddressIterateMessage
-org.gnunet.util.GnunetMessage$Body|496=org.gnunet.testbed.HelperReplyMessage
-org.gnunet.util.GnunetMessage$Body|495=org.gnunet.testbed.HelperInitMessage
+org.gnunet.util.GnunetMessage$Body|496=org.gnunet.testbed.messages.HelperReplyMessage
+org.gnunet.util.GnunetMessage$Body|495=org.gnunet.testbed.messages.HelperInitMessage
 org.gnunet.util.GnunetMessage$Body|360=org.gnunet.transport.StartMessage
 org.gnunet.construct.MessageUnion|525=org.gnunet.consensus.ConcludeDoneMessage
-# generated 2013/09/04 11:05:50
+# generated 2013/09/11 02:53:45

Modified: gnunet-java/src/main/resources/org/gnunet/voting/template.espec
===================================================================
--- gnunet-java/src/main/resources/org/gnunet/voting/template.espec     
2013-09-11 11:19:59 UTC (rev 29195)
+++ gnunet-java/src/main/resources/org/gnunet/voting/template.espec     
2013-09-11 11:28:31 UTC (rev 29196)
@@ -14,26 +14,48 @@
 # must be later than ELECTION_START
 ELECTION_END =
 
+# At what time must an authority complete round X of the voting protocol
+# (fixme: need to define exactly which rounds there will be...)
+AUTHORITY_ROUND_X_TIME =
+
 # peer identity of the certificate authority for voting eligibility
-CA =
+# currently the CA is a single peer, this may change in the future
+CA_PEER =
 
+# public key of the certificate authority
+CA_PUB =
+
 # public key of the election issuer
-ISSUER_PUB =
+# ISSUER_PUB =
 
-# the signature of the issuer will be filled in by gnunet-vote-call
-# ISSUER_SIGNATURE =
 
-# At what time must an authority complete round X of the voting protocol
-# (fixme: need to define exactly which rounds there will be...)
-AUTHORITY_ROUND_X_TIME = 
-
 [authorities]
 # specified as <authority-alias> = <peer-identity>, one entry for each 
authority; e.g.
 # awesome_authority_one = 123abc
 
 
-[authority-affirmation]
+[registration-authorities]
 # will be filled in by gnunet-vote-call once
 # authorities agreed to participate, with one entry per authority
 # <authority-alias> = <signature>
-# where the signature is on the
+
+
+[registration-issuer]
+# the signature of the issuer will be filled in by gnunet-vote-call,
+# signing the sections 'election' and 'authorities'
+# ISSUER_SIGNATURE =
+
+
+[voter]
+# before a voter can submit his vote, the permission to do so
+# must be given by the certificate authority of the election
+# VOTER_PUB = ...
+# VOTER_CERT = ...
+
+
+[vote-data]
+# encrypted vote and non-interactive zero knowledge proofs come here
+
+
+[vouchers]
+# signatures by the authorities that counted the ballot, in the form of 
<alias> = <sig>

Modified: gnunet-java/src/test/java/org/gnunet/testbed/TestbedTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/testbed/TestbedTest.java       
2013-09-11 11:19:59 UTC (rev 29195)
+++ gnunet-java/src/test/java/org/gnunet/testbed/TestbedTest.java       
2013-09-11 11:28:31 UTC (rev 29196)
@@ -1,22 +1,22 @@
 package org.gnunet.testbed;
 
 
+import org.gnunet.testbed.callbacks.ControllerEventCallback;
+import org.gnunet.testbed.callbacks.ControllerStatusCallback;
+import org.gnunet.testbed.callbacks.PeerCreateCallback;
 import org.gnunet.testing.TestingFixture;
 import org.gnunet.util.Configuration;
 import org.gnunet.util.Program;
-import org.gnunet.util.Scheduler;
 import org.gnunet.util.Wrapper;
 import org.junit.Assert;
 import org.junit.Test;
 
 public class TestbedTest extends TestingFixture {
 
-
     @Test
     public void test_controller_proc() {
         final Wrapper<Boolean> success = new Wrapper<Boolean>(false);
-        new Program() {
-
+        new Program("-LDEBUG") {
             @Override
             public void run() {
                 // use local peer's config, does that really make sense?
@@ -31,11 +31,59 @@
                     @Override
                     public void onStartupFailure() {
                         Assert.fail();
-                        //To change body of implemented methods use File | 
Settings | File Templates.
                     }
                 });
             }
         }.start();
         Assert.assertTrue(success.get());
     }
+
+
+
+
+    @Test
+    public void test_peer_create() {
+        new Program("-LDEBUG") {
+            ControllerProc cp;
+            Host h;
+            Controller c;
+
+            class CEC extends ControllerEventCallback {
+            }
+
+            class PCB implements PeerCreateCallback {
+                @Override
+                public void onPeerCreated(Controller.Peer peer) {
+                    System.out.println("peer created!");
+                    c.disconnect();
+                    cp.stop();
+                }
+
+                @Override
+                public void onError(String errorMessage) {
+                    Assert.fail();
+                }
+            }
+
+            @Override
+            public void run() {
+                // use local peer's config, does that really make sense?
+                h = new Host(null, null, getConfiguration(), 0);
+                cp = new ControllerProc();
+                cp.start("127.0.0.1", h, new ControllerStatusCallback() {
+                    @Override
+                    public void onStartupSuccess(Configuration cfg) {
+                        System.out.println("startup success");
+                        c = new Controller(h, 1 | 2 | 4 | 8 | 32, new CEC());
+                        // FIXME: use config from resource
+                        c.createPeer(h, getConfiguration(), new PCB());
+                    }
+                    @Override
+                    public void onStartupFailure() {
+                        Assert.fail();
+                    }
+                });
+            }
+        }.start();
+    }
 }

Modified: gnunet-java/src/test/java/org/gnunet/util/CryptoECCTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/util/CryptoECCTest.java        
2013-09-11 11:19:59 UTC (rev 29195)
+++ gnunet-java/src/test/java/org/gnunet/util/CryptoECCTest.java        
2013-09-11 11:28:31 UTC (rev 29196)
@@ -14,7 +14,7 @@
     public void test_sign_success() {
         Random r = new Random();
         // the test uses random data, repeat it multiple times!
-        for (int i = 0; i < 10; i++) {
+        for (int i = 0; i < 5; i++) {
             byte[] msg = new byte[16];
             r.nextBytes(msg);
 
@@ -22,11 +22,11 @@
             privateKey.d = new byte[32];
             r.nextBytes(privateKey.d);
             CryptoECC.PublicKey publicKey = 
CryptoECC.computePublicKey(privateKey);
-
+            System.out.println("gen");
             CryptoECC.Signature sig = CryptoECC.sign(msg, privateKey, 
publicKey);
-
+            System.out.println("sign");
             boolean valid = CryptoECC.verify(sig, msg, publicKey);
-
+            System.out.println("verify");
             Assert.assertTrue(valid);
         }
     }
@@ -38,21 +38,20 @@
     public void test_sign_failure() {
         Random r = new Random();
         // the test uses random data, repeat it multiple times!
-        for (int i = 0; i < 10; i++) {
+        for (int i = 0; i < 5; i++) {
             byte[] msg = new byte[16];
             r.nextBytes(msg);
-
             CryptoECC.PrivateKey privateKey = new CryptoECC.PrivateKey();
             privateKey.d = new byte[32];
             r.nextBytes(privateKey.d);
             CryptoECC.PublicKey publicKey = 
CryptoECC.computePublicKey(privateKey);
-
+            System.out.println("gen");
             CryptoECC.Signature sig = CryptoECC.sign(msg, privateKey, 
publicKey);
-
+            System.out.println("sign");
+            // corrupt the message
             msg[0] = (byte) (msg[0] + 1);
-
             boolean valid = CryptoECC.verify(sig, msg, publicKey);
-
+            System.out.println("verify");
             Assert.assertFalse(valid);
         }
     }




reply via email to

[Prev in Thread] Current Thread [Next in Thread]