gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] r30015 - in gnunet-java: . bin src/main/java/org/gnunet src


From: gnunet
Subject: [GNUnet-SVN] r30015 - in gnunet-java: . bin src/main/java/org/gnunet src/main/java/org/gnunet/arm src/main/java/org/gnunet/arm/messages src/main/java/org/gnunet/construct/parsers src/main/java/org/gnunet/identity src/main/java/org/gnunet/identity/messages src/main/java/org/gnunet/mq src/main/java/org/gnunet/testbed src/main/java/org/gnunet/testbed/callbacks src/main/java/org/gnunet/testbed/messages src/main/java/org/gnunet/util src/main/java/org/gnunet/voting src/main/java/org/gnunet/voting/messages src/main/resources/org/gnunet/construct src/main/resources/org/gnunet/voting src/test/java/org/gnunet src/test/java/org/gnunet/identity src/test/java/org/gnunet/testbed src/test/java/org/gnunet/util
Date: Tue, 8 Oct 2013 23:22:43 +0200

Author: dold
Date: 2013-10-08 23:22:43 +0200 (Tue, 08 Oct 2013)
New Revision: 30015

Added:
   gnunet-java/bin/gnunet-ballot
   gnunet-java/bin/gnunet-daemon-ballot-ca
   gnunet-java/bin/gnunet-daemon-ballot-tally
   gnunet-java/src/main/java/org/gnunet/arm/
   gnunet-java/src/main/java/org/gnunet/arm/Arm.java
   gnunet-java/src/main/java/org/gnunet/arm/ArmMonitor.java
   gnunet-java/src/main/java/org/gnunet/arm/ResultHandler.java
   gnunet-java/src/main/java/org/gnunet/arm/ServiceListHandler.java
   gnunet-java/src/main/java/org/gnunet/arm/ServiceStatusHandler.java
   gnunet-java/src/main/java/org/gnunet/arm/messages/
   gnunet-java/src/main/java/org/gnunet/arm/messages/ListResultMessage.java
   gnunet-java/src/main/java/org/gnunet/arm/messages/RequestMessage.java
   gnunet-java/src/main/java/org/gnunet/arm/messages/ResultMessage.java
   gnunet-java/src/main/java/org/gnunet/arm/messages/StatusMessage.java
   gnunet-java/src/main/java/org/gnunet/identity/
   gnunet-java/src/main/java/org/gnunet/identity/Identity.java
   gnunet-java/src/main/java/org/gnunet/identity/IdentityCallback.java
   gnunet-java/src/main/java/org/gnunet/identity/IdentityContinuation.java
   gnunet-java/src/main/java/org/gnunet/identity/IdentityListCallback.java
   gnunet-java/src/main/java/org/gnunet/identity/messages/
   
gnunet-java/src/main/java/org/gnunet/identity/messages/CreateRequestMessage.java
   gnunet-java/src/main/java/org/gnunet/identity/messages/DeleteMessage.java
   gnunet-java/src/main/java/org/gnunet/identity/messages/GetDefaultMessage.java
   gnunet-java/src/main/java/org/gnunet/identity/messages/RenameMessage.java
   gnunet-java/src/main/java/org/gnunet/identity/messages/ResultCodeMessage.java
   gnunet-java/src/main/java/org/gnunet/identity/messages/SetDefaultMessage.java
   gnunet-java/src/main/java/org/gnunet/identity/messages/StartMessage.java
   gnunet-java/src/main/java/org/gnunet/identity/messages/UpdateListMessage.java
   gnunet-java/src/main/java/org/gnunet/util/MessageStreamTokenizer.java
   gnunet-java/src/main/java/org/gnunet/util/MstCalllback.java
   gnunet-java/src/main/java/org/gnunet/voting/CertificateAuthorityDaemon.java
   gnunet-java/src/main/java/org/gnunet/voting/CertifyGroupCommand.java
   
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterFailureMessage.java
   
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterSuccessMessage.java
   
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateDenyMessage.java
   
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateGrantMessage.java
   
gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitFailureMessage.java
   
gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitSuccessMessage.java
   gnunet-java/src/test/java/org/gnunet/identity/
   gnunet-java/src/test/java/org/gnunet/identity/IdentityTest.java
Removed:
   
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/ControllerEventCallback.java
   gnunet-java/src/main/java/org/gnunet/voting/CertificateAuthorityService.java
   gnunet-java/src/main/java/org/gnunet/voting/PermissionCommand.java
   
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterRespondMessage.java
   
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateResponseMessage.java
   
gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitResponseMessage.java
Modified:
   gnunet-java/ISSUES
   gnunet-java/src/main/java/org/gnunet/construct/parsers/FillParser.java
   gnunet-java/src/main/java/org/gnunet/construct/parsers/StringParser.java
   gnunet-java/src/main/java/org/gnunet/mq/MessageQueue.java
   gnunet-java/src/main/java/org/gnunet/testbed/Controller.java
   
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerInformationMessage.java
   gnunet-java/src/main/java/org/gnunet/util/AbsoluteTime.java
   gnunet-java/src/main/java/org/gnunet/util/Connection.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/Scheduler.java
   gnunet-java/src/main/java/org/gnunet/util/Server.java
   gnunet-java/src/main/java/org/gnunet/util/Service.java
   gnunet-java/src/main/java/org/gnunet/voting/Ballot.java
   gnunet-java/src/main/java/org/gnunet/voting/BallotTool.java
   gnunet-java/src/main/java/org/gnunet/voting/RegisterCommand.java
   gnunet-java/src/main/java/org/gnunet/voting/SubmitCommand.java
   gnunet-java/src/main/java/org/gnunet/voting/TallyAuthorityDaemon.java
   
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterRequestMessage.java
   
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateRequestMessage.java
   gnunet-java/src/main/java/org/gnunet/voting/messages/QueryFailureMessage.java
   gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitMessage.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:
- identity service implemented
- started with arm implementation
- removed locking from scheduler
- separated TaskConfiguration and TaskIdentifier
- implemented proper message stream tokenizer
- work on voting


Modified: gnunet-java/ISSUES
===================================================================
--- gnunet-java/ISSUES  2013-10-08 20:56:51 UTC (rev 30014)
+++ gnunet-java/ISSUES  2013-10-08 21:22:43 UTC (rev 30015)
@@ -1,91 +1,46 @@
-== testbed ==
+testbed api is now quite complete
+ * problem with reconfigure was a bug in the testbed service
+ * only thing left to to is to implement arm for manageService
+  * (BUT: I don't get how arm works in conjunction with testbed -- when the 
arm api can't connect to
+    arm it tries to start the arm service *locally*, which is often wrong ...)
+  * talked to sriharsha about it
 
-padding: PACKED / NETWORK_STRUCT don't really pack some misaligned structs:
-  struct GNUNET_TESTBED_PeerConfigurationInformationMessage
-is misaligned anyway, *but* sizeof the struct is 84, when it should be 82!
+gnunet-java finally has a proper stream tokenizer ...
+ * and locking has been removes from Scheduler, Helper is properly implemented
 
-see https://gnunet.org/bugs/view.php?id=3043
+new java API implementation for identity :)
+ * why is there no way to import keys?
+  * at least API-wise
+ * voting should use identity ...
 
-I managed to break testbed (this is a GNUNET_assert, no GNUNET_break)
-  Sep 24 20:06:14-146897 testbed-18586 ERROR Assertion failed at 
testing.c:1548.
-but this only occurs *after* the shutdown and when trying to reconfigure a 
peer!
+timing information in ballot: we talked about round times,
+but shouldn't this be done transparently by consensus?
+aren't START_TIME, CLOSING_TIME, QUERY_TIME, END_TIME and maybe 
CONSENSUS_PARAMS be enough?
 
-OPTIONS/PREFIX does not work with testbed helper
+certificate authority: is the CAs pubkey different from its peer?
+ * it definitely makes sense to have it seperate for other cert methods
+  * like sending a cert per email, snail mail, social network ...
+ * how do we specify how to reach the cert? one peer? multiple peers?
+  * maybe use GADS? (I know very little about GADS right now)
+ * does it even make sense to have the CA service at this time?
 
-what works (and is tested) now in org.gnunet.testbed:
- * creating and destroying peers
- * starting and stopping peers
- * getting peer id / configuration
- * overlay-connecting two peers
-other stuff:
- * does gnunet-java need barriers?
- * what's the state of the overlay implementation
- * does service_connect do anything other than retrieve the configuration?
-  * primary purpose is to be able to have opqueue management, right?
- * why do we have manage service when we have arm?
-  * someone has to start arm, I suppose?
-
-== crypto ==
-two types of public keys, do I understand the reasons correctly:
- * NaCl compatibility
- * fastest representation for each type of operation
-
-why is there no way to convert from signing key -> encryption key?
- * other way around is not possible
-
-
-== voting ==
-
 what now works:
- * creating a ballot and registering it
- * selecting a choice in the ballot and submitting it
-  * vote + 512-bit ballot GUID
- * querying the results (also with the GUID)
+ * authorities check for double vote submission, late / early voting, early 
result query,
+   double registering, vouchers (I don't like to call vouchers receipts 
because that term has
+   a certain meaning in voting literature already)
 
-next steps??
-- Ballot: (a) voter ID, (b) election information, (c) election eligibility 
group (Bavaria 18+), (d) ballot GUID
-- no double submission: check: no duplicate voter ID (for any given election)
-- no early queries
-- voter <--> CA interaction
-  => ideally, CA has a list of voter public keys or at least a policy (i.e. 
"accept all") 
-     for a certain voter group (i.e. Bavaria 18+). 
-  => CA also has a private CA key (surprise!)
-  => Voter has voter public key and voter group, sends THOSE to CA;
-  => CA signs: this voter is in this voter group (with expiration time for 
signature!)
-  => voter takes signature, can re-use it for ALL elections with this voter 
group
-- Authorities have CA public keys, check voter group sigs.
+but: group certs are not checked right now
 
-what should be stored in the ballot about authorities: peer identities or peer 
public keys?
-=> public keys
+how to test voting without waiting too long or missing the right time?
 
- * pubkey makes more sense, but I have the feeling that GNUnet prefers to use
-   peer IDs whenever possible
-=> Nah.
+any progress on crypto?
+ * luckily the private key has the same size, so identity can be used
 
-docs of identity service say:
-  For giving names to other users and manage their public keys securely, we 
use GNS.
-In what way does GNS manage public keys? 
-  GNS allows you to give names to other user's public keys.
-Does GNS in any way relate peer identities to public keys?
-  No.
+next:
+ * use identity
+ * multiple authorities should do consensus on unencrypted votes
+ * tests for this with testbed
+ * encrypting votes
 
-persistent storage of tallies?
-  => Later.
+suggestions?
 
-now that the pubkey is smaller, are there reasons for still having
-a separate peer identity?
- * except for that it would be a lot of work to change now
-=> exactly.
-
-the command line took looks a bit complicated now, any suggestions?
-=> Later.
-
-asking permission to vote should not require the private key, right?
- * how do we do this interface-wise? pubkey on the command line?
-=> Identity service, ego!
-
-== general java stuff ==
-what's your opinion on option types: should they be used more in gnunet-java?
-
-We have a lot of callbacks in java that all do almost the same. Should we have 
a generic callback type?
-

Added: gnunet-java/bin/gnunet-ballot
===================================================================
--- gnunet-java/bin/gnunet-ballot                               (rev 0)
+++ gnunet-java/bin/gnunet-ballot       2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+if [ "%GNJ_INSTALLED" = "true" ];
+then
+    export CLASSPATH="%INSTALL_PATH/share/java/*"
+else
+    DIR=`dirname $0`
+    # if we are in the development environment use class files directly 
instead of jar
+    export 
CLASSPATH="$DIR/../build-gradle/classes/main/:$DIR/../build-gradle/resources/main/:$DIR/../lib/*"
+fi
+
+java -ea org.gnunet.voting.BallotTool "$@"


Property changes on: gnunet-java/bin/gnunet-ballot
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: gnunet-java/bin/gnunet-daemon-ballot-ca
===================================================================
--- gnunet-java/bin/gnunet-daemon-ballot-ca                             (rev 0)
+++ gnunet-java/bin/gnunet-daemon-ballot-ca     2013-10-08 21:22:43 UTC (rev 
30015)
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+if [ "%GNJ_INSTALLED" = "true" ];
+then
+    export CLASSPATH="%INSTALL_PATH/share/java/*"
+else
+    DIR=`dirname $0`
+    # if we are in the development environment use class files directly 
instead of jar
+    export 
CLASSPATH="$DIR/../build-gradle/classes/main/:$DIR/../build-gradle/resources/main/:$DIR/../lib/*"
+fi
+
+java -ea org.gnunet.voting.CertificateAuthorityDaemon "$@"


Property changes on: gnunet-java/bin/gnunet-daemon-ballot-ca
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: gnunet-java/bin/gnunet-daemon-ballot-tally
===================================================================
--- gnunet-java/bin/gnunet-daemon-ballot-tally                          (rev 0)
+++ gnunet-java/bin/gnunet-daemon-ballot-tally  2013-10-08 21:22:43 UTC (rev 
30015)
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+if [ "%GNJ_INSTALLED" = "true" ];
+then
+    export CLASSPATH="%INSTALL_PATH/share/java/*"
+else
+    DIR=`dirname $0`
+    # if we are in the development environment use class files directly 
instead of jar
+    export 
CLASSPATH="$DIR/../build-gradle/classes/main/:$DIR/../build-gradle/resources/main/:$DIR/../lib/*"
+fi
+
+java -ea org.gnunet.voting.TallyAuthorityDaemon "$@"


Property changes on: gnunet-java/bin/gnunet-daemon-ballot-tally
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: gnunet-java/src/main/java/org/gnunet/arm/Arm.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/arm/Arm.java                           
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/arm/Arm.java   2013-10-08 21:22:43 UTC 
(rev 30015)
@@ -0,0 +1,70 @@
+/*
+ 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.arm;
+
+import org.gnunet.util.Client;
+import org.gnunet.util.Configuration;
+
+/**
+ * API for the Automatic Restart Manager (ARM)
+ */
+public class Arm {
+    private final Configuration configuration;
+    private Client client;
+    public Arm(Configuration configuration) {
+        this.configuration = configuration;
+        client = new Client("arm", configuration);
+    }
+
+    /**
+     * Disconnect from ARM, the Arm object may not be used afterwards.
+     */
+    public void disconnect() {
+        client.disconnect();
+    }
+    public void requestServiceList(ServiceListHandler serviceListHandler) {
+
+    }
+
+    /**
+     * Request a service to be stopped.
+     * Stopping arm itself will not invalidate its handle, and
+     * ARM API will try to restore connection to the ARM service,
+     * even if ARM connection was lost because you asked for ARM to be stopped.
+     * Call Arm.disconnect to free the handle and prevent
+     * further connection attempts.
+     *
+     * @param serviceName name of the service
+     * @param resultHandler called with the result of the request
+     */
+    public void requestServiceStop(String serviceName, ResultHandler 
resultHandler) {
+
+    }
+
+    /**
+     * Request for a service to be started.
+     *
+     * @param serviceName name of the service
+     */
+    public void requestServiceStart(String serviceName, ResultHandler 
resultHandler) {
+
+    }
+}

Added: gnunet-java/src/main/java/org/gnunet/arm/ArmMonitor.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/arm/ArmMonitor.java                    
        (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/arm/ArmMonitor.java    2013-10-08 
21:22:43 UTC (rev 30015)
@@ -0,0 +1,27 @@
+/*
+ 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.arm;
+
+/**
+ * API for monitoring ARM services.
+ */
+public class ArmMonitor  {
+}

Added: gnunet-java/src/main/java/org/gnunet/arm/ResultHandler.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/arm/ResultHandler.java                 
        (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/arm/ResultHandler.java 2013-10-08 
21:22:43 UTC (rev 30015)
@@ -0,0 +1,31 @@
+/*
+ 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.arm;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: dold
+ * Date: 10/7/13
+ * Time: 4:00 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public interface ResultHandler {
+}

Added: gnunet-java/src/main/java/org/gnunet/arm/ServiceListHandler.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/arm/ServiceListHandler.java            
                (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/arm/ServiceListHandler.java    
2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,28 @@
+/*
+ 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.arm;
+
+
+import java.util.List;
+
+public interface ServiceListHandler {
+    void onServiceList(List<String> services);
+}

Added: gnunet-java/src/main/java/org/gnunet/arm/ServiceStatusHandler.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/arm/ServiceStatusHandler.java          
                (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/arm/ServiceStatusHandler.java  
2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,25 @@
+/*
+ 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.arm;
+
+public interface ServiceStatusHandler {
+
+}

Added: gnunet-java/src/main/java/org/gnunet/arm/messages/ListResultMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/arm/messages/ListResultMessage.java    
                        (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/arm/messages/ListResultMessage.java    
2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,41 @@
+/*
+ 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.arm.messages;
+
+import org.gnunet.construct.*;
+import org.gnunet.util.GnunetMessage;
+
address@hidden(13)
+public class ListResultMessage implements GnunetMessage.Body {
+    public class StringMessage implements Message {
+        @ZeroTerminatedString
+        public String string;
+    }
+
+    @UInt64
+    public long requestId;
+
+    @UInt16
+    public int count;
+
+    @FillWith
+    public StringMessage[] services;
+}

Added: gnunet-java/src/main/java/org/gnunet/arm/messages/RequestMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/arm/messages/RequestMessage.java       
                        (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/arm/messages/RequestMessage.java       
2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,25 @@
+/*
+ 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.arm.messages;
+
+
+public class RequestMessage {
+}

Added: gnunet-java/src/main/java/org/gnunet/arm/messages/ResultMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/arm/messages/ResultMessage.java        
                        (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/arm/messages/ResultMessage.java        
2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,35 @@
+/*
+ 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.arm.messages;
+
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UInt64;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+
address@hidden(10)
+public class ResultMessage implements GnunetMessage.Body {
+    @UInt64
+    public long requestId;
+
+    @UInt32
+    public int result;
+}

Added: gnunet-java/src/main/java/org/gnunet/arm/messages/StatusMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/arm/messages/StatusMessage.java        
                        (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/arm/messages/StatusMessage.java        
2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,61 @@
+/*
+ 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.
+ */
+
+/*
+ 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.arm.messages;
+
+import org.gnunet.construct.*;
+import org.gnunet.util.GnunetMessage;
+
address@hidden(11)
+public class StatusMessage implements GnunetMessage.Body {
+    public class StringMessage implements Message {
+        @ZeroTerminatedString
+        public String string;
+    }
+
+    @UInt64
+    public long requestId;
+
+    @UInt32
+    public int status;
+
+    @ZeroTerminatedString
+    public String serviceName;
+}

Modified: gnunet-java/src/main/java/org/gnunet/construct/parsers/FillParser.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/parsers/FillParser.java      
2013-10-08 20:56:51 UTC (rev 30014)
+++ gnunet-java/src/main/java/org/gnunet/construct/parsers/FillParser.java      
2013-10-08 21:22:43 UTC (rev 30015)
@@ -66,15 +66,12 @@
             throw new AssertionError("FillParser expects a non-null 
frameSizePath. Does the message have a @FrameSizePath annotation?");
         }
 
-
-
         final int frameSize = ReflectUtil.justGetInt(dstObj, frameSizePath);
         int remaining = frameOffset + frameSize - srcBuf.position();
         int size = 0;
 
         Class<?> elemType = targetField.getType().getComponentType();
 
-
         ArrayList<Message> list = new ArrayList<Message>(10);
 
         while (remaining > 0) {

Modified: 
gnunet-java/src/main/java/org/gnunet/construct/parsers/StringParser.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/parsers/StringParser.java    
2013-10-08 20:56:51 UTC (rev 30014)
+++ gnunet-java/src/main/java/org/gnunet/construct/parsers/StringParser.java    
2013-10-08 21:22:43 UTC (rev 30015)
@@ -67,7 +67,7 @@
             if (frameSizePath == null) {
                 throw new AssertionError("optional string with no length field 
in the message!");
             }
-            final int frameSize = ReflectUtil.justGetInt(dstObj, 
frameSizePath);
+            final int frameSize = ReflectUtil.justGetInt(frameObj, 
frameSizePath);
             int remaining = frameOffset + frameSize - srcBuf.position();
 
             if (remaining == 0) {
@@ -79,6 +79,11 @@
             }
         }
 
+        if (!srcBuf.hasRemaining()) {
+            throw new ProtocolViolationException("no data for non-optional 
string field " +
+                targetField);
+        }
+
         int length = 0;
 
         while (srcBuf.get(srcBuf.position() + length) != 0) {

Added: gnunet-java/src/main/java/org/gnunet/identity/Identity.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/identity/Identity.java                 
        (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/identity/Identity.java 2013-10-08 
21:22:43 UTC (rev 30015)
@@ -0,0 +1,344 @@
+/*
+ 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.identity;
+
+
+import com.google.common.collect.Lists;
+import org.gnunet.identity.messages.*;
+import org.gnunet.mq.Envelope;
+import org.gnunet.requests.RequestContainer;
+import org.gnunet.requests.SequentialRequestContainer;
+import org.gnunet.util.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+public class Identity {
+    private static final Logger logger = LoggerFactory
+            .getLogger(Identity.class);
+    private Configuration configuration;
+    private SequentialRequestContainer<IdentityRequest> requests;
+    private Client client;
+    private IdentityListCallback identityListCallback;
+    private List<Ego> knownEgos = Lists.newLinkedList();
+
+    private static Ego anonymousEgo;
+
+    public static class Ego {
+        private String name;
+        private CryptoECC.PrivateKey privateKey;
+
+        public Ego(String egoName, CryptoECC.PrivateKey privateKey) {
+            this.name = egoName;
+            this.privateKey = privateKey;
+        }
+        public CryptoECC.PrivateKey getPrivateKey() {
+            return privateKey;
+        }
+        public CryptoECC.PublicSignKey getPublicKey() {
+            return CryptoECC.computePublicKey(privateKey);
+        }
+        public String getName() {
+            return name;
+        }
+    }
+
+    public abstract class IdentityRequest extends RequestContainer.Request {
+
+        public void onError(String errorMessage) {
+            throw new AssertionError("unexpected error message: " + 
errorMessage);
+        }
+
+        public void onResult() {
+            throw new AssertionError("unexpected result");
+        }
+    }
+
+    public class GetDefaultRequest extends IdentityRequest {
+        IdentityCallback identityCallback;
+        String serviceName;
+        GetDefaultRequest(String serviceName, IdentityCallback 
identityCallback) {
+            this.identityCallback = identityCallback;
+            this.serviceName = serviceName;
+        }
+        @Override
+        public Envelope assembleRequest() {
+            GetDefaultMessage m = new GetDefaultMessage();
+            m.nameLength = serviceName.length() + 1;
+            m.serviceName = serviceName;
+            return new Envelope(m);
+        }
+
+        @Override
+        public void onError(String errorMessage) {
+            identityCallback.onError(errorMessage);
+        }
+    }
+
+    public class SetDefaultRequest extends IdentityRequest {
+        IdentityContinuation cont;
+        String serviceName;
+        Ego ego;
+        SetDefaultRequest(String serviceName, Ego ego) {
+            this.serviceName = serviceName;
+            this.ego = ego;
+        }
+        @Override
+        public Envelope assembleRequest() {
+            SetDefaultMessage m = new SetDefaultMessage();
+            m.nameLength = serviceName.length() + 1;
+            m.serviceName = serviceName;
+            m.privateKey = ego.privateKey;
+            return new Envelope(m);
+        }
+        @Override
+        public void onError(String errorMessage) {
+            cont.onError(errorMessage);
+        }
+        @Override
+        public void onResult() {
+            cont.onDone();
+        }
+    }
+
+    public class RenameRequest extends IdentityRequest {
+        IdentityContinuation cont;
+        String oldName;
+        String newName;
+        RenameRequest(String newName, String oldName) {
+            this.oldName = oldName;
+            this.newName = newName;
+        }
+        @Override
+        public Envelope assembleRequest() {
+            RenameMessage m = new RenameMessage();
+            m.newName = newName;
+            m.newNameLength = newName.length() + 1;
+            m.oldName = oldName;
+            m.oldNameLength = oldName.length() + 1;
+            return new Envelope(m);
+        }
+        @Override
+        public void onError(String errorMessage) {
+            cont.onError(errorMessage);
+        }
+        @Override
+        public void onResult() {
+            cont.onDone();
+        }
+    }
+
+    public class DeleteRequest extends IdentityRequest {
+        IdentityContinuation cont;
+        String name;
+        DeleteRequest(String name) {
+            this.name = name;
+        }
+        @Override
+        public Envelope assembleRequest() {
+            DeleteMessage m = new DeleteMessage();
+            m.name = name;
+            m.nameLength = name.length() + 1;
+            return new Envelope(m);
+        }
+        @Override
+        public void onError(String errorMessage) {
+            cont.onError(errorMessage);
+        }
+        @Override
+        public void onResult() {
+            cont.onDone();
+        }
+    }
+
+    public class CreateRequest extends IdentityRequest {
+        final CryptoECC.PrivateKey privateKey;
+        IdentityContinuation cont;
+        String name;
+        CreateRequest(String name, CryptoECC.PrivateKey privateKey, 
IdentityContinuation cont) {
+            this.cont = cont;
+            this.privateKey = privateKey;
+            this.name = name;
+        }
+        @Override
+        public Envelope assembleRequest() {
+            CreateRequestMessage m = new CreateRequestMessage();
+            m.name = name;
+            m.nameLength = name.length() + 1;
+            m.privateKey = privateKey;
+            return new Envelope(m);
+        }
+        @Override
+        public void onError(String errorMessage) {
+            cont.onError(errorMessage);
+        }
+
+        @Override
+        public void onResult() {
+            cont.onDone();
+        }
+    }
+
+    public static Ego getAnonymousEgo() {
+        if (anonymousEgo == null) {
+            anonymousEgo = new Ego(null, CryptoECC.getAnonymous());
+        }
+        return anonymousEgo;
+    }
+
+
+    public Identity() {
+        // do nothing
+    }
+
+    public void connect(Configuration configuration, IdentityListCallback 
identityListCallback) {
+        this.configuration = configuration;
+        this.client = new Client("identity", configuration);
+        this.client.installReceiver(new IdentityReceiver());
+        requests = new 
SequentialRequestContainer<IdentityRequest>(this.client);
+        this.identityListCallback = identityListCallback;
+        StartMessage m = new StartMessage();
+        client.send(m);
+    }
+
+    public Cancelable get(String serviceName, IdentityCallback 
identityCallback) {
+        return requests.addRequest(new GetDefaultRequest(serviceName, 
identityCallback));
+    }
+
+    /**
+     * Set the default ego for a service.
+     *
+     * @param serviceName service
+     * @param ego ego
+     * @return object for cancellation
+     */
+    public Cancelable set(String serviceName, Ego ego) {
+        return requests.addRequest(new SetDefaultRequest(serviceName, ego));
+    }
+
+    public void disconnect() {
+        client.disconnect();
+        client = null;
+    }
+
+    /**
+     * Create a new ego with the given name.
+     *
+     * @param name ego name
+     * @param cont continuation
+     * @return object for cancellation
+     */
+    public Cancelable create(String name, IdentityContinuation cont) {
+        CryptoECC.PrivateKey privateKey = CryptoECC.PrivateKey.createRandom();
+        return requests.addRequest(new CreateRequest(name, privateKey, cont));
+    }
+
+    /**
+     * Rename an ego.
+     *
+     * @param oldName old name of the ego
+     * @param newName new name of the ego
+     * @return object for cancellation
+     */
+    public Cancelable rename(String oldName, String newName) {
+        return requests.addRequest(new RenameRequest(newName, oldName));
+    }
+
+    /**
+     * Delete an ego.
+     *
+     * @param name name of the ego to delete
+     * @return object for cancellation
+     */
+    public Cancelable delete(String name) {
+        return requests.addRequest(new DeleteRequest(name));
+    }
+
+    private Ego getEgoForKey(CryptoECC.PrivateKey privateKey) {
+        for (Ego ex : knownEgos) {
+            if (ex.privateKey.equals(privateKey)) {
+                return ex;
+            }
+        }
+        return null;
+    }
+
+    public class IdentityReceiver extends RunaboutMessageReceiver {
+        @Override
+        public void handleError() {
+            logger.warn("identity service disconnected");
+            client.reconnect();
+        }
+
+        public void visit(ResultCodeMessage m) {
+            IdentityRequest r = requests.getRequest();
+            if (null == r) {
+                logger.warn("unsolicited result code message");
+                return;
+            }
+            if (m.errorMessage != null) {
+                r.onError(m.errorMessage);
+            } else {
+                r.onResult();
+            }
+            requests.next();
+        }
+
+        public void visit(SetDefaultMessage m) {
+            IdentityRequest r = requests.getRequest();
+            if (!(r instanceof GetDefaultRequest)) {
+                logger.error("unexpected 'default ego' response");
+                return;
+            }
+            GetDefaultRequest gdr = (GetDefaultRequest) r;
+            Ego ego = getEgoForKey(m.privateKey);
+            if (null != ego)
+                gdr.identityCallback.onEgo(ego);
+        }
+
+        public void visit(final UpdateListMessage m) {
+            if (m.endOfList != 0) {
+                identityListCallback.onListEnd();
+                return;
+            }
+            if (m.nameLength == 0) {
+                Ego e = getEgoForKey(m.privateKey);
+                if (null != e) {
+                    knownEgos.remove(e);
+                }
+                identityListCallback.onEgoDelete(e);
+            } else {
+                Ego existingEgo = getEgoForKey(m.privateKey);
+                if (existingEgo == null) {
+                    Ego ego = new Ego(m.egoName, m.privateKey);
+                    knownEgos.add(ego);
+                    identityListCallback.onEgoAdd(ego);
+                } else {
+                    // rename
+                    String oldName = existingEgo.name;
+                    existingEgo.name = m.egoName;
+                    identityListCallback.onEgoRename(oldName, existingEgo);
+                }
+            }
+        }
+    }
+}

Added: gnunet-java/src/main/java/org/gnunet/identity/IdentityCallback.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/identity/IdentityCallback.java         
                (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/identity/IdentityCallback.java 
2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,27 @@
+/*
+ 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.identity;
+
+public interface IdentityCallback {
+    void onEgo(Identity.Ego ego);
+
+    void onError(String errorMessage);
+}

Added: gnunet-java/src/main/java/org/gnunet/identity/IdentityContinuation.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/identity/IdentityContinuation.java     
                        (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/identity/IdentityContinuation.java     
2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,26 @@
+/*
+ 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.identity;
+
+public interface IdentityContinuation {
+    void onError(String errorMessage);
+    void onDone();
+}

Added: gnunet-java/src/main/java/org/gnunet/identity/IdentityListCallback.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/identity/IdentityListCallback.java     
                        (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/identity/IdentityListCallback.java     
2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,29 @@
+/*
+ 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.identity;
+
+
+public interface IdentityListCallback {
+    void onEgoAdd(Identity.Ego ego);
+    void onEgoDelete(Identity.Ego ego);
+    void onEgoRename(String oldName, Identity.Ego ego);
+    void onListEnd();
+}

Added: 
gnunet-java/src/main/java/org/gnunet/identity/messages/CreateRequestMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/identity/messages/CreateRequestMessage.java
                            (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/identity/messages/CreateRequestMessage.java
    2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,63 @@
+/*
+ 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.
+ */
+
+/*
+ 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.identity.messages;
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UInt16;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.construct.ZeroTerminatedString;
+import org.gnunet.util.CryptoECC;
+import org.gnunet.util.GnunetMessage;
+
address@hidden(629)
+public class CreateRequestMessage implements GnunetMessage.Body {
+    /**
+     * Length of the name, INCLUDING the 0-terminator.
+     */
+    @UInt16
+    public int nameLength;
+    @UInt16
+    public int reserved;
+    @NestedMessage
+    public CryptoECC.PrivateKey privateKey;
+    @ZeroTerminatedString
+    public String name;
+}

Added: gnunet-java/src/main/java/org/gnunet/identity/messages/DeleteMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/identity/messages/DeleteMessage.java   
                        (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/identity/messages/DeleteMessage.java   
2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,36 @@
+/*
+ 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.identity.messages;
+
+import org.gnunet.construct.UInt16;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.construct.ZeroTerminatedString;
+import org.gnunet.util.GnunetMessage;
+
address@hidden(631)
+public class DeleteMessage implements GnunetMessage.Body {
+    @UInt16
+    public int nameLength;
+    @UInt16
+    public int reserved;
+    @ZeroTerminatedString
+    public String name;
+}

Added: 
gnunet-java/src/main/java/org/gnunet/identity/messages/GetDefaultMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/identity/messages/GetDefaultMessage.java   
                            (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/identity/messages/GetDefaultMessage.java   
    2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,98 @@
+/*
+ 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.
+ */
+
+/*
+ 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.
+ */
+
+/*
+ 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.
+ */
+
+/*
+ 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.identity.messages;
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UInt16;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.construct.ZeroTerminatedString;
+import org.gnunet.util.CryptoECC;
+import org.gnunet.util.GnunetMessage;
+
address@hidden(627)
+public class GetDefaultMessage implements GnunetMessage.Body {
+    @UInt16
+    public int nameLength;
+    @UInt16
+    public int reserved;
+    @ZeroTerminatedString
+    public String serviceName;
+}

Added: gnunet-java/src/main/java/org/gnunet/identity/messages/RenameMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/identity/messages/RenameMessage.java   
                        (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/identity/messages/RenameMessage.java   
2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,58 @@
+/*
+ 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.
+ */
+
+/*
+ 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.identity.messages;
+
+import org.gnunet.construct.UInt16;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.construct.ZeroTerminatedString;
+import org.gnunet.util.GnunetMessage;
+
address@hidden(630)
+public class RenameMessage implements GnunetMessage.Body {
+    @UInt16
+    public int oldNameLength;
+    @UInt16
+    public int newNameLength;
+    @ZeroTerminatedString
+    public String oldName;
+    @ZeroTerminatedString
+    public String newName;
+}

Added: 
gnunet-java/src/main/java/org/gnunet/identity/messages/ResultCodeMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/identity/messages/ResultCodeMessage.java   
                            (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/identity/messages/ResultCodeMessage.java   
    2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,121 @@
+/*
+ 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.
+ */
+
+/*
+ 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.
+ */
+
+/*
+ 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.
+ */
+
+/*
+ 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.
+ */
+
+/*
+ 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.identity.messages;
+
+import org.gnunet.construct.*;
+import org.gnunet.util.CryptoECC;
+import org.gnunet.util.GnunetMessage;
+
+/**
+ * Answer from service to client about last operation;
+ * GET_DEFAULT maybe answered with this message on failure;
+ * CREATE and RENAME will always be answered with this message.
+ */
address@hidden(625)
+public class ResultCodeMessage implements GnunetMessage.Body {
+    /**
+     * Result code, currently unused.
+     */
+    @UInt32
+    public int resultCode;
+    @ZeroTerminatedString(optional = true)
+    public String errorMessage;
+}

Added: 
gnunet-java/src/main/java/org/gnunet/identity/messages/SetDefaultMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/identity/messages/SetDefaultMessage.java   
                            (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/identity/messages/SetDefaultMessage.java   
    2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,85 @@
+/*
+ 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.
+ */
+
+/*
+ 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.
+ */
+
+/*
+ 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.identity.messages;
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UInt16;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.construct.ZeroTerminatedString;
+import org.gnunet.util.CryptoECC;
+import org.gnunet.util.GnunetMessage;
+
+
+/**
+ * Used from service to client as a result to the GET_DEFAULT
+ * message, used from client to service to SET_DEFAULT.
+ */
address@hidden(628)
+public class SetDefaultMessage implements GnunetMessage.Body {
+    @UInt16
+    public int nameLength;
+    @UInt16
+    public int reserved;
+    @NestedMessage
+    public CryptoECC.PrivateKey privateKey;
+    @ZeroTerminatedString
+    public String serviceName;
+}

Added: gnunet-java/src/main/java/org/gnunet/identity/messages/StartMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/identity/messages/StartMessage.java    
                        (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/identity/messages/StartMessage.java    
2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,73 @@
+/*
+ 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.
+ */
+
+/*
+ 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.
+ */
+
+/*
+ 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.identity.messages;
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UInt16;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.construct.ZeroTerminatedString;
+import org.gnunet.util.CryptoECC;
+import org.gnunet.util.GnunetMessage;
+
address@hidden(624)
+public class StartMessage implements GnunetMessage.Body {
+
+}

Added: 
gnunet-java/src/main/java/org/gnunet/identity/messages/UpdateListMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/identity/messages/UpdateListMessage.java   
                            (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/identity/messages/UpdateListMessage.java   
    2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,104 @@
+/*
+ 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.
+ */
+
+/*
+ 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.
+ */
+
+/*
+ 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.
+ */
+
+/*
+ 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.identity.messages;
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UInt16;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.construct.ZeroTerminatedString;
+import org.gnunet.util.CryptoECC;
+import org.gnunet.util.GnunetMessage;
+
+
+/**
+ * Service informs client about status of a pseudonym.
+ */
address@hidden(626)
+public class UpdateListMessage implements GnunetMessage.Body{
+    @UInt16
+    public int nameLength;
+    @UInt16
+    public int endOfList;
+    @NestedMessage
+    public CryptoECC.PrivateKey privateKey;
+    @ZeroTerminatedString
+    public String egoName;
+}

Modified: gnunet-java/src/main/java/org/gnunet/mq/MessageQueue.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/mq/MessageQueue.java   2013-10-08 
20:56:51 UTC (rev 30014)
+++ gnunet-java/src/main/java/org/gnunet/mq/MessageQueue.java   2013-10-08 
21:22:43 UTC (rev 30015)
@@ -73,6 +73,10 @@
         trySubmitNext();
     }
 
+    /**
+     * Report to the message queue that the message has been sent irrevocably.
+     * Only up to calling reportMessageSend, a message can be canceled.
+     */
     protected void reportMessageSent() {
         if (null == currentEnvelope)
             throw new AssertionError();

Modified: gnunet-java/src/main/java/org/gnunet/testbed/Controller.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/Controller.java        
2013-10-08 20:56:51 UTC (rev 30014)
+++ gnunet-java/src/main/java/org/gnunet/testbed/Controller.java        
2013-10-08 21:22:43 UTC (rev 30015)
@@ -352,20 +352,16 @@
      * @param host host to run the controller on; This should be the same host 
if
      *          the controller was previously started with
      *          GNUNET_TESTBED_controller_start()
-     * @param event_mask bit mask with set of events to call 'cc' for;
-     *                   or-ed values of "1LL" shifted by the
-     *                   respective 'enum GNUNET_TESTBED_EventType'
-     *                   (i.e.  "(1LL << GNUNET_TESTBED_ET_CONNECT) | ...")
-     * @param cb controller callback to invoke on events
      */
-    public Controller(Host host, long event_mask, ControllerEventCallback cb) {
+    public Controller(Host host) {
         this.host = host;
         client = new Client("testbed", host.cfg);
         client.installReceiver(new ControllerMessageReceiver());
         requests = new MatchingRequestContainer<Long, 
OperationRequest>(client);
 
         ControllerInitMessage m = new ControllerInitMessage();
-        m.event_mask = event_mask;
+        // we are interested in all events
+        m.event_mask = 1 | 2 | 4 | 8 | 16;
         m.controler_hostname = (host.hostname == null) ? "127.0.0.1" : 
host.hostname;
         m.host_id = host.id;
         client.send(m);
@@ -500,7 +496,6 @@
             return requests.addRequest(r.operationId, r);
         }
 
-
         public Cancelable requestInformation(PeerInformationCallback cb) {
             PeerInformationRequest r = new PeerInformationRequest(this, cb);
             return requests.addRequest(r.operationId, r);

Deleted: 
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/ControllerEventCallback.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/ControllerEventCallback.java
 2013-10-08 20:56:51 UTC (rev 30014)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/callbacks/ControllerEventCallback.java
 2013-10-08 21:22:43 UTC (rev 30015)
@@ -1,21 +0,0 @@
-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");
-    }
-}

Modified: 
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerInformationMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerInformationMessage.java
   2013-10-08 20:56:51 UTC (rev 30014)
+++ 
gnunet-java/src/main/java/org/gnunet/testbed/messages/PeerInformationMessage.java
   2013-10-08 21:22:43 UTC (rev 30015)
@@ -48,9 +48,6 @@
     @UInt16
     public int uncompressedConfigSize;
 
-    @UInt16
-    public int pading1;
-
     @FillWith @UInt8
     public byte[] compressedConfig;
 }

Modified: gnunet-java/src/main/java/org/gnunet/util/AbsoluteTime.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/AbsoluteTime.java 2013-10-08 
20:56:51 UTC (rev 30014)
+++ gnunet-java/src/main/java/org/gnunet/util/AbsoluteTime.java 2013-10-08 
21:22:43 UTC (rev 30015)
@@ -23,7 +23,11 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
 import java.util.Date;
+import java.util.GregorianCalendar;
 
 /**
  * A specific point in time.
@@ -270,4 +274,46 @@
     public long getSeconds() {
         return abs_value_us / (1000 * 1000);
     }
+
+    public static AbsoluteTime fromSeconds(long stamp) {
+        return new AbsoluteTime(stamp * 1000 * 1000);
+    }
+
+    public String toFancyString() {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+        return sdf.format(new Date(getMilliseconds()));
+    }
+
+    private long getMilliseconds() {
+        return abs_value_us / 1000;
+    }
+
+    public static AbsoluteTime fromString(String s) {
+        Date date = null;
+
+        try {
+            SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
+            date = sdf.parse(s);
+            return new AbsoluteTime(date.getTime() * 1000);
+        } catch (ParseException e) {
+            // try next format
+        }
+
+        try {
+            SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd HH:mm");
+            date = sdf.parse(s);
+            return new AbsoluteTime(date.getTime() * 1000);
+        } catch (ParseException e) {
+            // try next format
+        }
+
+        try {
+            SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd");
+            date = sdf.parse(s);
+            return new AbsoluteTime(date.getTime() * 1000);
+        } catch (ParseException e) {
+            // try next format
+        }
+        return null;
+    }
 }

Modified: gnunet-java/src/main/java/org/gnunet/util/Connection.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/Connection.java   2013-10-08 
20:56:51 UTC (rev 30014)
+++ gnunet-java/src/main/java/org/gnunet/util/Connection.java   2013-10-08 
21:22:43 UTC (rev 30015)
@@ -31,6 +31,7 @@
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
 import java.nio.channels.SocketChannel;
 import java.nio.channels.spi.SelectorProvider;
 import java.util.LinkedList;
@@ -101,7 +102,7 @@
     /**
      * Timeout task for the connect notify.
      */
-    private Scheduler.TaskConfiguration notifyConnectedTimeout;
+    private Scheduler.TaskIdentifier notifyConnectedTimeout;
 
     /**
      * Continuation to call when connected
@@ -159,7 +160,7 @@
         private MessageReceiver receiver;
         private RelativeTime timeout;
         private GnunetMessage.Header msgh = null;
-        private Scheduler.TaskConfiguration recvTask = null;
+        private Scheduler.TaskIdentifier recvTask = null;
         private boolean finished = false;
         // is this receiver actively working? if not, the connection process 
has to kick off the receiver
         // (or select behaves badly)
@@ -367,7 +368,7 @@
             // of a message, only the max. wait time before transmission.
             // cancel must be called on the transmitTask if we disconnect
             Scheduler.TaskConfiguration tc = new 
Scheduler.TaskConfiguration(RelativeTime.FOREVER, this);
-            tc.selectWrite(connectionChannel);
+            tc.addSelectEvent(connectionChannel, SelectionKey.OP_WRITE);
             this.transmitTask = tc.schedule();
         }
 
@@ -450,7 +451,7 @@
                 return;
             }
 
-            tc.selectConnect(channel);
+            tc.addSelectEvent(channel, SelectionKey.OP_CONNECT);
 
             addressProbe.connectTask = tc.schedule();
         }

Modified: gnunet-java/src/main/java/org/gnunet/util/CryptoECC.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/CryptoECC.java    2013-10-08 
20:56:51 UTC (rev 30014)
+++ gnunet-java/src/main/java/org/gnunet/util/CryptoECC.java    2013-10-08 
21:22:43 UTC (rev 30015)
@@ -24,17 +24,16 @@
 import org.gnunet.construct.Message;
 
 import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOError;
 import java.io.IOException;
 import java.math.BigInteger;
 import java.nio.ByteBuffer;
 import java.nio.file.Files;
-import java.nio.file.OpenOption;
 import java.nio.file.StandardOpenOption;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
+import java.util.Arrays;
 import java.util.Random;
 
 /**
@@ -42,7 +41,6 @@
  * Original Java version written and placed into the public domain by k3d3 
(https://github.com/k3d3/ed25519-java).
  */
 public class CryptoECC {
-
     /**
      * Private ECC key.
      */
@@ -91,7 +89,7 @@
     /**
      * Public ECC key.
      */
-    public static final class PublicKey implements Message {
+    public static final class PublicSignKey implements Message {
         /**
          * x-coordinate of the point on the curve.
          * The number is stored as little endian.
@@ -116,8 +114,8 @@
             return new BigInteger[]{decodeint(x), decodeint(y)};
         }
 
-        public static PublicKey fromString(String s) {
-            PublicKey pk = new PublicKey();
+        public static PublicSignKey fromString(String s) {
+            PublicSignKey pk = new PublicSignKey();
             byte[] data = Strings.stringToData(s, 32);
             if (null == data)
                 return null;
@@ -126,6 +124,26 @@
             pk.y = encodeint(point[1]);
             return pk;
         }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            PublicSignKey that = (PublicSignKey) o;
+
+            if (!Arrays.equals(x, that.x)) return false;
+            if (!Arrays.equals(y, that.y)) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = Arrays.hashCode(x);
+            result = 31 * result + Arrays.hashCode(y);
+            return result;
+        }
     }
 
     /**
@@ -336,10 +354,10 @@
      * @param sk private key
      * @return public key derived from 'sk'
      */
-    static public PublicKey computePublicKey(PrivateKey sk) {
+    static public PublicSignKey computePublicKey(PrivateKey sk) {
         BigInteger a = computePublicKeyCoefficient(sk);
         BigInteger[] A = scalarmult(B, a);
-        PublicKey publicKey = new PublicKey();
+        PublicSignKey publicKey = new PublicSignKey();
         publicKey.x = encodeint(A[0]);
         publicKey.y = encodeint(A[1]);
         return publicKey;
@@ -370,7 +388,7 @@
      *           parameter for performance reasons
      * @return a signature on m
      */
-    public static Signature sign(byte[] m, PrivateKey sk, PublicKey pk) {
+    public static Signature sign(byte[] m, PrivateKey sk, PublicSignKey pk) {
         byte[] compressed_pk = encodepoint(new BigInteger[]{decodeint(pk.x), 
decodeint(pk.y)});
         byte[] h = sha512.digest(sk.d);
         BigInteger a = BigInteger.valueOf(2).pow(b-2);
@@ -453,7 +471,7 @@
      * @param pk public key of the signature creator
      * @return whether the signature is valid
      */
-    public static boolean verify(Signature sig, byte[] m, PublicKey pk) {
+    public static boolean verify(Signature sig, byte[] m, PublicSignKey pk) {
         BigInteger[] R = decodepoint(sig.r);
         BigInteger[] A = new BigInteger[]{decodeint(pk.x), decodeint(pk.y)};
         BigInteger S = decodeint(sig.s);
@@ -472,7 +490,7 @@
      * @param publicKey public key to use for the ECDH (yG)
      * @return key material (xyG)
      */
-    public static HashCode ecdh(PrivateKey privateKey, PublicKey publicKey) {
+    public static HashCode ecdh(PrivateKey privateKey, PublicSignKey 
publicKey) {
         BigInteger[] publicPoint = new BigInteger[]{decodeint(publicKey.x), 
decodeint(publicKey.y)};
         BigInteger coeff = computePublicKeyCoefficient(privateKey);
         BigInteger[] R = scalarmult(publicPoint, coeff);
@@ -480,4 +498,16 @@
         sha512.update(R[0].toByteArray());
         return new HashCode(sha512.digest(R[1].toByteArray()));
     }
+
+    /**
+     * Get the shared private key we use for anonymous users.
+     *
+     * @return "anonymous" private key
+     */
+    public static PrivateKey getAnonymous() {
+        PrivateKey privateKey = new PrivateKey();
+        privateKey.d = encodeint(BigInteger.ONE);
+        return privateKey;
+    }
+
 }

Modified: gnunet-java/src/main/java/org/gnunet/util/Helper.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/Helper.java       2013-10-08 
20:56:51 UTC (rev 30014)
+++ gnunet-java/src/main/java/org/gnunet/util/Helper.java       2013-10-08 
21:22:43 UTC (rev 30015)
@@ -19,23 +19,18 @@
  */
 package org.gnunet.util;
 
+
 import org.gnunet.construct.Construct;
-import org.gnunet.construct.Message;
-import org.gnunet.construct.MessageLoader;
-import org.gnunet.construct.ProtocolViolationException;
 import org.gnunet.mq.Envelope;
 import org.gnunet.mq.MessageQueue;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.File;
+import java.io.ByteArrayOutputStream;
 import java.io.IOError;
 import java.io.IOException;
-import java.nio.Buffer;
 import java.nio.ByteBuffer;
-import java.nio.channels.Channels;
-import java.nio.channels.ReadableByteChannel;
-import java.util.EnumSet;
+import java.nio.channels.*;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -50,145 +45,103 @@
     private final ProcessBuilder processBuilder;
     private final RunaboutMessageReceiver receiver;
     private Process process;
-    private volatile GnunetMessage.Body writeMessage;
+
     private WriteThread writeThread;
     private ReadThread readThread;
+
+    private Scheduler.TaskConfiguration writeTaskConfig;
+    private Scheduler.TaskIdentifier writeTaskId;
+
+    private Scheduler.TaskConfiguration readTaskConfig;
+    private Scheduler.TaskIdentifier readTaskId;
+
+    private ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
+
+    private MessageStreamTokenizer mst;
+
+    private boolean killed;
+
+
     /**
-     * Task that guarantees scheduler lifeness while the helper process
-     * is running.
+     * Thread that writes data from a pipe to the helper process.
      */
-    private Cancelable lifenessTask;
-
     private final class WriteThread extends Thread {
+        final Pipe pipe;
+        public WriteThread() {
+            try {
+                pipe = Pipe.open();
+            } catch (IOException e) {
+                throw new RuntimeException("JVM does not support pipes");
+            }
+        }
         @Override
         public void run() {
-            logger.debug("in write thread");
-            GnunetMessage.Body msg;
+            WritableByteChannel channel = 
Channels.newChannel(process.getOutputStream());
+            ByteBuffer buffer = ByteBuffer.allocate(1024);
             while (true) {
-                synchronized (Helper.this) {
-                    while (writeMessage == null) {
-                        try {
-                            Helper.this.wait();
-                        } catch (InterruptedException e) {
-                            // do nothing
-                        }
+                buffer.clear();
+                try {
+                    logger.debug("waiting for readable pipe in thread");
+                    int n = pipe.source().read(buffer);
+                    if (n == -1) {
+                        logger.debug("write thread pipe closed");
+                        return;
                     }
-                    // we now have a message we can send
-                    msg = writeMessage;
-                    writeMessage = null;
-                    // somebody can set the next send message
-                }
-                logger.debug("helper got message");
-                GnunetMessage gm = GnunetMessage.fromBody(msg);
-                byte[] data = Construct.toBinary(gm);
-                try {
-                    process.getOutputStream().write(data);
-                    process.getOutputStream().flush();
+                    logger.debug("read {} bytes from pipe", n);
+                    buffer.flip();
+                    while (buffer.hasRemaining()) {
+                        n = channel.write(buffer);
+                        process.getOutputStream().flush();
+                        logger.debug("written {} bytes to process", n);
+                    }
+                } catch (ClosedChannelException e) {
+                    logger.debug("channel closed for write thread");
+                    return;
                 } catch (IOException e) {
                     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");
             }
         }
     }
 
+    /**
+     * Thread that reads data from the helper process and writes it
+     * to a pipe.
+     */
     private final class ReadThread extends Thread {
-        private ByteBuffer buffer;
-        ReadableByteChannel channel;
+        Pipe pipe;
 
-        /**
-         * Read until our buffer is full, or an error occurs.
-         *
-         * @return true on success
-         */
-        private boolean fillBuffer() {
-            while (buffer.hasRemaining()) {
-                try {
-                    int n = channel.read(buffer);
-                    if (n == -1) {
-                        logger.debug("read eof");
-                        return false;
-                    }
-                } catch (IOException e) {
-                    logger.debug("read error");
-                    return false;
-                }
+        public ReadThread() {
+            try {
+                pipe = Pipe.open();
+            } catch (IOException e) {
+                throw new RuntimeException("JVM does not support pipes");
             }
-            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));
-
-        }
-
         @Override
         public void run() {
-            // allocate just enough for the message header
-            buffer = ByteBuffer.allocate(4);
-            channel = Channels.newChannel(process.getInputStream());
+            byte[] buf = new byte[1024];
             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);
-                if (!fillBuffer())
+                int n;
+                try {
+                    logger.debug("reading from process");
+                    n = process.getInputStream().read(buf);
+                    if (n == -1) {
+                        logger.debug("reached EOF while reading from process");
+                        break;
+                    }
+                    logger.debug("read {} bytes from process", n);
+                    ByteBuffer b = ByteBuffer.wrap(buf, 0, n);
+                    while (b.hasRemaining()) {
+                        pipe.sink().write(b);
+                    }
+                } catch (ClosedChannelException e) {
+                    logger.debug("channel closed for read thread");
                     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);
-                        buffer.flip();
-                        newBuf.put(buffer);
-                        buffer = newBuf;
-                    }
-                    buffer.limit(msgh.messageSize);
-                    if (!fillBuffer())
-                        return;
                 }
-                // we now have a complete message
-                // prepare for reading again
-                buffer.flip();
-
-                boolean found = true;
-                try {
-                    MessageLoader.getUnionClass(GnunetMessage.Body.class, 
msgh.messageType);
-                } catch (ProtocolViolationException e) {
-                    found = false;
+                catch (IOException e) {
+                    throw new IOError(e);
                 }
-                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");
             }
         }
     }
@@ -203,6 +156,50 @@
         return prefix + "/lib/" + "gnunet/" + "libexec/" +  binaryName;
     }
 
+
+    private class ReadTask implements Scheduler.Task {
+        @Override
+        public void run(Scheduler.RunContext ctx) {
+            readTaskId = null;
+            int n = mst.readFrom(readThread.pipe.source());
+            if (n != -1 && readThread.pipe.source().isOpen()) {
+                readTaskId = readTaskConfig.schedule();
+            }
+        }
+    }
+
+    private class WriteTask implements Scheduler.Task {
+        @Override
+        public void run(Scheduler.RunContext ctx) {
+            writeTaskId = null;
+            try {
+                int n = writeThread.pipe.sink().write(writeBuffer);
+                logger.debug("wrote {} bytes in write task", n);
+            } catch (IOException e) {
+                throw new IOError(e);
+            }
+            if (writeBuffer.hasRemaining()) {
+                writeTaskId = writeTaskConfig.schedule();
+            } else {
+                reportMessageSent();
+                reportReadyForSubmit();
+            }
+        }
+    }
+
+    private class HelperMstCallback implements MstCalllback {
+        @Override
+        public void onUnknownMessage(UnknownMessageBody b) {
+            logger.warn("got unknown message type");
+        }
+
+        @Override
+        public void onKnownMessage(GnunetMessage msg) {
+            logger.debug("processing message from helper");
+            receiver.process(msg.body);
+        }
+    }
+
     /**
      * Create and start a new helper process
      *
@@ -229,21 +226,31 @@
             throw new IOError(e);
         }
 
-        lifenessTask = Scheduler.addDelayed(RelativeTime.FOREVER, new 
Scheduler.Task() {
-            @Override
-            public void run(Scheduler.RunContext ctx) {
-                // do nothing
-            }
-        });
+        mst = new MessageStreamTokenizer(new HelperMstCallback());
 
         writeThread = new WriteThread();
         readThread = new ReadThread();
 
         logger.debug("creating helper");
 
+        try {
+            readThread.pipe.source().configureBlocking(false);
+            writeThread.pipe.sink().configureBlocking(false);
+        } catch (IOException e) {
+            throw new IOError(e);
+        }
+
         writeThread.start();
         readThread.start();
 
+        readTaskConfig = new Scheduler.TaskConfiguration(RelativeTime.FOREVER, 
new ReadTask());
+        readTaskConfig.addSelectEvent(readThread.pipe.source(), 
SelectionKey.OP_READ);
+
+        writeTaskConfig = new 
Scheduler.TaskConfiguration(RelativeTime.FOREVER, new WriteTask());
+        writeTaskConfig.addSelectEvent(writeThread.pipe.sink(), 
SelectionKey.OP_WRITE);
+
+        readTaskId = readTaskConfig.schedule();
+
         reportReadyForSubmit();
     }
 
@@ -255,7 +262,24 @@
      * @return true on success, false on failure
      */
     public boolean kill(boolean softkill) {
-        lifenessTask.cancel();
+        killed = true;
+        if (readTaskId != null) {
+            readTaskId.cancel();
+            readTaskId = null;
+        }
+        if (writeTaskId != null) {
+            writeTaskId.cancel();
+            writeTaskId = null;
+        }
+
+        try {
+            readThread.pipe.source().close();
+            readThread.pipe.sink().close();
+            writeThread.pipe.source().close();
+            writeThread.pipe.sink().close();
+        } catch (IOException e) {
+            throw new IOError(e);
+        }
         if (softkill) {
             try {
                 process.getInputStream().close();
@@ -278,7 +302,6 @@
     public boolean waitFor() {
         try {
             process.waitFor();
-            process.waitFor();
         } catch (InterruptedException e) {
             return false;
         }
@@ -287,20 +310,27 @@
 
     @Override
     protected void submit(Envelope ev) {
+        if (writeTaskId != null) {
+            throw new AssertionError();
+        }
         logger.debug("submitting envelope to helper thread");
-        synchronized (this) {
-            if (writeMessage != null)
-                throw new AssertionError("message queue not implemented 
correctly");
-            writeMessage = ev.message;
-            notifyAll();
+        final GnunetMessage gm = new GnunetMessage();
+        gm.header = new GnunetMessage.Header();
+        gm.body = ev.message;
+        Construct.patch(gm);
+        gm.header.messageSize = Construct.getSize(gm);
+        if (writeBuffer.capacity() < gm.header.messageSize) {
+            writeBuffer = ByteBuffer.allocate(gm.header.messageSize);
         }
-        reportReadyForSubmit();
+        writeBuffer.clear();
+        int n = Construct.write(writeBuffer, gm);
+        writeBuffer.flip();
+        logger.debug("wrote message size {} to write buffer", n);
+        writeTaskId = writeTaskConfig.schedule();
     }
 
     @Override
     protected void retract() {
-        synchronized (this) {
-            writeMessage = null;
-        }
+        throw new UnsupportedOperationException();
     }
 }

Added: gnunet-java/src/main/java/org/gnunet/util/MessageStreamTokenizer.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/MessageStreamTokenizer.java       
                        (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/MessageStreamTokenizer.java       
2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,122 @@
+/*
+ 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;
+import org.gnunet.construct.MessageLoader;
+import org.gnunet.construct.ProtocolViolationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOError;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channel;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.Pipe;
+import java.nio.channels.ReadableByteChannel;
+
+/**
+ * Extract GNUnet messages from a stream of bytes.
+ */
+public class MessageStreamTokenizer {
+    private static final Logger logger = LoggerFactory
+            .getLogger(Service.class);
+    private MstCalllback mstCalllback;
+    private ByteBuffer buffer;
+    GnunetMessage.Header msgh;
+    public MessageStreamTokenizer(MstCalllback mstCalllback) {
+        this.mstCalllback = mstCalllback;
+        // large enough buffer for a message header
+        this.buffer = ByteBuffer.allocate(4);
+    }
+
+    public void ensureBufferSize() {
+        if (buffer.capacity() < msgh.messageSize) {
+            ByteBuffer buf = ByteBuffer.allocate(msgh.messageSize);
+            buffer.flip();
+            buf.put(buffer);
+            buf.flip();
+            buffer = buf;
+        }
+    }
+
+    public void readAndDispatch() {
+        Class unionClass = null;
+        boolean found = true;
+
+        try {
+            unionClass = MessageLoader.getUnionClass(GnunetMessage.Body.class, 
msgh.messageType);
+        } catch (ProtocolViolationException e) {
+            found = false;
+        }
+
+        logger.debug("dispatching message");
+        if (found) {
+            GnunetMessage msg;
+            try {
+                msg = Construct.parseAs(buffer, GnunetMessage.class);
+            } catch (OutOfMemoryError e) {
+                throw new OutOfMemoryError("oom while parsing " + unionClass);
+            }
+            mstCalllback.onKnownMessage(msg);
+        } else {
+            UnknownMessageBody b = new UnknownMessageBody();
+            b.id = msgh.messageType;
+            mstCalllback.onUnknownMessage(b);
+        }
+    }
+
+    /**
+     * Read from a channel into the mst.
+     *
+     * @param source channel to read from
+     * @return -1 on end of stream, number of bytes read otherwise
+     */
+    public int readFrom(ReadableByteChannel source) {
+        int n;
+        try {
+            n = source.read(buffer);
+        } catch (ClosedChannelException e) {
+            return -1;
+        }catch (IOException e) {
+            throw new IOError(e);
+        }
+        if (msgh == null && buffer.position() >= 4) {
+            logger.debug("got header in mst");
+            // remember write position and prepare for reading
+            int writePos = buffer.position();
+            buffer.flip();
+            msgh = Construct.parseAs(buffer, GnunetMessage.Header.class);
+            ensureBufferSize();
+            // prepare for writing again, and restore write position
+            buffer.position(0);
+            buffer.compact();
+        }
+        if (msgh != null && buffer.position() >= msgh.messageSize) {
+            buffer.flip();
+            readAndDispatch();
+            msgh = null;
+            buffer.compact();
+        }
+        return n;
+    }
+}

Added: gnunet-java/src/main/java/org/gnunet/util/MstCalllback.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/MstCalllback.java                 
        (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/MstCalllback.java 2013-10-08 
21:22:43 UTC (rev 30015)
@@ -0,0 +1,27 @@
+/*
+ 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;
+
+public interface MstCalllback {
+    void onUnknownMessage(UnknownMessageBody b);
+
+    void onKnownMessage(GnunetMessage msg);
+}

Modified: gnunet-java/src/main/java/org/gnunet/util/Scheduler.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/Scheduler.java    2013-10-08 
20:56:51 UTC (rev 30014)
+++ gnunet-java/src/main/java/org/gnunet/util/Scheduler.java    2013-10-08 
21:22:43 UTC (rev 30015)
@@ -20,6 +20,7 @@
 
 package org.gnunet.util;
 
+import com.google.common.collect.Lists;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -28,10 +29,13 @@
 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.
+ * <p/>
+ * By design, it is not safe to scheduler tasks from different threads.
+ * When threads can't be avoided, they should communicate with the scheduler by
+ * a pipe.
  *
  * @author Florian Dold
  */
@@ -39,12 +43,10 @@
     private static final Logger logger = LoggerFactory
             .getLogger(Scheduler.class);
 
-    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;
+    private static TaskIdentifier activeTask = null;
 
     /**
      * Number of tasks in the ready lists, that is, number of tasks that is 
ready to run
@@ -69,21 +71,14 @@
      * 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];
+    final private static LinkedList<TaskIdentifier>[] readyLists = new 
LinkedList[Priority.numberOfPriorities];
 
     static {
         for (int i = 0; i < Priority.numberOfPriorities; ++i) {
-            readyLists[i] = new LinkedList<TaskConfiguration>();
+            readyLists[i] = new LinkedList<TaskIdentifier>();
         }
     }
 
-    private static final int EVENT_READ = 0, EVENT_WRITE = 1, EVENT_ACCEPT = 
2, EVENT_CONNECT = 3;
-    private static final int[] eventToInterestOp = new 
int[]{SelectionKey.OP_READ, SelectionKey.OP_WRITE,
-            SelectionKey.OP_ACCEPT, SelectionKey.OP_CONNECT};
-    private static final Reason[] eventToReason = new 
Reason[]{Reason.READ_READY, Reason.WRITE_READY,
-            Reason.ACCEPT_READY, Reason.CONNECT_READY};
-
-
     /**
      * Selector, used to check file descriptors for readiness.
      */
@@ -102,38 +97,21 @@
     /**
      * true iff the scheduler is currently running.
      */
-    private static boolean scheduler_running = false;
+    private static boolean schedulerRunning = false;
 
-
     /**
      * 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>() {
+    final private static Queue<TaskIdentifier> pending = new 
PriorityQueue<TaskIdentifier>(5, new Comparator
+            <TaskIdentifier>() {
         @Override
-        public int compare(TaskConfiguration a, TaskConfiguration b) {
+        public int compare(TaskIdentifier a, TaskIdentifier b) {
             return a.deadline.compareTo(b.deadline);
         }
     });
 
-
     /**
-     * Reset the scheduler forcefully.
-     * Intended to be used internally in the Scheduler, as well as in test 
teardown.
-     */
-    public static void forceReset() {
-        scheduler_running = false;
-        readyCount = 0;
-        activeTask = null;
-        for (int i = 0; i < Priority.numberOfPriorities; ++i) {
-            readyLists[i] = new LinkedList<TaskConfiguration>();
-        }
-        pending.clear();
-    }
-
-
-    /**
      * Reasons for executing a task.
      */
     public enum Reason {
@@ -147,94 +125,133 @@
         /**
          * The reason this task has been called by the scheduler.
          */
-        public Set<Reason> reasons = EnumSet.noneOf(Reason.class);
+        public EnumSet<Reason> reasons = EnumSet.noneOf(Reason.class);
     }
 
     /**
-     * A task is the basic unit of work that is managed by the scheduler.
+     * Which operations is a task identifier interested in?
      */
-    public static interface Task {
-        public void run(RunContext ctx);
+    private static class TaskInterestOps {
+        TaskIdentifier tid;
+        int interestOps;
     }
 
     /**
-     * A TaskConfiguration represents a Task that will execute or has already 
been executed.
+     * Manage subscriptions for selection events on channels.
      */
-    public static class TaskConfiguration implements Cancelable {
-        private final Task task;
-        private RunContext ctx = new RunContext();
-        private boolean lifeness = true;
-        private Priority priority;
-        private final AbsoluteTime deadline;
+    private static class Subscriptions {
+        private static class ChannelInterest {
+            SelectableChannel channel;
+            int interestOps;
+        }
 
-        private ArrayList<SelectableChannel> eventChannels = null;
-        private ArrayList<Integer> eventTypes = null;
+        List<ChannelInterest> channelInterests = Lists.newLinkedList();
 
-        private boolean hasRun = false;
-        private boolean isCanceled = false;
-
-        /**
-         * Create a TaskIdentifier.
-         *
-         * @param delay when will the task be run?
-         *              may be null to indicate that this task may not be run
-         *              (but only queued directly)
-         * @param task task to run with this TaskIdentifier
-         */
-        TaskConfiguration(RelativeTime delay, Task task) {
-            this.task = task;
-            if (delay == null)
-                this.deadline = null;
-            else
-                this.deadline = delay.toAbsolute();
+        void add(SelectableChannel channel, int interestOps) {
+            boolean found = false;
+            for (ChannelInterest ci : channelInterests) {
+                if (ci.channel == channel) {
+                    ci.interestOps |= interestOps;
+                    if ((ci.interestOps | SelectionKey.OP_CONNECT | 
SelectionKey.OP_READ) != 0) {
+                        throw new AssertionError("OP_CONNECT and OP_READ are 
incompatible in java");
+                    }
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                ChannelInterest ci = new ChannelInterest();
+                ci.channel = channel;
+                ci.interestOps = interestOps;
+                channelInterests.add(ci);
+            }
         }
 
-        /**
-         * 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");
+        void apply(TaskIdentifier tid) {
+            for (ChannelInterest ci : channelInterests) {
+                SelectionKey key = ci.channel.keyFor(selector);
+                if (key == null || !key.isValid()) {
+                    try {
+                        key = ci.channel.register(selector, ci.interestOps);
+                        key.attach(new LinkedList());
+                    } catch (ClosedChannelException e) {
+                        throw new IOError(e);
+                    }
+                } else {
+                    key.interestOps(key.interestOps() | ci.interestOps);
+                }
+                @SuppressWarnings("unchecked")
+                LinkedList<TaskInterestOps> opl = 
(LinkedList<TaskInterestOps>) key.attachment();
+                TaskInterestOps tio = new TaskInterestOps();
+                tio.tid = tid;
+                tio.interestOps = ci.interestOps;
+                opl.add(tio);
             }
-            if (eventChannels == null) {
-                eventChannels = new ArrayList<SelectableChannel>();
-                eventTypes = new ArrayList<Integer>();
-            }
-            eventChannels.add(channel);
-            eventTypes.add(eventType);
+        }
 
-            int interestOp = eventToInterestOp[eventType];
-
-            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);
+        void stop(TaskIdentifier tid) {
+            for (ChannelInterest ci : channelInterests) {
+                SelectionKey key = ci.channel.keyFor(selector);
+                if (key == null || !key.isValid()) {
+                    logger.warn("missing selection key");
+                    return;
                 }
-            } else {
-                if ((key.interestOps() & interestOp) != 0) {
-                    throw new AssertionError("interest op registered twice");
+                @SuppressWarnings("unchecked")
+                LinkedList<TaskInterestOps> interestList = 
(LinkedList<TaskInterestOps>) key.attachment();
+                Iterator<TaskInterestOps> it = interestList.iterator();
+                int remainingInterestOps = 0;
+                while (it.hasNext()) {
+                    TaskInterestOps ops = it.next();
+                    if (ops.tid == tid) {
+                        it.remove();
+                    } else {
+                        remainingInterestOps |= ops.interestOps;
+                    }
                 }
-                key.interestOps(key.interestOps() | interestOp);
+                key.interestOps(remainingInterestOps);
             }
+        }
+    }
 
-            TaskConfiguration[] subscribers = (TaskConfiguration[]) 
key.attachment();
-            if (subscribers[eventType] != null) {
-                throw new AssertionError("subscriber registered twice");
-            }
-            subscribers[eventType] = this;
+    /**
+     * A task is the basic unit of work that is managed by the scheduler.
+     */
+    public static interface Task {
+        public void run(RunContext ctx);
+    }
 
-            if (subscribers[EVENT_CONNECT] != null && subscribers[EVENT_READ] 
!= null) {
-                throw new AssertionError("OP_CONNECT and OP_READ are 
incompatible in java");
-            }
+    /**
+     * Representation of a task that has been scheduled, and can be canceled
+     * until the task has run.
+     */
+    public static class TaskIdentifier implements Cancelable {
+        private boolean hasRun = false;
+        private boolean isCanceled = false;
+        private final Task task;
+        private final RunContext ctx = new RunContext();
+        private final boolean lifeness;
+        private final Priority priority;
+        private final AbsoluteTime deadline;
+        private final Subscriptions subscriptions;
+
+        public TaskIdentifier(Task task, EnumSet<Reason> reasons) {
+            this.ctx.reasons = reasons;
+            this.task = task;
+            lifeness = true;
+            priority = Priority.DEFAULT;
+            deadline = null;
+            subscriptions = null;
         }
 
+        public TaskIdentifier(TaskConfiguration tc) {
+            this.task = tc.task;
+            this.subscriptions = tc.subscriptions;
+            this.deadline = tc.deadline;
+            this.priority = tc.priority;
+            this.lifeness = tc.lifeness;
+        }
+
+
         private void run() {
             if (hasRun) {
                 throw new AssertionError("same task ran twice");
@@ -242,14 +259,18 @@
             if (isCanceled) {
                 return;
             }
-            TaskConfiguration old = activeTask;
+            TaskIdentifier old = activeTask;
             activeTask = this;
             task.run(ctx);
             hasRun = true;
             activeTask = old;
         }
 
+        @Override
         public void cancel() {
+            if (hasRun) {
+                throw new AssertionError("can't cancel task that already ran");
+            }
             if (isCanceled) {
                 throw new AssertionError("task canceled twice");
             }
@@ -257,55 +278,59 @@
             pending.remove(this);
         }
 
-        public Cancelable schedule() {
-            lock.lock();
-            if (this.deadline == null)
-                throw new AssertionError("a task without deadline may not be 
scheduled");
-            if (priority == null) {
-                if (activeTask != null) {
-                    priority = activeTask.priority;
-                } else {
-                    priority = Priority.DEFAULT;
-                }
+        public void deregister() {
+            if (subscriptions != null) {
+                subscriptions.stop(this);
             }
-            pending.add(this);
-            lock.unlock();
-            return this;
         }
+    }
 
-        private void deregister() {
-            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();
-                int interestOp = eventToInterestOp[eventTypes.get(i)];
-                if (subscribers[eventTypes.get(i)] == null || 
(key.interestOps() | interestOp) == 0) {
-                    throw new AssertionError("deregistering event that has not 
been registered");
-                }
-                subscribers[eventTypes.get(i)] = null;
-                key.interestOps(key.interestOps() & (~interestOp));
-            }
+    /**
+     * A TaskConfiguration contains all information to schedule a task.
+     */
+    public static class TaskConfiguration {
+        private final Task task;
+        private boolean lifeness = true;
+        private Priority priority;
+        private final AbsoluteTime deadline;
 
-            lock.unlock();
-        }
+        private Subscriptions subscriptions;
 
-        public void selectRead(SelectableChannel channel) {
-            addChannelEvent(channel, EVENT_READ);
+        /**
+         * Create a TaskIdentifier.
+         *
+         * @param delay when will the task be run?
+         *              may be null to indicate that this task may not be run
+         *              (but only queued directly)
+         * @param task  task to run with this TaskIdentifier
+         */
+        TaskConfiguration(RelativeTime delay, Task task) {
+            if (delay == null)
+                throw new AssertionError("task delay may not be 'null'");
+            this.task = task;
+            this.deadline = delay.toAbsolute();
         }
 
-        public void selectWrite(SelectableChannel channel) {
-            addChannelEvent(channel, EVENT_WRITE);
-        }
+        public TaskIdentifier schedule() {
 
-        public void selectConnect(SelectableChannel channel) {
-            addChannelEvent(channel, EVENT_CONNECT);
+            if (priority == null) {
+                if (activeTask != null) {
+                    priority = activeTask.priority;
+                } else {
+                    priority = Priority.DEFAULT;
+                }
+            }
+            TaskIdentifier tid = new TaskIdentifier(this);
+            if (subscriptions != null)
+                subscriptions.apply(tid);
+            pending.add(tid);
+            return tid;
         }
 
-        public void selectAccept(SelectableChannel channel) {
-            addChannelEvent(channel, EVENT_ACCEPT);
+        public void addSelectEvent(SelectableChannel channel, int event) {
+            if (subscriptions == null)
+                subscriptions = new Subscriptions();
+            subscriptions.add(channel, event);
         }
     }
 
@@ -314,14 +339,7 @@
      * the same priority.
      */
     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();
+        queueReady(new TaskIdentifier(task, reasons));
     }
 
     /**
@@ -343,26 +361,41 @@
      * @param task  the task to run after delay
      * @return the TaskIdentifier, can be used to cancel the task until it has 
been executed.
      */
-    public static TaskConfiguration addDelayed(RelativeTime delay, Task task) {
+    public static TaskIdentifier addDelayed(RelativeTime delay, Task task) {
         TaskConfiguration tid = new TaskConfiguration(delay, task);
-        tid.schedule();
-        return tid;
+        return tid.schedule();
     }
 
-    public static TaskConfiguration addRead(RelativeTime timeout,
-                                            SelectableChannel chan, Task task) 
{
+    /**
+     * Add a task to run after the specified delay, or after the given channel
+     * is ready to read, whichever occurs first.
+     *
+     * @param timeout time to wait until running the task
+     * @param chan    chennel of interest
+     * @param task    task to run
+     * @return task identifier
+     */
+    public static TaskIdentifier addRead(RelativeTime timeout,
+                                         SelectableChannel chan, Task task) {
         TaskConfiguration tid = new TaskConfiguration(timeout, task);
-        tid.addChannelEvent(chan, EVENT_READ);
-        tid.schedule();
-        return tid;
+        tid.addSelectEvent(chan, SelectionKey.OP_READ);
+        return tid.schedule();
     }
 
-    public static TaskConfiguration addWrite(RelativeTime timeout,
-                                             SelectableChannel chan, Task 
task) {
+    /**
+     * Add a task to run after the specified delay, or after the given channel
+     * is ready to write, whichever occurs first.
+     *
+     * @param timeout to wait until running the task
+     * @param chan    channel of interest
+     * @param task    task to run
+     * @return task identifier
+     */
+    public static TaskIdentifier addWrite(RelativeTime timeout,
+                                          SelectableChannel chan, Task task) {
         TaskConfiguration tid = new TaskConfiguration(timeout, task);
-        tid.addChannelEvent(chan, EVENT_WRITE);
-        tid.schedule();
-        return tid;
+        tid.addSelectEvent(chan, SelectionKey.OP_WRITE);
+        return tid.schedule();
     }
 
     /**
@@ -372,14 +405,11 @@
      * @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) {
+        for (TaskIdentifier t : pending) {
             if (t.lifeness) {
-                lock.unlock();
                 return true;
             }
         }
@@ -387,30 +417,23 @@
         if (!pending.isEmpty()) {
             logger.debug("tasks pending but not alive -- disconnect");
             shutdown();
-            lock.unlock();
             return true;
         }
-
-        lock.unlock();
         return false;
     }
 
-
     /**
      * Queue a Task for execution.
      *
      * @param tid TaskIdentifier of the ready task
      */
-    private static void queueReady(TaskConfiguration tid) {
-        lock.lock();
+    private static void queueReady(TaskIdentifier tid) {
         int idx = tid.priority.ordinal();
         readyLists[idx].add(tid);
         readyCount++;
         pending.remove(tid);
-        lock.unlock();
     }
 
-
     /**
      * Queue all tasks with expired timeout.
      *
@@ -418,11 +441,10 @@
      */
     private static RelativeTime handleTimeouts() {
         RelativeTime timeout = RelativeTime.FOREVER;
-        lock.lock();
 
         // check if any timeouts occurred
         while (true) {
-            TaskConfiguration t = pending.peek();
+            TaskIdentifier t = pending.peek();
             if (t == null) {
                 break;
             }
@@ -436,25 +458,19 @@
                 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) {
-        TaskConfiguration tc = subscribers[eventType];
-        if (tc == null) {
-            return;
-        }
-        executableTasks.add(tc);
-        tc.ctx.reasons.add(eventToReason[eventType]);
+
+    private static void addReasonsFromInterestOp(EnumSet<Reason> reasons, int 
interestOps) {
+        if ((interestOps & SelectionKey.OP_READ) != 0)
+            reasons.add(Reason.READ_READY);
+        if ((interestOps & SelectionKey.OP_WRITE) != 0)
+            reasons.add(Reason.WRITE_READY);
+        if ((interestOps & SelectionKey.OP_CONNECT) != 0)
+            reasons.add(Reason.CONNECT_READY);
+        if ((interestOps & SelectionKey.OP_ACCEPT) != 0)
+            reasons.add(Reason.ACCEPT_READY);
     }
 
     /**
@@ -463,10 +479,8 @@
      * @param timeout timeout for select
      */
     private static void handleSelect(RelativeTime timeout) {
-        if (!lock.isHeldByCurrentThread())
-            throw new AssertionError();
+        // gnunet-java uses microseconds, but the select api uses milliseconds
         long timeout_ms = timeout.getMicroseconds() / 1000;
-        lock.unlock();
         try {
             // selector.select(0) would block indefinitely (counter-intuitive, 
java's fault)
             if (timeout_ms == 0) {
@@ -480,39 +494,29 @@
             }
         } catch (IOException e) {
             throw new IOError(e);
-        } finally {
-            lock.lock();
         }
 
         logger.debug("select over");
 
         // we use a set so that we don't execute any task twice
-        Collection<TaskConfiguration> executableTasks = new 
HashSet<TaskConfiguration>();
+        Collection<TaskIdentifier> executableTasks = new 
HashSet<TaskIdentifier>();
         for (SelectionKey sk : selector.selectedKeys()) {
-            TaskConfiguration[] subscribers = (TaskConfiguration[]) 
sk.attachment();
-
-            if (sk.isReadable()) {
-                addSubscriberTask(executableTasks, subscribers, EVENT_READ);
+            @SuppressWarnings("unchecked")
+            LinkedList<TaskInterestOps> subscribers = 
(LinkedList<TaskInterestOps>) sk.attachment();
+            for (TaskInterestOps ops : subscribers) {
+                if ((sk.readyOps() & ops.interestOps) != 0) {
+                    executableTasks.add(ops.tid);
+                    addReasonsFromInterestOp(ops.tid.ctx.reasons, 
sk.readyOps() & ops.interestOps);
+                }
             }
-            if (sk.isWritable()) {
-                addSubscriberTask(executableTasks, subscribers, EVENT_WRITE);
-            }
-            if (sk.isAcceptable()) {
-                addSubscriberTask(executableTasks, subscribers, EVENT_ACCEPT);
-            }
-            if (sk.isConnectable()) {
-                addSubscriberTask(executableTasks, subscribers, EVENT_CONNECT);
-            }
-
         }
-        for (TaskConfiguration tt : executableTasks) {
+        for (TaskIdentifier tt : executableTasks) {
             // cancel subscriptions to other events, we can execute now!
             tt.deregister();
             queueReady(tt);
         }
     }
 
-
     /**
      * Initialize and run scheduler. This function will return when all tasks
      * have completed.
@@ -529,10 +533,10 @@
      */
     public static void run(Task initialTask) {
         logger.debug("running scheduler");
-        if (scheduler_running) {
+        if (schedulerRunning) {
             throw new AssertionError("Scheduler already running");
         }
-        scheduler_running = true;
+        schedulerRunning = true;
         try {
             run_unchecked(initialTask);
         } finally {
@@ -543,7 +547,6 @@
         }
     }
 
-
     /**
      * Initialize and run scheduler. This function will return when all tasks
      * have completed. Don't check if the scheduler is already running or not.
@@ -556,12 +559,7 @@
         }
 
         // the gnunet main loop
-        while (true) {
-            lock.lock();
-            if (checkLiveness() == false) {
-                lock.unlock();
-                break;
-            }
+        while (checkLiveness()) {
             RelativeTime nextTimeout = handleTimeouts();
             if (nextTimeout.getMicroseconds() < 0) {
                 logger.warn("negative timeout for select");
@@ -569,7 +567,6 @@
 
             // don't select if there are no tasks; we are done!
             if (readyCount == 0 && pending.isEmpty()) {
-                lock.unlock();
                 return;
             }
 
@@ -580,7 +577,6 @@
                 handleSelect(nextTimeout);
             }
             runReady();
-            lock.unlock();
         }
 
         if (readyCount != 0) {
@@ -618,9 +614,9 @@
             // start executing from the highest priority down to 0
             for (int p = Priority.numberOfPriorities - 1; p >= 0; p--) {
                 // execute all tasks with priority p
-                LinkedList<TaskConfiguration> queue = readyLists[p];
+                LinkedList<TaskIdentifier> queue = readyLists[p];
                 while (!queue.isEmpty()) {
-                    TaskConfiguration tid = queue.removeFirst();
+                    TaskIdentifier tid = queue.removeFirst();
                     readyCount--;
                     tid.run();
                 }
@@ -637,14 +633,28 @@
      */
     public static void shutdown() {
         // queueReady() while iterating would yield concurrent modification 
exn otherwise
-        for (TaskConfiguration tid : new 
ArrayList<TaskConfiguration>(pending)) {
+        for (TaskIdentifier tid : new ArrayList<TaskIdentifier>(pending)) {
             tid.ctx.reasons.add(Reason.SHUTDOWN);
             queueReady(tid);
         }
         pending.clear();
     }
 
+    /**
+     * Reset the scheduler forcefully.
+     * Intended to be used internally in the Scheduler, as well as in test 
teardown.
+     */
+    public static void forceReset() {
+        schedulerRunning = false;
+        readyCount = 0;
+        activeTask = null;
+        for (int i = 0; i < Priority.numberOfPriorities; ++i) {
+            readyLists[i] = Lists.newLinkedList();
+        }
+        pending.clear();
+    }
 
+
     /**
      * A handle to a file system object that can be selected on.
      */

Modified: gnunet-java/src/main/java/org/gnunet/util/Server.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/Server.java       2013-10-08 
20:56:51 UTC (rev 30014)
+++ gnunet-java/src/main/java/org/gnunet/util/Server.java       2013-10-08 
21:22:43 UTC (rev 30015)
@@ -27,6 +27,7 @@
 
 import java.io.IOException;
 import java.net.SocketAddress;
+import java.nio.channels.SelectionKey;
 import java.nio.channels.ServerSocketChannel;
 import java.nio.channels.SocketChannel;
 import java.util.ArrayList;
@@ -403,7 +404,7 @@
                         addAcceptSocket(sock);
                     }
                 });
-        b.selectAccept(sock);
+        b.addSelectEvent(sock, SelectionKey.OP_ACCEPT);
         acceptTask = b.schedule();
     }
 

Modified: gnunet-java/src/main/java/org/gnunet/util/Service.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/Service.java      2013-10-08 
20:56:51 UTC (rev 30014)
+++ gnunet-java/src/main/java/org/gnunet/util/Service.java      2013-10-08 
21:22:43 UTC (rev 30015)
@@ -30,6 +30,7 @@
 import java.net.SocketAddress;
 import java.nio.ByteBuffer;
 import java.nio.channels.Pipe;
+import java.nio.channels.SelectionKey;
 import java.util.LinkedList;
 
 /**
@@ -107,7 +108,7 @@
 
             Scheduler.TaskConfiguration t = new 
Scheduler.TaskConfiguration(RelativeTime.FOREVER,
                     new SigpipeTask());
-            t.selectRead(p.getSource());
+            t.addSelectEvent(p.getSource(), SelectionKey.OP_READ);
             sigpipeTask = t.schedule();
             sigpipeChannel = p.getSource();
         }

Modified: gnunet-java/src/main/java/org/gnunet/voting/Ballot.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/Ballot.java     2013-10-08 
20:56:51 UTC (rev 30014)
+++ gnunet-java/src/main/java/org/gnunet/voting/Ballot.java     2013-10-08 
21:22:43 UTC (rev 30015)
@@ -24,7 +24,7 @@
 import com.google.common.base.Optional;
 import com.google.common.collect.BiMap;
 import com.google.common.collect.HashBiMap;
-import com.google.common.collect.Maps;
+import com.google.common.primitives.Longs;
 import org.gnunet.util.*;
 
 import java.security.MessageDigest;
@@ -38,18 +38,22 @@
 public class Ballot {
 
     String topic;
+    String group;
     List<String> choices;
-    AbsoluteTime electionStartTime;
-    AbsoluteTime electionEndTime;
+    AbsoluteTime startTime;
+    AbsoluteTime closingTime;
+    AbsoluteTime queryTime;
+    AbsoluteTime endTime;
     BiMap<String,PeerIdentity> authorities;
     SortedMap<String,CryptoECC.Signature> registrationSigs;
-    CryptoECC.PublicKey caPub;
-    CryptoECC.PublicKey issuerPub;
+    CryptoECC.PublicSignKey caPub;
+    CryptoECC.PublicSignKey issuerPub;
     CryptoECC.Signature issuerSig;
-    CryptoECC.PublicKey voter_pub;
+    CryptoECC.PublicSignKey voterPub;
+    CryptoECC.Signature voterGroupCert;
     CryptoECC.Signature permission;
-    CryptoECC.PublicKey voter_sig;
-    SortedMap<String,CryptoECC.Signature> vouchers;
+    CryptoECC.PublicSignKey voterSig;
+    SortedMap<String,CryptoECC.Signature> voucherSigs;
 
     /**
      * Choice in plaintext.
@@ -60,8 +64,8 @@
     /**
      * Load a ballot from file.
      *
+     * @param filename name of file to load ballot from
      * @throws InvalidBallotException
-     * @param filename
      */
     public Ballot(String filename) {
         Configuration cfg = new Configuration();
@@ -69,10 +73,49 @@
         fillBallot(cfg);
     }
 
+    /**
+     * Load a ballot from a configuration.
+     *
+     * @param cfg configuration to load ballot from
+     * @throws InvalidBallotException
+     */
     public Ballot(Configuration cfg) {
         fillBallot(cfg);
     }
 
+    /**
+     * Parse the specified time value from the ballot,
+     * converting a human-readable time value to human time when no
+     * timestamp is given.
+     * @param cfg configuration to read the value from
+     * @param timeValueName name suffix of the time option
+     * @return the time value
+     */
+    private AbsoluteTime getTime(Configuration cfg, String timeValueName) {
+        Optional<String> optTimeHuman = cfg.getValueString("election", "TIME_" 
+ timeValueName);
+        Optional<String> optTimeStamp = cfg.getValueString("election", 
"TIMESTAMP_" + timeValueName);
+        if (optTimeStamp.isPresent()) {
+            try {
+                long stamp = Long.parseLong(optTimeStamp.get());
+                return AbsoluteTime.fromSeconds(stamp);
+            } catch (NumberFormatException e) {
+                throw new InvalidBallotException("time value " + timeValueName 
+ " malformed");
+            }
+        } else if (optTimeHuman.isPresent()) {
+            AbsoluteTime time = AbsoluteTime.fromString(optTimeHuman.get());
+            if (null == time) {
+                throw new InvalidBallotException("timestamp value " + 
timeValueName + " malformed");
+            }
+            return time;
+        }
+        throw new InvalidBallotException("time value " + timeValueName + " 
missing");
+    }
+
+    /**
+     * Fill the ballot with information from the given configuration.
+     *
+     * @param cfg configuration to read from
+     */
     private void fillBallot(Configuration cfg) {
         Optional<String> optTopic = cfg.getValueString("election", "TOPIC");
         if (!optTopic.isPresent()) {
@@ -87,6 +130,11 @@
         if (choices.size() < 2) {
             throw new InvalidBallotException("less than two choices present");
         }
+        Optional<String> optGroup = cfg.getValueString("election", "GROUP");
+        if (!optGroup.isPresent()) {
+            throw new InvalidBallotException("ballot must have elegibility 
group");
+        }
+        group = optGroup.get();
         authorities = HashBiMap.create();
         for (Map.Entry<String,String> e : 
cfg.getSection("authorities").entrySet()) {
             String alias = e.getKey();
@@ -104,13 +152,13 @@
         if (!optCaPub.isPresent()) {
             throw new InvalidBallotException("no CA pub key given");
         }
-        caPub = CryptoECC.PublicKey.fromString(optCaPub.get());
+        caPub = CryptoECC.PublicSignKey.fromString(optCaPub.get());
         if (null == caPub) {
             throw new InvalidBallotException("CA pub key invalid");
         }
         Optional<String> optIssuerPub = cfg.getValueString("election", 
"ISSUER_PUB");
         if (optIssuerPub.isPresent()) {
-            issuerPub = CryptoECC.PublicKey.fromString(optIssuerPub.get());
+            issuerPub = CryptoECC.PublicSignKey.fromString(optIssuerPub.get());
             Optional<String> optIssuerSig = cfg.getValueString("election", 
"ISSUER_SIG");
             if (!optIssuerSig.isPresent()) {
                 throw new InvalidBallotException("issuer public key present, 
but no signature");
@@ -128,6 +176,17 @@
             }
             registrationSigs.put(e.getKey(), sig);
         }
+        voucherSigs = new TreeMap<String, CryptoECC.Signature>();
+        for (Map.Entry<String,String> e : 
cfg.getSection("vouchers").entrySet()) {
+            CryptoECC.Signature sig = 
CryptoECC.Signature.fromString(e.getValue());
+            if (null == sig) {
+                throw new InvalidBallotException("voucher signature has 
invalid format");
+            }
+            if (!authorities.containsKey(e.getKey())) {
+                throw new InvalidBallotException("ballot contains superfluous 
voucher signature");
+            }
+            voucherSigs.put(e.getKey(), sig);
+        }
         Optional<String> optChoiceId = cfg.getValueString("vote", "CHOICE_ID");
         if (optChoiceId.isPresent()) {
             choiceId = Integer.parseInt(optChoiceId.get());
@@ -137,11 +196,27 @@
         } else {
             choiceId = -1;
         }
+
+        Optional<String> optVoterPub = cfg.getValueString("vote", "VOTER_PUB");
+        if (optVoterPub.isPresent()) {
+            voterPub = CryptoECC.PublicSignKey.fromString(optVoterPub.get());
+        }
+
+        startTime = getTime(cfg, "START");
+        closingTime = getTime(cfg, "CLOSING");
+        queryTime = getTime(cfg, "QUERY");
+        endTime = getTime(cfg, "END");
     }
 
+    /**
+     * Get a hash code that uniquely defines the election information of
+     * the ballot.
+     *
+     * @return GUID of this ballot
+     */
     public HashCode getBallotGuid() {
-        if (issuerSig == null) {
-            throw new InvalidBallotException("can't compute GUID of non-issued 
ballot");
+        if (issuerPub == null) {
+            throw new InvalidBallotException("can't compute GUID of a ballot 
without issuer");
         }
         MessageDigest digest;
         try {
@@ -150,8 +225,6 @@
             throw new RuntimeException("crypto algorithm required but not 
provided");
         }
         digest.update(topic.getBytes());
-        //digest.update(Longs.toByteArray(electionStartTime.getSeconds()));
-        //digest.update(Longs.toByteArray(electionEndTime.getSeconds()));
         for (String choice : choices) {
             digest.update(choice.getBytes());
         }
@@ -163,11 +236,16 @@
         digest.update(issuerPub.y);
         digest.update(caPub.x);
         digest.update(caPub.y);
+        digest.update(Longs.toByteArray(startTime.getSeconds()));
+        digest.update(Longs.toByteArray(endTime.getSeconds()));
+        digest.update(Longs.toByteArray(closingTime.getSeconds()));
+        digest.update(Longs.toByteArray(queryTime.getSeconds()));
         return new HashCode(digest.digest());
     }
 
     /**
      * Encode the given choice permanently in the ballot.
+     * Also encodes the voter's public key.
      *
      * @param choice the choice to encode the ballot
      * @param privateKey the private key to use for encoding
@@ -181,22 +259,40 @@
             }
             i++;
         }
+        voterPub = CryptoECC.computePublicKey(privateKey);
         if (choiceId == -1) {
             throw new InvalidBallotException(String.format("choice '%s' not 
valid", choice));
         }
     }
 
+    /**
+     * Write the current state of the ballot to a configuration.
+     *
+     * @return a configuration with the state of this ballot
+     */
     public Configuration toConfiguration() {
         Configuration cfg = new Configuration();
         cfg.setValueString("election", "TOPIC", topic);
+        cfg.setValueString("election", "GROUP", group);
         cfg.setValueString("election", "CHOICES", 
Joiner.on("//").join(choices));
         cfg.setValueString("election", "CA_PUB", caPub.toString());
+        cfg.setValueNumber("election", "TIMESTAMP_START", 
startTime.getSeconds());
+        cfg.setValueNumber("election", "TIMESTAMP_CLOSING", 
startTime.getSeconds());
+        cfg.setValueNumber("election", "TIMESTAMP_QUERY", 
startTime.getSeconds());
+        cfg.setValueNumber("election", "TIMESTAMP_END", 
startTime.getSeconds());
         for (Map.Entry<String, PeerIdentity> e : authorities.entrySet()) {
             cfg.setValueString("authorities", e.getKey(), 
e.getValue().toString());
         }
-        for (Map.Entry<String, CryptoECC.Signature> e : 
registrationSigs.entrySet()) {
-            cfg.setValueString("registration-signatures", e.getKey(), 
e.getValue().toString());
+        if (null != registrationSigs) {
+            for (Map.Entry<String, CryptoECC.Signature> e : 
registrationSigs.entrySet()) {
+                cfg.setValueString("registration-signatures", e.getKey(), 
e.getValue().toString());
+            }
         }
+        if (null != voucherSigs) {
+            for (Map.Entry<String, CryptoECC.Signature> e : 
voucherSigs.entrySet()) {
+                cfg.setValueString("vouchers", e.getKey(), 
e.getValue().toString());
+            }
+        }
         if (null != issuerPub) {
             cfg.setValueString("election", "ISSUER_PUB", issuerPub.toString());
             cfg.setValueString("election", "ISSUER_SIG", issuerSig.toString());
@@ -204,19 +300,52 @@
         if (-1 != choiceId) {
             cfg.setValueNumber("vote", "CHOICE_ID", choiceId);
         }
+        if (null != voterPub) {
+            cfg.setValueString("vote", "VOTER_PUB", voterPub.toString());
+        }
         return cfg;
     }
 
+    /**
+     * Serialize the ballot to a string
+     *
+     * @return the serialized ballot
+     */
     public String serialize() {
         return toConfiguration().serialize();
     }
 
+
+    /**
+     * Get a human readable description of the ballot's current state.
+     *
+     * @return the ballot description
+     */
     public String describe() {
         StringBuilder buf = new StringBuilder();
+
         buf.append("Topic: ");
         buf.append("'");
         buf.append(topic);
         buf.append("'\n");
+
+        buf.append("Voter Group: ");
+        buf.append(group);
+        buf.append("\n");
+
+        buf.append("Start Time: ");
+        buf.append(startTime.toFancyString());
+        buf.append("\n");
+        buf.append("Closing Time: ");
+        buf.append(closingTime.toFancyString());
+        buf.append("\n");
+        buf.append("Query Time: ");
+        buf.append(queryTime.toFancyString());
+        buf.append("\n");
+        buf.append("End Time: ");
+        buf.append(endTime.toFancyString());
+        buf.append("\n");
+
         buf.append("Choices:\n");
         for (int i = 0; i < choices.size(); i++) {
             buf.append(""+(i+1));
@@ -247,6 +376,14 @@
             }
             buf.append("\n");
         }
+        if (!voucherSigs.isEmpty()) {
+            buf.append("ballot's vote has been submitted to with the following 
authorities:\n");
+            for (Map.Entry<String, CryptoECC.Signature> e : 
voucherSigs.entrySet()) {
+                buf.append(e.getKey());
+                buf.append(" ");
+            }
+            buf.append("\n");
+        }
         else {
             buf.append("ballot not registered\n");
         }
@@ -258,12 +395,27 @@
         return buf.toString();
     }
 
+
+    /**
+     * Get the list of authorities that did not yet receive the ballot's vote.
+     *
+     * @return list of unsubmitted-to authorities
+     */
     public List<PeerIdentity> getRemainingSubmitAuthorities() {
-        // FIXME: only return remaining authorities
-        return new ArrayList<PeerIdentity>(authorities.values());
+        LinkedList<PeerIdentity> remaining = new LinkedList<PeerIdentity>();
+        for (SortedMap.Entry<String,PeerIdentity> x : authorities.entrySet()) {
+            if (!voucherSigs.containsKey(x.getKey()))
+                remaining.add(x.getValue());
+        }
+        return remaining;
     }
 
-
+    /**
+     * Get a list of authorities that did not receive the registration for this
+     * ballot yet.
+     *
+     * @return list of authorities that don't know about this ballot
+     */
     public List<PeerIdentity> getRemainingRegisterAuthorities() {
         LinkedList<PeerIdentity> remaining = new LinkedList<PeerIdentity>();
         for (SortedMap.Entry<String,PeerIdentity> x : authorities.entrySet()) {
@@ -273,16 +425,44 @@
         return remaining;
     }
 
+    /**
+     * Add the issuer to the ballot, and sign the election information in the 
ballot.
+     *
+     * @param privateKey private key of the issuer
+     */
     public void issue(CryptoECC.PrivateKey privateKey) {
         issuerPub = CryptoECC.computePublicKey(privateKey);
         issuerSig = CryptoECC.sign(getBallotGuid().data, privateKey, 
issuerPub);
     }
 
+    /**
+     * Add an authorities registration signature to the list of known 
registrations.
+     *
+     * @param currentAuthority authority we registered with
+     * @param registrationSignature signature over this ballot's GUID from the 
authority
+     */
     public void addRegistrationSignature(PeerIdentity currentAuthority, 
CryptoECC.Signature registrationSignature) {
         String alias = authorities.inverse().get(currentAuthority);
         registrationSigs.put(alias, registrationSignature);
     }
 
+    /**
+     * Add a voucher, that is, a signature about the fact that an authority 
received a vote,
+     * to the list of vouchers
+     *
+     * @param currentAuthority authority that received the vote
+     * @param voucherSignature signature from the authority
+     */
+    public void addVoucher(PeerIdentity currentAuthority, CryptoECC.Signature 
voucherSignature) {
+        String alias = authorities.inverse().get(currentAuthority);
+        voucherSigs.put(alias, voucherSignature);
+    }
+
+    /**
+     * Get a list of all authorities.
+     *
+     * @return list of all authorities
+     */
     public List<PeerIdentity> getAuthorities() {
         return new ArrayList<PeerIdentity>(authorities.values());
     }

Modified: gnunet-java/src/main/java/org/gnunet/voting/BallotTool.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/BallotTool.java 2013-10-08 
20:56:51 UTC (rev 30014)
+++ gnunet-java/src/main/java/org/gnunet/voting/BallotTool.java 2013-10-08 
21:22:43 UTC (rev 30015)
@@ -25,26 +25,15 @@
 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.mesh.TunnelEndHandler;
-import org.gnunet.util.Configuration;
 import org.gnunet.util.CryptoECC;
-import org.gnunet.util.PeerIdentity;
 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.List;
-import java.util.regex.Pattern;
 
 /**
  * Tool for creating, manipulating and submitting ballot files.
@@ -89,11 +78,11 @@
             String select = null;
 
             @Argument(
-                    shortname = "p",
-                    longname = "permission",
+                    shortname = "G",
+                    longname = "certify-group",
                     action = ArgumentAction.SET,
-                    description = "request permission to vote from the 
certificate authority")
-             boolean permission = false;
+                    description = "request a certificate that the voter 
belongs to the ballot's group")
+             boolean certifyGroup = false;
 
             @Argument(
                     shortname = "V",
@@ -226,7 +215,7 @@
                     System.err.println("key invalid");
                     return;
                 }
-                CryptoECC.PublicKey publicKey = 
CryptoECC.computePublicKey(privateKey);
+                CryptoECC.PublicSignKey publicKey = 
CryptoECC.computePublicKey(privateKey);
                 System.out.println(publicKey.toString());
             }
 
@@ -302,12 +291,12 @@
                     c.run();
                     return;
                 }
-                if (permission) {
+                if (certifyGroup) {
                     if (this.unprocessedArgs.length != 2) {
-                        System.err.println("-p/--permission requires exactly 
two positional arguments");
+                        System.err.println("-G/--certify-group requires 
exactly two positional arguments");
                         return;
                     }
-                    PermissionCommand c = new 
PermissionCommand(getConfiguration(),
+                    CertifyGroupCommand c = new 
CertifyGroupCommand(getConfiguration(),
                             unprocessedArgs[0], unprocessedArgs[1]);
                     c.run();
                     return;

Copied: 
gnunet-java/src/main/java/org/gnunet/voting/CertificateAuthorityDaemon.java 
(from rev 29922, 
gnunet-java/src/main/java/org/gnunet/voting/CertificateAuthorityService.java)
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/CertificateAuthorityDaemon.java 
                        (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/voting/CertificateAuthorityDaemon.java 
2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,70 @@
+/*
+ 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.collect.Maps;
+import org.gnunet.mesh.Mesh;
+import org.gnunet.mesh.MeshRunabout;
+import org.gnunet.testbed.CompressedConfig;
+import org.gnunet.util.*;
+import org.gnunet.voting.messages.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Gives a voter a certificate that acknowledges that he belongs to a certain 
group
+ * (e.g. all people from bavaria over 18 years old)
+ */
+public class CertificateAuthorityDaemon extends Program {
+    private static final Logger logger = LoggerFactory
+            .getLogger(CertificateAuthorityDaemon.class);
+
+    public static final int MESH_PORT = 1002;
+    private Mesh mesh;
+
+    public class CaMeshReceiver extends MeshRunabout {
+        public void visit(CertificateRequestMessage m) {
+            logger.info("granting group cert for '" + m.group + "'");
+            CertificateGrantMessage gm = new CertificateGrantMessage();
+            gm.expiration = AbsoluteTime.FOREVER.asMessage();
+            gm.groupCertificate = CryptoECC.Signature.randomSignature();
+            getSender().receiveDone();
+        }
+    }
+
+    public CertificateAuthorityDaemon(String[] args) {
+        super(args);
+    }
+
+    public static void main(String[] args) {
+        CertificateAuthorityDaemon daemon = new 
CertificateAuthorityDaemon(args);
+        daemon.start();
+    }
+
+    @Override
+    public void run() {
+        logger.info("running ca daemon");
+        mesh = new Mesh(getConfiguration(), null, null, new CaMeshReceiver(), 
MESH_PORT);
+    }
+}

Deleted: 
gnunet-java/src/main/java/org/gnunet/voting/CertificateAuthorityService.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/voting/CertificateAuthorityService.java    
    2013-10-08 20:56:51 UTC (rev 30014)
+++ 
gnunet-java/src/main/java/org/gnunet/voting/CertificateAuthorityService.java    
    2013-10-08 21:22:43 UTC (rev 30015)
@@ -1,55 +0,0 @@
-/*
- 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 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);
-    }
-}

Copied: gnunet-java/src/main/java/org/gnunet/voting/CertifyGroupCommand.java 
(from rev 29922, 
gnunet-java/src/main/java/org/gnunet/voting/PermissionCommand.java)
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/CertifyGroupCommand.java        
                        (rev 0)
+++ gnunet-java/src/main/java/org/gnunet/voting/CertifyGroupCommand.java        
2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,129 @@
+/*
+ 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.
+ */
+
+/*
+ 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.
+ */
+
+/*
+ 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.mesh.TunnelEndHandler;
+import org.gnunet.util.Configuration;
+import org.gnunet.util.CryptoECC;
+import org.gnunet.voting.messages.CertificateGrantMessage;
+import org.gnunet.voting.messages.CertificateRequestMessage;
+import org.gnunet.voting.messages.QueryFailureMessage;
+
+import java.io.File;
+import java.util.Random;
+
+public class CertifyGroupCommand extends MeshRunabout implements 
TunnelEndHandler {
+    private final String ballotFilename;
+    private final String pubKeyString;
+    private Ballot ballot;
+    private final Configuration cfg;
+    private Mesh mesh;
+    private Mesh.Tunnel<Void> tunnel;
+    private boolean submitted = false;
+
+    @Override
+    public void onTunnelEnd(Mesh.Tunnel tunnel) {
+        if (!submitted)
+            throw new AssertionError();
+    }
+
+    public void visit(CertificateGrantMessage m) {
+        submitted = true;
+        System.out.println("certificate granted");
+
+        tunnel.destroy();
+        mesh.destroy();
+    }
+
+
+    public void visit(QueryFailureMessage m) {
+        submitted = true;
+        System.out.println("failure to query result: authority refused");
+        tunnel.destroy();
+        mesh.destroy();
+    }
+
+    public CertifyGroupCommand(Configuration cfg, String ballotFilename, 
String pubKeyString) {
+        this.cfg = cfg;
+        this.ballotFilename = ballotFilename;
+        this.pubKeyString = pubKeyString;
+    }
+
+    public void run() {
+        File bf = new File(ballotFilename);
+        if (!bf.exists()) {
+            System.err.println("ballot file does not exist");
+            return;
+        }
+        ballot = new Ballot(ballotFilename);
+
+        Random r = new Random();
+        mesh = new Mesh(cfg, this, this);
+        tunnel = mesh.createTunnel(null /* FIXME */, 
CertificateAuthorityDaemon.MESH_PORT, true, true, null);
+        CertificateRequestMessage m = new CertificateRequestMessage();
+        m.group = ballot.group;
+        m.publicKey = CryptoECC.PublicSignKey.fromString(pubKeyString);
+        tunnel.send(m);
+    }
+}

Deleted: gnunet-java/src/main/java/org/gnunet/voting/PermissionCommand.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/PermissionCommand.java  
2013-10-08 20:56:51 UTC (rev 30014)
+++ gnunet-java/src/main/java/org/gnunet/voting/PermissionCommand.java  
2013-10-08 21:22:43 UTC (rev 30015)
@@ -1,132 +0,0 @@
-/*
- 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.
- */
-
-/*
- 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.
- */
-
-/*
- 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.mesh.TunnelEndHandler;
-import org.gnunet.util.Configuration;
-import org.gnunet.util.PeerIdentity;
-import org.gnunet.voting.messages.QueryFailureMessage;
-import org.gnunet.voting.messages.QueryMessage;
-import org.gnunet.voting.messages.QueryResponseMessage;
-
-import java.io.File;
-import java.util.List;
-import java.util.Random;
-
-public class PermissionCommand extends MeshRunabout implements 
TunnelEndHandler {
-    private final String ballotFilename;
-    private Ballot ballot;
-    private final Configuration cfg;
-    private Mesh mesh;
-    private Mesh.Tunnel<Void> tunnel;
-    private boolean submitted = false;
-
-    @Override
-    public void onTunnelEnd(Mesh.Tunnel tunnel) {
-        if (!submitted)
-            throw new AssertionError();
-    }
-
-    public void visit(QueryResponseMessage m) {
-        submitted = true;
-        if (m.results.length != ballot.choices.size()) {
-            System.out.println("failure to query result: malformed response");
-        } else {
-            System.out.println("got results:");
-            for (int i = 0; i < m.results.length; i++) {
-                System.out.println("'" + ballot.choices.get(i) + "': " + 
m.results[i]);
-            }
-        }
-
-        tunnel.destroy();
-        mesh.destroy();
-    }
-
-
-    public void visit(QueryFailureMessage m) {
-        submitted = true;
-        System.out.println("failure to query result: authority refused");
-        tunnel.destroy();
-        mesh.destroy();
-    }
-
-    public PermissionCommand(Configuration cfg, String ballotFilename, String 
pubKeyString) {
-        this.cfg = cfg;
-        this.ballotFilename = ballotFilename;
-    }
-
-    public void run() {
-        File bf = new File(ballotFilename);
-        if (!bf.exists()) {
-            System.err.println("ballot file does not exist");
-            return;
-        }
-        ballot = new Ballot(ballotFilename);
-
-        Random r = new Random();
-        mesh = new Mesh(cfg, this, this);
-        tunnel = mesh.createTunnel(null /* FIXME */, 
CertificateAuthorityService.MESH_PORT, true, true, null);
-        //tunnel.send(m);
-    }
-}

Modified: gnunet-java/src/main/java/org/gnunet/voting/RegisterCommand.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/RegisterCommand.java    
2013-10-08 20:56:51 UTC (rev 30014)
+++ gnunet-java/src/main/java/org/gnunet/voting/RegisterCommand.java    
2013-10-08 21:22:43 UTC (rev 30015)
@@ -49,16 +49,18 @@
 import org.gnunet.testbed.CompressedConfig;
 import org.gnunet.util.Configuration;
 import org.gnunet.util.PeerIdentity;
+import org.gnunet.voting.messages.BallotRegisterFailureMessage;
 import org.gnunet.voting.messages.BallotRegisterRequestMessage;
-import org.gnunet.voting.messages.BallotRegisterRespondMessage;
-import org.gnunet.voting.messages.SubmitMessage;
-import org.gnunet.voting.messages.SubmitResponseMessage;
+import org.gnunet.voting.messages.BallotRegisterSuccessMessage;
 
 import java.io.File;
 import java.io.IOException;
 import java.util.List;
 import java.util.Random;
 
+/**
+ * Command for registering a ballot with an authority.
+ */
 public class RegisterCommand extends MeshRunabout implements TunnelEndHandler {
     private final String ballotFilename;
     private Ballot ballot;
@@ -74,9 +76,9 @@
             throw new AssertionError();
     }
 
-    public void visit(BallotRegisterRespondMessage m) {
+    public void visit(BallotRegisterSuccessMessage m) {
         submitted = true;
-        System.out.println("vote successfully registered");
+        System.out.println("ballot successfully registered");
         ballot.addRegistrationSignature(currentAuthority, 
m.registrationSignature);
         try {
             Files.write(ballot.serialize(), new File(ballotFilename), 
Charsets.UTF_8);
@@ -88,6 +90,14 @@
         mesh.destroy();
     }
 
+
+    public void visit(BallotRegisterFailureMessage m) {
+        submitted = true;
+        System.out.println("registering failed: " + m.reason);
+        tunnel.destroy();
+        mesh.destroy();
+    }
+
     public RegisterCommand(Configuration cfg, String ballotFilename) {
         this.cfg = cfg;
         this.ballotFilename = ballotFilename;

Modified: gnunet-java/src/main/java/org/gnunet/voting/SubmitCommand.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/SubmitCommand.java      
2013-10-08 20:56:51 UTC (rev 30014)
+++ gnunet-java/src/main/java/org/gnunet/voting/SubmitCommand.java      
2013-10-08 21:22:43 UTC (rev 30015)
@@ -21,18 +21,27 @@
 package org.gnunet.voting;
 
 
+import com.google.common.base.Charsets;
+import com.google.common.io.Files;
 import org.gnunet.mesh.Mesh;
 import org.gnunet.mesh.MeshRunabout;
 import org.gnunet.mesh.TunnelEndHandler;
+import org.gnunet.util.AbsoluteTime;
 import org.gnunet.util.Configuration;
+import org.gnunet.util.CryptoECC;
 import org.gnunet.util.PeerIdentity;
+import org.gnunet.voting.messages.SubmitFailureMessage;
 import org.gnunet.voting.messages.SubmitMessage;
-import org.gnunet.voting.messages.SubmitResponseMessage;
+import org.gnunet.voting.messages.SubmitSuccessMessage;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.List;
 import java.util.Random;
 
+/**
+ * Command that submits a ballot with a vote to a remaining authority.
+ */
 public class SubmitCommand extends MeshRunabout implements TunnelEndHandler {
     private final String ballotFilename;
     private Ballot ballot;
@@ -40,6 +49,7 @@
     private Mesh mesh;
     private Mesh.Tunnel<Void> tunnel;
     private boolean submitted = false;
+    private PeerIdentity currentAuthority;
 
     @Override
     public void onTunnelEnd(Mesh.Tunnel tunnel) {
@@ -47,13 +57,27 @@
             throw new AssertionError();
     }
 
-    public void visit(SubmitResponseMessage m) {
+    public void visit(SubmitSuccessMessage m) {
         submitted = true;
         System.out.println("vote successfully submitted");
+        ballot.addVoucher(currentAuthority, m.voucherSig);
+        try {
+            Files.write(ballot.serialize(), new File(ballotFilename), 
Charsets.UTF_8);
+        } catch (IOException e) {
+            System.out.println("could not write ballot file");
+            return;
+        }
         tunnel.destroy();
         mesh.destroy();
     }
 
+    public void visit(SubmitFailureMessage m) {
+        submitted = true;
+        System.out.println("vote not submitted: " + m.reason);
+        tunnel.destroy();
+        mesh.destroy();
+    }
+
     public SubmitCommand(Configuration cfg, String ballotFilename) {
         this.cfg = cfg;
         this.ballotFilename = ballotFilename;
@@ -74,9 +98,17 @@
         Random r = new Random();
         PeerIdentity authority = 
remainingAuthorities.get(r.nextInt(remainingAuthorities.size()));
         System.out.println("submitting to authority" + authority.toString());
+        currentAuthority = authority;
         mesh = new Mesh(cfg, null, this);
         tunnel = mesh.createTunnel(authority, TallyAuthorityDaemon.MESH_PORT, 
true, true, null);
         SubmitMessage m = new SubmitMessage();
+        if (ballot.voterPub == null) {
+            throw new InvalidBallotException("no voter in ballot");
+        }
+        m.voterPub = ballot.voterPub;
+        // FIXME: implement certs
+        m.groupCertExpiration = AbsoluteTime.FOREVER.asMessage();
+        m.groupCert = CryptoECC.Signature.randomSignature();
         m.ballotGuid = ballot.getBallotGuid();
         m.choiceId = ballot.choiceId;
         tunnel.send(m);

Modified: gnunet-java/src/main/java/org/gnunet/voting/TallyAuthorityDaemon.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/TallyAuthorityDaemon.java       
2013-10-08 20:56:51 UTC (rev 30014)
+++ gnunet-java/src/main/java/org/gnunet/voting/TallyAuthorityDaemon.java       
2013-10-08 21:22:43 UTC (rev 30015)
@@ -31,6 +31,10 @@
 
 import java.util.*;
 
+
+/**
+ * Daemon that is responsible for counting votes.
+ */
 public class TallyAuthorityDaemon extends Program {
     private static final Logger logger = LoggerFactory
             .getLogger(TallyAuthorityDaemon.class);
@@ -38,14 +42,23 @@
     public static final int MESH_PORT = 1002;
     private Mesh mesh;
 
+    /**
+     * All elections known to this authority
+     */
     private HashMap<HashCode, ElectionState> elections = Maps.newHashMap();
 
+    /**
+     * State of one election.
+     */
     class ElectionState {
+        /**
+         * The ballot that describes this election.
+         */
         Ballot ballot;
         /**
          * Set of voters that have submitted their ballot.
          */
-        Set<CryptoECC.PublicKey> voters = new HashSet<CryptoECC.PublicKey>();
+        Set<CryptoECC.PublicSignKey> voters = new 
HashSet<CryptoECC.PublicSignKey>();
 
         /**
          * Maping from choice to number of votes for that choice.
@@ -53,47 +66,92 @@
         int[] tally;
     }
 
-
     private class TallyMeshReceiver extends MeshRunabout {
         public void visit(SubmitMessage m) {
+            logger.debug("got submit message");
             ElectionState electionState = elections.get(m.ballotGuid);
             if (null == electionState) {
-                return;
+                SubmitFailureMessage fm = new SubmitFailureMessage();
+                fm.reason = "no matching ballot found";
+                getSender().send(fm);
+            } else if (m.choiceId < 0 || m.choiceId >= 
electionState.tally.length) {
+                SubmitFailureMessage fm = new SubmitFailureMessage();
+                fm.reason = "invalid vote";
+                getSender().send(fm);
+            } else if (electionState.voters.contains(m.voterPub)) {
+                SubmitFailureMessage fm = new SubmitFailureMessage();
+                fm.reason = "duplicate vote detected";
+                getSender().send(fm);
+            } else if (!electionState.ballot.startTime.isDue()) {
+                SubmitFailureMessage fm = new SubmitFailureMessage();
+                fm.reason = "too early to submit vote (start "
+                        + electionState.ballot.startTime.toFancyString() + ", 
now "
+                        + AbsoluteTime.now().toFancyString() + ")";
+                getSender().send(fm);
+            } else if (!electionState.ballot.closingTime.isDue()) {
+                SubmitFailureMessage fm = new SubmitFailureMessage();
+                fm.reason = "too late to submit vote";
+                getSender().send(fm);
             }
-            if (m.choiceId < 0 || m.choiceId >= electionState.tally.length) {
-                return;
+            // FIXME: check signatures of voter and CA
+            else {
+                electionState.voters.add(m.voterPub);
+                electionState.tally[m.choiceId] += 1;
+                SubmitSuccessMessage sm = new SubmitSuccessMessage();
+                sm.voucherSig = CryptoECC.Signature.randomSignature();
+                getSender().send(sm);
             }
-            electionState.tally[m.choiceId] += 1;
-            SubmitResponseMessage rm = new SubmitResponseMessage();
-            getSender().send(rm);
+
             getSender().receiveDone();
         }
 
         public void visit(BallotRegisterRequestMessage m) {
             logger.info("ballot register requested");
+            CompressedConfig ccfg = new 
CompressedConfig(m.compressedBallotConfig);
+            Ballot b;
+            HashCode guid;
+            try {
+                b = new Ballot(ccfg.decompress());
+                guid = b.getBallotGuid();
+            } catch (InvalidBallotException e) {
+                BallotRegisterFailureMessage fm = new 
BallotRegisterFailureMessage();
+                fm.reason = "invalid ballot (" + e.getMessage() + ")";
+                getSender().send(fm);
+                getSender().receiveDone();
+                return;
+            }
+            if (elections.containsKey(guid)) {
+                BallotRegisterFailureMessage fm = new 
BallotRegisterFailureMessage();
+                fm.reason = "ballot with same GUID already registered";
+                getSender().send(fm);
+            } else {
+                ElectionState electionState = new ElectionState();
+                electionState.tally = new int[b.choices.size()];
+                electionState.ballot = b;
+                elections.put(guid, electionState);
+                BallotRegisterSuccessMessage rm = new 
BallotRegisterSuccessMessage();
+                rm.registrationSignature = 
CryptoECC.Signature.randomSignature();
+                getSender().send(rm);
+            }
 
-            CompressedConfig ccfg = new 
CompressedConfig(m.compressedBallotConfig);
-            Ballot b = new Ballot(ccfg.decompress());
-            ElectionState electionState = new ElectionState();
-            electionState.tally = new int[b.choices.size()];
-            electionState.ballot = b;
-            elections.put(b.getBallotGuid(), electionState);
-            BallotRegisterRespondMessage rm = new 
BallotRegisterRespondMessage();
-            rm.registrationSignature = CryptoECC.Signature.randomSignature();
-            getSender().send(rm);
-            getSender().receiveDone();
         }
 
         public void visit(QueryMessage m) {
             ElectionState electionState = elections.get(m.ballotGUID);
             if (null == electionState) {
                 QueryFailureMessage rm = new QueryFailureMessage();
+                rm.reason = "no matching ballot found";
                 getSender().send(rm);
-
             } else {
-                QueryResponseMessage rm = new QueryResponseMessage();
-                rm.results = electionState.tally;
-                getSender().send(rm);
+                if (electionState.ballot.queryTime.isDue()) {
+                    QueryResponseMessage rm = new QueryResponseMessage();
+                    rm.results = electionState.tally;
+                    getSender().send(rm);
+                } else {
+                    QueryFailureMessage rm = new QueryFailureMessage();
+                    rm.reason = "result query not allowed yet";
+                    getSender().send(rm);
+                }
             }
             getSender().receiveDone();
         }

Added: 
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterFailureMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterFailureMessage.java
                              (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterFailureMessage.java
      2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,37 @@
+/*
+ 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.messages;
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.construct.ZeroTerminatedString;
+import org.gnunet.util.CryptoECC;
+import org.gnunet.util.GnunetMessage;
+
+
+/**
+ * Response from the authorities to the issuer.
+ */
address@hidden(42002)
+public class BallotRegisterFailureMessage implements GnunetMessage.Body {
+    @ZeroTerminatedString
+    public String reason;
+}

Modified: 
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterRequestMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterRequestMessage.java
      2013-10-08 20:56:51 UTC (rev 30014)
+++ 
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterRequestMessage.java
      2013-10-08 21:22:43 UTC (rev 30015)
@@ -4,6 +4,9 @@
 import org.gnunet.construct.UnionCase;
 import org.gnunet.util.GnunetMessage;
 
+/**
+ * Sent by an issuer to the authorities to register a ballot with them.
+ */
 @UnionCase(42001)
 public class BallotRegisterRequestMessage implements GnunetMessage.Body {
     @IntegerFill(signed = false, bitSize = 8)

Deleted: 
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterRespondMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterRespondMessage.java
      2013-10-08 20:56:51 UTC (rev 30014)
+++ 
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterRespondMessage.java
      2013-10-08 21:22:43 UTC (rev 30015)
@@ -1,12 +0,0 @@
-package org.gnunet.voting.messages;
-
-import org.gnunet.construct.NestedMessage;
-import org.gnunet.construct.UnionCase;
-import org.gnunet.util.CryptoECC;
-import org.gnunet.util.GnunetMessage;
-
address@hidden(42002)
-public class BallotRegisterRespondMessage implements GnunetMessage.Body {
-    @NestedMessage
-    public CryptoECC.Signature registrationSignature;
-}

Copied: 
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterSuccessMessage.java
 (from rev 29922, 
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterRespondMessage.java)
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterSuccessMessage.java
                              (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/voting/messages/BallotRegisterSuccessMessage.java
      2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,16 @@
+package org.gnunet.voting.messages;
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.CryptoECC;
+import org.gnunet.util.GnunetMessage;
+
+
+/**
+ * Response from the authorities to the issuer.
+ */
address@hidden(42012)
+public class BallotRegisterSuccessMessage implements GnunetMessage.Body {
+    @NestedMessage
+    public CryptoECC.Signature registrationSignature;
+}

Added: 
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateDenyMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateDenyMessage.java
                            (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateDenyMessage.java
    2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,34 @@
+/*
+ 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.messages;
+
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.construct.ZeroTerminatedString;
+import org.gnunet.util.CryptoECC;
+import org.gnunet.util.GnunetMessage;
+
address@hidden(42011)
+public class CertificateDenyMessage implements GnunetMessage.Body {
+    @ZeroTerminatedString
+    public String reason;
+}

Copied: 
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateGrantMessage.java
 (from rev 29922, 
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateResponseMessage.java)
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateGrantMessage.java
                           (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateGrantMessage.java
   2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,19 @@
+package org.gnunet.voting.messages;
+
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UInt64;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.AbsoluteTime;
+import org.gnunet.util.AbsoluteTimeMessage;
+import org.gnunet.util.CryptoECC;
+import org.gnunet.util.GnunetMessage;
+
address@hidden(42004)
+public class CertificateGrantMessage implements GnunetMessage.Body {
+    @NestedMessage
+    public CryptoECC.Signature groupCertificate;
+    @NestedMessage
+    public AbsoluteTimeMessage expiration;
+}

Modified: 
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateRequestMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateRequestMessage.java
 2013-10-08 20:56:51 UTC (rev 30014)
+++ 
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateRequestMessage.java
 2013-10-08 21:22:43 UTC (rev 30015)
@@ -1,6 +1,8 @@
 package org.gnunet.voting.messages;
 
+import org.gnunet.construct.NestedMessage;
 import org.gnunet.construct.UnionCase;
+import org.gnunet.util.CryptoECC;
 import org.gnunet.util.GnunetMessage;
 
 /**
@@ -9,4 +11,13 @@
  */
 @UnionCase(42003)
 public class CertificateRequestMessage implements GnunetMessage.Body {
+    /**
+     * Public Key of the voter that requests group certification.
+     */
+    @NestedMessage
+    public CryptoECC.PublicSignKey publicKey;
+    /**
+     * Group that the voter wants to be certified for.
+     */
+    public String group;
 }

Deleted: 
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateResponseMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateResponseMessage.java
        2013-10-08 20:56:51 UTC (rev 30014)
+++ 
gnunet-java/src/main/java/org/gnunet/voting/messages/CertificateResponseMessage.java
        2013-10-08 21:22:43 UTC (rev 30015)
@@ -1,9 +0,0 @@
-package org.gnunet.voting.messages;
-
-
-import org.gnunet.construct.UnionCase;
-import org.gnunet.util.GnunetMessage;
-
address@hidden(42004)
-public class CertificateResponseMessage implements GnunetMessage.Body {
-}

Modified: 
gnunet-java/src/main/java/org/gnunet/voting/messages/QueryFailureMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/voting/messages/QueryFailureMessage.java   
    2013-10-08 20:56:51 UTC (rev 30014)
+++ 
gnunet-java/src/main/java/org/gnunet/voting/messages/QueryFailureMessage.java   
    2013-10-08 21:22:43 UTC (rev 30015)
@@ -21,8 +21,11 @@
 package org.gnunet.voting.messages;
 
 import org.gnunet.construct.UnionCase;
+import org.gnunet.construct.ZeroTerminatedString;
 import org.gnunet.util.GnunetMessage;
 
 @UnionCase(42009)
 public class QueryFailureMessage implements GnunetMessage.Body {
+    @ZeroTerminatedString
+    public String reason;
 }

Added: 
gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitFailureMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitFailureMessage.java  
                            (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitFailureMessage.java  
    2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,32 @@
+/*
+ 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.messages;
+
+
+import org.gnunet.construct.UnionCase;
+import org.gnunet.construct.ZeroTerminatedString;
+import org.gnunet.util.GnunetMessage;
+
address@hidden(42010)
+public class SubmitFailureMessage implements GnunetMessage.Body {
+    @ZeroTerminatedString
+    public String reason;
+}

Modified: 
gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitMessage.java     
2013-10-08 20:56:51 UTC (rev 30014)
+++ gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitMessage.java     
2013-10-08 21:22:43 UTC (rev 30015)
@@ -3,17 +3,37 @@
 import org.gnunet.construct.NestedMessage;
 import org.gnunet.construct.UInt32;
 import org.gnunet.construct.UnionCase;
-import org.gnunet.construct.ZeroTerminatedString;
-import org.gnunet.util.GnunetMessage;
-import org.gnunet.util.HashCode;
+import org.gnunet.util.*;
 
 /**
  * Message send by the voter to the election authority to submit a vote.
  */
 @UnionCase(42007)
 public class SubmitMessage implements GnunetMessage.Body {
+    /**
+     * Identifier of the ballot we want to vote in.
+     */
     @NestedMessage
     public HashCode ballotGuid;
+    /**
+     * Public key of the voter.
+     */
+    @NestedMessage
+    public CryptoECC.PublicSignKey voterPub;
+    /**
+     * Group certificate of the voter.
+     */
+    @NestedMessage
+    public CryptoECC.Signature groupCert;
+    /**
+     * Expiration time of the group certificate, checked by the authority.
+     */
+    @NestedMessage
+    public AbsoluteTimeMessage groupCertExpiration;
+    /**
+     * The actual vote.
+     * FIXME: this will be encrypted!
+     */
     @UInt32
     public int choiceId;
 }

Deleted: 
gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitResponseMessage.java
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitResponseMessage.java 
    2013-10-08 20:56:51 UTC (rev 30014)
+++ 
gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitResponseMessage.java 
    2013-10-08 21:22:43 UTC (rev 30015)
@@ -1,9 +0,0 @@
-package org.gnunet.voting.messages;
-
-
-import org.gnunet.construct.UnionCase;
-import org.gnunet.util.GnunetMessage;
-
address@hidden(42008)
-public class SubmitResponseMessage implements GnunetMessage.Body {
-}

Copied: 
gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitSuccessMessage.java 
(from rev 29922, 
gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitResponseMessage.java)
===================================================================
--- 
gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitSuccessMessage.java  
                            (rev 0)
+++ 
gnunet-java/src/main/java/org/gnunet/voting/messages/SubmitSuccessMessage.java  
    2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,13 @@
+package org.gnunet.voting.messages;
+
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.CryptoECC;
+import org.gnunet.util.GnunetMessage;
+
address@hidden(42008)
+public class SubmitSuccessMessage implements GnunetMessage.Body {
+    @NestedMessage
+    public CryptoECC.Signature voucherSig;
+}

Modified: gnunet-java/src/main/resources/org/gnunet/construct/MsgMap.txt
===================================================================
--- gnunet-java/src/main/resources/org/gnunet/construct/MsgMap.txt      
2013-10-08 20:56:51 UTC (rev 30014)
+++ gnunet-java/src/main/resources/org/gnunet/construct/MsgMap.txt      
2013-10-08 21:22:43 UTC (rev 30015)
@@ -1,31 +1,37 @@
 org.gnunet.util.Resolver$Address|0=org.gnunet.util.Resolver$TextualAddress
 org.gnunet.util.Resolver$Address|1=org.gnunet.util.Resolver$NumericAddress
+org.gnunet.util.GnunetMessage$Body|274=org.gnunet.mesh.TunnelDestroyMessage
 org.gnunet.util.GnunetMessage$Body|1=org.gnunet.util.TestMessage
-org.gnunet.util.GnunetMessage$Body|274=org.gnunet.mesh.TunnelDestroyMessage
 org.gnunet.util.GnunetMessage$Body|273=org.gnunet.mesh.TunnelCreateMessage
 org.gnunet.util.GnunetMessage$Body|272=org.gnunet.mesh.ClientConnectMessage
 org.gnunet.util.GnunetMessage$Body|4=org.gnunet.util.Resolver$GetMessage
 org.gnunet.util.GnunetMessage$Body|5=org.gnunet.util.Resolver$ResolverResponse
 org.gnunet.util.GnunetMessage$Body|143=org.gnunet.dht.ClientGetMessage
 org.gnunet.util.GnunetMessage$Body|142=org.gnunet.dht.ClientPutMessage
+org.gnunet.util.GnunetMessage$Body|10=org.gnunet.arm.messages.ResultMessage
+org.gnunet.util.GnunetMessage$Body|11=org.gnunet.arm.messages.StatusMessage
 org.gnunet.util.GnunetMessage$Body|286=org.gnunet.mesh.LocalAckMessage
+org.gnunet.util.GnunetMessage$Body|13=org.gnunet.arm.messages.ListResultMessage
 org.gnunet.util.GnunetMessage$Body|285=org.gnunet.mesh.DataMessage
 
org.gnunet.util.GnunetMessage$Body|42003=org.gnunet.voting.messages.CertificateRequestMessage
 org.gnunet.util.GnunetMessage$Body|153=org.gnunet.dht.MonitorStartStop
-org.gnunet.util.GnunetMessage$Body|42002=org.gnunet.voting.messages.BallotRegisterRespondMessage
+org.gnunet.util.GnunetMessage$Body|42002=org.gnunet.voting.messages.BallotRegisterFailureMessage
 
org.gnunet.util.GnunetMessage$Body|42001=org.gnunet.voting.messages.BallotRegisterRequestMessage
 
org.gnunet.util.GnunetMessage$Body|155=org.gnunet.dht.ClientPutConfirmationMessage
 
org.gnunet.util.GnunetMessage$Body|42007=org.gnunet.voting.messages.SubmitMessage
 
org.gnunet.util.GnunetMessage$Body|42006=org.gnunet.voting.messages.QueryResponseMessage
 
org.gnunet.util.GnunetMessage$Body|42005=org.gnunet.voting.messages.QueryMessage
-org.gnunet.util.GnunetMessage$Body|42004=org.gnunet.voting.messages.CertificateResponseMessage
+org.gnunet.util.GnunetMessage$Body|42004=org.gnunet.voting.messages.CertificateGrantMessage
+org.gnunet.util.GnunetMessage$Body|42011=org.gnunet.voting.messages.CertificateDenyMessage
 org.gnunet.util.GnunetMessage$Body|144=org.gnunet.dht.ClientGetStopMessage
 org.gnunet.util.GnunetMessage$Body|145=org.gnunet.dht.ClientResultMessage
+org.gnunet.util.GnunetMessage$Body|42010=org.gnunet.voting.messages.SubmitFailureMessage
 
org.gnunet.util.GnunetMessage$Body|42009=org.gnunet.voting.messages.QueryFailureMessage
-org.gnunet.util.GnunetMessage$Body|42008=org.gnunet.voting.messages.SubmitResponseMessage
+org.gnunet.util.GnunetMessage$Body|42008=org.gnunet.voting.messages.SubmitSuccessMessage
 org.gnunet.util.GnunetMessage$Body|149=org.gnunet.dht.MonitorGetMessage
 org.gnunet.util.GnunetMessage$Body|150=org.gnunet.dht.MonitorGetRespMessage
 org.gnunet.util.GnunetMessage$Body|151=org.gnunet.dht.MonitorPutMessage
+org.gnunet.util.GnunetMessage$Body|42012=org.gnunet.voting.messages.BallotRegisterSuccessMessage
 
org.gnunet.util.GnunetMessage$Body|171=org.gnunet.statistics.GetResponseEndMessage
 org.gnunet.util.GnunetMessage$Body|170=org.gnunet.statistics.GetResponseMessage
 org.gnunet.util.GnunetMessage$Body|169=org.gnunet.statistics.GetMessage
@@ -57,9 +63,17 @@
 
org.gnunet.util.GnunetMessage$Body|464=org.gnunet.testbed.messages.PeerCreateMessage
 org.gnunet.util.GnunetMessage$Body|75=org.gnunet.core.SendMessageReady
 
org.gnunet.util.GnunetMessage$Body|465=org.gnunet.testbed.messages.PeerReconfigureMessage
+org.gnunet.util.GnunetMessage$Body|627=org.gnunet.identity.messages.GetDefaultMessage
+org.gnunet.util.GnunetMessage$Body|626=org.gnunet.identity.messages.UpdateListMessage
+org.gnunet.util.GnunetMessage$Body|625=org.gnunet.identity.messages.ResultCodeMessage
 
org.gnunet.util.GnunetMessage$Body|460=org.gnunet.testbed.messages.ControllerInitMessage
+org.gnunet.util.GnunetMessage$Body|624=org.gnunet.identity.messages.StartMessage
+org.gnunet.util.GnunetMessage$Body|631=org.gnunet.identity.messages.DeleteMessage
+org.gnunet.util.GnunetMessage$Body|630=org.gnunet.identity.messages.RenameMessage
 org.gnunet.util.GnunetMessage$Body|323=org.gnunet.nse.UpdateMessage
+org.gnunet.util.GnunetMessage$Body|629=org.gnunet.identity.messages.CreateRequestMessage
 org.gnunet.util.GnunetMessage$Body|321=org.gnunet.nse.StartMessage
+org.gnunet.util.GnunetMessage$Body|628=org.gnunet.identity.messages.SetDefaultMessage
 org.gnunet.util.GnunetMessage$Body|332=org.gnunet.peerinfo.InfoMessage
 org.gnunet.util.GnunetMessage$Body|333=org.gnunet.peerinfo.InfoEnd
 org.gnunet.util.GnunetMessage$Body|331=org.gnunet.peerinfo.ListAllPeersMessage
@@ -73,4 +87,4 @@
 org.gnunet.util.GnunetMessage$Body|360=org.gnunet.transport.StartMessage
 
org.gnunet.util.GnunetMessage$Body|483=org.gnunet.testbed.messages.ManagePeerServiceMessage
 org.gnunet.construct.MessageUnion|525=org.gnunet.consensus.ConcludeDoneMessage
-# generated 2013/09/25 01:34:20
+# generated 2013/10/08 22:01:30

Modified: gnunet-java/src/main/resources/org/gnunet/voting/template.espec
===================================================================
--- gnunet-java/src/main/resources/org/gnunet/voting/template.espec     
2013-10-08 20:56:51 UTC (rev 30014)
+++ gnunet-java/src/main/resources/org/gnunet/voting/template.espec     
2013-10-08 21:22:43 UTC (rev 30015)
@@ -9,20 +9,23 @@
 # choices for the voter, separated by a double slash
 CHOICES = yes//no
 
+# group of elegible voters, voters must be certified by the CA to
+# belong to this group
+GROUP =
+
 # starting time of the election, in the local time of the election issuer
 # authorities affirm that they are available for the election from this point 
in time
-ELECTION_START =
+TIME_START =
 
-# election start time, as posix time stamp
-# ELECTION_START_POSIX
+# what is the deadline for vote submission?
+# after this deadline, authorities work together to count ballots
+TIME_CLOSING =
 
-# deadline for vote submission, in the local time of the election issuer
-# must be later than ELECTION_START
-ELECTION_END =
+# when may results be queried?
+TIME_QUERY =
 
-# 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 =
+# FIXME: specify more parameters for consensus? which ones?
+# CONSENSUS_PARAMETERS =
 
 # public key of the certificate authority
 CA_PUB =
@@ -48,14 +51,8 @@
 # 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]
+[vote]
+# voter signature, pubkey, group cert,
 # encrypted vote and non-interactive zero knowledge proofs come here
 
 

Added: gnunet-java/src/test/java/org/gnunet/identity/IdentityTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/identity/IdentityTest.java             
                (rev 0)
+++ gnunet-java/src/test/java/org/gnunet/identity/IdentityTest.java     
2013-10-08 21:22:43 UTC (rev 30015)
@@ -0,0 +1,123 @@
+/*
+ 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.identity;
+
+
+import org.gnunet.testing.TestingSubsystem;
+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 IdentityTest {
+    @Test
+    public void test_identity_connect() {
+        final Wrapper<Boolean> reachedEnd = new Wrapper<Boolean>(false);
+        Program.configureLogging("DEBUG");
+        TestingSubsystem ts = new TestingSubsystem("identity");
+
+        final Identity identity = new Identity();
+        identity.connect(ts.getConfiguration(), new IdentityListCallback() {
+            @Override
+            public void onEgoAdd(Identity.Ego ego) {
+                System.out.println("got ego " + ego.getName());
+            }
+
+            @Override
+            public void onEgoDelete(Identity.Ego ego) {
+                // should only happen after end of list,
+                // but we disconnect on end of list
+                Assert.fail();
+            }
+
+            @Override
+            public void onEgoRename(String oldName, Identity.Ego ego) {
+                Assert.fail();
+            }
+
+            @Override
+            public void onListEnd() {
+                System.out.println("got end of list");
+                reachedEnd.set(true);
+                identity.disconnect();
+            }
+        });
+        Scheduler.run();
+        Assert.assertTrue(reachedEnd.get());
+    }
+
+    @Test
+    public void test_identity_create() {
+        final Wrapper<Boolean> created = new Wrapper<Boolean>(false);
+        final Wrapper<Boolean> gotEnd = new Wrapper<Boolean>(false);
+        final Wrapper<Boolean> gotCreated = new Wrapper<Boolean>(false);
+        Program.configureLogging("DEBUG");
+        TestingSubsystem ts = new TestingSubsystem("identity");
+
+        final String myEgoName = "gnunet-java-test-ego";
+
+        final Identity identity = new Identity();
+        identity.connect(ts.getConfiguration(), new IdentityListCallback() {
+            @Override
+            public void onEgoAdd(Identity.Ego ego) {
+                if (created.get() && ego.getName().equals(myEgoName)) {
+                    gotCreated.set(true);
+                    identity.disconnect();
+                }
+            }
+
+            @Override
+            public void onEgoDelete(Identity.Ego ego) {
+                // should only happen after end of list,
+                // but we disconnect on end of list
+                Assert.fail();
+            }
+
+            @Override
+            public void onEgoRename(String oldName, Identity.Ego ego) {
+                Assert.fail();
+            }
+
+            @Override
+            public void onListEnd() {
+                System.out.println("got end of list");
+                gotEnd.set(true);
+            }
+        });
+        identity.create(myEgoName, new IdentityContinuation() {
+            @Override
+            public void onError(String errorMessage) {
+                Assert.fail(errorMessage);
+            }
+
+            @Override
+            public void onDone() {
+                Assert.assertFalse(created.get());
+                created.set(true);
+            }
+        });
+        Scheduler.run();
+        Assert.assertTrue(created.get());
+        Assert.assertTrue(gotCreated.get());
+        Assert.assertTrue(gotEnd.get());
+    }
+}

Modified: gnunet-java/src/test/java/org/gnunet/testbed/TestbedTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/testbed/TestbedTest.java       
2013-10-08 20:56:51 UTC (rev 30014)
+++ gnunet-java/src/test/java/org/gnunet/testbed/TestbedTest.java       
2013-10-08 21:22:43 UTC (rev 30015)
@@ -12,7 +12,7 @@
 
 public class TestbedTest extends TestingFixture {
 
-    @Test(timeout = 1000)
+    @Test(timeout = 10000)
     public void test_controller_proc() {
         final Wrapper<Boolean> success = new Wrapper<Boolean>(false);
         new Program("-LDEBUG") {
@@ -38,16 +38,13 @@
     }
 
 
-    @Test(timeout = 1000)
+    @Test(timeout = 10000)
     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) {
@@ -71,7 +68,7 @@
                     @Override
                     public void onStartupSuccess(Configuration cfg) {
                         System.out.println("startup success");
-                        c = new Controller(h, 1 | 2 | 4 | 8 | 32, new CEC());
+                        c = new Controller(h);
                         // FIXME: use config from resource
                         c.createPeer(h, getConfiguration(), new PCB());
                     }
@@ -84,16 +81,13 @@
         }.start();
     }
 
-    @Test(timeout = 1000)
+    @Test(timeout = 10000)
     public void test_peer_destroy() {
         new Program("-LDEBUG") {
             ControllerProc cp;
             Host h;
             Controller c;
 
-            class CEC extends ControllerEventCallback {
-            }
-
             class PCB implements PeerCreateCallback {
                 @Override
                 public void onPeerCreated(final Controller.Peer peer) {
@@ -128,7 +122,7 @@
                     @Override
                     public void onStartupSuccess(Configuration cfg) {
                         System.out.println("startup success");
-                        c = new Controller(h, 1 | 2 | 4 | 8 | 32, new CEC());
+                        c = new Controller(h);
                         // FIXME: use config from resource
                         c.createPeer(h, getConfiguration(), new PCB());
                     }
@@ -141,7 +135,7 @@
         }.start();
     }
 
-    @Test(timeout = 5000)
+    @Test(timeout = 10000)
     public void test_peer_start() {
         final Wrapper<Boolean> startSuccessful = new Wrapper<Boolean>(false);
         int ret = new Program("-LDEBUG") {
@@ -149,9 +143,6 @@
             Host h;
             Controller c;
 
-            class CEC extends ControllerEventCallback {
-            }
-
             class MyPeerChurnCallback implements PeerChurnCallback {
 
                 @Override
@@ -190,7 +181,7 @@
                     @Override
                     public void onStartupSuccess(Configuration cfg) {
                         System.out.println("controller started");
-                        c = new Controller(h, 1 | 2 | 4 | 8 | 32, new CEC());
+                        c = new Controller(h);
                         // FIXME: use config from resource
                         c.createPeer(h, getConfiguration(), new 
MyPeerCreateCallback());
                     }
@@ -205,7 +196,7 @@
         Assert.assertEquals(0, ret);
     }
 
-    @Test(timeout = 5000)
+    @Test(timeout = 10000)
     public void test_peer_stop() {
         final Wrapper<Boolean> startSuccessful = new Wrapper<Boolean>(false);
         final Wrapper<Boolean> stopSuccessful = new Wrapper<Boolean>(false);
@@ -215,9 +206,6 @@
             Controller c;
             Controller.Peer p;
 
-            class CEC extends ControllerEventCallback {
-            }
-
             class MyPeerStopCallback implements PeerChurnCallback {
 
                 @Override
@@ -271,7 +259,7 @@
                     @Override
                     public void onStartupSuccess(Configuration cfg) {
                         System.out.println("controller started");
-                        c = new Controller(h, 1 | 2 | 4 | 8 | 32, new CEC());
+                        c = new Controller(h);
                         // FIXME: use config from resource
                         c.createPeer(h, getConfiguration(), new 
MyPeerCreateCallback());
                     }
@@ -287,7 +275,7 @@
         Assert.assertEquals(0, ret);
     }
 
-    @Test(timeout = 5000)
+    @Test(timeout = 10000)
     public void test_peer_stop_destroy() {
         final Wrapper<Boolean> startSuccessful = new Wrapper<Boolean>(false);
         final Wrapper<Boolean> stopSuccessful = new Wrapper<Boolean>(false);
@@ -298,9 +286,6 @@
             Controller c;
             Controller.Peer p;
 
-            class CEC extends ControllerEventCallback {
-            }
-
             class MyPeerDestroyCallback implements OperationCompletionCallback 
{
 
                 @Override
@@ -367,7 +352,7 @@
                     @Override
                     public void onStartupSuccess(Configuration cfg) {
                         System.out.println("controller started");
-                        c = new Controller(h, 1 | 2 | 4 | 8 | 32, new CEC());
+                        c = new Controller(h);
                         // FIXME: use config from resource
                         c.createPeer(h, getConfiguration(), new 
MyPeerCreateCallback());
                     }
@@ -394,9 +379,6 @@
             Controller c;
             Controller.Peer p;
 
-            class CEC extends ControllerEventCallback {
-            }
-
             class MyPeerInformationCallback implements PeerInformationCallback 
{
                 @Override
                 public void onSuccess(PeerIdentity peerIdentity, Configuration 
configuration) {
@@ -433,7 +415,7 @@
                     @Override
                     public void onStartupSuccess(Configuration cfg) {
                         System.out.println("controller started");
-                        c = new Controller(h, 1 | 2 | 4 | 8 | 32, new CEC());
+                        c = new Controller(h);
                         // FIXME: use config from resource
                         c.createPeer(h, getConfiguration(), new 
MyPeerCreateCallback());
                     }
@@ -449,10 +431,9 @@
         Assert.assertEquals(0, ret);
     }
 
-    @Test(timeout = 5000)
+    @Test
     public void test_peer_reconfigure() {
         final Wrapper<Boolean> startSuccessful = new Wrapper<Boolean>(false);
-        final Wrapper<Boolean> infoSuccessful = new Wrapper<Boolean>(false);
         final Wrapper<Boolean> reconfigureSuccessful = new 
Wrapper<Boolean>(false);
         int ret = new Program("-LDEBUG") {
             ControllerProc cp;
@@ -460,9 +441,6 @@
             Controller c;
             Controller.Peer p;
 
-            class CEC extends ControllerEventCallback {
-            }
-
             class MyUpdateConfigDoneCallback implements 
OperationCompletionCallback {
                 @Override
                 public void onCompletion() {
@@ -478,30 +456,15 @@
                 }
             }
 
-            /*
-            class MyPeerInformationCallback implements PeerInformationCallback 
{
-                @Override
-                public void onSuccess(PeerIdentity peerIdentity, Configuration 
configuration) {
-                    Assert.assertNotNull(peerIdentity);
-                    Assert.assertNotNull(configuration);
-                    Assert.assertTrue(configuration.getSections().size() > 0);
-                    infoSuccessful.set(true);
-                    System.out.println("updating configuration");
-                    p.updateConfiguration(cfg, new 
MyUpdateConfigDoneCallback());
-                }
-            }
-
-            */
-
             class MyPeerCreateCallback implements PeerCreateCallback {
                 @Override
                 public void onPeerCreated(Controller.Peer peer) {
                     p = peer;
                     System.out.println("peer created");
                     startSuccessful.set(true);
-                    //peer.requestInformation(new MyPeerInformationCallback());
 
                     Configuration cfg = new Configuration();
+                    cfg.setValueNumber("foo", "bar", 42);
                     cfg.setValueString("my-test-section", "my-test-option", 
"my-test-value");
                     peer.updateConfiguration(cfg, new 
MyUpdateConfigDoneCallback());
                 }
@@ -522,7 +485,7 @@
                     @Override
                     public void onStartupSuccess(Configuration cfg) {
                         System.out.println("controller started");
-                        c = new Controller(h, 1 | 2 | 4 | 8 | 32, new CEC());
+                        c = new Controller(h);
                         // FIXME: use config from resource
                         c.createPeer(h, configuration, new 
MyPeerCreateCallback());
                     }
@@ -549,9 +512,6 @@
             Controller.Peer p1;
             int peersStarted = 0;
 
-            class CEC extends ControllerEventCallback {
-            }
-
             class MyConnectCompleteCallback implements 
OperationCompletionCallback {
 
                 @Override
@@ -620,7 +580,7 @@
                     @Override
                     public void onStartupSuccess(Configuration cfg) {
                         System.out.println("controller started");
-                        c = new Controller(h, 1 | 2 | 4 | 8 | 32, new CEC());
+                        c = new Controller(h);
                         // FIXME: use config from resource
                         c.createPeer(h, getConfiguration(), new 
MyPeerCreateCallback(0));
                         c.createPeer(h, getConfiguration(), new 
MyPeerCreateCallback(1));

Modified: gnunet-java/src/test/java/org/gnunet/util/CryptoECCTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/util/CryptoECCTest.java        
2013-10-08 20:56:51 UTC (rev 30014)
+++ gnunet-java/src/test/java/org/gnunet/util/CryptoECCTest.java        
2013-10-08 21:22:43 UTC (rev 30015)
@@ -21,7 +21,7 @@
             CryptoECC.PrivateKey privateKey = new CryptoECC.PrivateKey();
             privateKey.d = new byte[32];
             r.nextBytes(privateKey.d);
-            CryptoECC.PublicKey publicKey = 
CryptoECC.computePublicKey(privateKey);
+            CryptoECC.PublicSignKey publicKey = 
CryptoECC.computePublicKey(privateKey);
             System.out.println("gen");
             CryptoECC.Signature sig = CryptoECC.sign(msg, privateKey, 
publicKey);
             System.out.println("sign");
@@ -44,7 +44,7 @@
             CryptoECC.PrivateKey privateKey = new CryptoECC.PrivateKey();
             privateKey.d = new byte[32];
             r.nextBytes(privateKey.d);
-            CryptoECC.PublicKey publicKey = 
CryptoECC.computePublicKey(privateKey);
+            CryptoECC.PublicSignKey publicKey = 
CryptoECC.computePublicKey(privateKey);
             System.out.println("gen");
             CryptoECC.Signature sig = CryptoECC.sign(msg, privateKey, 
publicKey);
             System.out.println("sign");
@@ -66,12 +66,12 @@
         CryptoECC.PrivateKey privateAlice = new CryptoECC.PrivateKey();
         privateAlice.d = new byte[32];
         r.nextBytes(privateAlice.d);
-        CryptoECC.PublicKey publicAlice = 
CryptoECC.computePublicKey(privateAlice);
+        CryptoECC.PublicSignKey publicAlice = 
CryptoECC.computePublicKey(privateAlice);
 
         CryptoECC.PrivateKey privateBob = new CryptoECC.PrivateKey();
         privateBob.d = new byte[32];
         r.nextBytes(privateBob.d);
-        CryptoECC.PublicKey publicBob = CryptoECC.computePublicKey(privateBob);
+        CryptoECC.PublicSignKey publicBob = 
CryptoECC.computePublicKey(privateBob);
 
         HashCode ssAlice = CryptoECC.ecdh(privateAlice, publicBob);
         HashCode ssBob = CryptoECC.ecdh(privateBob, publicAlice);




reply via email to

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