aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2012-08-29 23:27:31 +0000
committerFlorian Dold <florian.dold@gmail.com>2012-08-29 23:27:31 +0000
commit945e2116dae6dc7529dc46002dd08b45daa4856f (patch)
tree3f64a396d24bb8339c913252e59fc90172a586bb
parent19c310288ed6d289a4f663141662cdaca2aabdf9 (diff)
downloadgnunet-java-945e2116dae6dc7529dc46002dd08b45daa4856f.tar.gz
gnunet-java-945e2116dae6dc7529dc46002dd08b45daa4856f.zip
many bug fixes, server/service working, signal pipe working
-rw-r--r--ISSUES300
-rwxr-xr-xbin/gnunet-dht2
-rw-r--r--src/org/gnunet/construct/ByteFill.java39
-rw-r--r--src/org/gnunet/construct/Construct.java61
-rw-r--r--src/org/gnunet/construct/Double.java3
-rw-r--r--src/org/gnunet/construct/FixedSizeArray.java1
-rw-r--r--src/org/gnunet/construct/FixedSizeByteArray.java39
-rw-r--r--src/org/gnunet/construct/FixedSizeIntegerArray.java21
-rw-r--r--src/org/gnunet/construct/Int16.java2
-rw-r--r--src/org/gnunet/construct/Int32.java2
-rw-r--r--src/org/gnunet/construct/Int64.java4
-rw-r--r--src/org/gnunet/construct/Int8.java2
-rw-r--r--src/org/gnunet/construct/IntegerFill.java4
-rw-r--r--src/org/gnunet/construct/MessageIdAnnotationProcessor.java2
-rw-r--r--src/org/gnunet/construct/MessageLoader.java31
-rw-r--r--src/org/gnunet/construct/MessageUnion.java2
-rw-r--r--src/org/gnunet/construct/MsgMap.txt9
-rw-r--r--src/org/gnunet/construct/ProtocolViolationException.java (renamed from src/org/gnunet/construct/ProtocolViolation.java)6
-rw-r--r--src/org/gnunet/construct/ReflectUtil.java10
-rw-r--r--src/org/gnunet/construct/UInt16.java2
-rw-r--r--src/org/gnunet/construct/UInt32.java2
-rw-r--r--src/org/gnunet/construct/UInt64.java2
-rw-r--r--src/org/gnunet/construct/UInt8.java2
-rw-r--r--src/org/gnunet/construct/Union.java3
-rw-r--r--src/org/gnunet/construct/UnionCase.java6
-rw-r--r--src/org/gnunet/construct/parsers/ByteFillParser.java100
-rw-r--r--src/org/gnunet/construct/parsers/FillParser.java10
-rw-r--r--src/org/gnunet/construct/parsers/FixedSizeArrayParser.java3
-rw-r--r--src/org/gnunet/construct/parsers/FixedSizeByteArrayParser.java71
-rw-r--r--src/org/gnunet/construct/parsers/FixedSizeIntegerArrayParser.java99
-rw-r--r--src/org/gnunet/construct/parsers/IntegerFillParser.java20
-rw-r--r--src/org/gnunet/construct/parsers/IntegerParser.java7
-rw-r--r--src/org/gnunet/construct/parsers/NestedParser.java8
-rw-r--r--src/org/gnunet/construct/parsers/SequenceParser.java7
-rw-r--r--src/org/gnunet/construct/parsers/StringParser.java24
-rw-r--r--src/org/gnunet/construct/parsers/UnionParser.java4
-rw-r--r--src/org/gnunet/construct/parsers/VariableSizeArrayParser.java2
-rw-r--r--src/org/gnunet/construct/parsers/VariableSizeIntegerArrayParser.java1
-rw-r--r--src/org/gnunet/construct/parsers/package-info.java (renamed from src/org/gnunet/util/getopt/OptionAction.java)9
-rw-r--r--src/org/gnunet/core/ConnectNotifyMessage.java7
-rw-r--r--src/org/gnunet/core/NotifyInboundTrafficMessage.java2
-rw-r--r--src/org/gnunet/core/NotifyOutboundTrafficMessage.java2
-rw-r--r--src/org/gnunet/dht/ClientGetMessage.java2
-rw-r--r--src/org/gnunet/dht/ClientPutMessage.java2
-rw-r--r--src/org/gnunet/dht/ClientResultMessage.java2
-rw-r--r--src/org/gnunet/dht/DistributedHashTable.java18
-rw-r--r--src/org/gnunet/dht/MonitorGetRespMessage.java2
-rw-r--r--src/org/gnunet/dht/MonitorPutMessage.java2
-rw-r--r--src/org/gnunet/hello/HelloMessage.java (renamed from src/org/gnunet/util/HelloMessage.java)4
-rw-r--r--src/org/gnunet/hello/package-info.java (renamed from test/org/gnunet/construct/SimpleTestMessage2.java)12
-rw-r--r--src/org/gnunet/mesh/ClientConnectMessage.java13
-rw-r--r--src/org/gnunet/mesh/ConnectHandler.java9
-rw-r--r--src/org/gnunet/mesh/DisconnectHandler.java9
-rw-r--r--src/org/gnunet/mesh/Mesh.java158
-rw-r--r--src/org/gnunet/mesh/TunnelCreateMessage.java14
-rw-r--r--src/org/gnunet/mesh/package-info.java (renamed from src/org/gnunet/construct/Constructable.java)7
-rw-r--r--src/org/gnunet/nse/NetworkSizeEstimation.java10
-rw-r--r--src/org/gnunet/peerinfo/InfoMessage.java2
-rw-r--r--src/org/gnunet/peerinfo/PeerInfo.java2
-rw-r--r--src/org/gnunet/peerinfo/PeerProcessor.java2
-rw-r--r--src/org/gnunet/peerinfo/RsaPublicKeyBinaryEncoded.java4
-rw-r--r--src/org/gnunet/peerinfo/package-info.java25
-rw-r--r--src/org/gnunet/requests/Request.java4
-rw-r--r--src/org/gnunet/requests/package-info.java25
-rw-r--r--src/org/gnunet/statistics/Statistics.java24
-rw-r--r--src/org/gnunet/testing/TestingServer.java2
-rw-r--r--src/org/gnunet/testing/TestingSetup.java37
-rw-r--r--src/org/gnunet/testing/TestingSubsystem.java6
-rw-r--r--src/org/gnunet/testing/package-info.java27
-rw-r--r--src/org/gnunet/transport/Transport.java2
-rw-r--r--src/org/gnunet/transport/package-info.java25
-rw-r--r--src/org/gnunet/util/AbsoluteTime.java37
-rw-r--r--src/org/gnunet/util/Client.java111
-rw-r--r--src/org/gnunet/util/Configuration.java6
-rw-r--r--src/org/gnunet/util/Connection.java78
-rw-r--r--src/org/gnunet/util/Continuation.java2
-rw-r--r--src/org/gnunet/util/HashCode.java7
-rw-r--r--src/org/gnunet/util/PeerIdentity.java4
-rw-r--r--src/org/gnunet/util/Program.java48
-rw-r--r--src/org/gnunet/util/Resolver.java20
-rw-r--r--src/org/gnunet/util/RunaboutUtil.java1
-rw-r--r--src/org/gnunet/util/Scheduler.java21
-rw-r--r--src/org/gnunet/util/Server.java365
-rw-r--r--src/org/gnunet/util/Service.java97
-rw-r--r--src/org/gnunet/util/Strings.java75
-rw-r--r--src/org/gnunet/util/TestMessage.java (renamed from src/org/gnunet/util/TESTMessage.java)2
-rw-r--r--src/org/gnunet/util/UnknownMessageBody.java2
-rw-r--r--src/org/gnunet/util/getopt/Argument.java (renamed from src/org/gnunet/util/getopt/Option.java)7
-rw-r--r--src/org/gnunet/util/getopt/ArgumentAction.java (renamed from test/org/gnunet/construct/VarTestMessage.java)14
-rw-r--r--src/org/gnunet/util/getopt/Parser.java66
-rw-r--r--src/org/grothoff/Runabout.java5
-rw-r--r--src/org/grothoff/package-info.java2
-rw-r--r--test/org/gnunet/construct/ByteFillMessage.java2
-rw-r--r--test/org/gnunet/construct/ConstructTest.java2
-rw-r--r--test/org/gnunet/construct/FillParserTest.java37
-rw-r--r--test/org/gnunet/construct/FixedSizeTest.java52
-rw-r--r--test/org/gnunet/construct/FrameSizeTest.java50
-rw-r--r--test/org/gnunet/construct/QueryMessage.java2
-rw-r--r--test/org/gnunet/construct/SendMessageTest.java34
-rw-r--r--test/org/gnunet/construct/SimpleTestMessage.java36
-rw-r--r--test/org/gnunet/construct/SizeTestMessage.java34
-rw-r--r--test/org/gnunet/construct/StringTest.java50
-rw-r--r--test/org/gnunet/construct/StringTuple.java29
-rw-r--r--test/org/gnunet/construct/VariableSizeArrayTest.java33
-rw-r--r--test/org/gnunet/core/CoreTest.java11
-rw-r--r--test/org/gnunet/dht/DHTTest.java4
-rw-r--r--test/org/gnunet/nse/NSETest.java (renamed from test/org/nse/NSETest.java)6
-rw-r--r--test/org/gnunet/statistics/StatisticsTest.java10
-rw-r--r--test/org/gnunet/testing/TestingSetupTest.java12
-rw-r--r--test/org/gnunet/util/ClientServerTest.java171
-rw-r--r--test/org/gnunet/util/FilePipeExample.java3
-rw-r--r--test/org/gnunet/util/MeshTest.java36
-rw-r--r--test/org/gnunet/util/ResolverTest.java4
-rw-r--r--test/org/gnunet/util/ServerExample.java5
-rw-r--r--test/org/gnunet/util/StringsTest.java20
-rw-r--r--test/org/gnunet/util/getopt/GetoptTest.java113
-rwxr-xr-xtools/build3
-rwxr-xr-xtools/coverage3
118 files changed, 2057 insertions, 1059 deletions
diff --git a/ISSUES b/ISSUES
index 2528f68..4b5544d 100644
--- a/ISSUES
+++ b/ISSUES
@@ -1,248 +1,106 @@
1 1
2* I'm currently confused about the statistics API bug (from C), and how shutdown/disconnect is/should be handled. 2in gnunet-java-ext there is a working example of a service and a corresponding client program, that actually work ;)
3* gnunet vs GNUnet, gnunet-java project name 3 * simple greeting server, client gives name and server returns greeting
4* I'm currently trying to increase the robustness of the service APIs, 4 * illustrates using program/service, using the configuration, creating messages
5 discuss behavior in some cases 5 * works with os control pipe / arm
6* packaging requirements
7 6
7arm-4477 WARNING Configuration file `(null)' for service `greeting' not valid: option missing
8 8
9==================================================================== 9even when not using the signal pipe, does arm really kill processes?
10 * arm does never seem to send a sigkill if process does not respond
11 * sometimes arm command hangs!
10 12
11* IzPack is ~15MB, do we really want to have it in the svn repo? 13 $ gnunet-arm -c config/greeting.conf -k greeting -LDEBUG
12No, env var. 14 Aug 29 19:25:22-808046 arm-api-5971 INFO Stopping service `greeting' within 60000 ms
15 Service `greeting' was already not running.
13 16
14* the Runabout can now be an anonymous inner class
15 * implementation overhead: for public subclasses only constant overhead in the Runabout constructor
16 * for private/anonymous inner classes: 10-20% overhead, measured over 100M calls
17 * only issue left: visit methods have to be public, but this is a non issue.
18 17
19* review the RequestQueue mechanism 18Aug 29 18:21:19-505909 arm-4751 ERROR Failed to start service `greeting'
19Service `greeting' has been started.
20 20
21* Statistics: 21logging with arm: what gets piped to where
22 * currently watches can't be canceled on the service level, only on the api level, is this intentional? 22 * seems like service stdout->/dev/null, service stderr->arm stderr
23=> fine for now
24 23
25* DHT: 24Construct: has gotten very complex, i'm currently trying to trace a particular bug
26 * getStart timeout does not really make sense (why timeout for transmission to the service, 25 * UPDATE: bug is gone!
27 but not for retrieval of answers?) 26 * unit tests for construct have gotten better, still not good enough
28 Is this just a documentation error? 27 * FrameSize
29=> fine to NOT have the timeout argument in the Java API 28 * recursive messages
29 * indirect recursion (over unions) (see core.SendMessage) works
30 * direct recursion has problems (see test/org.gnunet.construct.FrameSizeTest)
30 31
31* core: 32Question: Is all this too complicated? Should I invest the time to fix things as they are now intended, or should
32 * what happens if during a transmission the service disconnects? should we retry? 33we simplify?
33=> "no"
34 34
35* with the changes in ARM there is no way to restart gnunet with arm if some client is misbehaving 35* found some problems with timeouts in client/connection.
36=> SVN UP 36 * should i write unit-tests for this timing-stuff?
37 * UPDATE: should be fixed now!
37 38
38* I'm often getting 39* program/service in general:
39 May 09 09:21:49-194786 util-11121 WARNING `socket' failed at connection.c:892 with error: Too many open files 40 * how to handle the return value of main?
40=> SVN UP 41 * java has no return value for main
42 * we must use System.exit(n) instead
43 * how about a (Program/Service).exit(n) that does cleanup and then calls System.exit(n)?
41 44
45* configuration: what is $DEFAULTCONFIG? and CONFIG=?
42 46
43================== 47mesh:
48 * we can't use multipe instances of org.gnunet.mesh.Mesh to test the API
49 * the local peer can't be the peer on the other end!
50 * the C-api has practically no coverage on mesh_api.c
51 * see below for a suggestion!
52 * LOCAL_TUNNEL_CREATE was used for two things, creating tunnels and being notified about incoming tunnels
44 53
45#!bin/sh 54* extending org.gnunet.testing so that multiple peers can be started and communicate with each other!
46java -jar $GNUNET_JAVA_PREFIX/lib/gnunet.jar 55 * the C-testing-api allows to create multiple peers, but they don't seem to be able to communicate with each
56 other!
57 * => the peers should somehow exchange their hellos / use a shared directory for the hellos
47 58
59 testbed vs testing: is this correct?
60 * testbed for large-scale testing across many "real" nodes
61 * testing for testcases on one host
48 62
49================== 63* test coverage approaching a better state, any feedback?
50 64
51#!/bin/sh 65* I think there should be some documentation in addition to the source code and the tutorial
52if test -z $GNUNET_JAVA_PREFIX 66 * what would be the preferred format for such documentation? latex?
53then 67 * (considering that they perhaps should end up on a website / should be browsable)
54 GNUNET_JAVA_PREFIX=%INSTALL_PREFIX% 68 * examples:
55fi 69 * how do unions work in construct?
56java -jar $GNUNET_JAVA_PREFIX/lib/gnunet.jar 70 * other stuff in construct
71 * how does annotation processing work?
72 * project layout - what goes where
73 * as there is no standard java project layout
57 74
58 75
76rationale for putting org.gnunet.testing in the src/-tree, not in test/:
77 * when developing an extension for gnunet-java, the developers may want to access the testing functionality from
78 the jar, so it should be included there!
79 * the code itself is tested, we want coverage etc.
59 80
60=========================================================== 81* is there an effort to document what hostkeys files are etc.?
61 82
62* @UNIXONLY@ PORT = 2089 in src/util/resolver.conf.on 83continuous integration: using Jenkins (=Hudson, forked away from Oracle)
63 * what's the purpose? we also need this line to be enabled on JAVAPORT 84 * easier to configure than buildbot
85 * support for JUnit out-of-the-box
86 * support for cobertura via plugin
64 87
65* something I didn't think through from the beginning: 88build system: still maintaining bash scripts, trying out gradle
66 how should unknown message types be handled by message handlers? 89 * faster builds, build scripts far easier to read/write
67 * sometimes we want to see the message (e.g. in server), sometimes it is an error 90 * no integration with cobertura :(
68 * alternative 1: signal an error to the message handler, somehow pass the original message 91 * gradle has excellent Ant integration => Coverage (bash wrapper not very usable)
69 * alternative 2: pass a special UnknownMessage to the message handler, filter it for higher-level 92 * can generate project files for eclipse/intellij
70 APIs and signal an error.
71 93
94what's next?
95 * some actual stuff built with gnunet-java?
72 96
73* the recvDone is kind of clunky (see test/org.gnunet.util.ServerExample) 97* general question: when should an api use per-connection receive, and per-service-receive?
74 98
75* finally core/statistics/dht/resolver/... have unit tests! 99does this make sense / do we need it:
76 (and coverage works again, but i can't access the cobertura via ssh yet) 100 * support in the scheduler for communicating asynchronously with other processes via stdin/stdout/stderr
77 * currently most test rely on a running gnunet, and use the default configuration 101 * currently only used in testing, uses blocking i/o
78 * alternative approach:
79 * configuration is copied from resource (may be in a jar!) to a temp file, then passed on the command
80 line to gunet-service-*
81 * useful to test behavior on disconnects
82 * problem: java sucks at managing processes, processes stay alive if we abort a test
83 * dht get: can we assume that "our" peer immediately stores the value?
84 102
85* naming: when do we use destroy, when do we use disconnect, or is this arbitrary? 103* stream is implemented as a library, not as a service
86 start-stop, create-destroy, connect-disconnect; constructor: fine, destructor: see C API 104 * why?
105 * should GNUnet-java also implement it?
87 106
88* implications of using exceptions in callbacks
89 * esp. when the exception is non-fatal, i.e. the exception is caught, handled, and the program continues
90 * java exceptions have no restarts, may leave gnunet-java in inconsistent state; FINALLY!
91
92* how to test callbacks? we do not only need to test for the right values, but also check that callback has actually
93 been called.
94 * first approach: thow a TestSuccess exception, discarded (see above)
95 * current approach: build a list of assertions, check assertions after scheduler is done.
96 * each assertion stores whether it already succeeded and a message
97
98
99* finalziers: used to destroy object. lead to heisenbug/double disconnect. now policy: check if object
100 has been disposed of properly, otherwise log a warning.
101 * cannot guarantee cleanup anyway
102 (java behavior: run finalizers iff unreachabla during gc, may never happen, finalizers on jvm shutdown deprecated)
103
104
105* regarding peerinfo
106 * i don't fully understand how HELLOs work.
107
108* what are the next important services to implement? (probably mesh, peerinfo, transport)
109
110
111* i'm currently considering to use the google guava library
112 * Apache License 2.0
113 * con: large (1.8MB jar)
114 * but: unused class files could be stripped from the jar, e.g. using ProGuard
115 * would replace the apache commons io library
116 * contains collections used throughout gnunet
117 * bloomfilter
118 * multimap, alleviates the boilerplate code when dealing with hashmaps of lists
119 * methods to deal with "signed" primitives
120 * dealing with files (e.g. copying)
121 * redirecting i/o streams from/to files (when issuing external commands)
122 * hashing utilities
123 * tables (mapping from key pair to value), would replace nested Maps in e.g. Configurations
124 * ...
125
126
127
128
129* long-term todos:
130 * refactor the Construct implementation, implement the "nicer" syntax
131 * refactor the getopt implementation
132
133
134
135
136============================================================
137
138* tests now run on the cobertura account :)
139 * see https://gnunet.org/cobertura/
140 * gnunet needs to compiled with --disable-nls to work on the server
141 * cronjob added
142 * could/should we report the success of JUnit tests?
143 * (as somehow my bugs only seem to show when running on another system ;)
144
145* gnunet-java now can now start/restart services for testing with the testing wrapper executable
146 * i duplicated the code for GNUNET_TESTING_service_run_restartable
147 * now passes the Peer to main, which can start/stop it
148 * probably also should pass the config file name (not only the handle)
149 * how about a GNUNET_TESTING_peer_get_config_path?
150 * what about windows?
151
152* server/service:
153 * needed for testing the server: getting an unused port with java
154 * how do we test the signal pipeline?
155 * probably with runin arm in a testing peer, but then we would also have to talk to arm
156
157
158the following notes are old:
159* we are still not able to test "temporary destruction"
160 * because every time a new port may be generated
161 * we need a way to kill a service and run it with the same config
162 * now implemented!
163* review if everything in Makefile.am is correct
164 * what is *_DEPENDENCIES vs *_LDADD?
165* how do we get a handle to stdin (in a non-hacky way) that can be selected on by scheduler?
166* c-getopt question: GNUNET_GETOPT_run returns index of first non-option.
167 so options and non-options may not be mixed?
168* i have to manually write the config file, why isn't there a way to get the
169 file name, not just the ConfigurationHandle?
170* could we get a confirmation that a service *really* is dead?
171 * or is this guaranteed if TESTING_service_run returns?
172 * otherwise there is no way to reliably test behavior on interrupted connection
173* TESTING_service_run does not indicate that the service could not be run!
174 * just logs an error
175 * currently we check availability of data on stderr.
176
177
178PEERINFO_GET vs PEERINFO_GET_ALL
179 * if we have PEERINFO_GET_ALL, why is the peer-field in ListPeerMessage(with type=PEERINFO_GET) empty?
180
181
182* are peerinfo requests queued?
183 * i remember discussing peerinfo as a compilicated example for a general message queueing implementation. why?
184 * if we have to queue: how about a "choke/release" for the outgoing message queue?
185 * otherwise we don't know which requests belongs to which response
186* can peerinfo return more than one record per peer?
187
188
189--------------------------------------------------------------
190
191* see mantis for problem with the signal pipe
192
193* what should the gnunet-testing-run-server tool be called, now that
194 there already is plain gnunet-testing?
195
196* where should TESTMessage and HELLOMessage, PeerIdentity, HashCode go?
197 * and do we want to call them TESTMessage or TestMessage?
198
199* had a bug in the IPv6 address parsing code
200 * tried to fix it / rewrite it, eventually got frustrating
201 * found out guava has an implementation of this :)
202 * also implements shortening (like ::1)
203 * by reading the code: implementing all this correctly would not have been a fun time
204
205* TestingServer now allows the client/connection/server to be tested easily
206 * found quite some bugs during this
207
208* thoughts about exponential backoff / the client-connection stuff in GNUnet and gnunet-java
209 * why do we wait the entire backoff period, if the connection could be available earlier?
210
211* discuss what mesh does, what transport does
212 * i found the documentation for transport on gnunet.org
213 * the is not much information about mesh, except for the source code
214
215---------------------------------------------------------------
216
217* reference count / receive_done behavior is a bit strange / confusing
218 * clients are disconnected only when refcnt==0 *and* shutdown is requested?
219 * behavior on receive done: when success=1 but refcnt=0, why don't we disconnect the client?
220
221 /**
222 * Was processing if incoming messages suspended while
223 * we were still processing data already received?
224 * This is a counter saying how often processing was
225 * suspended (once per handler invoked).
226 */
227
228I don't understand that comment!
229
230
231
232* im currently confused about the different layers of GNUnet / I don't get the big picture
233 * e.g. transport's distance vector plugin vs mesh
234 * peerinfo / mesh
235 * assuming a large network, doesn't a client have to store a large amout of information?
236
237* how to test MESH?
238 * maybe talk to Harsha about testbed? :)
239
240* interesting things happen with JUnit
241 * failure of one test causes timeout in another
242
243* review org.gnunet.testing
244
245cp a x ; cp b x
246is not the same as
247cp b x ; cp a x
248if x does not exist prior to copying
diff --git a/bin/gnunet-dht b/bin/gnunet-dht
index 840db34..951355a 100755
--- a/bin/gnunet-dht
+++ b/bin/gnunet-dht
@@ -1,11 +1,11 @@
1#!/bin/sh 1#!/bin/sh
2 2
3DIR=`dirname $0`
4 3
5if [ "%GNJ_INSTALLED" = "true" ]; 4if [ "%GNJ_INSTALLED" = "true" ];
6then 5then
7 export CLASSPATH="%INSTALL_PATH/share/java/*" 6 export CLASSPATH="%INSTALL_PATH/share/java/*"
8else 7else
8 DIR=`dirname $0`
9 export CLASSPATH="$DIR/../build/:$DIR/../lib/*" 9 export CLASSPATH="$DIR/../build/:$DIR/../lib/*"
10fi 10fi
11 11
diff --git a/src/org/gnunet/construct/ByteFill.java b/src/org/gnunet/construct/ByteFill.java
deleted file mode 100644
index febc64c..0000000
--- a/src/org/gnunet/construct/ByteFill.java
+++ /dev/null
@@ -1,39 +0,0 @@
1/*
2 This file is part of GNUnet.
3 (C) 2011, 2012 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21package org.gnunet.construct;
22
23import java.lang.annotation.ElementType;
24import java.lang.annotation.Retention;
25import java.lang.annotation.RetentionPolicy;
26import java.lang.annotation.Target;
27
28/**
29 * Fills a byte array with the remaining data in the current frame.
30 * Annotation target must be of type "byte[]"
31 *
32 * Deprecated, you should use @IntegerFill(false, 8), or @FillWith @UInt8 once it is available.
33 *
34 * @author Florian Dold
35 */
36@Retention(RetentionPolicy.RUNTIME)
37@Target(ElementType.FIELD)
38public @interface ByteFill {
39}
diff --git a/src/org/gnunet/construct/Construct.java b/src/org/gnunet/construct/Construct.java
index 603f5a5..965b97b 100644
--- a/src/org/gnunet/construct/Construct.java
+++ b/src/org/gnunet/construct/Construct.java
@@ -50,7 +50,7 @@ Wanted syntax (not fully implemented yet)
50 50
51 51
52/** 52/**
53 * Parse and write the binary representation of java classes, as defined by org.gnunet.construct.*-Annotations 53 * Parse and write the binary representation of java classes, as defined by org.gnunet.construct.*-annotations
54 * on their members. 54 * on their members.
55 * 55 *
56 * @author Christian Grothoff 56 * @author Christian Grothoff
@@ -62,9 +62,18 @@ public class Construct {
62 .getLogger(Construct.class); 62 .getLogger(Construct.class);
63 63
64 64
65 private static HashMap<Class<? extends Message>, Parser> parserCache = new HashMap<Class<? extends Message>, 65 private static Map<Class<? extends Message>, Parser> parserCache = new HashMap<Class<? extends Message>,
66 Parser>(100); 66 Parser>(100);
67 67
68
69 /**
70 * The class Construct is not intended to be instantiated, this its constructor is private.
71 */
72 private Construct() {
73
74 }
75
76
68 /** 77 /**
69 * Given a byte buffer with a message, parse it into an object of type c. The 78 * Given a byte buffer with a message, parse it into an object of type c. The
70 * fields of the class are expected to be annotated with annotations from 79 * fields of the class are expected to be annotated with annotations from
@@ -82,6 +91,15 @@ public class Construct {
82 return m; 91 return m;
83 } 92 }
84 93
94 /**
95 * Given a byte array with a message, parse it into an object of type c. The
96 * fields of the class are expected to be annotated with annotations from
97 * the construct package.
98 *
99 * @param srcBuf buffer with the serialized binary data
100 * @param c desired object type to return
101 * @return instance of the desired object type
102 */
85 public static <T extends Message> T parseAs(byte[] srcBuf, Class<T> c) { 103 public static <T extends Message> T parseAs(byte[] srcBuf, Class<T> c) {
86 return parseAs(ByteBuffer.wrap(srcBuf), c); 104 return parseAs(ByteBuffer.wrap(srcBuf), c);
87 } 105 }
@@ -248,8 +266,7 @@ public class Construct {
248 Field nestedField = field; 266 Field nestedField = field;
249 267
250 if (n.newFrame()) { 268 if (n.newFrame()) {
251 ParserGenerator pg = new ParserGenerator(); 269 Parser p = getParser((Class<Message>) nestedField.getType());
252 Parser p = getParser((Class<Message>) nestedField.getType(), pg);
253 270
254 parser = new NestedParser(p, n.optional(), nestedField, true); 271 parser = new NestedParser(p, n.optional(), nestedField, true);
255 272
@@ -269,11 +286,6 @@ public class Construct {
269 } 286 }
270 } 287 }
271 288
272 public void visit(ByteFill bf) {
273 parser = new ByteFillParser(field);
274 }
275
276
277 public void visit(FixedSizeArray fsa) { 289 public void visit(FixedSizeArray fsa) {
278 Field f = field; 290 Field f = field;
279 int elemNumber = fsa.length(); 291 int elemNumber = fsa.length();
@@ -284,14 +296,13 @@ public class Construct {
284 parser = new FixedSizeArrayParser(elemNumber, parser, f); 296 parser = new FixedSizeArrayParser(elemNumber, parser, f);
285 } 297 }
286 298
287 public void visit(FixedSizeByteArray fsba) {
288 Field f = field;
289 int elemNumber = fsba.length();
290 299
291 parser = new FixedSizeByteArrayParser(elemNumber, f); 300 public void visit(FixedSizeIntegerArray fsa) {
301 Field f = field;
302 int elemNumber = fsa.length();
303 parser = new FixedSizeIntegerArrayParser(elemNumber, fsa.signed(), fsa.bitSize() / 8, f);
292 } 304 }
293 305
294
295 public void visit(Double d) { 306 public void visit(Double d) {
296 if (!field.getType().equals(java.lang.Double.TYPE)) { 307 if (!field.getType().equals(java.lang.Double.TYPE)) {
297 throw new AssertionError("@Double target must be a primitive 'double' field"); 308 throw new AssertionError("@Double target must be a primitive 'double' field");
@@ -322,6 +333,10 @@ public class Construct {
322 Parser p = getParser((Class<? extends Message>) field.getType() 333 Parser p = getParser((Class<? extends Message>) field.getType()
323 .getComponentType()); 334 .getComponentType());
324 335
336 if (!Message.class.isAssignableFrom(field.getType().getComponentType())) {
337 throw new AssertionError("VariableSizeArray only valid on arrays of messages.");
338 }
339
325 try { 340 try {
326 parser = new VariableSizeArrayParser(p, c.getField(vsa 341 parser = new VariableSizeArrayParser(p, c.getField(vsa
327 .lengthField()), field); 342 .lengthField()), field);
@@ -412,10 +427,10 @@ public class Construct {
412 } 427 }
413 428
414 /** 429 /**
415 * Compute the size of a serialized message. 430 * Compute the exact size of a serialized message.
416 * 431 *
417 * @param m object to serialize 432 * @param m object to serialize
418 * @return number of bytes required, -1 on error 433 * @return number of bytes required to store the message in binary form
419 */ 434 */
420 public static int getSize(Message m) { 435 public static int getSize(Message m) {
421 if (m == null) { 436 if (m == null) {
@@ -425,6 +440,13 @@ public class Construct {
425 return p.getSize(m); 440 return p.getSize(m);
426 } 441 }
427 442
443
444 /**
445 * Return the binary representation of the message m
446 *
447 * @param m the message to serialize
448 * @return a byte array containing the serialized message
449 */
428 public static byte[] toBinary(Message m) { 450 public static byte[] toBinary(Message m) {
429 byte[] a = new byte[getSize(m)]; 451 byte[] a = new byte[getSize(m)];
430 ByteBuffer buf = ByteBuffer.wrap(a); 452 ByteBuffer buf = ByteBuffer.wrap(a);
@@ -432,6 +454,13 @@ public class Construct {
432 return a; 454 return a;
433 } 455 }
434 456
457 /**
458 * Fill in all fields of a message that are inferable from existing information.
459 *
460 * Examples: The size field for variable size arrays, the type of unions, ...
461 *
462 * @param m the message that should be patched
463 */
435 public static void patch(Message m) { 464 public static void patch(Message m) {
436 Parser p = getParser(m.getClass()); 465 Parser p = getParser(m.getClass());
437 p.patch(m, p.getSize(m), null, m); 466 p.patch(m, p.getSize(m), null, m);
diff --git a/src/org/gnunet/construct/Double.java b/src/org/gnunet/construct/Double.java
index 21f128e..f20e137 100644
--- a/src/org/gnunet/construct/Double.java
+++ b/src/org/gnunet/construct/Double.java
@@ -25,6 +25,9 @@ import java.lang.annotation.Retention;
25import java.lang.annotation.RetentionPolicy; 25import java.lang.annotation.RetentionPolicy;
26import java.lang.annotation.Target; 26import java.lang.annotation.Target;
27 27
28/**
29 * A number stored in the IEEE 754 double-precision binary floating-point format.
30 */
28@Retention(RetentionPolicy.RUNTIME) 31@Retention(RetentionPolicy.RUNTIME)
29@Target(ElementType.FIELD) 32@Target(ElementType.FIELD)
30public @interface Double { 33public @interface Double {
diff --git a/src/org/gnunet/construct/FixedSizeArray.java b/src/org/gnunet/construct/FixedSizeArray.java
index ce6ff6b..699ae68 100644
--- a/src/org/gnunet/construct/FixedSizeArray.java
+++ b/src/org/gnunet/construct/FixedSizeArray.java
@@ -29,7 +29,6 @@ import java.lang.annotation.Target;
29 * An array of messages with static size. 29 * An array of messages with static size.
30 * 30 *
31 * @author Florian Dold 31 * @author Florian Dold
32 *
33 */ 32 */
34@Retention(RetentionPolicy.RUNTIME) 33@Retention(RetentionPolicy.RUNTIME)
35@Target(ElementType.FIELD) 34@Target(ElementType.FIELD)
diff --git a/src/org/gnunet/construct/FixedSizeByteArray.java b/src/org/gnunet/construct/FixedSizeByteArray.java
deleted file mode 100644
index 6232718..0000000
--- a/src/org/gnunet/construct/FixedSizeByteArray.java
+++ /dev/null
@@ -1,39 +0,0 @@
1/*
2 This file is part of GNUnet.
3 (C) 2011, 2012 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21package org.gnunet.construct;
22
23
24import java.lang.annotation.ElementType;
25import java.lang.annotation.Retention;
26import java.lang.annotation.RetentionPolicy;
27import java.lang.annotation.Target;
28
29/**
30 * An array of bytes with static size.
31 *
32 * @author Florian Dold
33 *
34 */
35@Retention(RetentionPolicy.RUNTIME)
36@Target(ElementType.FIELD)
37public @interface FixedSizeByteArray {
38 int length();
39} \ No newline at end of file
diff --git a/src/org/gnunet/construct/FixedSizeIntegerArray.java b/src/org/gnunet/construct/FixedSizeIntegerArray.java
new file mode 100644
index 0000000..b2418b8
--- /dev/null
+++ b/src/org/gnunet/construct/FixedSizeIntegerArray.java
@@ -0,0 +1,21 @@
1package org.gnunet.construct;
2
3
4import java.lang.annotation.ElementType;
5import java.lang.annotation.Retention;
6import java.lang.annotation.RetentionPolicy;
7import java.lang.annotation.Target;
8
9
10/**
11 * An array of integers with static size.
12 *
13 * @author Florian Dold
14 */
15@Retention(RetentionPolicy.RUNTIME)
16@Target(ElementType.FIELD)
17public @interface FixedSizeIntegerArray {
18 int length();
19 int bitSize();
20 boolean signed();
21}
diff --git a/src/org/gnunet/construct/Int16.java b/src/org/gnunet/construct/Int16.java
index 8017636..677324b 100644
--- a/src/org/gnunet/construct/Int16.java
+++ b/src/org/gnunet/construct/Int16.java
@@ -26,7 +26,7 @@ import java.lang.annotation.RetentionPolicy;
26import java.lang.annotation.Target; 26import java.lang.annotation.Target;
27 27
28/** 28/**
29 * Synonym for Integer(byteSize=2, signed=true) 29 * Signed 16-bit integer value.
30 * 30 *
31 * @author Florian Dold 31 * @author Florian Dold
32 * 32 *
diff --git a/src/org/gnunet/construct/Int32.java b/src/org/gnunet/construct/Int32.java
index 97d904a..da993ca 100644
--- a/src/org/gnunet/construct/Int32.java
+++ b/src/org/gnunet/construct/Int32.java
@@ -26,7 +26,7 @@ import java.lang.annotation.RetentionPolicy;
26import java.lang.annotation.Target; 26import java.lang.annotation.Target;
27 27
28/** 28/**
29 * Synonym for Integer(byteSize=4, signed=true) 29 * Signed 32-bit integer value.
30 * 30 *
31 * @author Florian Dold 31 * @author Florian Dold
32 * 32 *
diff --git a/src/org/gnunet/construct/Int64.java b/src/org/gnunet/construct/Int64.java
index 7318c0d..be5d940 100644
--- a/src/org/gnunet/construct/Int64.java
+++ b/src/org/gnunet/construct/Int64.java
@@ -26,9 +26,7 @@ import java.lang.annotation.RetentionPolicy;
26import java.lang.annotation.Target; 26import java.lang.annotation.Target;
27 27
28/** 28/**
29 * Synonym for Integer(byteSize=8, signed=true) 29 * Signed 64-bit integer value.
30 *
31 * @author Florian Dold
32 * 30 *
33 */ 31 */
34 32
diff --git a/src/org/gnunet/construct/Int8.java b/src/org/gnunet/construct/Int8.java
index fbf83f4..a0aaa14 100644
--- a/src/org/gnunet/construct/Int8.java
+++ b/src/org/gnunet/construct/Int8.java
@@ -27,7 +27,7 @@ import java.lang.annotation.Target;
27 27
28 28
29/** 29/**
30 * Synonym for Integer(byteSize=1, signed=true) 30 * Signed 8-bit integer value.
31 * 31 *
32 * @author Florian Dold 32 * @author Florian Dold
33 * 33 *
diff --git a/src/org/gnunet/construct/IntegerFill.java b/src/org/gnunet/construct/IntegerFill.java
index 846ee14..4564c83 100644
--- a/src/org/gnunet/construct/IntegerFill.java
+++ b/src/org/gnunet/construct/IntegerFill.java
@@ -25,6 +25,10 @@ import java.lang.annotation.Retention;
25import java.lang.annotation.RetentionPolicy; 25import java.lang.annotation.RetentionPolicy;
26import java.lang.annotation.Target; 26import java.lang.annotation.Target;
27 27
28/**
29 * Fills the rest of the message with integers of the specified kind. The annotation may only be present on the
30 * last serialized field of message.
31 */
28@Retention(RetentionPolicy.RUNTIME) 32@Retention(RetentionPolicy.RUNTIME)
29@Target(ElementType.FIELD) 33@Target(ElementType.FIELD)
30public @interface IntegerFill { 34public @interface IntegerFill {
diff --git a/src/org/gnunet/construct/MessageIdAnnotationProcessor.java b/src/org/gnunet/construct/MessageIdAnnotationProcessor.java
index d27c992..8a17ba9 100644
--- a/src/org/gnunet/construct/MessageIdAnnotationProcessor.java
+++ b/src/org/gnunet/construct/MessageIdAnnotationProcessor.java
@@ -42,7 +42,7 @@ import java.util.*;
42 42
43 43
44/** 44/**
45 * Creates a resource file 'MsgMap.txt' in the package 'org.gnunet.construct'. 45 * Creates a resource file 'MsgMap.txt' in the package 'org.gnunet.construct' of the source tree.
46 */ 46 */
47@SupportedAnnotationTypes("org.gnunet.construct.UnionCase") 47@SupportedAnnotationTypes("org.gnunet.construct.UnionCase")
48@SupportedSourceVersion(SourceVersion.RELEASE_6) 48@SupportedSourceVersion(SourceVersion.RELEASE_6)
diff --git a/src/org/gnunet/construct/MessageLoader.java b/src/org/gnunet/construct/MessageLoader.java
index d40dfda..7ba2e60 100644
--- a/src/org/gnunet/construct/MessageLoader.java
+++ b/src/org/gnunet/construct/MessageLoader.java
@@ -37,21 +37,26 @@ import java.util.Map;
37 37
38 38
39/** 39/**
40 * Load message maps 40 * Load message maps, which contain the information the parse/write unions.
41 */ 41 */
42public class MessageLoader { 42public class MessageLoader {
43 private static final Logger logger = LoggerFactory 43 private static final Logger logger = LoggerFactory
44 .getLogger(MessageLoader.class); 44 .getLogger(MessageLoader.class);
45 45
46 46
47 47 /**
48 48 * Thrown when a trying to serialize an object that is not registered as a union type.
49 */
49 public static class UnknownUnionException extends RuntimeException { 50 public static class UnknownUnionException extends RuntimeException {
50 public UnknownUnionException(String msg) { 51 public UnknownUnionException(String msg) {
51 super(msg); 52 super(msg);
52 } 53 }
53 } 54 }
54 55
56
57 /**
58 * Thrown when parsing a union whose ID is not known.
59 */
55 public static class UnknownUnionIdException extends RuntimeException { 60 public static class UnknownUnionIdException extends RuntimeException {
56 61
57 } 62 }
@@ -86,19 +91,22 @@ public class MessageLoader {
86 } 91 }
87 92
88 public static void loadMessageMap(URL loc) { 93 public static void loadMessageMap(URL loc) {
89 if (loc == null) 94 if (loc == null) {
90 throw new RuntimeException("could not load message map"); 95 throw new RuntimeException("could not load message map");
96 }
91 BufferedReader in = null; 97 BufferedReader in = null;
92 try { 98 try {
93 in = new BufferedReader(new InputStreamReader(loc.openStream())); 99 in = new BufferedReader(new InputStreamReader(loc.openStream()));
94 String line; 100 String line;
95 while ((line = in.readLine()) != null) { 101 while ((line = in.readLine()) != null) {
96 // skip empty lines and comments 102 // skip empty lines and comments
97 if (line.isEmpty() || line.charAt(0) == '#') 103 if (line.isEmpty() || line.charAt(0) == '#') {
98 continue; 104 continue;
105 }
99 String[] m = line.split("="); 106 String[] m = line.split("=");
100 if (m.length != 2) 107 if (m.length != 2) {
101 throw new RuntimeException("invalid message map format (separation by '=')"); 108 throw new RuntimeException("invalid message map format (separation by '=')");
109 }
102 String[] left = m[0].split("[|]"); 110 String[] left = m[0].split("[|]");
103 if (left.length != 2) { 111 if (left.length != 2) {
104 logger.debug(m[0]); 112 logger.debug(m[0]);
@@ -134,8 +142,9 @@ public class MessageLoader {
134 142
135 private static void maybeClose(Closeable in) { 143 private static void maybeClose(Closeable in) {
136 try { 144 try {
137 if (in != null) 145 if (in != null) {
138 in.close(); 146 in.close();
147 }
139 } catch (IOException e) { 148 } catch (IOException e) {
140 throw new RuntimeException("error closing stream: " + e.getMessage()); 149 throw new RuntimeException("error closing stream: " + e.getMessage());
141 } 150 }
@@ -164,7 +173,7 @@ public class MessageLoader {
164 173
165 Class<? extends MessageUnion> cls = map.get(tag); 174 Class<? extends MessageUnion> cls = map.get(tag);
166 if (cls == null) { 175 if (cls == null) {
167 throw new ProtocolViolation("don't know how to translate message of type " + tag); 176 throw new ProtocolViolationException("don't know how to translate message of type " + tag);
168 } 177 }
169 178
170 return cls; 179 return cls;
@@ -173,10 +182,12 @@ public class MessageLoader {
173 182
174 public static int getUnionTag(Class<? extends MessageUnion> unionInterface, Class<? extends MessageUnion> unionCase) { 183 public static int getUnionTag(Class<? extends MessageUnion> unionInterface, Class<? extends MessageUnion> unionCase) {
175 Map<Class<? extends MessageUnion>, Integer> map = tagmap.get(unionInterface); 184 Map<Class<? extends MessageUnion>, Integer> map = tagmap.get(unionInterface);
176 if (map == null) 185 if (map == null) {
177 throw new AssertionError(String.format("%s is not a known union type", unionInterface)); 186 throw new AssertionError(String.format("%s is not a known union type", unionInterface));
178 if (!map.containsKey(unionCase)) 187 }
188 if (!map.containsKey(unionCase)) {
179 throw new AssertionError(String.format("%s is not a known instance of %s", unionCase, unionInterface)); 189 throw new AssertionError(String.format("%s is not a known instance of %s", unionCase, unionInterface));
190 }
180 return map.get(unionCase); 191 return map.get(unionCase);
181 } 192 }
182} 193}
diff --git a/src/org/gnunet/construct/MessageUnion.java b/src/org/gnunet/construct/MessageUnion.java
index 260b9f6..0481df2 100644
--- a/src/org/gnunet/construct/MessageUnion.java
+++ b/src/org/gnunet/construct/MessageUnion.java
@@ -21,7 +21,7 @@
21package org.gnunet.construct; 21package org.gnunet.construct;
22 22
23/** 23/**
24 * Marker interface for Message Unions 24 * Marker interface for message unions
25 */ 25 */
26public interface MessageUnion extends Message { 26public interface MessageUnion extends Message {
27} 27}
diff --git a/src/org/gnunet/construct/MsgMap.txt b/src/org/gnunet/construct/MsgMap.txt
index 9136d6e..8f09b68 100644
--- a/src/org/gnunet/construct/MsgMap.txt
+++ b/src/org/gnunet/construct/MsgMap.txt
@@ -1,9 +1,12 @@
1org.gnunet.util.Resolver$Address|0=org.gnunet.util.Resolver$TextualAddress 1org.gnunet.util.Resolver$Address|0=org.gnunet.util.Resolver$TextualAddress
2org.gnunet.util.Resolver$Address|1=org.gnunet.util.Resolver$NumericAddress 2org.gnunet.util.Resolver$Address|1=org.gnunet.util.Resolver$NumericAddress
3org.gnunet.util.GnunetMessage$Body|68=org.gnunet.core.DisconnectNotifyMessage 3org.gnunet.util.GnunetMessage$Body|68=org.gnunet.core.DisconnectNotifyMessage
4org.gnunet.util.GnunetMessage$Body|1=org.gnunet.util.TESTMessage 4org.gnunet.util.GnunetMessage$Body|1=org.gnunet.util.TestMessage
5org.gnunet.util.GnunetMessage$Body|274=org.gnunet.mesh.TunnelDestroyMessage
6org.gnunet.util.GnunetMessage$Body|273=org.gnunet.mesh.TunnelCreateMessage
5org.gnunet.util.GnunetMessage$Body|70=org.gnunet.core.NotifyInboundTrafficMessage 7org.gnunet.util.GnunetMessage$Body|70=org.gnunet.core.NotifyInboundTrafficMessage
6org.gnunet.util.GnunetMessage$Body|71=org.gnunet.core.NotifyOutboundTrafficMessage 8org.gnunet.util.GnunetMessage$Body|71=org.gnunet.core.NotifyOutboundTrafficMessage
9org.gnunet.util.GnunetMessage$Body|272=org.gnunet.mesh.ClientConnectMessage
7org.gnunet.util.GnunetMessage$Body|4=org.gnunet.util.Resolver$GetMessage 10org.gnunet.util.GnunetMessage$Body|4=org.gnunet.util.Resolver$GetMessage
8org.gnunet.util.GnunetMessage$Body|64=org.gnunet.core.InitMessage 11org.gnunet.util.GnunetMessage$Body|64=org.gnunet.core.InitMessage
9org.gnunet.util.GnunetMessage$Body|5=org.gnunet.util.Resolver$ResolverResponse 12org.gnunet.util.GnunetMessage$Body|5=org.gnunet.util.Resolver$ResolverResponse
@@ -22,8 +25,8 @@ org.gnunet.util.GnunetMessage$Body|144=org.gnunet.dht.ClientGetStopMessage
22org.gnunet.util.GnunetMessage$Body|145=org.gnunet.dht.ClientResultMessage 25org.gnunet.util.GnunetMessage$Body|145=org.gnunet.dht.ClientResultMessage
23org.gnunet.util.GnunetMessage$Body|332=org.gnunet.peerinfo.InfoMessage 26org.gnunet.util.GnunetMessage$Body|332=org.gnunet.peerinfo.InfoMessage
24org.gnunet.util.GnunetMessage$Body|333=org.gnunet.peerinfo.InfoEnd 27org.gnunet.util.GnunetMessage$Body|333=org.gnunet.peerinfo.InfoEnd
25org.gnunet.util.GnunetMessage$Body|331=org.gnunet.peerinfo.ListAllPeersMessage
26org.gnunet.util.GnunetMessage$Body|149=org.gnunet.dht.MonitorGetMessage 28org.gnunet.util.GnunetMessage$Body|149=org.gnunet.dht.MonitorGetMessage
29org.gnunet.util.GnunetMessage$Body|331=org.gnunet.peerinfo.ListAllPeersMessage
27org.gnunet.util.GnunetMessage$Body|150=org.gnunet.dht.MonitorGetRespMessage 30org.gnunet.util.GnunetMessage$Body|150=org.gnunet.dht.MonitorGetRespMessage
28org.gnunet.util.GnunetMessage$Body|151=org.gnunet.dht.MonitorPutMessage 31org.gnunet.util.GnunetMessage$Body|151=org.gnunet.dht.MonitorPutMessage
29org.gnunet.util.GnunetMessage$Body|171=org.gnunet.statistics.GetResponseEndMessage 32org.gnunet.util.GnunetMessage$Body|171=org.gnunet.statistics.GetResponseEndMessage
@@ -32,4 +35,4 @@ org.gnunet.util.GnunetMessage$Body|169=org.gnunet.statistics.GetMessage
32org.gnunet.util.GnunetMessage$Body|168=org.gnunet.statistics.SetMessage 35org.gnunet.util.GnunetMessage$Body|168=org.gnunet.statistics.SetMessage
33org.gnunet.util.GnunetMessage$Body|173=org.gnunet.statistics.WatchResponseMessage 36org.gnunet.util.GnunetMessage$Body|173=org.gnunet.statistics.WatchResponseMessage
34org.gnunet.util.GnunetMessage$Body|172=org.gnunet.statistics.WatchMessage 37org.gnunet.util.GnunetMessage$Body|172=org.gnunet.statistics.WatchMessage
35# generated 2012/06/27 15:23:37 38# generated 2012/08/22 15:06:49
diff --git a/src/org/gnunet/construct/ProtocolViolation.java b/src/org/gnunet/construct/ProtocolViolationException.java
index 028c62c..a21cf17 100644
--- a/src/org/gnunet/construct/ProtocolViolation.java
+++ b/src/org/gnunet/construct/ProtocolViolationException.java
@@ -22,14 +22,14 @@ package org.gnunet.construct;
22 22
23 23
24/** 24/**
25 * Thrown when a received message is invalid 25 * Thrown when a received message is invalid.
26 * 26 *
27 * @author Florian Dold 27 * @author Florian Dold
28 * 28 *
29 */ 29 */
30public class ProtocolViolation extends RuntimeException { 30public class ProtocolViolationException extends RuntimeException {
31 31
32 public ProtocolViolation(String s) { 32 public ProtocolViolationException(String s) {
33 super(s); 33 super(s);
34 } 34 }
35} 35}
diff --git a/src/org/gnunet/construct/ReflectUtil.java b/src/org/gnunet/construct/ReflectUtil.java
index 0bc50bc..532f4fa 100644
--- a/src/org/gnunet/construct/ReflectUtil.java
+++ b/src/org/gnunet/construct/ReflectUtil.java
@@ -58,11 +58,11 @@ public class ReflectUtil {
58 } else if (t.equals(Integer.TYPE)) { 58 } else if (t.equals(Integer.TYPE)) {
59 Array.setInt(arr, i, (int) v); 59 Array.setInt(arr, i, (int) v);
60 } else if (t.equals(Short.TYPE)) { 60 } else if (t.equals(Short.TYPE)) {
61 Array.setInt(arr, i, (short) v); 61 Array.setShort(arr, i, (short) v);
62 } else if (t.equals(Byte.TYPE)) { 62 } else if (t.equals(Byte.TYPE)) {
63 Array.setInt(arr, i, (byte) v); 63 Array.setByte(arr, i, (byte) v);
64 } else if (t.equals(Character.TYPE)) { 64 } else if (t.equals(Character.TYPE)) {
65 Array.setInt(arr, i, (char) v); 65 Array.setChar(arr, i, (char) v);
66 } 66 }
67 } 67 }
68 68
@@ -71,8 +71,7 @@ public class ReflectUtil {
71 } 71 }
72 72
73 /** 73 /**
74 * assign an enum value to each numeric type we want to serialize in 74 * An enumeration of all built-in type that can store integers.
75 * order do switch statements on field types
76 */ 75 */
77 public enum NumFieldType { 76 public enum NumFieldType {
78 BIGNUM, BYTE_PRIM, SHORT_PRIM, INT_PRIM, LONG_PRIM, CHAR_PRIM 77 BIGNUM, BYTE_PRIM, SHORT_PRIM, INT_PRIM, LONG_PRIM, CHAR_PRIM
@@ -252,6 +251,7 @@ public class ReflectUtil {
252 for (int i = 0; i < path.size() - 1; ++i) { 251 for (int i = 0; i < path.size() - 1; ++i) {
253 try { 252 try {
254 obj = path.get(i).get(obj); 253 obj = path.get(i).get(obj);
254
255 } catch (IllegalArgumentException e) { 255 } catch (IllegalArgumentException e) {
256 throw new RuntimeException(e); 256 throw new RuntimeException(e);
257 } catch (IllegalAccessException e) { 257 } catch (IllegalAccessException e) {
diff --git a/src/org/gnunet/construct/UInt16.java b/src/org/gnunet/construct/UInt16.java
index 64e4341..18c24b2 100644
--- a/src/org/gnunet/construct/UInt16.java
+++ b/src/org/gnunet/construct/UInt16.java
@@ -27,7 +27,7 @@ import java.lang.annotation.Target;
27 27
28 28
29/** 29/**
30 * Synonym for Integer(byteSize=2, signed=false) 30 * Unsigned 16-bit integer value
31 * 31 *
32 * @author Florian Dold 32 * @author Florian Dold
33 * 33 *
diff --git a/src/org/gnunet/construct/UInt32.java b/src/org/gnunet/construct/UInt32.java
index 4bd4e6b..ab4a278 100644
--- a/src/org/gnunet/construct/UInt32.java
+++ b/src/org/gnunet/construct/UInt32.java
@@ -26,7 +26,7 @@ import java.lang.annotation.RetentionPolicy;
26import java.lang.annotation.Target; 26import java.lang.annotation.Target;
27 27
28/** 28/**
29 * Synonym for Integer(byteSize=4, signed=false) 29 * Unsigned 32-bit integer value
30 * 30 *
31 * @author Florian Dold 31 * @author Florian Dold
32 * 32 *
diff --git a/src/org/gnunet/construct/UInt64.java b/src/org/gnunet/construct/UInt64.java
index 3d3b22a..d45cf69 100644
--- a/src/org/gnunet/construct/UInt64.java
+++ b/src/org/gnunet/construct/UInt64.java
@@ -26,7 +26,7 @@ import java.lang.annotation.RetentionPolicy;
26import java.lang.annotation.Target; 26import java.lang.annotation.Target;
27 27
28/** 28/**
29 * Synonym for Integer(byteSize=8, signed=false) 29 * Unsigned 64-bit integer value
30 * 30 *
31 * @author Florian Dold 31 * @author Florian Dold
32 * 32 *
diff --git a/src/org/gnunet/construct/UInt8.java b/src/org/gnunet/construct/UInt8.java
index 64e881e..58b8335 100644
--- a/src/org/gnunet/construct/UInt8.java
+++ b/src/org/gnunet/construct/UInt8.java
@@ -28,7 +28,7 @@ import java.lang.annotation.Target;
28 28
29 29
30/** 30/**
31 * Synonym for Integer(byteSize=1, signed=false) 31 * Unsigned 8-bit integer value.
32 * 32 *
33 * @author Florian Dold 33 * @author Florian Dold
34 * 34 *
diff --git a/src/org/gnunet/construct/Union.java b/src/org/gnunet/construct/Union.java
index 9e319aa..d35512e 100644
--- a/src/org/gnunet/construct/Union.java
+++ b/src/org/gnunet/construct/Union.java
@@ -26,6 +26,9 @@ import java.lang.annotation.Retention;
26import java.lang.annotation.RetentionPolicy; 26import java.lang.annotation.RetentionPolicy;
27import java.lang.annotation.Target; 27import java.lang.annotation.Target;
28 28
29/**
30 * A field that stores a union, whose cases are discriminated by the field specified with {@literal tag}.
31 */
29@Target(ElementType.FIELD) 32@Target(ElementType.FIELD)
30@Retention(RetentionPolicy.RUNTIME) 33@Retention(RetentionPolicy.RUNTIME)
31public @interface Union { 34public @interface Union {
diff --git a/src/org/gnunet/construct/UnionCase.java b/src/org/gnunet/construct/UnionCase.java
index 9171ba9..7622dd4 100644
--- a/src/org/gnunet/construct/UnionCase.java
+++ b/src/org/gnunet/construct/UnionCase.java
@@ -26,6 +26,12 @@ import java.lang.annotation.Retention;
26import java.lang.annotation.RetentionPolicy; 26import java.lang.annotation.RetentionPolicy;
27import java.lang.annotation.Target; 27import java.lang.annotation.Target;
28 28
29/**
30 * Annotation for messages that are a case of a union, with a distinct value to discriminate the case.
31 *
32 * Classes annotated by {@literal UnionCase} should implement
33 * the marker interface for their respective union type.
34 */
29@Retention(RetentionPolicy.SOURCE) 35@Retention(RetentionPolicy.SOURCE)
30@Target(ElementType.TYPE) 36@Target(ElementType.TYPE)
31public @interface UnionCase { 37public @interface UnionCase {
diff --git a/src/org/gnunet/construct/parsers/ByteFillParser.java b/src/org/gnunet/construct/parsers/ByteFillParser.java
deleted file mode 100644
index a581229..0000000
--- a/src/org/gnunet/construct/parsers/ByteFillParser.java
+++ /dev/null
@@ -1,100 +0,0 @@
1/*
2 This file is part of GNUnet.
3 (C) 2011, 2012 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21package org.gnunet.construct.parsers;
22
23import org.gnunet.construct.Message;
24import org.gnunet.construct.ReflectUtil;
25import org.gnunet.construct.ProtocolViolation;
26import org.slf4j.Logger;
27import org.slf4j.LoggerFactory;
28
29import java.lang.reflect.Array;
30import java.lang.reflect.Field;
31import java.nio.ByteBuffer;
32import java.util.List;
33
34/**
35 * Parse a byte array that takes up all the remaining space in its frame.
36 * A 0-element array takes up no space.
37 * 'null' is an invalid value for a field of this type.
38 *
39 * @author Florian Dold
40 *
41 */
42public class ByteFillParser implements Parser {
43 private static final Logger logger = LoggerFactory
44 .getLogger(ByteFillParser.class);
45
46 private final Field targetField;
47
48
49 public ByteFillParser(Field field) {
50 targetField = field;
51 }
52
53 @Override
54 public int getSize(Message src) {
55 return Array.getLength(ReflectUtil.justGet(src, targetField));
56 }
57
58
59 @Override
60 public int parse(ByteBuffer srcBuf, int frameOffset, Message frameObj, Message dst, List<Field> frameSizePath) {
61 int frameSize = ReflectUtil.justGetInt(frameObj, frameSizePath);
62 int remaining = frameOffset + frameSize - srcBuf.position();
63
64 if (remaining < 0) {
65 throw new ProtocolViolation("negative size remaining for variable size message");
66 }
67
68 if (remaining == 0) {
69 ReflectUtil.justSet(dst, targetField, new byte[0]);
70 return 0;
71 }
72
73 byte[] a = new byte[remaining];
74
75 srcBuf.get(a);
76
77 ReflectUtil.justSet(dst, targetField, a);
78
79 return frameOffset;
80 }
81
82 @Override
83 public int write(ByteBuffer dstBuf, Message src) {
84 byte[] a = (byte[]) ReflectUtil.justGet(src, targetField);
85 dstBuf.put(a);
86 return a.length;
87 }
88
89 @Override
90 public void patch(Message message, int frameSize, List<Field> frameSizePath, Message frameObject) {
91 // the size field is contained in the frameObject
92 ReflectUtil.justSetInt(frameObject, frameSizePath, frameSize);
93 }
94
95 @Override
96 public int getStaticSize() {
97 // not known!
98 return 0;
99 }
100}
diff --git a/src/org/gnunet/construct/parsers/FillParser.java b/src/org/gnunet/construct/parsers/FillParser.java
index b8e4b43..b266424 100644
--- a/src/org/gnunet/construct/parsers/FillParser.java
+++ b/src/org/gnunet/construct/parsers/FillParser.java
@@ -62,10 +62,15 @@ public class FillParser implements Parser {
62 public int parse(ByteBuffer srcBuf, int frameOffset, 62 public int parse(ByteBuffer srcBuf, int frameOffset,
63 Message frameObj, final Message dstObj, List<Field> frameSizePath) { 63 Message frameObj, final Message dstObj, List<Field> frameSizePath) {
64 64
65
66
65 final int frameSize = ReflectUtil.justGetInt(dstObj, frameSizePath); 67 final int frameSize = ReflectUtil.justGetInt(dstObj, frameSizePath);
66 int remaining = frameOffset + frameSize - srcBuf.position(); 68 int remaining = frameOffset + frameSize - srcBuf.position();
67 int size = 0; 69 int size = 0;
68 70
71 Class<?> elemType = targetField.getType().getComponentType();
72
73
69 ArrayList<Message> list = new ArrayList<Message>(10); 74 ArrayList<Message> list = new ArrayList<Message>(10);
70 75
71 while (remaining > 0) { 76 while (remaining > 0) {
@@ -74,10 +79,13 @@ public class FillParser implements Parser {
74 int s = elemParser.parse(srcBuf, frameOffset, frameObj, next, null); 79 int s = elemParser.parse(srcBuf, frameOffset, frameObj, next, null);
75 size += s; 80 size += s;
76 remaining -= s; 81 remaining -= s;
82 list.add(next);
77 } 83 }
78 84
85 Object arr = Array.newInstance(elemType, list.size());
86
79 try { 87 try {
80 targetField.set(dstObj, list.toArray()); 88 targetField.set(dstObj, list.toArray((Object[]) arr));
81 } catch (IllegalAccessException e) { 89 } catch (IllegalAccessException e) {
82 throw new AssertionError("cannot access field"); 90 throw new AssertionError("cannot access field");
83 } 91 }
diff --git a/src/org/gnunet/construct/parsers/FixedSizeArrayParser.java b/src/org/gnunet/construct/parsers/FixedSizeArrayParser.java
index 855a685..3dbc720 100644
--- a/src/org/gnunet/construct/parsers/FixedSizeArrayParser.java
+++ b/src/org/gnunet/construct/parsers/FixedSizeArrayParser.java
@@ -82,6 +82,9 @@ public class FixedSizeArrayParser implements Parser {
82 final Message srcObj) { 82 final Message srcObj) {
83 int size = 0; 83 int size = 0;
84 final Object arr = ReflectUtil.justGet(srcObj, targetField); 84 final Object arr = ReflectUtil.justGet(srcObj, targetField);
85 if (Array.getLength(arr) != elemNumber) {
86 throw new AssertionError("wrong number of elements");
87 }
85 for (int i = 0; i < Array.getLength(arr); ++i) { 88 for (int i = 0; i < Array.getLength(arr); ++i) {
86 size += elemParser.write(dstBuf, (Message) Array.get(arr, i)); 89 size += elemParser.write(dstBuf, (Message) Array.get(arr, i));
87 } 90 }
diff --git a/src/org/gnunet/construct/parsers/FixedSizeByteArrayParser.java b/src/org/gnunet/construct/parsers/FixedSizeByteArrayParser.java
deleted file mode 100644
index 5349f05..0000000
--- a/src/org/gnunet/construct/parsers/FixedSizeByteArrayParser.java
+++ /dev/null
@@ -1,71 +0,0 @@
1/*
2 This file is part of GNUnet.
3 (C) 2011, 2012 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21package org.gnunet.construct.parsers;
22
23import org.gnunet.construct.Message;
24import org.gnunet.construct.ReflectUtil;
25
26import java.lang.reflect.Field;
27import java.nio.ByteBuffer;
28import java.util.List;
29
30public class FixedSizeByteArrayParser implements Parser {
31 private final int elemNumber;
32 private final Field targetField;
33
34 public FixedSizeByteArrayParser(int elemNumber, Field f) {
35 this.elemNumber = elemNumber;
36 this.targetField = f;
37 }
38
39 @Override
40 public int getSize(Message srcObj) {
41 return elemNumber;
42 }
43
44 @Override
45 public int parse(ByteBuffer srcBuf, int frameStart, Message frameObj, Message dstObj, List<Field> frameSizePath) {
46 byte[] data = new byte[elemNumber];
47 srcBuf.get(data);
48 ReflectUtil.justSet(dstObj, targetField, data);
49 return elemNumber;
50 }
51
52 @Override
53 public int write(ByteBuffer dstBuf, Message srcObj) {
54 byte[] data = (byte[]) ReflectUtil.justGet(srcObj, targetField);
55 if (data.length != elemNumber) {
56 throw new AssertionError("fixed size array has wrong size");
57 }
58 dstBuf.put(data);
59 return elemNumber;
60 }
61
62 @Override
63 public void patch(Message m, int frameSize, List<Field> frameSizePath, Message frameObj) {
64 // nothing to do
65 }
66
67 @Override
68 public int getStaticSize() {
69 return elemNumber;
70 }
71}
diff --git a/src/org/gnunet/construct/parsers/FixedSizeIntegerArrayParser.java b/src/org/gnunet/construct/parsers/FixedSizeIntegerArrayParser.java
new file mode 100644
index 0000000..3605e97
--- /dev/null
+++ b/src/org/gnunet/construct/parsers/FixedSizeIntegerArrayParser.java
@@ -0,0 +1,99 @@
1/*
2 This file is part of GNUnet.
3 (C) 2011, 2012 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21package org.gnunet.construct.parsers;
22
23import org.gnunet.construct.Message;
24import org.gnunet.construct.ReflectUtil;
25
26import java.lang.reflect.Array;
27import java.lang.reflect.Field;
28import java.nio.ByteBuffer;
29import java.util.List;
30
31public class FixedSizeIntegerArrayParser implements Parser {
32
33 private final int byteSize;
34 private final boolean signed;
35
36 private final Field targetField;
37
38 private final int elemNumber;
39
40 public FixedSizeIntegerArrayParser(final int elemNumber, boolean signed, int byteSize, final Field f) {
41 targetField = f;
42 this.elemNumber = elemNumber;
43 this.signed = signed;
44 this.byteSize = byteSize;
45 }
46
47 @Override
48 public int getSize(final Message srcObj) {
49 return byteSize * elemNumber;
50 }
51
52 @Override
53 public int parse(ByteBuffer srcBuf, int frameOffset,
54 Message frameObj, final Message dstObj, List<Field> frameSizePath) {
55 int size = 0;
56
57 @SuppressWarnings("unchecked")
58 final Class<Message> arrayElementType = (Class<Message>) targetField.getType().getComponentType();
59
60 if (!arrayElementType.isPrimitive()) {
61 throw new AssertionError("IntegerFillParser is expected to be of primitive type, not " + arrayElementType);
62 }
63
64 final Object arr = Array.newInstance(targetField.getType().getComponentType(), elemNumber);
65 ReflectUtil.justSet(dstObj, targetField, arr);
66
67 for (int i = 0; i < elemNumber; ++i) {
68 long v = IntegerUtil.readLong(srcBuf, signed, byteSize);
69 ReflectUtil.justSetArray(arr, i, v);
70 }
71
72 return size;
73 }
74
75 @Override
76 public int write(final ByteBuffer dstBuf,
77 final Message srcObj) {
78 int size = 0;
79 final Object arr = ReflectUtil.justGet(srcObj, targetField);
80 if (Array.getLength(arr) != elemNumber) {
81 throw new AssertionError("wrong number of elements");
82 }
83 for (int i = 0; i < Array.getLength(arr); ++i) {
84 IntegerUtil.writeLong(Array.getLong(arr, i), dstBuf, signed, byteSize);
85 size += byteSize;
86 }
87 return size;
88 }
89
90 @Override
91 public void patch(Message m, int frameSize, List<Field> frameSizePath, Message frameObj) {
92 // nothing to patch!
93 }
94
95 @Override
96 public int getStaticSize() {
97 return elemNumber * byteSize;
98 }
99}
diff --git a/src/org/gnunet/construct/parsers/IntegerFillParser.java b/src/org/gnunet/construct/parsers/IntegerFillParser.java
index 1d485da..8c08627 100644
--- a/src/org/gnunet/construct/parsers/IntegerFillParser.java
+++ b/src/org/gnunet/construct/parsers/IntegerFillParser.java
@@ -58,9 +58,25 @@ public class IntegerFillParser implements Parser {
58 final int frameSize = ReflectUtil.justGetInt(frameObj, frameSizePath); 58 final int frameSize = ReflectUtil.justGetInt(frameObj, frameSizePath);
59 int remaining = frameStart + frameSize - srcBuf.position(); 59 int remaining = frameStart + frameSize - srcBuf.position();
60 60
61 throw new UnsupportedOperationException("not yet implemented"); 61 int elemNumber = remaining / byteSize;
62 62
63 // return getSize(dstObj); 63 @SuppressWarnings("unchecked")
64 final Class<Message> arrayElementType = (Class<Message>) targetField.getType().getComponentType();
65
66 if (!arrayElementType.isPrimitive()) {
67 throw new AssertionError("IntegerFillParser is expected to be of primitive type, not " + arrayElementType);
68 }
69
70 final Object arr = Array.newInstance(arrayElementType, elemNumber);
71 ReflectUtil.justSet(dstObj, targetField, arr);
72
73
74 for (int i = 0; i < elemNumber; ++i) {
75 long v = IntegerUtil.readLong(srcBuf, signed, byteSize);
76 ReflectUtil.justSetArray(arr, i, v);
77 }
78
79 return remaining;
64 } 80 }
65 81
66 @Override 82 @Override
diff --git a/src/org/gnunet/construct/parsers/IntegerParser.java b/src/org/gnunet/construct/parsers/IntegerParser.java
index 42646a7..4f71aa5 100644
--- a/src/org/gnunet/construct/parsers/IntegerParser.java
+++ b/src/org/gnunet/construct/parsers/IntegerParser.java
@@ -80,7 +80,12 @@ public class IntegerParser implements Parser {
80 80
81 @Override 81 @Override
82 public void patch(Message m, int frameSize, List<Field> frameSizePath, Message frameObj) { 82 public void patch(Message m, int frameSize, List<Field> frameSizePath, Message frameObj) {
83 // nothing to do 83 // todo: optimize this!
84 /*
85 if (frameSizePath != null) {
86 ReflectUtil.justSetInt(frameObj, frameSizePath, frameSize);
87 }
88 */
84 } 89 }
85 90
86 @Override 91 @Override
diff --git a/src/org/gnunet/construct/parsers/NestedParser.java b/src/org/gnunet/construct/parsers/NestedParser.java
index d42a43c..d36fad6 100644
--- a/src/org/gnunet/construct/parsers/NestedParser.java
+++ b/src/org/gnunet/construct/parsers/NestedParser.java
@@ -21,8 +21,8 @@
21package org.gnunet.construct.parsers; 21package org.gnunet.construct.parsers;
22 22
23import org.gnunet.construct.Message; 23import org.gnunet.construct.Message;
24import org.gnunet.construct.ProtocolViolationException;
24import org.gnunet.construct.ReflectUtil; 25import org.gnunet.construct.ReflectUtil;
25import org.gnunet.construct.ProtocolViolation;
26 26
27import java.lang.reflect.Field; 27import java.lang.reflect.Field;
28import java.nio.ByteBuffer; 28import java.nio.ByteBuffer;
@@ -62,11 +62,11 @@ public class NestedParser implements Parser {
62 if (optional) { 62 if (optional) {
63 int remaining = frameOffset + ReflectUtil.justGetInt(frameObj, frameSizePath) - srcBuf.position(); 63 int remaining = frameOffset + ReflectUtil.justGetInt(frameObj, frameSizePath) - srcBuf.position();
64 if (remaining < 0) { 64 if (remaining < 0) {
65 throw new ProtocolViolation("remaining size negative"); 65 throw new ProtocolViolationException("remaining size negative");
66 } 66 }
67 if (remaining == 0) { 67 if (remaining == 0) {
68 if (!optional) { 68 if (!optional) {
69 throw new ProtocolViolation("not optional"); 69 throw new ProtocolViolationException("not optional");
70 } 70 }
71 ReflectUtil.justSet(dstObj, targetField, null); 71 ReflectUtil.justSet(dstObj, targetField, null);
72 return 0; 72 return 0;
@@ -89,7 +89,7 @@ public class NestedParser implements Parser {
89 Message nestedMessage = (Message) ReflectUtil.justGet(m, targetField); 89 Message nestedMessage = (Message) ReflectUtil.justGet(m, targetField);
90 90
91 if (newFrame) { 91 if (newFrame) {
92 nestedParser.patch(nestedMessage, nestedParser.getSize(nestedMessage), null, m); 92 nestedParser.patch(nestedMessage, nestedParser.getSize(nestedMessage), null, nestedMessage);
93 } else { 93 } else {
94 nestedParser.patch(nestedMessage, frameSize, frameSizePath, frameObj); 94 nestedParser.patch(nestedMessage, frameSize, frameSizePath, frameObj);
95 } 95 }
diff --git a/src/org/gnunet/construct/parsers/SequenceParser.java b/src/org/gnunet/construct/parsers/SequenceParser.java
index 7d35cc4..f472533 100644
--- a/src/org/gnunet/construct/parsers/SequenceParser.java
+++ b/src/org/gnunet/construct/parsers/SequenceParser.java
@@ -21,6 +21,7 @@
21package org.gnunet.construct.parsers; 21package org.gnunet.construct.parsers;
22 22
23import org.gnunet.construct.Message; 23import org.gnunet.construct.Message;
24import org.gnunet.construct.ReflectUtil;
24 25
25import java.lang.reflect.Field; 26import java.lang.reflect.Field;
26import java.nio.ByteBuffer; 27import java.nio.ByteBuffer;
@@ -58,7 +59,6 @@ public class SequenceParser implements Parser {
58 Message frameObj, final Message dst, List<Field> frameSizePath) { 59 Message frameObj, final Message dst, List<Field> frameSizePath) {
59 int size = 0; 60 int size = 0;
60 for (final Parser p : childParsers) { 61 for (final Parser p : childParsers) {
61 List<Field> path;
62 size += p.parse(srcBuf, frameOffset, frameObj, dst, 62 size += p.parse(srcBuf, frameOffset, frameObj, dst,
63 frameSizePath == null ? myFrameSizePath : frameSizePath); 63 frameSizePath == null ? myFrameSizePath : frameSizePath);
64 } 64 }
@@ -76,6 +76,11 @@ public class SequenceParser implements Parser {
76 76
77 @Override 77 @Override
78 public void patch(Message m, int frameSize, List<Field> frameSizePath, Message frameObj) { 78 public void patch(Message m, int frameSize, List<Field> frameSizePath, Message frameObj) {
79 // todo: this should be optimized / only be done by the topmost sequence parse => introduce a boolean parameter
80 if (myFrameSizePath != null) {
81 ReflectUtil.justSetInt(frameObj, myFrameSizePath, frameSize);
82 }
83
79 for (final Parser p : childParsers) { 84 for (final Parser p : childParsers) {
80 p.patch(m, frameSize, frameSizePath == null ? myFrameSizePath : frameSizePath, frameObj); 85 p.patch(m, frameSize, frameSizePath == null ? myFrameSizePath : frameSizePath, frameObj);
81 } 86 }
diff --git a/src/org/gnunet/construct/parsers/StringParser.java b/src/org/gnunet/construct/parsers/StringParser.java
index a96d396..8df171e 100644
--- a/src/org/gnunet/construct/parsers/StringParser.java
+++ b/src/org/gnunet/construct/parsers/StringParser.java
@@ -21,7 +21,7 @@
21package org.gnunet.construct.parsers; 21package org.gnunet.construct.parsers;
22 22
23import org.gnunet.construct.Message; 23import org.gnunet.construct.Message;
24import org.gnunet.construct.ProtocolViolation; 24import org.gnunet.construct.ProtocolViolationException;
25import org.gnunet.construct.ReflectUtil; 25import org.gnunet.construct.ReflectUtil;
26 26
27import java.io.UnsupportedEncodingException; 27import java.io.UnsupportedEncodingException;
@@ -63,12 +63,20 @@ public class StringParser implements Parser {
63 public int parse(final ByteBuffer srcBuf, int frameOffset, Message frameObj, final Message dstObj, List<Field> 63 public int parse(final ByteBuffer srcBuf, int frameOffset, Message frameObj, final Message dstObj, List<Field>
64 frameSizePath) { 64 frameSizePath) {
65 65
66 if (srcBuf.get(srcBuf.position()) == 0) { 66 if (optional) {
67 if (!optional) { 67 if (frameSizePath == null) {
68 throw new ProtocolViolation("no data received for non-optional string"); 68 throw new AssertionError("optional string with no length field in the message!");
69 }
70 final int frameSize = ReflectUtil.justGetInt(dstObj, frameSizePath);
71 int remaining = frameOffset + frameSize - srcBuf.position();
72
73 if (remaining == 0) {
74 if (!optional) {
75 throw new ProtocolViolationException("no data received for non-optional string");
76 }
77 ReflectUtil.justSet(dstObj, targetField, null);
78 return 0;
69 } 79 }
70 ReflectUtil.justSet(dstObj, targetField, null);
71 return 1;
72 } 80 }
73 81
74 int length = 0; 82 int length = 0;
@@ -125,7 +133,9 @@ public class StringParser implements Parser {
125 133
126 @Override 134 @Override
127 public void patch(Message m, int frameSize, List<Field> frameSizePath, Message frameObj) { 135 public void patch(Message m, int frameSize, List<Field> frameSizePath, Message frameObj) {
128 // nothing to patch 136 if (frameSizePath != null) {
137 ReflectUtil.justSetInt(frameObj, frameSizePath, frameSize);
138 }
129 } 139 }
130 140
131 @Override 141 @Override
diff --git a/src/org/gnunet/construct/parsers/UnionParser.java b/src/org/gnunet/construct/parsers/UnionParser.java
index ba167cd..23d265a 100644
--- a/src/org/gnunet/construct/parsers/UnionParser.java
+++ b/src/org/gnunet/construct/parsers/UnionParser.java
@@ -21,7 +21,7 @@
21package org.gnunet.construct.parsers; 21package org.gnunet.construct.parsers;
22 22
23import org.gnunet.construct.*; 23import org.gnunet.construct.*;
24import org.gnunet.construct.ProtocolViolation; 24import org.gnunet.construct.ProtocolViolationException;
25 25
26import java.lang.reflect.Field; 26import java.lang.reflect.Field;
27import java.nio.ByteBuffer; 27import java.nio.ByteBuffer;
@@ -66,7 +66,7 @@ public class UnionParser implements Parser {
66 int remaining = frameOffset + ReflectUtil.justGetInt(frameObj, frameSizePath) - srcBuf.position(); 66 int remaining = frameOffset + ReflectUtil.justGetInt(frameObj, frameSizePath) - srcBuf.position();
67 if (remaining <= 0) { 67 if (remaining <= 0) {
68 if (!optional) { 68 if (!optional) {
69 throw new ProtocolViolation("not optional"); 69 throw new ProtocolViolationException("not optional");
70 } 70 }
71 ReflectUtil.justSet(dstObj, targetField, null); 71 ReflectUtil.justSet(dstObj, targetField, null);
72 return 0; 72 return 0;
diff --git a/src/org/gnunet/construct/parsers/VariableSizeArrayParser.java b/src/org/gnunet/construct/parsers/VariableSizeArrayParser.java
index a85aa0a..2e64f63 100644
--- a/src/org/gnunet/construct/parsers/VariableSizeArrayParser.java
+++ b/src/org/gnunet/construct/parsers/VariableSizeArrayParser.java
@@ -70,7 +70,7 @@ public class VariableSizeArrayParser implements Parser {
70 for (int i = 0; i < elemNumber; ++i) { 70 for (int i = 0; i < elemNumber; ++i) {
71 Message elemObj; 71 Message elemObj;
72 72
73 elemObj = (Message) ReflectUtil.justInstantiate(arrayElementType); 73 elemObj = ReflectUtil.justInstantiate(arrayElementType);
74 74
75 75
76 Array.set(arr, i, elemObj); 76 Array.set(arr, i, elemObj);
diff --git a/src/org/gnunet/construct/parsers/VariableSizeIntegerArrayParser.java b/src/org/gnunet/construct/parsers/VariableSizeIntegerArrayParser.java
index e5d49bd..b3f134d 100644
--- a/src/org/gnunet/construct/parsers/VariableSizeIntegerArrayParser.java
+++ b/src/org/gnunet/construct/parsers/VariableSizeIntegerArrayParser.java
@@ -45,7 +45,6 @@ public class VariableSizeIntegerArrayParser implements Parser {
45 45
46 @Override 46 @Override
47 public int getSize(final Message src) { 47 public int getSize(final Message src) {
48 int size = 0;
49 final Object arr = ReflectUtil.justGet(src, targetField); 48 final Object arr = ReflectUtil.justGet(src, targetField);
50 49
51 if (arr == null) { 50 if (arr == null) {
diff --git a/src/org/gnunet/util/getopt/OptionAction.java b/src/org/gnunet/construct/parsers/package-info.java
index 29b4a61..5da3a94 100644
--- a/src/org/gnunet/util/getopt/OptionAction.java
+++ b/src/org/gnunet/construct/parsers/package-info.java
@@ -18,9 +18,8 @@
18 Boston, MA 02111-1307, USA. 18 Boston, MA 02111-1307, USA.
19 */ 19 */
20 20
21package org.gnunet.util.getopt;
22 21
23 22/**
24public enum OptionAction { 23 * The actual parsers for reading and writing annotated messages.
25 SET, RESET, STORE_STRING, STORE_NUMBER, INCREMENT 24 */
26} 25package org.gnunet.construct.parsers;
diff --git a/src/org/gnunet/core/ConnectNotifyMessage.java b/src/org/gnunet/core/ConnectNotifyMessage.java
index 7d88472..4eafe02 100644
--- a/src/org/gnunet/core/ConnectNotifyMessage.java
+++ b/src/org/gnunet/core/ConnectNotifyMessage.java
@@ -20,10 +20,7 @@
20 20
21package org.gnunet.core; 21package org.gnunet.core;
22 22
23import org.gnunet.construct.ByteFill; 23import org.gnunet.construct.*;
24import org.gnunet.construct.NestedMessage;
25import org.gnunet.construct.UInt32;
26import org.gnunet.construct.UnionCase;
27import org.gnunet.util.GnunetMessage; 24import org.gnunet.util.GnunetMessage;
28import org.gnunet.util.PeerIdentity; 25import org.gnunet.util.PeerIdentity;
29 26
@@ -47,7 +44,7 @@ public class ConnectNotifyMessage implements GnunetMessage.Body {
47 public PeerIdentity peer; 44 public PeerIdentity peer;
48 45
49 46
50 @ByteFill 47 @FillWith @UInt8
51 public byte[] atsInfo; 48 public byte[] atsInfo;
52 49
53 50
diff --git a/src/org/gnunet/core/NotifyInboundTrafficMessage.java b/src/org/gnunet/core/NotifyInboundTrafficMessage.java
index 24df262..45647de 100644
--- a/src/org/gnunet/core/NotifyInboundTrafficMessage.java
+++ b/src/org/gnunet/core/NotifyInboundTrafficMessage.java
@@ -53,6 +53,6 @@ public class NotifyInboundTrafficMessage implements GnunetMessage.Body {
53 * Not typed as GnunetMessage.Body because the message type may not be known by this 53 * Not typed as GnunetMessage.Body because the message type may not be known by this
54 * peer. 54 * peer.
55 */ 55 */
56 @ByteFill 56 @FillWith @UInt8
57 public byte[] payloadBody; 57 public byte[] payloadBody;
58} 58}
diff --git a/src/org/gnunet/core/NotifyOutboundTrafficMessage.java b/src/org/gnunet/core/NotifyOutboundTrafficMessage.java
index f2080e6..900f8be 100644
--- a/src/org/gnunet/core/NotifyOutboundTrafficMessage.java
+++ b/src/org/gnunet/core/NotifyOutboundTrafficMessage.java
@@ -52,7 +52,7 @@ public class NotifyOutboundTrafficMessage implements GnunetMessage.Body {
52 * Not typed as GnunetMessage.Body because the message type may not be known by this 52 * Not typed as GnunetMessage.Body because the message type may not be known by this
53 * peer. 53 * peer.
54 */ 54 */
55 @ByteFill 55 @FillWith @UInt8
56 public byte[] payloadBody; 56 public byte[] payloadBody;
57 57
58} 58}
diff --git a/src/org/gnunet/dht/ClientGetMessage.java b/src/org/gnunet/dht/ClientGetMessage.java
index 40223eb..cd317fb 100644
--- a/src/org/gnunet/dht/ClientGetMessage.java
+++ b/src/org/gnunet/dht/ClientGetMessage.java
@@ -46,6 +46,6 @@ public class ClientGetMessage implements GnunetMessage.Body {
46 public HashCode key; 46 public HashCode key;
47 @UInt64 47 @UInt64
48 public long uniqueId; 48 public long uniqueId;
49 @ByteFill 49 @FillWith @UInt8
50 public byte[] xquery; 50 public byte[] xquery;
51} 51}
diff --git a/src/org/gnunet/dht/ClientPutMessage.java b/src/org/gnunet/dht/ClientPutMessage.java
index 398ebf6..4b63e92 100644
--- a/src/org/gnunet/dht/ClientPutMessage.java
+++ b/src/org/gnunet/dht/ClientPutMessage.java
@@ -49,6 +49,6 @@ public class ClientPutMessage implements GnunetMessage.Body {
49 public AbsoluteTimeMessage expiration; 49 public AbsoluteTimeMessage expiration;
50 @NestedMessage 50 @NestedMessage
51 public HashCode hash; 51 public HashCode hash;
52 @ByteFill 52 @FillWith @UInt8
53 public byte[] data; 53 public byte[] data;
54} 54}
diff --git a/src/org/gnunet/dht/ClientResultMessage.java b/src/org/gnunet/dht/ClientResultMessage.java
index 7d3f50f..fab614f 100644
--- a/src/org/gnunet/dht/ClientResultMessage.java
+++ b/src/org/gnunet/dht/ClientResultMessage.java
@@ -51,6 +51,6 @@ public class ClientResultMessage implements GnunetMessage.Body {
51 public PeerIdentity[] putPath; 51 public PeerIdentity[] putPath;
52 @VariableSizeArray(lengthField = "getPathLength") 52 @VariableSizeArray(lengthField = "getPathLength")
53 public PeerIdentity[] getPath; 53 public PeerIdentity[] getPath;
54 @ByteFill 54 @FillWith @UInt8
55 public byte[] data; 55 public byte[] data;
56} 56}
diff --git a/src/org/gnunet/dht/DistributedHashTable.java b/src/org/gnunet/dht/DistributedHashTable.java
index c868a08..e3d406b 100644
--- a/src/org/gnunet/dht/DistributedHashTable.java
+++ b/src/org/gnunet/dht/DistributedHashTable.java
@@ -23,8 +23,8 @@ package org.gnunet.dht;
23import org.gnunet.requests.Request; 23import org.gnunet.requests.Request;
24import org.gnunet.requests.RequestQueue; 24import org.gnunet.requests.RequestQueue;
25import org.gnunet.util.*; 25import org.gnunet.util.*;
26import org.gnunet.util.getopt.Option; 26import org.gnunet.util.getopt.Argument;
27import org.gnunet.util.getopt.OptionAction; 27import org.gnunet.util.getopt.ArgumentAction;
28import org.slf4j.Logger; 28import org.slf4j.Logger;
29import org.slf4j.LoggerFactory; 29import org.slf4j.LoggerFactory;
30 30
@@ -345,45 +345,45 @@ public class DistributedHashTable {
345 345
346 public static void main(String[] args) { 346 public static void main(String[] args) {
347 new Program(args) { 347 new Program(args) {
348 @Option(action = OptionAction.SET, 348 @Argument(action = ArgumentAction.SET,
349 shortname = "p", 349 shortname = "p",
350 longname = "put", 350 longname = "put",
351 description = "set a value in the DHT; default is get") 351 description = "set a value in the DHT; default is get")
352 boolean modePut = false; 352 boolean modePut = false;
353 353
354 @Option(action = OptionAction.SET, 354 @Argument(action = ArgumentAction.SET,
355 shortname = "m", 355 shortname = "m",
356 longname = "monitor", 356 longname = "monitor",
357 description = "monitor requests going to the local DHT") 357 description = "monitor requests going to the local DHT")
358 boolean monitor = false; 358 boolean monitor = false;
359 359
360 360
361 @Option(action = OptionAction.STORE_STRING, 361 @Argument(action = ArgumentAction.STORE_STRING,
362 shortname = "d", 362 shortname = "d",
363 longname = "data", 363 longname = "data",
364 description = "data (only used with --put)") 364 description = "data (only used with --put)")
365 String data = null; 365 String data = null;
366 366
367 @Option(action = OptionAction.STORE_STRING, 367 @Argument(action = ArgumentAction.STORE_STRING,
368 shortname = "k", 368 shortname = "k",
369 longname = "key", 369 longname = "key",
370 description = "key used for the operation") 370 description = "key used for the operation")
371 String key = null; 371 String key = null;
372 372
373 @Option(action = OptionAction.STORE_STRING, 373 @Argument(action = ArgumentAction.STORE_STRING,
374 shortname = "t", 374 shortname = "t",
375 longname = "type", 375 longname = "type",
376 description = "type of data used in this operation") 376 description = "type of data used in this operation")
377 String type = null; 377 String type = null;
378 378
379 @Option(action = OptionAction.STORE_STRING, 379 @Argument(action = ArgumentAction.STORE_STRING,
380 shortname = "e", 380 shortname = "e",
381 longname = "expire", 381 longname = "expire",
382 description = "expiration (ony use with --put)") 382 description = "expiration (ony use with --put)")
383 String expiration = null; 383 String expiration = null;
384 384
385 385
386 @Option(action = OptionAction.STORE_NUMBER, 386 @Argument(action = ArgumentAction.STORE_NUMBER,
387 shortname = "r", 387 shortname = "r",
388 longname = "replication", 388 longname = "replication",
389 description = "desired replication (only used with --put)") 389 description = "desired replication (only used with --put)")
diff --git a/src/org/gnunet/dht/MonitorGetRespMessage.java b/src/org/gnunet/dht/MonitorGetRespMessage.java
index b388b6c..3bf145b 100644
--- a/src/org/gnunet/dht/MonitorGetRespMessage.java
+++ b/src/org/gnunet/dht/MonitorGetRespMessage.java
@@ -67,6 +67,6 @@ public class MonitorGetRespMessage implements GnunetMessage.Body {
67 @VariableSizeArray(lengthField = "get_path_length") 67 @VariableSizeArray(lengthField = "get_path_length")
68 public PeerIdentity[] getPath; 68 public PeerIdentity[] getPath;
69 69
70 @ByteFill 70 @FillWith @UInt8
71 public byte[] data; 71 public byte[] data;
72} 72}
diff --git a/src/org/gnunet/dht/MonitorPutMessage.java b/src/org/gnunet/dht/MonitorPutMessage.java
index 7d7261f..103c05b 100644
--- a/src/org/gnunet/dht/MonitorPutMessage.java
+++ b/src/org/gnunet/dht/MonitorPutMessage.java
@@ -77,6 +77,6 @@ public class MonitorPutMessage implements GnunetMessage.Body {
77 @VariableSizeArray(lengthField = "put_path_length") 77 @VariableSizeArray(lengthField = "put_path_length")
78 public PeerIdentity[] putPath; 78 public PeerIdentity[] putPath;
79 79
80 @ByteFill 80 @FillWith @UInt8
81 public byte[] data; 81 public byte[] data;
82} 82}
diff --git a/src/org/gnunet/util/HelloMessage.java b/src/org/gnunet/hello/HelloMessage.java
index aec6637..0d90912 100644
--- a/src/org/gnunet/util/HelloMessage.java
+++ b/src/org/gnunet/hello/HelloMessage.java
@@ -18,7 +18,7 @@
18 Boston, MA 02111-1307, USA. 18 Boston, MA 02111-1307, USA.
19 */ 19 */
20 20
21package org.gnunet.util; 21package org.gnunet.hello;
22 22
23import org.gnunet.construct.*; 23import org.gnunet.construct.*;
24import org.gnunet.peerinfo.RsaPublicKeyBinaryEncoded; 24import org.gnunet.peerinfo.RsaPublicKeyBinaryEncoded;
@@ -45,6 +45,6 @@ public class HelloMessage implements Message {
45 @NestedMessage 45 @NestedMessage
46 public RsaPublicKeyBinaryEncoded publicKey; 46 public RsaPublicKeyBinaryEncoded publicKey;
47 47
48 @ByteFill 48 @FillWith @UInt8
49 public byte[] addresses; 49 public byte[] addresses;
50} 50}
diff --git a/test/org/gnunet/construct/SimpleTestMessage2.java b/src/org/gnunet/hello/package-info.java
index a6433d6..78a5193 100644
--- a/test/org/gnunet/construct/SimpleTestMessage2.java
+++ b/src/org/gnunet/hello/package-info.java
@@ -18,12 +18,8 @@
18 Boston, MA 02111-1307, USA. 18 Boston, MA 02111-1307, USA.
19 */ 19 */
20 20
21package org.gnunet.construct;
22 21
23//@MessageId(321) 22/**
24public class SimpleTestMessage2 implements Message { 23 * Management of hello-messages from peers.
25 24 */
26 @UInt32 25package org.gnunet.hello;
27 public long value;
28
29}
diff --git a/src/org/gnunet/mesh/ClientConnectMessage.java b/src/org/gnunet/mesh/ClientConnectMessage.java
index 3a09373..89332f9 100644
--- a/src/org/gnunet/mesh/ClientConnectMessage.java
+++ b/src/org/gnunet/mesh/ClientConnectMessage.java
@@ -1,9 +1,6 @@
1package org.gnunet.mesh; 1package org.gnunet.mesh;
2 2
3import org.gnunet.construct.FixedSizeArray; 3import org.gnunet.construct.*;
4import org.gnunet.construct.UInt16;
5import org.gnunet.construct.UnionCase;
6import org.gnunet.construct.VariableSizeArray;
7import org.gnunet.util.GnunetMessage; 4import org.gnunet.util.GnunetMessage;
8 5
9/** 6/**
@@ -14,11 +11,11 @@ import org.gnunet.util.GnunetMessage;
14@UnionCase(272) 11@UnionCase(272)
15public class ClientConnectMessage implements GnunetMessage.Body { 12public class ClientConnectMessage implements GnunetMessage.Body {
16 @UInt16 13 @UInt16
17 public int applications; 14 public int applications_length;
18 @UInt16 15 @UInt16
19 public int types; 16 public int types_length;
20 @VariableSizeArray(lengthField = "applications") 17 @VariableSizeIntegerArray(lengthField = "applications_length", signed = false, bitSize = 16)
21 public int[] apps_list; 18 public int[] apps_list;
22 @VariableSizeArray(lengthField = "types") 19 @VariableSizeIntegerArray(lengthField = "types_length", signed = false, bitSize = 16)
23 public int[] types_list; 20 public int[] types_list;
24} 21}
diff --git a/src/org/gnunet/mesh/ConnectHandler.java b/src/org/gnunet/mesh/ConnectHandler.java
new file mode 100644
index 0000000..9f9b5f8
--- /dev/null
+++ b/src/org/gnunet/mesh/ConnectHandler.java
@@ -0,0 +1,9 @@
1package org.gnunet.mesh;
2
3/**
4 * ...
5 *
6 * @author Florian Dold
7 */
8public class ConnectHandler {
9}
diff --git a/src/org/gnunet/mesh/DisconnectHandler.java b/src/org/gnunet/mesh/DisconnectHandler.java
new file mode 100644
index 0000000..6cbf02a
--- /dev/null
+++ b/src/org/gnunet/mesh/DisconnectHandler.java
@@ -0,0 +1,9 @@
1package org.gnunet.mesh;
2
3/**
4 * ...
5 *
6 * @author Florian Dold
7 */
8public interface DisconnectHandler {
9}
diff --git a/src/org/gnunet/mesh/Mesh.java b/src/org/gnunet/mesh/Mesh.java
index d739b61..4b43c97 100644
--- a/src/org/gnunet/mesh/Mesh.java
+++ b/src/org/gnunet/mesh/Mesh.java
@@ -25,36 +25,122 @@ import org.gnunet.requests.RequestQueue;
25import org.gnunet.util.*; 25import org.gnunet.util.*;
26import org.grothoff.Runabout; 26import org.grothoff.Runabout;
27 27
28import java.util.List;
29
30/** 28/**
29 *
30 *
31 * @author Florian Dold 31 * @author Florian Dold
32 */ 32 */
33public class Mesh { 33public class Mesh {
34 private RequestQueue requestQueue; 34 private RequestQueue requestQueue;
35 private TunnelEndHandler tunnelEndHandler; 35 private TunnelEndHandler tunnelEndHandler;
36 private Runabout messageReceiver; 36 private Runabout messageReceiver;
37 private List<Integer> applications; 37 private int[] applications;
38 private InboundTunnelHandler inboundTunnelHandler; 38 private InboundTunnelHandler inboundTunnelHandler;
39 39
40 40
41 public static class RootTunnel { 41 private int nextTunnelId = 0x80000000;
42 int tunnel_id; 42
43
44 public class RootTunnel extends Tunnel {
43 public void addPeer(PeerIdentity peerIdentity) { 45 public void addPeer(PeerIdentity peerIdentity) {
44 46
45 } 47 }
48 /**
49 * Request that the given peer isn't added to this tunnel in calls to
50 * connect_by_* calls, (due to misbehaviour, bad performance, ...).
51 *
52 * @param peerIdentity peer identity of the peer which should be blacklisted
53 * for the tunnel.
54 */
46 public void blacklist(PeerIdentity peerIdentity) { 55 public void blacklist(PeerIdentity peerIdentity) {
47 56
48 } 57 }
49 public void destroy() { 58 /**
50 // ... 59 * Request that the given peer isn't blacklisted anymore from this tunnel,
60 * and therefore can be added in future calls to connect*.
61 * The peer must have been previously blacklisted for this tunnel.
62 *
63 * @param peerIdentity peer identity of the peer which shouldn't be blacklisted
64 * for the tunnel anymore.
65 */
66 public void unblacklist(PeerIdentity peerIdentity) {
67
68 }
69 /**
70 * Request that the mesh should try to connect to a peer supporting the given
71 * message type.
72 *
73 * @param appType application type that must be supported by the peer
74 * (MESH should discover peer in proximity handling this type)
75 */
76 public void requestConnectByType (int appType) {
77
78 }
79
80 /**
81 * Request that the mesh should try to connect to a peer matching the
82 * description given in the service string.
83 *
84 * @param description string describing the destination node requirements
85 */
86 public void requestConnectByType (String description) {
87
88 }
89
90 /**
91 * Request that a peer should be added to the tunnel. The connect handler
92 * will be called when the peer connects
93 *
94 * @param peer peer to add
95 */
96 public void requestConnectAdd (PeerIdentity peer) {
97
98 }
99
100 /**
101 * Request that a peer should be removed from the tunnel. The existing
102 * disconnect handler will be called ONCE if we were connected.
103 *
104 * @param peer peer to remove
105 */
106 public void requestConnectDel (PeerIdentity peer) {
107
108 }
109
110 private void registerWithService() {
111 requestQueue.add(new TunnelCreateRequest(this));
51 } 112 }
52 } 113 }
53 114
54 public static class Tunnel extends RootTunnel { 115 public class Tunnel {
55 public Cancelable notifyTransmitReady(PeerIdentity target) { 116 int tunnel_id;
117
118 /**
119 * Ask the mesh to call "notify" once it is ready to transmit the
120 * given number of bytes to the specified tunnel or target.
121 * Only one call can be active at any time, to issue another request,
122 * wait for the callback or cancel the current request.
123 *
124 * @param maxdelay how long can the message wait?
125 * @param target destination for the message
126 * NULL for multicast to all tunnel targets
127 * @param notify_size how many bytes of buffer space does notify want?
128 * @param transmitter handler to call when buffer space is available;
129 * will be called with NULL on timeout or if the overall queue
130 * for this peer is larger than queue_size and this is currently
131 * the message with the lowest priority
132 * @return non-NULL if the notify callback was queued,
133 * NULL if we can not even queue the request (insufficient
134 * memory); if NULL is returned, "notify" will NOT be called.
135 */
136 public Cancelable notifyTransmitReady(RelativeTime maxdelay, PeerIdentity target, int notify_size, MessageTransmitter transmitter) {
56 return null; 137 return null;
57 } 138 }
139
140 public void destroy() {
141 // ...
142 }
143
58 } 144 }
59 145
60 146
@@ -62,7 +148,28 @@ public class Mesh {
62 148
63 @Override 149 @Override
64 public void transmit(Connection.MessageSink sink) { 150 public void transmit(Connection.MessageSink sink) {
65 //To change body of implemented methods use File | Settings | File Templates. 151 ClientConnectMessage ccm = new ClientConnectMessage();
152 ccm.applications_length = applications.length;
153 ccm.apps_list = applications;
154 int[] types = RunaboutUtil.getRunaboutMessageTypes(messageReceiver);
155 ccm.types_list = types;
156 ccm.types_length = types.length;
157 sink.send(ccm);
158 }
159 }
160
161 public class TunnelCreateRequest extends Request {
162 public RootTunnel tunnel;
163
164 public TunnelCreateRequest(RootTunnel rootTunnel) {
165 tunnel = rootTunnel;
166 }
167
168 @Override
169 public void transmit(Connection.MessageSink sink) {
170 TunnelCreateMessage tcm = new TunnelCreateMessage();
171 tcm.tunnel_id = tunnel.tunnel_id;
172 sink.send(tcm);
66 } 173 }
67 } 174 }
68 175
@@ -76,7 +183,7 @@ public class Mesh {
76 183
77 184
78 public Mesh(Configuration cfg, InboundTunnelHandler inboundTunnelHandler, 185 public Mesh(Configuration cfg, InboundTunnelHandler inboundTunnelHandler,
79 TunnelEndHandler tunnelEndHandler, Runabout messageReceiver, List<Integer> applications) { 186 TunnelEndHandler tunnelEndHandler, Runabout messageReceiver, int... applications) {
80 this.tunnelEndHandler = tunnelEndHandler; 187 this.tunnelEndHandler = tunnelEndHandler;
81 this.messageReceiver = messageReceiver; 188 this.messageReceiver = messageReceiver;
82 this.applications = applications; 189 this.applications = applications;
@@ -86,17 +193,38 @@ public class Mesh {
86 requestQueue = new RequestQueue(client, new MeshMessageReceiver()); 193 requestQueue = new RequestQueue(client, new MeshMessageReceiver());
87 194
88 requestQueue.add(new ClientConnectRequest()); 195 requestQueue.add(new ClientConnectRequest());
89
90 } 196 }
91 197
92 /** 198 /**
93 * Create a new tunnel (we're initiator and will be allowed to add/remove peers 199 * Create a new tunnel (we're initiator and will be allowed to add/remove peers
94 * and to broadcast). 200 * and to broadcast).
201 *
202 * @param connectHandler function to call when peers are actually connected
203 * @param disconnectHandler function to call when peers are disconnected
95 */ 204 */
96 public RootTunnel createTunnel(/* ... */) { 205 public RootTunnel createTunnel(ConnectHandler connectHandler, DisconnectHandler disconnectHandler) {
97 return null; 206 RootTunnel tunnel = new RootTunnel();
207 tunnel.tunnel_id = nextTunnelId++;
208 tunnel.registerWithService();
209 return tunnel;
98 } 210 }
99 211
212
213 /**
214 * Announce to ther peer the availability of services described by the regex,
215 * in order to be reachable to other peers via connect_by_string.
216 *
217 * Note that the first 8 characters are considered to be part of a prefix,
218 * (for instance 'gnunet://'). If you put a variable part in there (*, +. ()),
219 * all matching strings will be stored in the DHT.
220 *
221 * @param regex string with the regular expression describing local services.
222 */
223 public void announceRegex(String regex) {
224
225 }
226
227
100 /** 228 /**
101 * Disconnect from the mesh service. All tunnels will be destroyed. All tunnel 229 * Disconnect from the mesh service. All tunnels will be destroyed. All tunnel
102 * disconnect callbacks will be called on any still connected peers, notifying 230 * disconnect callbacks will be called on any still connected peers, notifying
@@ -104,6 +232,6 @@ public class Mesh {
104 * called should any inbound tunnels still exist. 232 * called should any inbound tunnels still exist.
105 */ 233 */
106 public void disconnect() { 234 public void disconnect() {
107 235 requestQueue.destroy();
108 } 236 }
109} 237}
diff --git a/src/org/gnunet/mesh/TunnelCreateMessage.java b/src/org/gnunet/mesh/TunnelCreateMessage.java
index 96d821c..7b63bc6 100644
--- a/src/org/gnunet/mesh/TunnelCreateMessage.java
+++ b/src/org/gnunet/mesh/TunnelCreateMessage.java
@@ -1,11 +1,17 @@
1package org.gnunet.mesh; 1package org.gnunet.mesh;
2 2
3import org.gnunet.construct.NestedMessage;
3import org.gnunet.construct.UInt32; 4import org.gnunet.construct.UInt32;
4import org.gnunet.construct.UnionCase; 5import org.gnunet.construct.UnionCase;
5import org.gnunet.util.GnunetMessage; 6import org.gnunet.util.GnunetMessage;
7import org.gnunet.util.PeerIdentity;
6 8
7/** 9/**
8 * ... 10 * Message used to
11 * a) request the service to create a new tunnel with the given tunnel id
12 * b) notify the client of a newly created tunnel
13 *
14 * todo: this is bad design, split into two messages in the C code!
9 * 15 *
10 * @author Florian Dold 16 * @author Florian Dold
11 */ 17 */
@@ -13,4 +19,10 @@ import org.gnunet.util.GnunetMessage;
13public class TunnelCreateMessage implements GnunetMessage.Body { 19public class TunnelCreateMessage implements GnunetMessage.Body {
14 @UInt32 20 @UInt32
15 public int tunnel_id; 21 public int tunnel_id;
22
23 /**
24 * Only present if sent from server to client (purpose b)
25 */
26 @NestedMessage(optional = true)
27 public PeerIdentity otherEnd;
16} 28}
diff --git a/src/org/gnunet/construct/Constructable.java b/src/org/gnunet/mesh/package-info.java
index 1981492..fb5a8a4 100644
--- a/src/org/gnunet/construct/Constructable.java
+++ b/src/org/gnunet/mesh/package-info.java
@@ -18,11 +18,8 @@
18 Boston, MA 02111-1307, USA. 18 Boston, MA 02111-1307, USA.
19 */ 19 */
20 20
21package org.gnunet.construct;
22 21
23/** 22/**
24 * Implemented by classes that know how to serialize/deserialize themselves. 23 * Create tunnels for packet-based communication to distant peers.
25 */ 24 */
26public interface Constructable { 25package org.gnunet.mesh;
27 // todo
28}
diff --git a/src/org/gnunet/nse/NetworkSizeEstimation.java b/src/org/gnunet/nse/NetworkSizeEstimation.java
index db4c8f0..284d144 100644
--- a/src/org/gnunet/nse/NetworkSizeEstimation.java
+++ b/src/org/gnunet/nse/NetworkSizeEstimation.java
@@ -23,10 +23,10 @@ package org.gnunet.nse;
23 23
24import org.gnunet.construct.Double; 24import org.gnunet.construct.Double;
25import org.gnunet.construct.*; 25import org.gnunet.construct.*;
26import org.gnunet.construct.ProtocolViolation; 26import org.gnunet.construct.ProtocolViolationException;
27import org.gnunet.util.*; 27import org.gnunet.util.*;
28import org.gnunet.util.getopt.Option; 28import org.gnunet.util.getopt.Argument;
29import org.gnunet.util.getopt.OptionAction; 29import org.gnunet.util.getopt.ArgumentAction;
30import org.slf4j.Logger; 30import org.slf4j.Logger;
31import org.slf4j.LoggerFactory; 31import org.slf4j.LoggerFactory;
32 32
@@ -72,7 +72,7 @@ public class NetworkSizeEstimation {
72 @Override 72 @Override
73 public void process(GnunetMessage.Body msg) { 73 public void process(GnunetMessage.Body msg) {
74 if (!(msg instanceof UpdateMessage)) { 74 if (!(msg instanceof UpdateMessage)) {
75 throw new ProtocolViolation("got unexcpected message"); 75 throw new ProtocolViolationException("got unexcpected message");
76 } 76 }
77 UpdateMessage uMsg = (UpdateMessage) msg; 77 UpdateMessage uMsg = (UpdateMessage) msg;
78 78
@@ -169,7 +169,7 @@ public class NetworkSizeEstimation {
169 169
170 public static void main(String[] args) { 170 public static void main(String[] args) {
171 new Program(args) { 171 new Program(args) {
172 @Option(action = OptionAction.SET, 172 @Argument(action = ArgumentAction.SET,
173 shortname = "w", 173 shortname = "w",
174 longname = "continuous", 174 longname = "continuous",
175 description = "don't exit after the first estimation response") 175 description = "don't exit after the first estimation response")
diff --git a/src/org/gnunet/peerinfo/InfoMessage.java b/src/org/gnunet/peerinfo/InfoMessage.java
index 72cafac..d8d7daa 100644
--- a/src/org/gnunet/peerinfo/InfoMessage.java
+++ b/src/org/gnunet/peerinfo/InfoMessage.java
@@ -23,7 +23,7 @@ package org.gnunet.peerinfo;
23import org.gnunet.construct.NestedMessage; 23import org.gnunet.construct.NestedMessage;
24import org.gnunet.construct.UInt32; 24import org.gnunet.construct.UInt32;
25import org.gnunet.construct.UnionCase; 25import org.gnunet.construct.UnionCase;
26import org.gnunet.util.HelloMessage; 26import org.gnunet.hello.HelloMessage;
27import org.gnunet.util.GnunetMessage; 27import org.gnunet.util.GnunetMessage;
28import org.gnunet.util.PeerIdentity; 28import org.gnunet.util.PeerIdentity;
29 29
diff --git a/src/org/gnunet/peerinfo/PeerInfo.java b/src/org/gnunet/peerinfo/PeerInfo.java
index 29510e4..2cc04d6 100644
--- a/src/org/gnunet/peerinfo/PeerInfo.java
+++ b/src/org/gnunet/peerinfo/PeerInfo.java
@@ -21,7 +21,7 @@
21package org.gnunet.peerinfo; 21package org.gnunet.peerinfo;
22 22
23 23
24import org.gnunet.util.HelloMessage; 24import org.gnunet.hello.HelloMessage;
25import org.gnunet.requests.Request; 25import org.gnunet.requests.Request;
26import org.gnunet.requests.RequestQueue; 26import org.gnunet.requests.RequestQueue;
27import org.gnunet.util.*; 27import org.gnunet.util.*;
diff --git a/src/org/gnunet/peerinfo/PeerProcessor.java b/src/org/gnunet/peerinfo/PeerProcessor.java
index c981afd..b096c37 100644
--- a/src/org/gnunet/peerinfo/PeerProcessor.java
+++ b/src/org/gnunet/peerinfo/PeerProcessor.java
@@ -1,6 +1,6 @@
1package org.gnunet.peerinfo; 1package org.gnunet.peerinfo;
2 2
3import org.gnunet.util.HelloMessage; 3import org.gnunet.hello.HelloMessage;
4import org.gnunet.util.PeerIdentity; 4import org.gnunet.util.PeerIdentity;
5 5
6/** 6/**
diff --git a/src/org/gnunet/peerinfo/RsaPublicKeyBinaryEncoded.java b/src/org/gnunet/peerinfo/RsaPublicKeyBinaryEncoded.java
index 0fc86f7..86985f3 100644
--- a/src/org/gnunet/peerinfo/RsaPublicKeyBinaryEncoded.java
+++ b/src/org/gnunet/peerinfo/RsaPublicKeyBinaryEncoded.java
@@ -20,7 +20,7 @@
20 20
21package org.gnunet.peerinfo; 21package org.gnunet.peerinfo;
22 22
23import org.gnunet.construct.FixedSizeByteArray; 23import org.gnunet.construct.FixedSizeIntegerArray;
24import org.gnunet.construct.Message; 24import org.gnunet.construct.Message;
25import org.gnunet.construct.UInt16; 25import org.gnunet.construct.UInt16;
26import org.gnunet.construct.UInt8; 26import org.gnunet.construct.UInt8;
@@ -45,7 +45,7 @@ public class RsaPublicKeyBinaryEncoded implements Message {
45 /** 45 /**
46 * The key itself, contains n followed by e. 46 * The key itself, contains n followed by e.
47 */ 47 */
48 @FixedSizeByteArray(length = RsaPublicKeyBinaryEncoded.GNUNET_CRYPTO_RSA_KEY_LENGTH) 48 @FixedSizeIntegerArray(length = RsaPublicKeyBinaryEncoded.GNUNET_CRYPTO_RSA_KEY_LENGTH, signed = false, bitSize = 8)
49 public byte[] key; 49 public byte[] key;
50 50
51 /** 51 /**
diff --git a/src/org/gnunet/peerinfo/package-info.java b/src/org/gnunet/peerinfo/package-info.java
new file mode 100644
index 0000000..19cebdb
--- /dev/null
+++ b/src/org/gnunet/peerinfo/package-info.java
@@ -0,0 +1,25 @@
1/*
2 This file is part of GNUnet.
3 (C) 2011, 2012 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21
22/**
23 * Access to information about known hosts.
24 */
25package org.gnunet.peerinfo;
diff --git a/src/org/gnunet/requests/Request.java b/src/org/gnunet/requests/Request.java
index a7b9ea9..ef36471 100644
--- a/src/org/gnunet/requests/Request.java
+++ b/src/org/gnunet/requests/Request.java
@@ -15,7 +15,7 @@ public abstract class Request {
15 /** 15 /**
16 * Called whenever the request could not be transmitted due to timeout. 16 * Called whenever the request could not be transmitted due to timeout.
17 * 17 *
18 * @return 18 * @return true if the request should be queued again
19 */ 19 */
20 public boolean onTransmitTimeout() { 20 public boolean onTransmitTimeout() {
21 // per default, just drop the message on timeout! 21 // per default, just drop the message on timeout!
@@ -55,7 +55,7 @@ public abstract class Request {
55 * Called to determine after how long the request should time out. 55 * Called to determine after how long the request should time out.
56 * Per default, the deadline is FOREVER. 56 * Per default, the deadline is FOREVER.
57 * 57 *
58 * @return 58 * @return the deadline for this request
59 */ 59 */
60 public AbsoluteTime getDeadline() { 60 public AbsoluteTime getDeadline() {
61 return deadline; 61 return deadline;
diff --git a/src/org/gnunet/requests/package-info.java b/src/org/gnunet/requests/package-info.java
new file mode 100644
index 0000000..892a606
--- /dev/null
+++ b/src/org/gnunet/requests/package-info.java
@@ -0,0 +1,25 @@
1/*
2 This file is part of GNUnet.
3 (C) 2011, 2012 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21
22/**
23 * General mechanism for queueing requests to a service.
24 */
25package org.gnunet.requests;
diff --git a/src/org/gnunet/statistics/Statistics.java b/src/org/gnunet/statistics/Statistics.java
index 89b91b5..2ef9fa0 100644
--- a/src/org/gnunet/statistics/Statistics.java
+++ b/src/org/gnunet/statistics/Statistics.java
@@ -29,8 +29,8 @@ package org.gnunet.statistics;
29import org.gnunet.requests.Request; 29import org.gnunet.requests.Request;
30import org.gnunet.requests.RequestQueue; 30import org.gnunet.requests.RequestQueue;
31import org.gnunet.util.*; 31import org.gnunet.util.*;
32import org.gnunet.util.getopt.Option; 32import org.gnunet.util.getopt.Argument;
33import org.gnunet.util.getopt.OptionAction; 33import org.gnunet.util.getopt.ArgumentAction;
34import org.slf4j.Logger; 34import org.slf4j.Logger;
35import org.slf4j.LoggerFactory; 35import org.slf4j.LoggerFactory;
36 36
@@ -190,7 +190,7 @@ public class Statistics {
190 } 190 }
191 191
192 public void transmit(Connection.MessageSink sink) { 192 public void transmit(Connection.MessageSink sink) {
193 sink.send(new TESTMessage()); 193 sink.send(new TestMessage());
194 // todo: disconnect when not receiving the TEST message back after timeout 194 // todo: disconnect when not receiving the TEST message back after timeout
195 } 195 }
196 } 196 }
@@ -208,7 +208,7 @@ public class Statistics {
208 } 208 }
209 } 209 }
210 210
211 public void visit(TESTMessage m) { 211 public void visit(TestMessage m) {
212 client.disconnect(); 212 client.disconnect();
213 } 213 }
214 214
@@ -331,28 +331,28 @@ public class Statistics {
331 */ 331 */
332 public static void main(String[] args) { 332 public static void main(String[] args) {
333 new Program(args) { 333 new Program(args) {
334 @Option( 334 @Argument(
335 shortname = "x", 335 shortname = "x",
336 longname = "set", 336 longname = "set",
337 action = OptionAction.SET, 337 action = ArgumentAction.SET,
338 description = "set a value") 338 description = "set a value")
339 boolean test; 339 boolean test;
340 @Option( 340 @Argument(
341 shortname = "w", 341 shortname = "w",
342 longname = "watch", 342 longname = "watch",
343 action = OptionAction.SET, 343 action = ArgumentAction.SET,
344 description = "set a value") 344 description = "set a value")
345 boolean watch; 345 boolean watch;
346 @Option( 346 @Argument(
347 shortname = "n", 347 shortname = "n",
348 longname = "name", 348 longname = "name",
349 action = OptionAction.STORE_STRING, 349 action = ArgumentAction.STORE_STRING,
350 description = "statistics name") 350 description = "statistics name")
351 String statisticsName = ""; 351 String statisticsName = "";
352 @Option( 352 @Argument(
353 shortname = "s", 353 shortname = "s",
354 longname = "subsystem", 354 longname = "subsystem",
355 action = OptionAction.STORE_STRING, 355 action = ArgumentAction.STORE_STRING,
356 description = "subsystem name") 356 description = "subsystem name")
357 String subsystemName = ""; 357 String subsystemName = "";
358 358
diff --git a/src/org/gnunet/testing/TestingServer.java b/src/org/gnunet/testing/TestingServer.java
index 84ccd93..fe57884 100644
--- a/src/org/gnunet/testing/TestingServer.java
+++ b/src/org/gnunet/testing/TestingServer.java
@@ -20,7 +20,7 @@ public class TestingServer {
20 public final Server server; 20 public final Server server;
21 private final ServerSocketChannel srvChan; 21 private final ServerSocketChannel srvChan;
22 22
23 TestingServer() { 23 public TestingServer() {
24 this(RelativeTime.FOREVER, true); 24 this(RelativeTime.FOREVER, true);
25 } 25 }
26 26
diff --git a/src/org/gnunet/testing/TestingSetup.java b/src/org/gnunet/testing/TestingSetup.java
index ebb3dbc..6f8d578 100644
--- a/src/org/gnunet/testing/TestingSetup.java
+++ b/src/org/gnunet/testing/TestingSetup.java
@@ -29,44 +29,23 @@ import org.gnunet.util.RelativeTime;
29 * 29 *
30 * @author Florian Dold 30 * @author Florian Dold
31 */ 31 */
32public class TestingSetup { 32public final class TestingSetup {
33
34 private TestingSetup() {
35
36 }
33 37
34 public static class SetupException extends RuntimeException { 38 public static class SetupException extends RuntimeException {
35 public SetupException(String msg, Throwable cause) { 39 public SetupException(Exception e) {
36 super(msg, cause); 40 super(e);
37 } 41 }
38
39 public SetupException(String msg) { 42 public SetupException(String msg) {
40 super(msg); 43 super(msg);
41 } 44 }
42 45
43 public SetupException(Throwable cause) {
44 super(cause);
45 }
46 }
47
48 /**
49 * Start a subsystem for testing. Note that subsystems started with this function
50 * are independent of each other.
51 *
52 * After the JVM exits, the subsystem will be shut down.
53 *
54 * @param name name of the Subsystem
55 * @return
56 */
57 public TestingSubsystem startSubsystem(String name) {
58 return new TestingSubsystem(name);
59 }
60
61 public TestingServer createServer() {
62 return new TestingServer();
63 }
64
65 public TestingServer createServer(RelativeTime idleTimeout, boolean requireFound) {
66 return new TestingServer(idleTimeout, requireFound);
67 } 46 }
68 47
69 public TestingSetup() { 48 public static void setup() {
70 String log = System.getenv("GNJ_LOGLEVEL"); 49 String log = System.getenv("GNJ_LOGLEVEL");
71 if (log != null) { 50 if (log != null) {
72 Program.configureLogging(log, null); 51 Program.configureLogging(log, null);
diff --git a/src/org/gnunet/testing/TestingSubsystem.java b/src/org/gnunet/testing/TestingSubsystem.java
index f38ac43..b96277d 100644
--- a/src/org/gnunet/testing/TestingSubsystem.java
+++ b/src/org/gnunet/testing/TestingSubsystem.java
@@ -30,7 +30,9 @@ import java.io.InputStreamReader;
30import java.io.OutputStreamWriter; 30import java.io.OutputStreamWriter;
31 31
32/** 32/**
33* @author Florian Dold 33 * Handle to a GNUnet subsystem that has been started for testing purposes.
34 *
35 * @author Florian Dold
34*/ 36*/
35public class TestingSubsystem { 37public class TestingSubsystem {
36 private static final Logger logger = LoggerFactory 38 private static final Logger logger = LoggerFactory
@@ -46,7 +48,7 @@ public class TestingSubsystem {
46 return cfg; 48 return cfg;
47 } 49 }
48 50
49 TestingSubsystem(String service) { 51 public TestingSubsystem(String service) {
50 try { 52 try {
51 p = Runtime.getRuntime().exec(new String[]{"gnunet-testing-run-service", "-s", service}); 53 p = Runtime.getRuntime().exec(new String[]{"gnunet-testing-run-service", "-s", service});
52 } catch (IOException e) { 54 } catch (IOException e) {
diff --git a/src/org/gnunet/testing/package-info.java b/src/org/gnunet/testing/package-info.java
new file mode 100644
index 0000000..1a91586
--- /dev/null
+++ b/src/org/gnunet/testing/package-info.java
@@ -0,0 +1,27 @@
1/*
2 This file is part of GNUnet.
3 (C) 2011, 2012 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21
22/**
23 * Various utilities for testing.
24 *
25 * This is in the main source code location, as the testing package itself has unit tests.
26 */
27package org.gnunet.testing;
diff --git a/src/org/gnunet/transport/Transport.java b/src/org/gnunet/transport/Transport.java
index 50b5c4f..fdb54fb 100644
--- a/src/org/gnunet/transport/Transport.java
+++ b/src/org/gnunet/transport/Transport.java
@@ -26,7 +26,7 @@ import org.gnunet.util.PeerIdentity;
26import org.gnunet.util.RelativeTime; 26import org.gnunet.util.RelativeTime;
27 27
28/** 28/**
29 * low-level peer-to-peer I/O API 29 * A connection to the transport service.
30 * 30 *
31 * @author Florian Dold 31 * @author Florian Dold
32 */ 32 */
diff --git a/src/org/gnunet/transport/package-info.java b/src/org/gnunet/transport/package-info.java
new file mode 100644
index 0000000..6b52f7a
--- /dev/null
+++ b/src/org/gnunet/transport/package-info.java
@@ -0,0 +1,25 @@
1/*
2 This file is part of GNUnet.
3 (C) 2011, 2012 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21
22/**
23 * Low-level peer-to-peer I/O API.
24 */
25package org.gnunet.transport;
diff --git a/src/org/gnunet/util/AbsoluteTime.java b/src/org/gnunet/util/AbsoluteTime.java
index 2856fb2..d9df13a 100644
--- a/src/org/gnunet/util/AbsoluteTime.java
+++ b/src/org/gnunet/util/AbsoluteTime.java
@@ -32,6 +32,9 @@ public class AbsoluteTime implements Comparable<AbsoluteTime> {
32 private static final Logger logger = LoggerFactory 32 private static final Logger logger = LoggerFactory
33 .getLogger(AbsoluteTime.class); 33 .getLogger(AbsoluteTime.class);
34 34
35 /**
36 * Constant for 'the beginning of time' in our frame.
37 */
35 public final static AbsoluteTime ZERO = new AbsoluteTime(0); 38 public final static AbsoluteTime ZERO = new AbsoluteTime(0);
36 public final static AbsoluteTime FOREVER = new AbsoluteTime(Long.MAX_VALUE); 39 public final static AbsoluteTime FOREVER = new AbsoluteTime(Long.MAX_VALUE);
37 40
@@ -95,16 +98,25 @@ public class AbsoluteTime implements Comparable<AbsoluteTime> {
95 } 98 }
96 99
97 100
101 /**
102 * {@inheritDoc}
103 */
98 @Override 104 @Override
99 public boolean equals(Object other) { 105 public boolean equals(Object other) {
100 return other instanceof AbsoluteTime && compareTo((AbsoluteTime) other) == 0; 106 return other instanceof AbsoluteTime && compareTo((AbsoluteTime) other) == 0;
101 } 107 }
102 108
109 /**
110 * {@inheritDoc}
111 */
103 @Override 112 @Override
104 public int hashCode() { 113 public int hashCode() {
105 return (int) this.abs_value; 114 return (int) this.abs_value;
106 } 115 }
107 116
117 /**
118 * {@inheritDoc}
119 */
108 @Override 120 @Override
109 public int compareTo(AbsoluteTime other) { 121 public int compareTo(AbsoluteTime other) {
110 if (this.abs_value < other.abs_value) { 122 if (this.abs_value < other.abs_value) {
@@ -115,7 +127,10 @@ public class AbsoluteTime implements Comparable<AbsoluteTime> {
115 } 127 }
116 return 0; 128 return 0;
117 } 129 }
118 130
131 /**
132 * {@inheritDoc}
133 */
119 @Override 134 @Override
120 public String toString() { 135 public String toString() {
121 if (this.isForever()) { 136 if (this.isForever()) {
@@ -132,8 +147,12 @@ public class AbsoluteTime implements Comparable<AbsoluteTime> {
132 public boolean isDue() { 147 public boolean isDue() {
133 return this.abs_value < now().abs_value; 148 return this.abs_value < now().abs_value;
134 } 149 }
135 150
136 151 /**
152 * Does this AbsoluteTime value represent forever?
153 *
154 * @return this==FOREVER
155 */
137 public boolean isForever() { 156 public boolean isForever() {
138 return this.abs_value == Long.MAX_VALUE; 157 return this.abs_value == Long.MAX_VALUE;
139 } 158 }
@@ -220,10 +239,22 @@ public class AbsoluteTime implements Comparable<AbsoluteTime> {
220 return new AbsoluteTime(abs_value - duration.getMilliseconds()); 239 return new AbsoluteTime(abs_value - duration.getMilliseconds());
221 } 240 }
222 241
242 /**
243 * Get a serializable message corresponding to this AbsoluteTime.
244 *
245 * @return a serializable message corresponding to this AbsoluteTime
246 */
223 public AbsoluteTimeMessage asMessage() { 247 public AbsoluteTimeMessage asMessage() {
224 return new AbsoluteTimeMessage(this); 248 return new AbsoluteTimeMessage(this);
225 } 249 }
226 250
251 /**
252 * Get the AbsoluteTime from a AbsoluteTimeMessage.
253 *
254 * @param m serializable representation of an AbsoluteTime
255 *
256 * @return the real AbsoluteTime associated with m
257 */
227 public static AbsoluteTime fromNetwork(AbsoluteTimeMessage m) { 258 public static AbsoluteTime fromNetwork(AbsoluteTimeMessage m) {
228 return m.value__ < 0 ? AbsoluteTime.FOREVER : new AbsoluteTime(m.value__); 259 return m.value__ < 0 ? AbsoluteTime.FOREVER : new AbsoluteTime(m.value__);
229 } 260 }
diff --git a/src/org/gnunet/util/Client.java b/src/org/gnunet/util/Client.java
index d2e1308..fbd94a6 100644
--- a/src/org/gnunet/util/Client.java
+++ b/src/org/gnunet/util/Client.java
@@ -22,6 +22,7 @@ package org.gnunet.util;
22import org.slf4j.Logger; 22import org.slf4j.Logger;
23import org.slf4j.LoggerFactory; 23import org.slf4j.LoggerFactory;
24 24
25
25/** 26/**
26 * A connection to a gnunet service. 27 * A connection to a gnunet service.
27 * 28 *
@@ -69,6 +70,12 @@ public class Client {
69 private boolean notifyTransmitReadyDelayed; 70 private boolean notifyTransmitReadyDelayed;
70 71
71 /** 72 /**
73 * When notifyTransmitReadyDelayed is true, this can be used to cancel the task
74 * waiting for the connection to be established.
75 */
76 private Cancelable delayedNotifyTransmitHandle;
77
78 /**
72 * Create a connection to a service. 79 * Create a connection to a service.
73 * 80 *
74 * @param serviceName name of the service 81 * @param serviceName name of the service
@@ -111,16 +118,6 @@ public class Client {
111 return connection.receive(timeout, receiver); 118 return connection.receive(timeout, receiver);
112 } 119 }
113 120
114
115 private static class DelayedTransmitHandle implements Cancelable {
116 Cancelable realTransmitHandle;
117 Cancelable timeoutHandle;
118 @Override
119 public void cancel() {
120 throw new UnsupportedOperationException();
121 }
122 }
123
124 /** 121 /**
125 * Ask the client to call us once it is able to send a message. 122 * Ask the client to call us once it is able to send a message.
126 * 123 *
@@ -132,39 +129,103 @@ public class Client {
132 * if the caller does not care about temporary connection errors, 129 * if the caller does not care about temporary connection errors,
133 * for example because the protocol is stateless 130 * for example because the protocol is stateless
134 * @param size size of the message we want to transmit, can be an upper bound 131 * @param size size of the message we want to transmit, can be an upper bound
135 *@param transmitter the MessageTransmitter object to call once the client is ready to transmit or 132 * @param transmitter the MessageTransmitter object to call once the client is ready to transmit or
136 * when the timeout is over. Guaranteed to be called *after* notifyTransmitReady has returned. @return a handle that can be used to cancel the transmit request 133 * when the timeout is over. Guaranteed to be called *after* notifyTransmitReady has returned. @return a handle that can be used to cancel the transmit request
134 *
135 * @return a handle to cancel the notification
137 */ 136 */
138 public Cancelable notifyTransmitReady(final RelativeTime timeout, 137 public Cancelable notifyTransmitReady(final RelativeTime timeout,
139 final boolean autoRetry, int size, final MessageTransmitter transmitter) { 138 final boolean autoRetry, int size, final MessageTransmitter transmitter) {
139 if (notifyTransmitReadyDelayed) {
140 throw new AssertionError("notifyTransmitReady called twice!");
141 }
140 if (connection.isConnected()) { 142 if (connection.isConnected()) {
141 return connection.notifyTransmitReady(0, timeout, transmitter); 143 return connection.notifyTransmitReady(0, timeout, transmitter);
142 } else { 144 } else {
143 notifyTransmitReadyDelayed = true; 145 notifyTransmitReadyDelayed = true;
144 final DelayedTransmitHandle delayedTransmitHandle = new DelayedTransmitHandle(); 146 final AbsoluteTime deadline = timeout.toAbsolute();
145 delayedTransmitHandle.timeoutHandle = Scheduler.addDelayed(connectBackoff, new Scheduler.Task() { 147 delayedNotifyTransmitHandle = connection.notifyConnected(connectBackoff, new Continuation() {
146 @Override 148 @Override
147 public void run(Scheduler.RunContext ctx) { 149 public void cont(boolean success) {
148 if (connection == null) { 150 delayedNotifyTransmitHandle = null;
149 return; 151 if (success) {
150 }
151 if (connection.isConnected()) {
152 notifyTransmitReadyDelayed = false; 152 notifyTransmitReadyDelayed = false;
153 connection.notifyTransmitReady(0, timeout, transmitter); 153 delayedNotifyTransmitHandle = connection.notifyTransmitReady(0, timeout, new MessageTransmitter() {
154 @Override
155 public void transmit(Connection.MessageSink sink) {
156 delayedNotifyTransmitHandle = null;
157 transmitter.transmit(sink);
158 }
159
160 @Override
161 public void handleError() {
162 delayedNotifyTransmitHandle = null;
163 transmitter.handleError();
164 }
165 });
154 } else { 166 } else {
155 logger.debug("still not connected, retrying in {}ms", connectBackoff.getMilliseconds()); 167 if (deadline.isDue()) {
156 reconnect(); 168 transmitter.handleError();
157 connectBackoff = RelativeTime.min(connectBackoff.multiply(2), MAX_BACKOFF); 169 } else {
158 Scheduler.addDelayed(connectBackoff, this); 170 RelativeTime timeout = deadline.getRemaining();
171 connectBackoff = RelativeTime.min(timeout, RelativeTime.min(connectBackoff.multiply(2), MAX_BACKOFF));
172 reconnect();
173 delayedNotifyTransmitHandle = connection.notifyConnected(connectBackoff, this);
174 }
159 } 175 }
160 } 176 }
161 }); 177 });
162 return delayedTransmitHandle; 178 return new Cancelable() {
179 @Override
180 public void cancel() {
181 if (delayedNotifyTransmitHandle != null) {
182 delayedNotifyTransmitHandle.cancel();
183 }
184 }
185 };
163 } 186 }
164 } 187 }
165 188
189 /**
190 * Convenience method for sending messages.
191 *
192 * @param timeout when should we give up sending the message, and call cont.cont(false)
193 * @param message the message to send
194 * @param cont called when the message has been sent successfully or on error
195 * @return a handle to cancel sending the message
196 */
197 public Cancelable transmitWhenReady(final RelativeTime timeout, final GnunetMessage.Body message, final Continuation cont) {
198 return notifyTransmitReady(timeout, false, 0, new MessageTransmitter() {
199 @Override
200 public void transmit(Connection.MessageSink sink) {
201 sink.send(message);
202 if (cont != null) {
203 cont.cont(true);
204 }
205 }
206
207 @Override
208 public void handleError() {
209 if (cont != null) {
210 cont.cont(false);
211 }
212 }
213 });
214 }
215
216 /**
217 * Convenience method for sending messages. Timeout defaults to FOREVER.
218 *
219 * @param message the message to send
220 * @param cont called when the message has been sent successfully or on error
221 * @return a handle to cancel sending the message
222 */
223 public Cancelable transmitWhenReady(final GnunetMessage.Body message, final Continuation cont) {
224 return transmitWhenReady(RelativeTime.FOREVER, message, cont);
225 }
226
166 227
167 public void reconnect() { 228 public final void reconnect() {
168 if (connection != null) { 229 if (connection != null) {
169 connection.disconnect(); 230 connection.disconnect();
170 } 231 }
diff --git a/src/org/gnunet/util/Configuration.java b/src/org/gnunet/util/Configuration.java
index bd2c545..001477a 100644
--- a/src/org/gnunet/util/Configuration.java
+++ b/src/org/gnunet/util/Configuration.java
@@ -348,7 +348,11 @@ public class Configuration {
348 } 348 }
349 for (File dir : dirs) { 349 for (File dir : dirs) {
350 if (dir.exists() && dir.isDirectory()) { 350 if (dir.exists() && dir.isDirectory()) {
351 for (File f : dir.listFiles()) { 351 File[] files = dir.listFiles();
352 if (files == null) {
353 continue;
354 }
355 for (File f : files) {
352 parse(f.getAbsolutePath()); 356 parse(f.getAbsolutePath());
353 } 357 }
354 } 358 }
diff --git a/src/org/gnunet/util/Connection.java b/src/org/gnunet/util/Connection.java
index 85d3c9b..fe7393d 100644
--- a/src/org/gnunet/util/Connection.java
+++ b/src/org/gnunet/util/Connection.java
@@ -22,7 +22,7 @@ package org.gnunet.util;
22 22
23import org.gnunet.construct.Construct; 23import org.gnunet.construct.Construct;
24import org.gnunet.construct.MessageLoader; 24import org.gnunet.construct.MessageLoader;
25import org.gnunet.construct.ProtocolViolation; 25import org.gnunet.construct.ProtocolViolationException;
26import org.slf4j.Logger; 26import org.slf4j.Logger;
27import org.slf4j.LoggerFactory; 27import org.slf4j.LoggerFactory;
28 28
@@ -33,7 +33,6 @@ import java.net.InetSocketAddress;
33import java.nio.ByteBuffer; 33import java.nio.ByteBuffer;
34import java.nio.channels.SocketChannel; 34import java.nio.channels.SocketChannel;
35import java.nio.channels.spi.SelectorProvider; 35import java.nio.channels.spi.SelectorProvider;
36import java.util.Deque;
37import java.util.LinkedList; 36import java.util.LinkedList;
38 37
39/** 38/**
@@ -95,6 +94,16 @@ public class Connection {
95 private ByteBuffer transmitBuffer = ByteBuffer.allocate(GnunetMessage.Header.SIZE); 94 private ByteBuffer transmitBuffer = ByteBuffer.allocate(GnunetMessage.Header.SIZE);
96 private boolean disconnected = false; 95 private boolean disconnected = false;
97 96
97 /**
98 * Timeout task for the connect notify.
99 */
100 private Scheduler.TaskConfiguration notifyConnectedTimeout;
101
102 /**
103 * Continuation to call when connected
104 */
105 private Continuation notifyConnectedContinuation;
106
98 107
99 private class AddressProbe { 108 private class AddressProbe {
100 Cancelable connectTask; 109 Cancelable connectTask;
@@ -150,7 +159,7 @@ public class Connection {
150 159
151 try { 160 try {
152 MessageLoader.getUnionClass(GnunetMessage.Body.class, msgh.messageType); 161 MessageLoader.getUnionClass(GnunetMessage.Body.class, msgh.messageType);
153 } catch (ProtocolViolation e) { 162 } catch (ProtocolViolationException e) {
154 found = false; 163 found = false;
155 } 164 }
156 165
@@ -187,7 +196,7 @@ public class Connection {
187 return; 196 return;
188 } 197 }
189 } 198 }
190 logger.debug(String.format("read %s bytes", n)); 199 logger.debug(String.format("read %s bytes from %s", n, connectionChannel.socket().toString()));
191 } catch (IOException e) { 200 } catch (IOException e) {
192 logger.error("read failed:", e); 201 logger.error("read failed:", e);
193 try { 202 try {
@@ -263,10 +272,6 @@ public class Connection {
263 notifyTimeoutTask = tc.schedule(); 272 notifyTimeoutTask = tc.schedule();
264 } 273 }
265 274
266 public boolean notifyDone() {
267 return notifyTimeoutTask == null;
268 }
269
270 public void cancel() { 275 public void cancel() {
271 if (transmitTask != null) { 276 if (transmitTask != null) {
272 transmitTask.cancel(); 277 transmitTask.cancel();
@@ -283,7 +288,7 @@ public class Connection {
283 this.transmitTask = null; 288 this.transmitTask = null;
284 try { 289 try {
285 int n = connectionChannel.write(transmitBuffer); 290 int n = connectionChannel.write(transmitBuffer);
286 logger.debug("connectionChannel has written " + n + " bytes"); 291 logger.debug("connectionChannel has written " + n + " bytes to " + connectionChannel.socket().toString());
287 } catch (IOException e) { 292 } catch (IOException e) {
288 throw new IOError(e); 293 throw new IOError(e);
289 } 294 }
@@ -372,7 +377,6 @@ public class Connection {
372 377
373 class ConnectionResolveHandler implements Resolver.AddressCallback { 378 class ConnectionResolveHandler implements Resolver.AddressCallback {
374 private final int port; 379 private final int port;
375 private Deque<InetAddress> addressList;
376 380
377 public ConnectionResolveHandler(int port) { 381 public ConnectionResolveHandler(int port) {
378 this.port = port; 382 this.port = port;
@@ -425,7 +429,7 @@ public class Connection {
425 } 429 }
426 430
427 private void finishConnect(SocketChannel channel) { 431 private void finishConnect(SocketChannel channel) {
428 boolean connected = false; 432 boolean connected;
429 try { 433 try {
430 connected = channel.finishConnect(); 434 connected = channel.finishConnect();
431 connectionChannel = channel; 435 connectionChannel = channel;
@@ -439,6 +443,7 @@ public class Connection {
439 logger.debug("finishConnect() was not successful: {}", (Object) e); 443 logger.debug("finishConnect() was not successful: {}", (Object) e);
440 return; 444 return;
441 } 445 }
446
442 if (connected) { 447 if (connected) {
443 if (currentTransmitHelper != null) { 448 if (currentTransmitHelper != null) {
444 currentTransmitHelper.start(); 449 currentTransmitHelper.start();
@@ -446,6 +451,16 @@ public class Connection {
446 if (currentReceiveHelper != null && !currentReceiveHelper.working) { 451 if (currentReceiveHelper != null && !currentReceiveHelper.working) {
447 currentReceiveHelper.schedule(); 452 currentReceiveHelper.schedule();
448 } 453 }
454 Continuation c = notifyConnectedContinuation;
455 notifyConnectedContinuation = null;
456 if (notifyConnectedTimeout != null) {
457 notifyConnectedTimeout.cancel();
458 notifyConnectedTimeout = null;
459 }
460 if (c != null) {
461 c.cont(true);
462 }
463
449 } else { 464 } else {
450 logger.error("socket reported OP_CONNECT but is not connected"); 465 logger.error("socket reported OP_CONNECT but is not connected");
451 } 466 }
@@ -477,10 +492,10 @@ public class Connection {
477 /** 492 /**
478 * Receive one message from the network. 493 * Receive one message from the network.
479 * 494 *
480 * @param timeout deadline after which MessageReceiver.onError will be called 495 * @param timeout deadline after which receiver.onError() will be called
481 * @param receiver MessageReceiver that is responsible for the received message 496 * @param receiver MessageReceiver that is responsible for the received message
482 */ 497 */
483 public ReceiveHandle receive(RelativeTime timeout, MessageReceiver receiver) { 498 public ReceiveHandle receive(RelativeTime timeout, final MessageReceiver receiver) {
484 if (currentReceiveHelper != null) { 499 if (currentReceiveHelper != null) {
485 throw new AssertionError("receive must not be called while receiving"); 500 throw new AssertionError("receive must not be called while receiving");
486 } 501 }
@@ -494,6 +509,8 @@ public class Connection {
494 final ReceiveHelper rh = new ReceiveHelper(receiver, timeout); 509 final ReceiveHelper rh = new ReceiveHelper(receiver, timeout);
495 currentReceiveHelper = rh; 510 currentReceiveHelper = rh;
496 511
512 // we can only schedule the receive helper if we are sure the connection is made, otherwise
513 // select will misbehave!
497 if (connectionChannel.isConnected()) { 514 if (connectionChannel.isConnected()) {
498 currentReceiveHelper.schedule(); 515 currentReceiveHelper.schedule();
499 } 516 }
@@ -507,7 +524,7 @@ public class Connection {
507 } 524 }
508 525
509 /** 526 /**
510 * Call notify once the we are ready to transmit data. 527 * Call the transmitter once the we are ready to transmit data.
511 * 528 *
512 * @param size number of bytes to send 529 * @param size number of bytes to send
513 * @param timeout after how long should we give up (and call transmitter.transmit(null)) 530 * @param timeout after how long should we give up (and call transmitter.transmit(null))
@@ -550,6 +567,33 @@ public class Connection {
550 }; 567 };
551 } 568 }
552 569
570
571 /**
572 * Call cont after establishing the connection or when the timeout has occured.
573 *
574 * @param timeout timeout
575 * @param cont continuation to call
576 * @return
577 */
578 /* package-protected */ Cancelable notifyConnected(RelativeTime timeout, final Continuation cont) {
579 if (notifyConnectedTimeout != null) {
580 throw new AssertionError();
581 }
582 this.notifyConnectedContinuation = cont;
583 this.notifyConnectedTimeout = Scheduler.addDelayed(timeout, new Scheduler.Task() {
584 @Override
585 public void run(Scheduler.RunContext ctx) {
586 Continuation c = notifyConnectedContinuation;
587 notifyConnectedContinuation = null;
588 Connection.this.notifyConnectedTimeout = null;
589 if (c != null) {
590 c.cont(false);
591 }
592 }
593 });
594 return this.notifyConnectedTimeout;
595 }
596
553 /** 597 /**
554 * Disconnect. There must not be any pending transmit/receive requests. 598 * Disconnect. There must not be any pending transmit/receive requests.
555 * Any buffered data scheduled for writing is discarded. 599 * Any buffered data scheduled for writing is discarded.
@@ -567,13 +611,15 @@ public class Connection {
567 } 611 }
568 612
569 if (nextTransmitHelper != null) { 613 if (nextTransmitHelper != null) {
570 logger.error("disconnect called, but there is a notifyTransmitReady pending"); 614 // todo: do we want the error/warning logging or not?
615 //logger.error("disconnect called, but there is a notifyTransmitReady pending");
571 nextTransmitHelper.cancel(); 616 nextTransmitHelper.cancel();
572 nextTransmitHelper = null; 617 nextTransmitHelper = null;
573 } 618 }
574 619
575 if (currentReceiveHelper != null) { 620 if (currentReceiveHelper != null) {
576 logger.error("disconnect called, but there is a receive pending"); 621 // todo: same here, want or not?
622 // logger.error("disconnect called, but there is a receive pending");
577 currentReceiveHelper.cancel(); 623 currentReceiveHelper.cancel();
578 currentReceiveHelper = null; 624 currentReceiveHelper = null;
579 } 625 }
diff --git a/src/org/gnunet/util/Continuation.java b/src/org/gnunet/util/Continuation.java
index d626c9e..e1027c0 100644
--- a/src/org/gnunet/util/Continuation.java
+++ b/src/org/gnunet/util/Continuation.java
@@ -21,5 +21,5 @@
21package org.gnunet.util; 21package org.gnunet.util;
22 22
23public interface Continuation { 23public interface Continuation {
24 public void cont(boolean success); 24 void cont(boolean success);
25} 25}
diff --git a/src/org/gnunet/util/HashCode.java b/src/org/gnunet/util/HashCode.java
index 02db150..3c3996e 100644
--- a/src/org/gnunet/util/HashCode.java
+++ b/src/org/gnunet/util/HashCode.java
@@ -21,11 +21,12 @@
21package org.gnunet.util; 21package org.gnunet.util;
22 22
23 23
24import org.gnunet.construct.FixedSizeByteArray; 24import org.gnunet.construct.FixedSizeIntegerArray;
25import org.gnunet.construct.Message; 25import org.gnunet.construct.Message;
26 26
27import java.security.MessageDigest; 27import java.security.MessageDigest;
28import java.security.NoSuchAlgorithmException; 28import java.security.NoSuchAlgorithmException;
29import java.util.Arrays;
29 30
30 31
31/** 32/**
@@ -33,7 +34,7 @@ import java.security.NoSuchAlgorithmException;
33 */ 34 */
34public class HashCode implements Message { 35public class HashCode implements Message {
35 36
36 @FixedSizeByteArray(length = 64) 37 @FixedSizeIntegerArray(length = 64, signed = false, bitSize = 8)
37 public byte[] data; // should be immutable, final, can't be due to construct 38 public byte[] data; // should be immutable, final, can't be due to construct
38 39
39 40
@@ -45,7 +46,7 @@ public class HashCode implements Message {
45 if (hash.length != 64) { 46 if (hash.length != 64) {
46 throw new AssertionError("HashCode has to have length 64"); 47 throw new AssertionError("HashCode has to have length 64");
47 } 48 }
48 data = hash; 49 data = Arrays.copyOf(hash, hash.length);
49 } 50 }
50 51
51 /** 52 /**
diff --git a/src/org/gnunet/util/PeerIdentity.java b/src/org/gnunet/util/PeerIdentity.java
index ceb6447..0d21528 100644
--- a/src/org/gnunet/util/PeerIdentity.java
+++ b/src/org/gnunet/util/PeerIdentity.java
@@ -21,7 +21,7 @@
21package org.gnunet.util; 21package org.gnunet.util;
22 22
23 23
24import org.gnunet.construct.FixedSizeByteArray; 24import org.gnunet.construct.FixedSizeIntegerArray;
25import org.gnunet.construct.Message; 25import org.gnunet.construct.Message;
26 26
27import java.util.Arrays; 27import java.util.Arrays;
@@ -32,7 +32,7 @@ import java.util.Arrays;
32 */ 32 */
33public class PeerIdentity implements Message { 33public class PeerIdentity implements Message {
34 34
35 @FixedSizeByteArray(length = 64) 35 @FixedSizeIntegerArray(length = 64, signed = false, bitSize = 8)
36 public byte[] data; 36 public byte[] data;
37 37
38 static final String HEXES = "0123456789ABCDEF"; 38 static final String HEXES = "0123456789ABCDEF";
diff --git a/src/org/gnunet/util/Program.java b/src/org/gnunet/util/Program.java
index a5cd147..1c7f1b9 100644
--- a/src/org/gnunet/util/Program.java
+++ b/src/org/gnunet/util/Program.java
@@ -21,8 +21,8 @@
21package org.gnunet.util; 21package org.gnunet.util;
22 22
23import org.apache.log4j.*; 23import org.apache.log4j.*;
24import org.gnunet.util.getopt.Option; 24import org.gnunet.util.getopt.Argument;
25import org.gnunet.util.getopt.OptionAction; 25import org.gnunet.util.getopt.ArgumentAction;
26import org.gnunet.util.getopt.Parser; 26import org.gnunet.util.getopt.Parser;
27import org.slf4j.Logger; 27import org.slf4j.Logger;
28import org.slf4j.LoggerFactory; 28import org.slf4j.LoggerFactory;
@@ -33,6 +33,8 @@ import java.io.IOException;
33/** 33/**
34 * Program is the entry point class for everything that uses gnunet services or APIs. 34 * Program is the entry point class for everything that uses gnunet services or APIs.
35 * 35 *
36 * Also specifies the default command line arguments using the org.gnunet.util.getopt annotations.
37 *
36 * @see Service 38 * @see Service
37 */ 39 */
38public abstract class Program { 40public abstract class Program {
@@ -42,33 +44,33 @@ public abstract class Program {
42 44
43 protected final Configuration cfg = new Configuration(); 45 protected final Configuration cfg = new Configuration();
44 46
45 @Option(shortname = "c", longname = "config", 47 @Argument(shortname = "c", longname = "config",
46 description = "Path of the configuration file", 48 description = "Path of the configuration file",
47 argumentName = "FILENAME", 49 argumentName = "FILENAME",
48 action = OptionAction.STORE_STRING) 50 action = ArgumentAction.STORE_STRING)
49 public String cfgFileName; 51 public String cfgFileName;
50 52
51 @Option(shortname = "h", longname = "help", 53 @Argument(shortname = "h", longname = "help",
52 description = "print this help message", 54 description = "print this help message",
53 action = OptionAction.SET) 55 action = ArgumentAction.SET)
54 public boolean printHelp; 56 public boolean printHelp;
55 57
56 @Option(shortname = "v", longname = "version", 58 @Argument(shortname = "v", longname = "version",
57 description = "print version", 59 description = "print version",
58 action = OptionAction.SET) 60 action = ArgumentAction.SET)
59 public boolean showVersion; 61 public boolean showVersion;
60 62
61 63
62 @Option(shortname = "L", longname = "log", 64 @Argument(shortname = "L", longname = "log",
63 description = "configure logging to use LOGLEVEL", 65 description = "configure logging to use LOGLEVEL",
64 argumentName = "LOGLEVEL", 66 argumentName = "LOGLEVEL",
65 action = OptionAction.STORE_STRING) 67 action = ArgumentAction.STORE_STRING)
66 public String logLevel; 68 public String logLevel;
67 69
68 @Option(shortname = "l", longname = "logfile", 70 @Argument(shortname = "l", longname = "logfile",
69 description = "configure logging to write logs to LOGFILE", 71 description = "configure logging to write logs to LOGFILE",
70 argumentName = "LOGFILE", 72 argumentName = "LOGFILE",
71 action = OptionAction.STORE_STRING) 73 action = ArgumentAction.STORE_STRING)
72 public String logFile; 74 public String logFile;
73 75
74 76
@@ -79,7 +81,7 @@ public abstract class Program {
79 81
80 /** 82 /**
81 * A program with the desired environment for a gnunet utility. 83 * A program with the desired environment for a gnunet utility.
82 * While executing the scheduler is guaranteed to run, command arguments are parsed, 84 * While executing, the scheduler is guaranteed to run, command arguments are parsed,
83 * the default configuration is loaded and the DNS Resolver is initialized. 85 * the default configuration is loaded and the DNS Resolver is initialized.
84 * 86 *
85 * @param args array of command line arguments to parse. used to automatically load additional settings 87 * @param args array of command line arguments to parse. used to automatically load additional settings
@@ -94,6 +96,12 @@ public abstract class Program {
94 */ 96 */
95 } 97 }
96 98
99 /**
100 * Configure logging with the given log level and log file.
101 *
102 * @param logLevel one of DEBUG,INFO,WARN,ERROR,OFF
103 * @param logFile logfile, absolute or relative to the current working directory
104 */
97 public static void configureLogging(String logLevel, String logFile) { 105 public static void configureLogging(String logLevel, String logFile) {
98 org.apache.log4j.Logger rootLogger = LogManager.getRootLogger(); 106 org.apache.log4j.Logger rootLogger = LogManager.getRootLogger();
99 107
@@ -155,7 +163,7 @@ public abstract class Program {
155 /** 163 /**
156 * Start the Program as the initial task of the Scheduler. 164 * Start the Program as the initial task of the Scheduler.
157 */ 165 */
158 public void start() { 166 public final void start() {
159 Parser optParser = new Parser(this); 167 Parser optParser = new Parser(this);
160 unprocessedArgs = optParser.parse(args); 168 unprocessedArgs = optParser.parse(args);
161 169
@@ -177,13 +185,23 @@ public abstract class Program {
177 } else { 185 } else {
178 Scheduler.run(new Scheduler.Task() { 186 Scheduler.run(new Scheduler.Task() {
179 public void run(Scheduler.RunContext c) { 187 public void run(Scheduler.RunContext c) {
180 Program.this.run(); 188 Program.this.runHook();
181 } 189 }
182 }); 190 });
183 } 191 }
184 } 192 }
185 193
186 /** 194 /**
195 * Overridden by specializations of Program, like Service.
196 *
197 * Allows for start() to be final.
198 */
199 /* package-private */
200 void runHook() {
201 run();
202 }
203
204 /**
187 * Override to implement the behavior of the Program. 205 * Override to implement the behavior of the Program.
188 */ 206 */
189 public abstract void run(); 207 public abstract void run();
diff --git a/src/org/gnunet/util/Resolver.java b/src/org/gnunet/util/Resolver.java
index ba47611..831da1e 100644
--- a/src/org/gnunet/util/Resolver.java
+++ b/src/org/gnunet/util/Resolver.java
@@ -22,14 +22,12 @@ package org.gnunet.util;
22 22
23import com.google.common.net.InetAddresses; 23import com.google.common.net.InetAddresses;
24import org.gnunet.construct.*; 24import org.gnunet.construct.*;
25import org.gnunet.construct.ProtocolViolation; 25import org.gnunet.construct.ProtocolViolationException;
26import org.gnunet.util.getopt.Option; 26import org.gnunet.util.getopt.Argument;
27import org.gnunet.util.getopt.OptionAction; 27import org.gnunet.util.getopt.ArgumentAction;
28import org.slf4j.Logger; 28import org.slf4j.Logger;
29import org.slf4j.LoggerFactory; 29import org.slf4j.LoggerFactory;
30 30
31import java.net.Inet4Address;
32import java.net.Inet6Address;
33import java.net.InetAddress; 31import java.net.InetAddress;
34import java.net.UnknownHostException; 32import java.net.UnknownHostException;
35import java.util.LinkedList; 33import java.util.LinkedList;
@@ -85,7 +83,7 @@ public class Resolver {
85 83
86 @UnionCase(GetMessage.DIRECTION_GET_NAME) 84 @UnionCase(GetMessage.DIRECTION_GET_NAME)
87 public static class NumericAddress implements Address { 85 public static class NumericAddress implements Address {
88 @ByteFill 86 @FillWith @UInt8
89 public byte[] addr; 87 public byte[] addr;
90 } 88 }
91 89
@@ -98,7 +96,7 @@ public class Resolver {
98 96
99 97
100 public static class ResponseBody implements Message { 98 public static class ResponseBody implements Message {
101 @ByteFill 99 @FillWith @UInt8
102 public byte[] addr; 100 public byte[] addr;
103 } 101 }
104 102
@@ -292,13 +290,13 @@ public class Resolver {
292 if (len == 4 || len == 16) { 290 if (len == 4 || len == 16) {
293 in_addr = InetAddress.getByAddress(gmsg.responseBody.addr); 291 in_addr = InetAddress.getByAddress(gmsg.responseBody.addr);
294 } else { 292 } else {
295 throw new ProtocolViolation("malformed address message"); 293 throw new ProtocolViolationException("malformed address message");
296 } 294 }
297 295
298 rh.cb.onAddress(in_addr); 296 rh.cb.onAddress(in_addr);
299 rh.receiveTask = client.receive(deadline.getRemaining(), this); 297 rh.receiveTask = client.receive(deadline.getRemaining(), this);
300 } catch (UnknownHostException e) { 298 } catch (UnknownHostException e) {
301 throw new ProtocolViolation("malformed address"); 299 throw new ProtocolViolationException("malformed address");
302 } 300 }
303 } else { 301 } else {
304 resolveActive = false; 302 resolveActive = false;
@@ -360,9 +358,9 @@ public class Resolver {
360 358
361 public static void main(final String[] argv) { 359 public static void main(final String[] argv) {
362 new Program(argv) { 360 new Program(argv) {
363 @Option(shortname = "r", longname = "reverse", 361 @Argument(shortname = "r", longname = "reverse",
364 description = "do reverse dns lookup", 362 description = "do reverse dns lookup",
365 action = OptionAction.SET) 363 action = ArgumentAction.SET)
366 boolean isReverse; 364 boolean isReverse;
367 365
368 @Override 366 @Override
diff --git a/src/org/gnunet/util/RunaboutUtil.java b/src/org/gnunet/util/RunaboutUtil.java
index 54c16e6..a82dc0a 100644
--- a/src/org/gnunet/util/RunaboutUtil.java
+++ b/src/org/gnunet/util/RunaboutUtil.java
@@ -44,7 +44,6 @@ public class RunaboutUtil {
44 } 44 }
45 45
46 @SuppressWarnings("unchecked") 46 @SuppressWarnings("unchecked")
47 // todo: where to put this?
48 public static int[] getRunaboutMessageTypes(Runabout r) { 47 public static int[] getRunaboutMessageTypes(Runabout r) {
49 ArrayList<Class> visitees = getRunaboutVisitees(r); 48 ArrayList<Class> visitees = getRunaboutVisitees(r);
50 int[] msgtypes = new int[visitees.size()]; 49 int[] msgtypes = new int[visitees.size()];
diff --git a/src/org/gnunet/util/Scheduler.java b/src/org/gnunet/util/Scheduler.java
index 611467e..0ea9e15 100644
--- a/src/org/gnunet/util/Scheduler.java
+++ b/src/org/gnunet/util/Scheduler.java
@@ -391,8 +391,9 @@ public class Scheduler {
391 391
392 private static void addSubscriberTask(Collection<TaskConfiguration> executableTasks, 392 private static void addSubscriberTask(Collection<TaskConfiguration> executableTasks,
393 TaskConfiguration[] subscribers, int eventType) { 393 TaskConfiguration[] subscribers, int eventType) {
394 if (subscribers[eventType] == null) 394 if (subscribers[eventType] == null) {
395 return; 395 return;
396 }
396 executableTasks.add(subscribers[eventType]); 397 executableTasks.add(subscribers[eventType]);
397 subscribers[eventType].ctx.reasons.add(eventToReason[eventType]); 398 subscribers[eventType].ctx.reasons.add(eventToReason[eventType]);
398 } 399 }
@@ -570,8 +571,10 @@ public class Scheduler {
570 571
571 ByteBuffer buffer = ByteBuffer.allocate(256); 572 ByteBuffer buffer = ByteBuffer.allocate(256);
572 573
574 boolean quit = false;
575
573 try { 576 try {
574 while (true) { 577 while (!quit) {
575 buffer.clear(); 578 buffer.clear();
576 579
577 fileChannel.read(buffer); 580 fileChannel.read(buffer);
@@ -581,17 +584,25 @@ public class Scheduler {
581 pipe.sink().write(buffer); 584 pipe.sink().write(buffer);
582 } 585 }
583 } catch (IOException e) { 586 } catch (IOException e) {
584 throw new IOError(e); 587 quit = true;
585 } 588 }
586 589
587 } 590 }
588 } 591 }
589 592
590 593 public static FilePipe openFilePipe(File file) {
591 public static FilePipe createFilePipe(File file) {
592 FilePipeThread fpt = new FilePipeThread(file); 594 FilePipeThread fpt = new FilePipeThread(file);
593 fpt.setDaemon(true); 595 fpt.setDaemon(true);
594 fpt.start(); 596 fpt.start();
595 return new FilePipe(fpt); 597 return new FilePipe(fpt);
596 } 598 }
599
600 public static class AsyncProcess {
601 // getIn, getOut, getErr
602
603 }
604
605 public static AsyncProcess openAsyncProcess(/*...*/) {
606 throw new UnsupportedOperationException("not implemented yet");
607 }
597} 608}
diff --git a/src/org/gnunet/util/Server.java b/src/org/gnunet/util/Server.java
index f2db539..3d65754 100644
--- a/src/org/gnunet/util/Server.java
+++ b/src/org/gnunet/util/Server.java
@@ -20,6 +20,7 @@
20 20
21package org.gnunet.util; 21package org.gnunet.util;
22 22
23import org.gnunet.construct.Construct;
23import org.grothoff.Runabout; 24import org.grothoff.Runabout;
24import org.slf4j.Logger; 25import org.slf4j.Logger;
25import org.slf4j.LoggerFactory; 26import org.slf4j.LoggerFactory;
@@ -29,47 +30,138 @@ import java.net.SocketAddress;
29import java.nio.channels.ServerSocketChannel; 30import java.nio.channels.ServerSocketChannel;
30import java.nio.channels.SocketChannel; 31import java.nio.channels.SocketChannel;
31import java.util.ArrayList; 32import java.util.ArrayList;
33import java.util.Collections;
32import java.util.LinkedList; 34import java.util.LinkedList;
33import java.util.List; 35import java.util.List;
34 36
37/**
38 * A server allows to wait for incoming connections from clients and respectively communicate with those clients.
39 */
35public class Server { 40public class Server {
36 private static final Logger logger = LoggerFactory 41 private static final Logger logger = LoggerFactory
37 .getLogger(Server.class); 42 .getLogger(Server.class);
38 43
44 /**
45 * Default idle timeout for new clients.
46 */
39 private final RelativeTime idleTimeout; 47 private final RelativeTime idleTimeout;
48
49 /**
50 * If true, disconnect a client when it sends a message we do not expect to receive. Otherwise, the unexpected
51 * message will just be discarded.
52 */
40 private final boolean requireFound; 53 private final boolean requireFound;
41 private List<ServerSocketChannel> listenSockets;
42 private List<ClientHandle> clients = new LinkedList<ClientHandle>();
43 54
44 private MessageRunabout receivedMessagehandler; 55 /**
56 * The sockets this server accepts new connections on.
57 */
58 private List<ServerSocketChannel> listenSockets = new ArrayList<ServerSocketChannel>();
59
60 /**
61 * The list of all clients connected to this server.
62 */
63 private List<ClientHandle> clientHandles = new LinkedList<ClientHandle>();
64
65 /**
66 * The runabout that receives received messages, as well as information about the sender of the last
67 * received message.
68 */
69 private MessageRunabout receivedMessageHandler;
70
71 /**
72 * Whenever a client is disconnected all disconnect handlers are informed.
73 */
45 private List<DisconnectHandler> disconnectHandlers = new LinkedList<DisconnectHandler>(); 74 private List<DisconnectHandler> disconnectHandlers = new LinkedList<DisconnectHandler>();
46 private ArrayList<Class> expectedMessages;
47 75
48 private boolean shutdownRequested; 76 /**
77 * Classes of the messages we expect to receive. If a received message is not in this list, the client
78 * will be disconnected, otherwise the message is just ignored.
79 */
80 private List<Class> expectedMessages = Collections.emptyList();
81
82 /**
83 * If true, shut down as soon as all non-monitor clients have finished, and do not allow new connections
84 * to be made to this server.
85 */
86 private boolean inSoftShutdown;
87
88 /**
89 * Task that is executed as soon as a connection is ready to be accepted.
90 */
49 private Cancelable acceptTask; 91 private Cancelable acceptTask;
50 92
93 /**
94 * True if we are destroyed, or in the process of being destroyed with no way back.
95 */
96 private boolean destroyed;
97
98
99 /**
100 * Interface implemented by disconnect handlers, whose onDisconnect method is called whenever a client
101 * is disconnected from the server.
102 */
51 public interface DisconnectHandler { 103 public interface DisconnectHandler {
104 /**
105 * Called whenever a client is disconnected from the server.
106 *
107 * @param clientHandle the handle for the client that was disconnected
108 */
52 void onDisconnect(ClientHandle clientHandle); 109 void onDisconnect(ClientHandle clientHandle);
53 } 110 }
54 111
55 112 /**
113 * A handle to a (remote) client connected to this server.
114 * <p/>
115 * Every client handle keeps a reference count..
116 * Whenever a part of the programs saves a client handle for further interaction with it, keep() should be called.
117 * This prevents the server from disconnecting the client when it is idle.
118 * Once this interaction is over, drop() will decrement the reference count and eventually disconnect the client
119 * after being idle for long enough.
120 */
56 public class ClientHandle { 121 public class ClientHandle {
57 private RelativeTime clientTimeout; 122 /**
123 * The underlying connection to the client-
124 */
58 private Connection connection; 125 private Connection connection;
59 126
127 /**
128 * When do we disconnect the client after it has been idle?
129 */
130 private RelativeTime clientTimeout;
131
132 /**
133 * When referenceCount==0, the server is allowed to drop the client after a timeout.
134 */
60 private int referenceCount = 0; 135 private int referenceCount = 0;
61 private Connection.ReceiveHandle currentReceive;
62 136
137 /**
138 * Handle for canceling the receive process of this client, null if no receive is currently going on.
139 */
140 private Cancelable currentReceive;
141
142 /**
143 * Set to true if the connection to this client should not prevent the server from shutting down.
144 */
63 private boolean isMonitor; 145 private boolean isMonitor;
64 146
65 private ClientHandle(SocketChannel accept) { 147 /**
66 connection = new Connection(accept); 148 * Iff true, disconnect the client as soon as possible.
149 * Disconnecting may sometimes not be possible immediately, for example when the reference count is not zero.
150 */
151 private boolean disconnectRequested;
152
153 /**
154 * Create a client handle.
155 *
156 * @param sock
157 */
158 private ClientHandle(SocketChannel sock) {
159 connection = new Connection(sock);
67 clientTimeout = idleTimeout; 160 clientTimeout = idleTimeout;
68 // start receiving 161 // start receiving
69 receiveDone(true); 162 receiveDone(true);
70 } 163 }
71 164
72
73 /** 165 /**
74 * Notify us when the server has enough space to transmit 166 * Notify us when the server has enough space to transmit
75 * a message of the given size to the given client. 167 * a message of the given size to the given client.
@@ -81,36 +173,63 @@ public class Server {
81 * @return a handle to cancel the notification 173 * @return a handle to cancel the notification
82 */ 174 */
83 public Cancelable notifyTransmitReady(int size, RelativeTime timeout, MessageTransmitter transmitter) { 175 public Cancelable notifyTransmitReady(int size, RelativeTime timeout, MessageTransmitter transmitter) {
84 return connection.notifyTransmitReady(0, timeout, transmitter); 176 return connection.notifyTransmitReady(size, timeout, transmitter);
177 }
178
179 /**
180 * Convenience method for sending messages.
181 *
182 * @param timeout when should we give up sending the message, and call cont.cont(false)
183 * @param message the message to send
184 * @param cont called when the message has been sent successfully or on error
185 * @return a handle to cancel sending the message
186 */
187 public Cancelable transmitWhenReady(final RelativeTime timeout, final GnunetMessage.Body message, final Continuation cont) {
188 return notifyTransmitReady(0, timeout, new MessageTransmitter() {
189 @Override
190 public void transmit(Connection.MessageSink sink) {
191 sink.send(message);
192 if (cont != null) {
193 cont.cont(true);
194 }
195 }
196
197 @Override
198 public void handleError() {
199 if (cont != null) {
200 cont.cont(false);
201 }
202 }
203 });
85 } 204 }
86 205
87 /** 206 /**
88 * Resume receiving from this client, we are done processing the 207 * Resume receiving from this client, we are done processing the
89 * current request. This function must be called from within each 208 * current request. This function must be called from within each
90 * message handler (or its respective continuations). 209 * message handler (or its respective continuations).
91 * <p/> 210 * <p/>
92 * The server does not automatically continue to receive messages to 211 * The server does not automatically continue to receive messages to
93 * support flow control. 212 * support flow control.
94 * 213 *
95 * @param keepClient false if connection to the client should be closed 214 * @param stayConnected false if connection to the client should be closed
96 */ 215 */
97 public void receiveDone(boolean keepClient) { 216 public void receiveDone(boolean stayConnected) {
98 if (keepClient) { 217 if (stayConnected) {
99 currentReceive = connection.receive(RelativeTime.FOREVER, new MessageReceiver() { 218 currentReceive = connection.receive(RelativeTime.FOREVER, new MessageReceiver() {
100 @Override 219 @Override
101 public void process(GnunetMessage.Body msg) { 220 public void process(GnunetMessage.Body msg) {
102 if (msg instanceof UnknownMessageBody) { 221 if ((msg instanceof UnknownMessageBody) || !expectedMessages.contains(msg.getClass())) {
103 if (requireFound) { 222 if (requireFound) {
104 logger.info("disconnecting client sending unknown message"); 223 logger.info("disconnecting client sending unknown message");
105 disconnect(); 224 disconnect();
106 } 225 }
107 // otherwise, just ignore it 226 // otherwise, just ignore it
108 } 227 }
109 if (receivedMessagehandler == null) { 228 if (receivedMessageHandler == null) {
110 throw new AssertionError("received message, but no handler installed"); 229 throw new AssertionError("received message, but no handler installed");
111 } 230 }
112 receivedMessagehandler.setSender(ClientHandle.this); 231 receivedMessageHandler.setSender(ClientHandle.this);
113 receivedMessagehandler.visitAppropriate(msg); 232 receivedMessageHandler.visitAppropriate(msg);
114 } 233 }
115 234
116 @Override 235 @Override
@@ -120,7 +239,12 @@ public class Server {
120 } 239 }
121 }); 240 });
122 } else { 241 } else {
123 disconnect(); 242 if (referenceCount > 0) {
243 this.disconnectRequested = true;
244 } else {
245 System.out.println("disconnecting " + this.isMonitor);
246 disconnect();
247 }
124 } 248 }
125 249
126 } 250 }
@@ -129,48 +253,86 @@ public class Server {
129 * Change the idle timeout of this particular client. 253 * Change the idle timeout of this particular client.
130 */ 254 */
131 public void setTimeout(RelativeTime newTimeout) { 255 public void setTimeout(RelativeTime newTimeout) {
256 this.clientTimeout = newTimeout;
132 } 257 }
133 258
259 /**
260 * Ask the server to disconnect from the given client.
261 * <p/>
262 * The client will be disconnected from the server, no matter what the current reference count is.
263 */
134 public void disconnect() { 264 public void disconnect() {
135 connection.disconnect(); 265 connection.disconnect();
136 Server.this.clients.remove(this); 266 // if we are in the process of destruction, to not remove, the destruction function will do this,
267 // removing the client handle while in destruction would yield a concurrent modification exception
268 if (!destroyed) {
269 Server.this.clientHandles.remove(this);
270 }
137 for (DisconnectHandler dh : disconnectHandlers) { 271 for (DisconnectHandler dh : disconnectHandlers) {
138 dh.onDisconnect(this); 272 dh.onDisconnect(this);
139 } 273 }
274 Server.this.testForSoftShutdown();
140 } 275 }
141 276
142 /** 277 /**
143 * Disable the warning the server issues if a message is not acknowledged 278 * Prevent the client from being disconnected.
144 * in a timely fashion. Use this call if a client is intentionally delayed 279 * For every keep, there should be an additional matching drop.
145 * for a while. Only applies to the current message.
146 */ 280 */
147 public void disableReceiveDoneWarning() {
148 // todo
149 }
150
151 public void keep() { 281 public void keep() {
152 referenceCount++; 282 referenceCount++;
153 } 283 }
154 284
285
286 /**
287 * Allow to disconnect this client, if not prevented by previous calls to keep.
288 * <p/>
289 * A call to drop should be executed for every call to keep.
290 * After drop() has been executed for every matching keep(), the next call to drop()
291 * allows the server to disconnect the client after a timeout.
292 */
155 public void drop() { 293 public void drop() {
294 assert referenceCount > 0;
156 referenceCount--; 295 referenceCount--;
157 if (referenceCount == 0 && shutdownRequested) { 296 if (referenceCount == 0 && disconnectRequested) {
158 disconnect(); 297 disconnect();
159 } 298 }
160 } 299 }
161 300
301
302 /**
303 * Set the 'monitor' flag on this client. Clients which have been
304 * marked as 'monitors' won't prevent the server from shutting down
305 * once 'GNUNET_SERVER_stop_listening' has been invoked. The idea is
306 * that for "normal" clients we likely want to allow them to process
307 * their requests; however, monitor-clients are likely to 'never'
308 * disconnect during shutdown and thus will not be considered when
309 * determining if the server should continue to exist after
310 * 'GNUNET_SERVER_destroy' has been called.
311 */
162 public void markMonitor() { 312 public void markMonitor() {
163 this.isMonitor = true; 313 this.isMonitor = true;
164 } 314 }
315
316 public boolean isMonitor() {
317 return isMonitor;
318 }
165 } 319 }
166 320
167 321
168 abstract static class MessageRunabout extends Runabout { 322 /**
323 * All handlers for receiving messages from clients have to inherit this class.
324 * <p/>
325 * MessageRunabout is a standard runabout with the added possibility of getting the sender of the message.
326 * This is necessary as the runabout's visit methods can have only one parameter.
327 */
328 public abstract static class MessageRunabout extends Runabout {
169 private ClientHandle currentSender; 329 private ClientHandle currentSender;
170 330
171 /** 331 /**
172 * Allows implementors of MessageRunabout to get the Client that sent the message 332 * Allows implementors of MessageRunabout to get the Client that sent the message
173 * currently visited. 333 * currently visited.
334 * <p/>
335 * The return value of getSender() is only valid while executing a visit method.
174 * 336 *
175 * @return handle of the client whose message is currently being visited 337 * @return handle of the client whose message is currently being visited
176 */ 338 */
@@ -178,39 +340,16 @@ public class Server {
178 return currentSender; 340 return currentSender;
179 } 341 }
180 342
343 /**
344 * Private method used to set the sender for the getSender() method.
345 *
346 * @param clientHandle the client handle to set as the sender
347 */
181 private void setSender(ClientHandle clientHandle) { 348 private void setSender(ClientHandle clientHandle) {
182 currentSender = clientHandle; 349 currentSender = clientHandle;
183 } 350 }
184 } 351 }
185 352
186
187 private void doAccept(final ServerSocketChannel srv) {
188 Scheduler.TaskConfiguration b = new Scheduler.TaskConfiguration(RelativeTime.FOREVER,
189 new Scheduler.Task() {
190 @Override
191 public void run(Scheduler.RunContext ctx) {
192 acceptTask = null;
193 try {
194 SocketChannel cli = srv.accept();
195
196 if (cli != null) {
197 logger.debug("client connected");
198 cli.configureBlocking(false);
199 ClientHandle clientHandle = new ClientHandle(cli);
200 clients.add(clientHandle);
201 }
202
203 } catch (IOException e) {
204 throw new RuntimeException("accept failed", e);
205 }
206 doAccept(srv);
207 }
208 });
209 b.selectAccept(srv);
210 acceptTask = b.schedule();
211 }
212
213
214 /** 353 /**
215 * Create a server listening on all specified addresses. 354 * Create a server listening on all specified addresses.
216 * 355 *
@@ -221,7 +360,6 @@ public class Server {
221 public Server(List<SocketAddress> addresses, RelativeTime idleTimeout, boolean requireFound) { 360 public Server(List<SocketAddress> addresses, RelativeTime idleTimeout, boolean requireFound) {
222 this.idleTimeout = idleTimeout; 361 this.idleTimeout = idleTimeout;
223 this.requireFound = requireFound; 362 this.requireFound = requireFound;
224 listenSockets = new ArrayList<ServerSocketChannel>(addresses.size());
225 try { 363 try {
226 for (SocketAddress addr : addresses) { 364 for (SocketAddress addr : addresses) {
227 ServerSocketChannel socket = ServerSocketChannel.open(); 365 ServerSocketChannel socket = ServerSocketChannel.open();
@@ -229,20 +367,53 @@ public class Server {
229 socket.socket().bind(addr); 367 socket.socket().bind(addr);
230 logger.debug("socket listening on {}", addr.toString()); 368 logger.debug("socket listening on {}", addr.toString());
231 listenSockets.add(socket); 369 listenSockets.add(socket);
232 doAccept(socket); 370 addAcceptSocket(socket);
233 } 371 }
234 } catch (IOException e) { 372 } catch (IOException e) {
235 throw new RuntimeException("could not bind"); 373 throw new RuntimeException("could not bind", e);
236 } 374 }
237 } 375 }
238 376
377 /**
378 * Create a server, not listening on any sockets yet for new connections.
379 *
380 * @param idleTimeout time after a client will be disconnected if idle
381 * @param requireFound allow unknown messages to be received without disconnecting the client in response
382 */
239 public Server(RelativeTime idleTimeout, boolean requireFound) { 383 public Server(RelativeTime idleTimeout, boolean requireFound) {
240 this.idleTimeout = idleTimeout; 384 this.idleTimeout = idleTimeout;
241 this.requireFound = requireFound; 385 this.requireFound = requireFound;
242 } 386 }
243 387
244 public void addAcceptSocket(ServerSocketChannel sock) { 388 /**
245 doAccept(sock); 389 * Accept new connections from the given server socket.
390 *
391 * @param sock the new socket to accept connections from
392 */
393 public final void addAcceptSocket(final ServerSocketChannel sock) {
394 Scheduler.TaskConfiguration b = new Scheduler.TaskConfiguration(RelativeTime.FOREVER,
395 new Scheduler.Task() {
396 @Override
397 public void run(Scheduler.RunContext ctx) {
398 acceptTask = null;
399 try {
400 SocketChannel cli = sock.accept();
401
402 if (cli != null) {
403 logger.debug("client connected");
404 cli.configureBlocking(false);
405 ClientHandle clientHandle = new ClientHandle(cli);
406 clientHandles.add(clientHandle);
407 }
408
409 } catch (IOException e) {
410 throw new RuntimeException("accept failed", e);
411 }
412 addAcceptSocket(sock);
413 }
414 });
415 b.selectAccept(sock);
416 acceptTask = b.schedule();
246 } 417 }
247 418
248 /** 419 /**
@@ -253,10 +424,18 @@ public class Server {
253 * @param msgRunabout handler 424 * @param msgRunabout handler
254 */ 425 */
255 public void setHandler(MessageRunabout msgRunabout) { 426 public void setHandler(MessageRunabout msgRunabout) {
256 receivedMessagehandler = msgRunabout; 427 receivedMessageHandler = msgRunabout;
257 expectedMessages = RunaboutUtil.getRunaboutVisitees(msgRunabout); 428 expectedMessages = RunaboutUtil.getRunaboutVisitees(msgRunabout);
258 } 429 }
259 430
431 /**
432 * Ask the server to notify us whenever a client disconnects.
433 * This handler is called whenever the actual network connection
434 * is closed; the reference count may be zero or larger than zero
435 * at this point. Note that the disconnect handler is also called when
436 *
437 * @param disconnectHandler handler to call on disconnect
438 */
260 public Cancelable notifyDisconnect(final DisconnectHandler disconnectHandler) { 439 public Cancelable notifyDisconnect(final DisconnectHandler disconnectHandler) {
261 this.disconnectHandlers.add(disconnectHandler); 440 this.disconnectHandlers.add(disconnectHandler);
262 return new Cancelable() { 441 return new Cancelable() {
@@ -268,19 +447,63 @@ public class Server {
268 } 447 }
269 448
270 /** 449 /**
271 * Stop the listen socket and get ready to shutdown the server 450 * Stop the listen socket destroy the server as soon as only monitor clients are left.
272 * once only 'monitor' clients are left.
273 */ 451 */
274 public void stopListening() { 452 public void stopListening() {
275 shutdownRequested = true; 453 inSoftShutdown = true;
276 // todo: shut down if only monitor clients left 454 if (acceptTask != null) {
455 acceptTask.cancel();
456 acceptTask = null;
457 }
458 testForSoftShutdown();
277 } 459 }
278 460
461 /**
462 * Disconnect all clients forcefully from the server and stop listening.
463 * <p/>
464 * No methods should be called on a server and its client handles after destroy() has been called.
465 */
279 public void destroy() { 466 public void destroy() {
280 for (ClientHandle h : new ArrayList<ClientHandle>(clients)) { 467 if (destroyed) {
468 return;
469 }
470 destroyed = true;
471 for (ClientHandle h : clientHandles) {
281 h.disconnect(); 472 h.disconnect();
282 } 473 }
283 acceptTask.cancel(); 474 clientHandles.clear();
475 if (acceptTask != null) {
476 acceptTask.cancel();
477 acceptTask = null;
478 }
479 for (ServerSocketChannel ssc : listenSockets) {
480 try {
481 ssc.close();
482 } catch (IOException e) {
483 logger.error("closing listen socket failed", e);
484 }
485 }
284 } 486 }
285 487
488 /**
489 * Test if we should destroy outselves.
490 */
491 private void testForSoftShutdown() {
492 // do this so we don't have many recursive calls to testForSoftShutdown when shutting down
493 if (destroyed) {
494 return;
495 }
496 if (inSoftShutdown) {
497 System.out.println(""+clientHandles.size());
498 boolean done = true;
499 for (ClientHandle clientHandle : this.clientHandles) {
500 if (!clientHandle.isMonitor) {
501 done = false;
502 }
503 }
504 if (done) {
505 destroy();
506 }
507 }
508 }
286} 509}
diff --git a/src/org/gnunet/util/Service.java b/src/org/gnunet/util/Service.java
index bbbba00..69742b6 100644
--- a/src/org/gnunet/util/Service.java
+++ b/src/org/gnunet/util/Service.java
@@ -29,14 +29,21 @@ import java.net.Inet4Address;
29import java.net.InetAddress; 29import java.net.InetAddress;
30import java.net.InetSocketAddress; 30import java.net.InetSocketAddress;
31import java.net.SocketAddress; 31import java.net.SocketAddress;
32import java.nio.ByteBuffer;
32import java.nio.channels.Channel; 33import java.nio.channels.Channel;
33import java.nio.channels.FileChannel; 34import java.nio.channels.FileChannel;
35import java.nio.channels.Pipe;
34import java.nio.channels.SelectableChannel; 36import java.nio.channels.SelectableChannel;
35import java.util.LinkedList; 37import java.util.LinkedList;
36 38
37/** 39/**
38 * Server the entry point class for every gnunet-java component providing services 40 * Server the entry point class for every gnunet-java component providing services
39 * to other components. 41 * to other components.
42 *
43 * The configuration for the server (i.e. ports/interfaces) is loaded with the standard configuration system.
44 *
45 * Note that other processes can send signals to the service via a pipe, whose name has to be given in the
46 * environment variable GNUNET_OS_CONTROL_PIPE
40 */ 47 */
41public abstract class Service extends Program { 48public abstract class Service extends Program {
42 private static final Logger logger = LoggerFactory 49 private static final Logger logger = LoggerFactory
@@ -47,8 +54,9 @@ public abstract class Service extends Program {
47 private RelativeTime idleTimeout; 54 private RelativeTime idleTimeout;
48 private boolean requireFound; 55 private boolean requireFound;
49 56
57
50 private Cancelable sigpipeTask; 58 private Cancelable sigpipeTask;
51 private SelectableChannel sigpipeChannel; 59 private Pipe.SourceChannel sigpipeChannel;
52 60
53 public Service(String serviceName, RelativeTime idleTimeout, boolean requireFound, String[] args) { 61 public Service(String serviceName, RelativeTime idleTimeout, boolean requireFound, String[] args) {
54 super(args); 62 super(args);
@@ -57,63 +65,94 @@ public abstract class Service extends Program {
57 this.requireFound = requireFound; 65 this.requireFound = requireFound;
58 } 66 }
59 67
60 68 /**
69 * Obtain the server used by a service. Note that the server must NOT
70 * be destroyed by the caller.
71 *
72 * @return handle to the server for this service, NULL if there is none
73 */
61 public final Server getServer() { 74 public final Server getServer() {
62 return s; 75 return s;
63 } 76 }
64 77
78 /**
79 * Stop the service.
80 */
65 public void stop() { 81 public void stop() {
66 82 s.stopListening();
67 } 83 }
68 84
69 public void start() { 85 public void runHook() {
70 super.start();
71 String ip4AddrList = getConfiguration().getValueString(serviceName, "ACCEPT_FROM"); 86 String ip4AddrList = getConfiguration().getValueString(serviceName, "ACCEPT_FROM");
72 String ip6AddrList = getConfiguration().getValueString(serviceName, "ACCEPT_FROM6"); 87 String ip6AddrList = getConfiguration().getValueString(serviceName, "ACCEPT_FROM6");
73 int port = (int) getConfiguration().getValueNumer(serviceName, "PORT"); 88 int port = (int) getConfiguration().getValueNumer(serviceName, "PORT");
74 89
75 LinkedList<SocketAddress> addrs = new LinkedList<SocketAddress>(); 90 LinkedList<SocketAddress> addrs = new LinkedList<SocketAddress>();
76 91
77 for (String ip4Addr : ip4AddrList.split("[;]")) { 92 if (ip4AddrList != null) {
78 InetAddress addr = Resolver.getInetAddressFromString(ip4Addr); 93 for (String ip4Addr : ip4AddrList.split("[;]")) {
79 addrs.add(new InetSocketAddress(addr, port)); 94 InetAddress addr = Resolver.getInetAddressFromString(ip4Addr);
95 addrs.add(new InetSocketAddress(addr, port));
96 }
80 } 97 }
81 98
82 for (String ip6Addr : ip6AddrList.split("[;]")) { 99 if (ip6AddrList != null) {
83 InetAddress addr = Resolver.getInetAddressFromString(ip6Addr); 100 for (String ip6Addr : ip6AddrList.split("[;]")) {
84 addrs.add(new InetSocketAddress(addr, port)); 101 InetAddress addr = Resolver.getInetAddressFromString(ip6Addr);
102 addrs.add(new InetSocketAddress(addr, port));
103 }
85 } 104 }
86 105
87 s = new Server(addrs, idleTimeout, requireFound); 106 s = new Server(addrs, idleTimeout, requireFound);
88 107
89 String pipeName = System.getenv("GNUNET_OS_CONTROL_PIPE"); 108 String pipeName = System.getenv("GNUNET_OS_CONTROL_PIPE");
90 if (pipeName != null) { 109 if (pipeName != null && !pipeName.isEmpty()) {
91 logger.debug("service started with control pipe"); 110 Scheduler.FilePipe p = Scheduler.openFilePipe(new File(pipeName));
92 FileChannel f;
93 try {
94 f = (new FileInputStream(pipeName)).getChannel();
95 } catch (FileNotFoundException e) {
96 logger.error("could not open control pipe");
97 }
98 111
99 Scheduler.TaskConfiguration t = new Scheduler.TaskConfiguration(RelativeTime.FOREVER, 112 Scheduler.TaskConfiguration t = new Scheduler.TaskConfiguration(RelativeTime.FOREVER,
100 new SigpipeTask()); 113 new SigpipeTask());
114 t.selectRead(p.getSource());
101 sigpipeTask = t.schedule(); 115 sigpipeTask = t.schedule();
116 sigpipeChannel = p.getSource();
102 } 117 }
103 }
104 118
105 public class SigpipeTask implements Scheduler.Task { 119 run();
120 }
106 121
122 private class SigpipeTask implements Scheduler.Task {
107 @Override 123 @Override
108 public void run(Scheduler.RunContext ctx) { 124 public void run(Scheduler.RunContext ctx) {
109 Scheduler.TaskConfiguration t = new Scheduler.TaskConfiguration(RelativeTime.FOREVER, 125 ByteBuffer b = ByteBuffer.allocate(1);
110 new SigpipeTask()); 126 int n;
111 sigpipeTask = t.schedule(); 127 try {
128 n = sigpipeChannel.read(b);
129 } catch (IOException e) {
130 logger.error("error reading signal pipe", e);
131 return;
132 }
133 b.flip();
134 boolean stopped = false;
135
136 if (n == 1) {
137 byte sig = b.get();
138 // 15=sigterm
139 if (sig == 15) {
140 logger.info("service shutting down");
141 getServer().stopListening();
142 stopped = true;
143 }
144 }
145 if (!stopped) {
146 Scheduler.TaskConfiguration t = new Scheduler.TaskConfiguration(RelativeTime.FOREVER, this);
147 sigpipeTask = t.schedule();
148 } else {
149 try {
150 sigpipeChannel.close();
151 } catch (IOException e) {
152 logger.error("could not close sigpipe channel, quitting");
153 System.exit(2);
154 }
155 }
112 } 156 }
113 } 157 }
114
115 /**
116 * Override to implement the behavior of the Program.
117 */
118 public abstract void run();
119} \ No newline at end of file 158} \ No newline at end of file
diff --git a/src/org/gnunet/util/Strings.java b/src/org/gnunet/util/Strings.java
index 3c369b1..a35568a 100644
--- a/src/org/gnunet/util/Strings.java
+++ b/src/org/gnunet/util/Strings.java
@@ -26,6 +26,21 @@ package org.gnunet.util;
26public class Strings { 26public class Strings {
27 private static final String encTable = "0123456789ABCDEFGHIJKLMNOPQRSTUV"; 27 private static final String encTable = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
28 28
29
30 /**
31 * Convert binary data to ASCII encoding. The ASCII encoding is rather
32 * GNUnet specific. It was chosen such that it only uses characters
33 * in [0-9A-V], can be produced without complex arithmetics and uses a
34 * small number of characters.
35 * Does not append 0-terminator, but returns a pointer to the place where
36 * it should be placed, if needed.
37 *
38 * returned string has length ((size*8) + (((size*8) % 5) > 0 ? 5 - ((size*8) % 5) : 0)) / 5 bytes
39 *
40 * @param data data to encode
41 * @return pointer to the next byte in 'out' or NULL on error.
42 */
43
29 public static String dataToString(byte[] data) { 44 public static String dataToString(byte[] data) {
30 StringBuilder sb = new StringBuilder(); 45 StringBuilder sb = new StringBuilder();
31 46
@@ -54,15 +69,25 @@ public class Strings {
54 return sb.toString(); 69 return sb.toString();
55 } 70 }
56 71
57 public static byte[] stringToData(String string) { 72 /**
58 /* 73 * Convert ASCII encoding back to data
74 * out_size must match exactly the size of the data before it was encoded.
75 *
76 * @param string the string to decode
77 * @param outSize size of the output buffer
78 * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding
79 */
80
81 public static byte[] stringToData(String string, int outSize) {
59 long rpos; 82 long rpos;
60 long wpos; 83 long wpos;
61 long bits; 84 long bits;
62 long vbit; 85 long vbit;
63 int ret; 86 long ret;
64 int shift; 87 long shift;
65 int encoded_len = out_size * 8; 88 int enclen = string.length();
89 int encoded_len = outSize * 8;
90 byte[] out = new byte[outSize];
66 if (encoded_len % 5 > 0) { 91 if (encoded_len % 5 > 0) {
67 // padding! 92 // padding!
68 vbit = encoded_len % 5; 93 vbit = encoded_len % 5;
@@ -75,29 +100,39 @@ public class Strings {
75 throw new AssertionError(); 100 throw new AssertionError();
76 } 101 }
77 102
78 wpos = out_size; 103 wpos = outSize;
79 rpos = enclen; 104 rpos = enclen;
80 bits = (ret = getValue__(enc[--rpos])) >> (5 - encoded_len % 5); 105 bits = (ret = getValue__(string.charAt((int) (--rpos)))) >> (5 - encoded_len % 5);
81 if (-1 == ret) 106 if (-1 == ret) {
82 return GNUNET_SYSERR; 107 throw new AssertionError();
108 }
83 while (wpos > 0) { 109 while (wpos > 0) {
84 GNUNET_assert(rpos > 0); 110 assert rpos > 0;
85 bits = ((ret = getValue__(enc[--rpos])) << vbit) | bits; 111 bits = ((ret = getValue__(string.charAt((int) (--rpos)))) << vbit) | bits;
86 if (-1 == ret) 112 if (-1 == ret) {
87 return GNUNET_SYSERR; 113 throw new AssertionError();
114 }
88 vbit += 5; 115 vbit += 5;
89 if (vbit >= 8) { 116 if (vbit >= 8) {
90 out[--wpos] = (unsigned char)bits; 117 out[(int)--wpos] = (byte)((char) bits);
91 bits >>= 8; 118 bits >>= 8;
92 vbit -= 8; 119 vbit -= 8;
93 } 120 }
94 } 121 }
95 GNUNET_assert(rpos == 0); 122 assert(rpos == 0);
96 GNUNET_assert(vbit == 0); 123 assert(vbit == 0);
97 return GNUNET_OK; 124 return out;
98
99 } 125 }
100 */ 126
101 throw new UnsupportedOperationException("not yet implemented"); 127
128 private static int getValue__ (char a) {
129 if ((a >= '0') && (a <= '9')) {
130 return a - '0';
131 }
132 if ((a >= 'A') && (a <= 'V')) {
133 return (a - 'A' + 10);
134 }
135 return -1;
102 } 136 }
137
103} 138}
diff --git a/src/org/gnunet/util/TESTMessage.java b/src/org/gnunet/util/TestMessage.java
index 44c28ce..b08a706 100644
--- a/src/org/gnunet/util/TESTMessage.java
+++ b/src/org/gnunet/util/TestMessage.java
@@ -26,6 +26,6 @@ import org.gnunet.construct.UnionCase;
26 * Sent back when a client sends this message to a service. 26 * Sent back when a client sends this message to a service.
27 */ 27 */
28@UnionCase(1) 28@UnionCase(1)
29public class TESTMessage implements GnunetMessage.Body { 29public class TestMessage implements GnunetMessage.Body {
30 // empty 30 // empty
31} 31}
diff --git a/src/org/gnunet/util/UnknownMessageBody.java b/src/org/gnunet/util/UnknownMessageBody.java
index 2270846..b978ec6 100644
--- a/src/org/gnunet/util/UnknownMessageBody.java
+++ b/src/org/gnunet/util/UnknownMessageBody.java
@@ -25,7 +25,7 @@ package org.gnunet.util;
25 * is not understood, and therefore no real message body could be constructed. 25 * is not understood, and therefore no real message body could be constructed.
26 * 26 *
27 * Note that this class implements GnunetMessage.Body but does not have a MessageID associated. 27 * Note that this class implements GnunetMessage.Body but does not have a MessageID associated.
28 * This message should not be sent/received over the network as a message body. 28 * This message should not, and can not, be sent/received over the network directly as a message body.
29 * 29 *
30 * @author Florian Dold 30 * @author Florian Dold
31 */ 31 */
diff --git a/src/org/gnunet/util/getopt/Option.java b/src/org/gnunet/util/getopt/Argument.java
index f2276e3..34159d0 100644
--- a/src/org/gnunet/util/getopt/Option.java
+++ b/src/org/gnunet/util/getopt/Argument.java
@@ -26,15 +26,18 @@ import java.lang.annotation.Retention;
26import java.lang.annotation.RetentionPolicy; 26import java.lang.annotation.RetentionPolicy;
27import java.lang.annotation.Target; 27import java.lang.annotation.Target;
28 28
29/**
30 * Annotation for fields receiving an argument from the command line.
31 */
29@Retention(RetentionPolicy.RUNTIME) 32@Retention(RetentionPolicy.RUNTIME)
30@Target(ElementType.FIELD) 33@Target(ElementType.FIELD)
31public @interface Option { 34public @interface Argument {
32 public String shortname(); 35 public String shortname();
33 public String longname(); 36 public String longname();
34 /** 37 /**
35 * Possible values: "store-string", "set", "reset", "count", "store-int" 38 * Possible values: "store-string", "set", "reset", "count", "store-int"
36 */ 39 */
37 public OptionAction action(); 40 public ArgumentAction action();
38 /* 41 /*
39 * Name of the Option's argument(s), empty string of option takes no arguments 42 * Name of the Option's argument(s), empty string of option takes no arguments
40 * 43 *
diff --git a/test/org/gnunet/construct/VarTestMessage.java b/src/org/gnunet/util/getopt/ArgumentAction.java
index 25e5bbc..077e71c 100644
--- a/test/org/gnunet/construct/VarTestMessage.java
+++ b/src/org/gnunet/util/getopt/ArgumentAction.java
@@ -18,12 +18,12 @@
18 Boston, MA 02111-1307, USA. 18 Boston, MA 02111-1307, USA.
19 */ 19 */
20 20
21package org.gnunet.construct; 21package org.gnunet.util.getopt;
22 22
23public class VarTestMessage implements Message { 23
24 @UInt16 24/**
25 public long length; 25 * Possibilities for what should happen when an argument is read from the command line
26 26 */
27 @VariableSizeArray(lengthField="length") 27public enum ArgumentAction {
28 public SimpleTestMessage2[] msgs; 28 SET, RESET, STORE_STRING, STORE_NUMBER
29} 29}
diff --git a/src/org/gnunet/util/getopt/Parser.java b/src/org/gnunet/util/getopt/Parser.java
index 9807146..6ecc220 100644
--- a/src/org/gnunet/util/getopt/Parser.java
+++ b/src/org/gnunet/util/getopt/Parser.java
@@ -22,7 +22,6 @@ package org.gnunet.util.getopt;
22 22
23import org.gnunet.construct.ReflectUtil; 23import org.gnunet.construct.ReflectUtil;
24import java.lang.reflect.Field; 24import java.lang.reflect.Field;
25import java.lang.reflect.Modifier;
26import java.util.*; 25import java.util.*;
27 26
28/** 27/**
@@ -45,10 +44,10 @@ public class Parser {
45 * An option together with its target field. 44 * An option together with its target field.
46 */ 45 */
47 static class OptionField { 46 static class OptionField {
48 Option opt; 47 Argument opt;
49 Field f; 48 Field f;
50 49
51 public OptionField(Option opt, Field f) { 50 public OptionField(Argument opt, Field f) {
52 this.opt = opt; 51 this.opt = opt;
53 this.f = f; 52 this.f = f;
54 } 53 }
@@ -66,7 +65,7 @@ public class Parser {
66 private Map<String, OptionField> longOpt = new HashMap<String, OptionField>(); 65 private Map<String, OptionField> longOpt = new HashMap<String, OptionField>();
67 private Map<String, OptionField> shortOpt = new HashMap<String, OptionField>(); 66 private Map<String, OptionField> shortOpt = new HashMap<String, OptionField>();
68 67
69 private Collection<Option> options = new LinkedList<Option>(); 68 private Collection<Argument> arguments = new LinkedList<Argument>();
70 69
71 private Object targetObject; 70 private Object targetObject;
72 71
@@ -75,11 +74,7 @@ public class Parser {
75 this.targetObject = targetObject; 74 this.targetObject = targetObject;
76 // gather option annotations 75 // gather option annotations
77 for (Field f : getFields(targetObject.getClass())) { 76 for (Field f : getFields(targetObject.getClass())) {
78 if (f.isSynthetic() || Modifier.isStatic(f.getModifiers())) { 77 Argument opt = f.getAnnotation(Argument.class);
79 continue;
80 }
81 // todo: validity checking of annotations
82 Option opt = f.getAnnotation(Option.class);
83 if (opt != null) { 78 if (opt != null) {
84 if (opt.shortname().length() != 1) { 79 if (opt.shortname().length() != 1) {
85 throw new AssertionError("short name must be of length 1"); 80 throw new AssertionError("short name must be of length 1");
@@ -89,14 +84,14 @@ public class Parser {
89 84
90 longOpt.put(opt.longname(), new OptionField(opt, f)); 85 longOpt.put(opt.longname(), new OptionField(opt, f));
91 shortOpt.put(opt.shortname(), new OptionField(opt, f)); 86 shortOpt.put(opt.shortname(), new OptionField(opt, f));
92 options.add(opt); 87 arguments.add(opt);
93 } 88 }
94 } 89 }
95 } 90 }
96 91
97 public String getHelp() { 92 public String getHelp() {
98 StringBuilder helpString = new StringBuilder(); 93 StringBuilder helpString = new StringBuilder();
99 for (Option opt : options) { 94 for (Argument opt : arguments) {
100 StringBuilder line = new StringBuilder(); 95 StringBuilder line = new StringBuilder();
101 line.append(" -"); 96 line.append(" -");
102 line.append(opt.shortname()); 97 line.append(opt.shortname());
@@ -118,10 +113,10 @@ public class Parser {
118 return helpString.toString(); 113 return helpString.toString();
119 } 114 }
120 115
121 public void doLongOpt(final LinkedList<String> argsList, Field targetField, Option option, String right) { 116 private void doLongOpt(final LinkedList<String> argsList, Field targetField, Argument argument, String right) {
122 try { 117 try {
123 Class targetFieldType = targetField.getType(); 118 Class targetFieldType = targetField.getType();
124 switch (option.action()) { 119 switch (argument.action()) {
125 case SET: 120 case SET:
126 if (!targetFieldType.equals(Boolean.TYPE)) { 121 if (!targetFieldType.equals(Boolean.TYPE)) {
127 throw new AssertionError("action SET only valid on boolean member"); 122 throw new AssertionError("action SET only valid on boolean member");
@@ -141,7 +136,7 @@ public class Parser {
141 if (right == null) { 136 if (right == null) {
142 argsList.removeFirst(); 137 argsList.removeFirst();
143 if (argsList.isEmpty()) { 138 if (argsList.isEmpty()) {
144 throw new ArgumentError("missing string argument to option " + option.longname()); 139 throw new ArgumentError("missing string argument to option " + argument.longname());
145 } 140 }
146 targetField.set(targetObject, argsList.getFirst()); 141 targetField.set(targetObject, argsList.getFirst());
147 } else { 142 } else {
@@ -154,7 +149,7 @@ public class Parser {
154 if (right == null) { 149 if (right == null) {
155 argsList.removeFirst(); 150 argsList.removeFirst();
156 if (argsList.isEmpty()) { 151 if (argsList.isEmpty()) {
157 throw new ArgumentError("missing number argument to option " + option.longname()); 152 throw new ArgumentError("missing number argument to option " + argument.longname());
158 } 153 }
159 numString = argsList.getFirst(); 154 numString = argsList.getFirst();
160 } else { 155 } else {
@@ -163,11 +158,9 @@ public class Parser {
163 try { 158 try {
164 nf.set(targetObject, Long.parseLong(numString)); 159 nf.set(targetObject, Long.parseLong(numString));
165 } catch (NumberFormatException e) { 160 } catch (NumberFormatException e) {
166 throw new ArgumentError("error in number format to option " + option.longname()); 161 throw new ArgumentError("error in number format to option " + argument.longname());
167 } 162 }
168 break; 163 break;
169 case INCREMENT:
170 throw new UnsupportedOperationException("not yet implemented");
171 } 164 }
172 } catch (IllegalAccessException e) { 165 } catch (IllegalAccessException e) {
173 throw new AssertionError( 166 throw new AssertionError(
@@ -175,9 +168,13 @@ public class Parser {
175 } 168 }
176 } 169 }
177 170
178 public boolean doShortOpt(final LinkedList<String> argsList, Field targetField, Option option, String shortName) { 171 /**
172 * returns true if we processed a shortopt with a parameter, and thus have to discard the rest
173 * of the current argument string (that is, stop scanning for more shortopts)
174 */
175 private boolean doShortOpt(final LinkedList<String> argsList, Field targetField, Argument argument, String shortName) {
179 try { 176 try {
180 switch (option.action()) { 177 switch (argument.action()) {
181 case SET: 178 case SET:
182 if (!targetField.getType().equals(Boolean.TYPE)) { 179 if (!targetField.getType().equals(Boolean.TYPE)) {
183 throw new AssertionError("action SET only valid on boolean member"); 180 throw new AssertionError("action SET only valid on boolean member");
@@ -186,16 +183,15 @@ public class Parser {
186 break; 183 break;
187 case RESET: 184 case RESET:
188 if (!targetField.getType().equals(Boolean.TYPE)) { 185 if (!targetField.getType().equals(Boolean.TYPE)) {
189 throw new AssertionError("action RESET only valid on boolean member"); 186 throw new AssertionError("action RESET only valid on boolean field");
190 } 187 }
191 targetField.set(targetObject, false); 188 targetField.set(targetObject, false);
192 break; 189 break;
193 case STORE_STRING: 190 case STORE_STRING:
194 if (!targetField.getType().equals(String.class)) { 191 if (!targetField.getType().equals(String.class)) {
195 throw new AssertionError("action STORE_STRING only valid on boolean " + 192 throw new AssertionError("action STORE_STRING only valid on 'String' field");
196 "member");
197 } 193 }
198 if (argsList.getFirst().length() == 2) { // -X 194 if (argsList.getFirst().length() == 2) { // -P xxx (with space)
199 argsList.removeFirst(); 195 argsList.removeFirst();
200 if (argsList.isEmpty()) { 196 if (argsList.isEmpty()) {
201 throw new ArgumentError(String.format("no argument for short option '%s'", 197 throw new ArgumentError(String.format("no argument for short option '%s'",
@@ -205,31 +201,25 @@ public class Parser {
205 } else { 201 } else {
206 targetField.set(targetObject, argsList.getFirst().substring(2)); // -Pxxx... 202 targetField.set(targetObject, argsList.getFirst().substring(2)); // -Pxxx...
207 } 203 }
208 // consumed entire shortopt
209 return true; 204 return true;
210 case STORE_NUMBER: 205 case STORE_NUMBER:
211 ReflectUtil.NumField nf = new ReflectUtil.NumField(targetField); 206 ReflectUtil.NumField nf = new ReflectUtil.NumField(targetField);
212 String numString; 207 String numString;
213 boolean consumed;
214 if (argsList.getFirst().length() == 2) { // -X 208 if (argsList.getFirst().length() == 2) { // -X
215 argsList.removeFirst(); 209 argsList.removeFirst();
216 if (argsList.isEmpty()) { 210 if (argsList.isEmpty()) {
217 throw new ArgumentError("missing number argument to option " + option.longname()); 211 throw new ArgumentError("missing number argument to option " + argument.longname());
218 } 212 }
219 numString = argsList.getFirst(); 213 numString = argsList.getFirst();
220 consumed = false;
221 } else { 214 } else {
222 numString = argsList.getFirst().substring(2); 215 numString = argsList.getFirst().substring(2);
223 consumed = true;
224 } 216 }
225 try { 217 try {
226 nf.set(targetObject, Long.parseLong(numString)); 218 nf.set(targetObject, Long.parseLong(numString));
227 } catch (NumberFormatException e) { 219 } catch (NumberFormatException e) {
228 throw new ArgumentError("error in number format to option " + option.longname()); 220 throw new ArgumentError("error in number format to option " + argument.longname());
229 } 221 }
230 return consumed; 222 return true;
231 case INCREMENT:
232 throw new UnsupportedOperationException("not yet implemented");
233 } 223 }
234 } catch (IllegalAccessException e) { 224 } catch (IllegalAccessException e) {
235 throw new ArgumentError( 225 throw new ArgumentError(
@@ -238,7 +228,6 @@ public class Parser {
238 return false; // did not consume entire shortopt -Xxxxxx 228 return false; // did not consume entire shortopt -Xxxxxx
239 } 229 }
240 230
241
242 /** 231 /**
243 * Parses the given arguments, and sets the target object's fields 232 * Parses the given arguments, and sets the target object's fields
244 * according to its annotations. 233 * according to its annotations.
@@ -271,7 +260,8 @@ public class Parser {
271 } 260 }
272 String right = (components.length == 2) ? components[1] : null; 261 String right = (components.length == 2) ? components[1] : null;
273 doLongOpt(argsList, of.f, of.opt, right); 262 doLongOpt(argsList, of.f, of.opt, right);
274 } else if (argsList.getFirst().length() > 1 && argsList.getFirst().startsWith("-")) { 263 } else if ((argsList.getFirst().length() > 1) && argsList.getFirst().startsWith("-")) {
264 // handle each flag after the "-"
275 for (int i = 1; i < argsList.getFirst().length(); ++i) { 265 for (int i = 1; i < argsList.getFirst().length(); ++i) {
276 String optShortName = argsList.getFirst().substring(i, i + 1); 266 String optShortName = argsList.getFirst().substring(i, i + 1);
277 OptionField of = shortOpt.get(optShortName); 267 OptionField of = shortOpt.get(optShortName);
@@ -280,13 +270,13 @@ public class Parser {
280 String.format("unknown short option: -%s", argsList.getFirst().charAt(i))); 270 String.format("unknown short option: -%s", argsList.getFirst().charAt(i)));
281 } 271 }
282 272
283 boolean consumed = doShortOpt(argsList, of.f, of.opt, optShortName); 273 boolean discard = doShortOpt(argsList, of.f, of.opt, optShortName);
284 274
285 if (consumed && i != 1) { 275 if (discard && (i != 1)) {
286 throw new ArgumentError("short options with argument must be seperate"); 276 throw new ArgumentError("short options with argument must be seperate");
287 } 277 }
288 278
289 if (consumed) { 279 if (discard) {
290 break; 280 break;
291 } 281 }
292 282
diff --git a/src/org/grothoff/Runabout.java b/src/org/grothoff/Runabout.java
index 39f771a..9646a7e 100644
--- a/src/org/grothoff/Runabout.java
+++ b/src/org/grothoff/Runabout.java
@@ -54,7 +54,7 @@ import java.util.HashMap;
54 * <ul> 54 * <ul>
55 * <li>all subclasses must be public, sadly this also means that <strong>you 55 * <li>all subclasses must be public, sadly this also means that <strong>you
56 * can not use an anonymous inner class</strong> (!)</li> 56 * can not use an anonymous inner class</strong> (!)</li>
57 * <li>the types to all arguments of visit methods must be public</li> 57 * <li>the types_length to all arguments of visit methods must be public</li>
58 * <li>all visit methods must be public (!)</li> 58 * <li>all visit methods must be public (!)</li>
59 * </ul> 59 * </ul>
60 * Otherwise the visitor will die with an IllegalAccessError during execution. 60 * Otherwise the visitor will die with an IllegalAccessError during execution.
@@ -265,7 +265,8 @@ public class Runabout {
265 } catch (IllegalAccessException e) { 265 } catch (IllegalAccessException e) {
266 throw new RunaboutException(e.toString()); 266 throw new RunaboutException(e.toString());
267 } catch (InvocationTargetException e) { 267 } catch (InvocationTargetException e) {
268 e.getCause().printStackTrace(); 268 System.err.println("stacktrace:");
269 e.getCause().printStackTrace(System.out);
269 throw new RunaboutException(e.getCause().toString()); 270 throw new RunaboutException(e.getCause().toString());
270 } 271 }
271 } 272 }
diff --git a/src/org/grothoff/package-info.java b/src/org/grothoff/package-info.java
index 19056a2..2a8b8f0 100644
--- a/src/org/grothoff/package-info.java
+++ b/src/org/grothoff/package-info.java
@@ -1,4 +1,4 @@
1/** 1/**
2 * java implementation of single argument multiple dispatch 2 * Pure java implementation of single argument multiple dispatch
3 */ 3 */
4package org.grothoff; 4package org.grothoff;
diff --git a/test/org/gnunet/construct/ByteFillMessage.java b/test/org/gnunet/construct/ByteFillMessage.java
index fe7716f..090f7d0 100644
--- a/test/org/gnunet/construct/ByteFillMessage.java
+++ b/test/org/gnunet/construct/ByteFillMessage.java
@@ -26,7 +26,7 @@ public class ByteFillMessage implements Message {
26 @UInt32 26 @UInt32
27 public int someValue; 27 public int someValue;
28 28
29 @ByteFill 29 @FillWith @UInt8
30 public byte[] rest; 30 public byte[] rest;
31 31
32} 32}
diff --git a/test/org/gnunet/construct/ConstructTest.java b/test/org/gnunet/construct/ConstructTest.java
index c7f9853..8853b1d 100644
--- a/test/org/gnunet/construct/ConstructTest.java
+++ b/test/org/gnunet/construct/ConstructTest.java
@@ -13,7 +13,7 @@ public class ConstructTest {
13 @FrameSize 13 @FrameSize
14 @UInt32 14 @UInt32
15 public int frameSize; 15 public int frameSize;
16 @ByteFill 16 @FillWith @UInt8
17 public byte[] bytes; 17 public byte[] bytes;
18 } 18 }
19 19
diff --git a/test/org/gnunet/construct/FillParserTest.java b/test/org/gnunet/construct/FillParserTest.java
new file mode 100644
index 0000000..115b567
--- /dev/null
+++ b/test/org/gnunet/construct/FillParserTest.java
@@ -0,0 +1,37 @@
1package org.gnunet.construct;
2
3import junit.framework.Assert;
4import org.junit.Test;
5
6/**
7 * ...
8 *
9 * @author Florian Dold
10 */
11public class FillParserTest {
12
13 public static class FillTestMessage implements Message {
14 @FrameSize
15 @UInt32
16 public int size;
17 @FillWith
18 public StringTuple[] strings;
19 }
20
21 @Test
22 public void test_fillParser() {
23 FillTestMessage m = new FillTestMessage();
24 m.strings = new StringTuple[]{new StringTuple("foo", "bar"), new StringTuple("quux", "spam")};
25 Construct.patch(m);
26 System.out.println(m.size);
27 byte[] data = Construct.toBinary(m);
28 Assert.assertEquals(m.size, data.length);
29
30 FillTestMessage m2 = Construct.parseAs(data, FillTestMessage.class);
31
32 Assert.assertEquals(m.strings.length, m2.strings.length);
33
34 Assert.assertEquals(m.strings[0], m2.strings[0]);
35 Assert.assertEquals(m.strings[1], m2.strings[1]);
36 }
37}
diff --git a/test/org/gnunet/construct/FixedSizeTest.java b/test/org/gnunet/construct/FixedSizeTest.java
new file mode 100644
index 0000000..573e120
--- /dev/null
+++ b/test/org/gnunet/construct/FixedSizeTest.java
@@ -0,0 +1,52 @@
1package org.gnunet.construct;
2
3import junit.framework.Assert;
4import org.junit.Test;
5
6/**
7 * ...
8 *
9 * @author Florian Dold
10 */
11public class FixedSizeTest {
12
13 public static class Msg implements Message {
14 @UInt8
15 public int v;
16
17 public Msg() {
18 // default ctor required by Construct
19 }
20
21 public Msg(int v) {
22 this.v = v;
23 }
24 }
25
26 public static class FixedSizeTestMessage implements Message {
27 @FixedSizeArray(length = 4)
28 public Msg[] msgs;
29 }
30
31
32 @Test
33 public void test_fixedNested() {
34 FixedSizeTestMessage m = new FixedSizeTestMessage();
35 m.msgs = new Msg[]{new Msg(1), new Msg(2), new Msg(3), new Msg(4)};
36 byte[] bytes = Construct.toBinary(m);
37
38 FixedSizeTestMessage m2 = Construct.parseAs(bytes, FixedSizeTestMessage.class);
39
40 Assert.assertEquals(m.msgs[0].v, m2.msgs[0].v);
41 Assert.assertEquals(m.msgs[1].v, m2.msgs[1].v);
42 Assert.assertEquals(m.msgs[2].v, m2.msgs[2].v);
43 Assert.assertEquals(m.msgs[3].v, m2.msgs[3].v);
44 }
45
46 @Test(expected = AssertionError.class)
47 public void test_sizeMismatch() {
48 FixedSizeTestMessage m = new FixedSizeTestMessage();
49 m.msgs = new Msg[]{new Msg(1), new Msg(2)};
50 byte[] bytes = Construct.toBinary(m);
51 }
52}
diff --git a/test/org/gnunet/construct/FrameSizeTest.java b/test/org/gnunet/construct/FrameSizeTest.java
new file mode 100644
index 0000000..dcce5de
--- /dev/null
+++ b/test/org/gnunet/construct/FrameSizeTest.java
@@ -0,0 +1,50 @@
1package org.gnunet.construct;
2
3import junit.framework.Assert;
4import org.gnunet.util.GnunetMessage;
5import org.junit.Test;
6
7/**
8 * ...
9 *
10 * @author Florian Dold
11 */
12public class FrameSizeTest {
13 public static class CoordMessage implements Message {
14 @FrameSize
15 @UInt32
16 public int size;
17 @UInt32
18 public int x;
19 @UInt8
20 public int y;
21 }
22
23 public static class RecursiveMessage implements Message {
24 @FrameSize
25 @UInt32
26 public int size;
27
28 @ZeroTerminatedString
29 public String data;
30
31 @NestedMessage(newFrame = true, optional = true)
32 public RecursiveMessage rec;
33
34 }
35
36 @Test
37 public void test_simple() {
38 CoordMessage m = new CoordMessage();
39 Construct.patch(m);
40 Assert.assertEquals(9, m.size);
41 }
42
43
44 //@Test
45 public void test_recursive_1() {
46 RecursiveMessage rm = new RecursiveMessage();
47 rm.data = "foo";
48 Construct.patch(rm);
49 }
50}
diff --git a/test/org/gnunet/construct/QueryMessage.java b/test/org/gnunet/construct/QueryMessage.java
index 2accd42..4bf9af5 100644
--- a/test/org/gnunet/construct/QueryMessage.java
+++ b/test/org/gnunet/construct/QueryMessage.java
@@ -26,6 +26,6 @@ public class QueryMessage implements Message {
26 @UInt8 26 @UInt8
27 public int query; 27 public int query;
28 28
29 @ByteFill 29 @FillWith @UInt8
30 public byte[] varsize; 30 public byte[] varsize;
31} 31}
diff --git a/test/org/gnunet/construct/SendMessageTest.java b/test/org/gnunet/construct/SendMessageTest.java
new file mode 100644
index 0000000..b95cc78
--- /dev/null
+++ b/test/org/gnunet/construct/SendMessageTest.java
@@ -0,0 +1,34 @@
1package org.gnunet.construct;
2
3import org.gnunet.core.SendMessage;
4import org.gnunet.util.AbsoluteTime;
5import org.gnunet.util.GnunetMessage;
6import org.gnunet.util.PeerIdentity;
7import org.gnunet.util.TestMessage;
8import org.junit.Test;
9
10/**
11 * Regression test for a message class in org.gnunet.core
12 *
13 * todo: should this test be really here?
14 *
15 * @author Florian Dold
16 */
17public class SendMessageTest {
18
19 @Test
20 public void test_patch() {
21 SendMessage m = new SendMessage();
22 m.deadline = AbsoluteTime.FOREVER.asMessage();
23 m.peer = new PeerIdentity(); // null identity
24 m.payloadMessage = new GnunetMessage();
25 m.payloadMessage.body = new TestMessage();
26 m.payloadMessage.header = new GnunetMessage.Header();
27
28 GnunetMessage container = new GnunetMessage();
29 container.body = m;
30 container.header = new GnunetMessage.Header();
31
32 Construct.patch(container);
33 }
34}
diff --git a/test/org/gnunet/construct/SimpleTestMessage.java b/test/org/gnunet/construct/SimpleTestMessage.java
deleted file mode 100644
index e55b3b0..0000000
--- a/test/org/gnunet/construct/SimpleTestMessage.java
+++ /dev/null
@@ -1,36 +0,0 @@
1/*
2 This file is part of GNUnet.
3 (C) 2011, 2012 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21package org.gnunet.construct;
22
23public class SimpleTestMessage implements Message {
24
25 @UInt8
26 public short v1;
27
28 @UInt8
29 public short v2;
30
31 @NestedMessage
32 public SimpleTestMessage2 mn;
33
34 @FixedSizeArray(length=5)
35 public SimpleTestMessage2[] mns;
36}
diff --git a/test/org/gnunet/construct/SizeTestMessage.java b/test/org/gnunet/construct/SizeTestMessage.java
deleted file mode 100644
index 4710ede..0000000
--- a/test/org/gnunet/construct/SizeTestMessage.java
+++ /dev/null
@@ -1,34 +0,0 @@
1/*
2 This file is part of GNUnet.
3 (C) 2011, 2012 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21package org.gnunet.construct;
22
23public class SizeTestMessage implements Message {
24
25 @FrameSize
26 @UInt16
27 public long totalSize;
28
29 @UInt16
30 public long someValue;
31
32 @ByteFill
33 public byte[] rest;
34}
diff --git a/test/org/gnunet/construct/StringTest.java b/test/org/gnunet/construct/StringTest.java
new file mode 100644
index 0000000..7839f8b
--- /dev/null
+++ b/test/org/gnunet/construct/StringTest.java
@@ -0,0 +1,50 @@
1package org.gnunet.construct;
2
3import junit.framework.Assert;
4import org.junit.Test;
5
6/**
7 * ...
8 *
9 * @author Florian Dold
10 */
11public class StringTest {
12 public static class StrMsg implements Message {
13 @FrameSize
14 @UInt32
15 public int len;
16 @ZeroTerminatedString(optional = false)
17 public String str1;
18 @ZeroTerminatedString(optional = true)
19 public String str2;
20 }
21
22
23 @Test
24 public void test_empty() {
25 StrMsg m = new StrMsg();
26 m.str1 = "";
27 m.str2 = "";
28 Construct.patch(m);
29 byte[] data = Construct.toBinary(m);
30 Assert.assertEquals(4+1+1, data.length);
31 StrMsg m2 = Construct.parseAs(data, StrMsg.class);
32 Assert.assertEquals("", m2.str1);
33 Assert.assertEquals("", m2.str2);
34 }
35
36 @Test
37 public void test_null() {
38 StrMsg m = new StrMsg();
39 m.str1 = "";
40 m.str2 = null;
41 Construct.patch(m);
42 byte[] data = Construct.toBinary(m);
43 Assert.assertEquals(4+1, data.length);
44 Assert.assertEquals(4+1, m.len);
45 StrMsg m2 = Construct.parseAs(data, StrMsg.class);
46 Assert.assertEquals("", m2.str1);
47 Assert.assertEquals(null, m2.str2);
48 }
49}
50
diff --git a/test/org/gnunet/construct/StringTuple.java b/test/org/gnunet/construct/StringTuple.java
new file mode 100644
index 0000000..085b7a9
--- /dev/null
+++ b/test/org/gnunet/construct/StringTuple.java
@@ -0,0 +1,29 @@
1package org.gnunet.construct;
2
3/**
4* ...
5*
6* @author Florian Dold
7*/
8public class StringTuple implements Message {
9 @ZeroTerminatedString
10 public String str1;
11 @ZeroTerminatedString
12 public String str2;
13
14 public StringTuple() {
15 // empty default ctor needed by Construct
16 }
17 public StringTuple(String str1, String str2) {
18 this.str1 = str1;
19 this.str2 = str2;
20 }
21 @Override
22 public boolean equals(Object other) {
23 if (!(other instanceof StringTuple)) {
24 return false;
25 }
26 StringTuple otherT = (StringTuple) other;
27 return otherT.str1.equals(this.str1) && otherT.str2.equals(this.str2);
28 }
29}
diff --git a/test/org/gnunet/construct/VariableSizeArrayTest.java b/test/org/gnunet/construct/VariableSizeArrayTest.java
new file mode 100644
index 0000000..f1d19c1
--- /dev/null
+++ b/test/org/gnunet/construct/VariableSizeArrayTest.java
@@ -0,0 +1,33 @@
1package org.gnunet.construct;
2
3import junit.framework.Assert;
4import org.junit.Test;
5
6/**
7 * ...
8 *
9 * @author Florian Dold
10 */
11public class VariableSizeArrayTest {
12 public static class VariableTestMessage implements Message {
13 @UInt32
14 public int num;
15 @VariableSizeArray(lengthField = "num")
16 public StringTuple[] msgs;
17 }
18
19 @Test
20 public void test_variableSizeArray() {
21 VariableTestMessage m = new VariableTestMessage();
22 m.msgs = new StringTuple[]{new StringTuple("foo", "bar"), new StringTuple("quux", "baz"), new StringTuple("spam", "eggs")};
23 Construct.patch(m);
24 Assert.assertEquals(3, m.num);
25 byte[] data = Construct.toBinary(m);
26 VariableTestMessage m2 = Construct.parseAs(data, VariableTestMessage.class);
27 Assert.assertEquals(m2.num, 3);
28 Assert.assertEquals(m.msgs[0], m2.msgs[0]);
29 Assert.assertEquals(m.msgs[1], m2.msgs[1]);
30 Assert.assertEquals(m.msgs[2], m2.msgs[2]);
31
32 }
33}
diff --git a/test/org/gnunet/core/CoreTest.java b/test/org/gnunet/core/CoreTest.java
index e4a9142..5e066ed 100644
--- a/test/org/gnunet/core/CoreTest.java
+++ b/test/org/gnunet/core/CoreTest.java
@@ -26,18 +26,15 @@ import org.gnunet.testing.TestingSubsystem;
26import org.gnunet.util.*; 26import org.gnunet.util.*;
27import org.grothoff.Runabout; 27import org.grothoff.Runabout;
28import org.junit.Assert; 28import org.junit.Assert;
29import org.junit.Ignore;
30import org.junit.Test; 29import org.junit.Test;
31 30
32import static org.junit.Assert.assertTrue; 31import static org.junit.Assert.assertTrue;
33 32
34public class CoreTest { 33public class CoreTest {
35 TestingSetup testing = new TestingSetup();
36
37 @Test(timeout = 500) 34 @Test(timeout = 500)
38 public void test_core_init() { 35 public void test_core_init() {
39 36
40 TestingSubsystem ts = testing.startSubsystem("core"); 37 TestingSubsystem ts = new TestingSubsystem("core");
41 38
42 final Wrapper<Boolean> res = new Wrapper<Boolean>(false); 39 final Wrapper<Boolean> res = new Wrapper<Boolean>(false);
43 40
@@ -68,13 +65,13 @@ public class CoreTest {
68 @Test(timeout = 5000) 65 @Test(timeout = 5000)
69 public void test_core_echo() { 66 public void test_core_echo() {
70 67
71 TestingSubsystem ts = testing.startSubsystem("core"); 68 TestingSubsystem ts = new TestingSubsystem("core");
72 69
73 final Wrapper<Boolean> gotResponse = new Wrapper<Boolean>(false); 70 final Wrapper<Boolean> gotResponse = new Wrapper<Boolean>(false);
74 71
75 final Core core = new Core(ts.getConfiguration()); 72 final Core core = new Core(ts.getConfiguration());
76 core.setMessageHandler(new Runabout() { 73 core.setMessageHandler(new Runabout() {
77 public void visit(TESTMessage t) { 74 public void visit(TestMessage t) {
78 gotResponse.set(true); 75 gotResponse.set(true);
79 core.disconnect(); 76 core.disconnect();
80 } 77 }
@@ -86,7 +83,7 @@ public class CoreTest {
86 core.notifyTransmitReady(0, RelativeTime.FOREVER, myIdentity, 4, new MessageTransmitter() { 83 core.notifyTransmitReady(0, RelativeTime.FOREVER, myIdentity, 4, new MessageTransmitter() {
87 @Override 84 @Override
88 public void transmit(Connection.MessageSink sink) { 85 public void transmit(Connection.MessageSink sink) {
89 sink.send(new TESTMessage()); 86 sink.send(new TestMessage());
90 } 87 }
91 88
92 @Override 89 @Override
diff --git a/test/org/gnunet/dht/DHTTest.java b/test/org/gnunet/dht/DHTTest.java
index b684aef..6c93356 100644
--- a/test/org/gnunet/dht/DHTTest.java
+++ b/test/org/gnunet/dht/DHTTest.java
@@ -33,9 +33,7 @@ public class DHTTest {
33 public void test_dht_put() { 33 public void test_dht_put() {
34 final Wrapper<Boolean> putFinished = new Wrapper<Boolean>(true); 34 final Wrapper<Boolean> putFinished = new Wrapper<Boolean>(true);
35 35
36 TestingSetup testing = new TestingSetup(); 36 TestingSubsystem ts = new TestingSubsystem("dht");
37
38 TestingSubsystem ts = testing.startSubsystem("dht");
39 37
40 final DistributedHashTable dht = new DistributedHashTable(ts.getConfiguration()); 38 final DistributedHashTable dht = new DistributedHashTable(ts.getConfiguration());
41 dht.put(new HashCode("gnj-test"), new byte[]{1, 2, 3}, 1, EnumSet.noneOf(RouteOption.class), 39 dht.put(new HashCode("gnj-test"), new byte[]{1, 2, 3}, 1, EnumSet.noneOf(RouteOption.class),
diff --git a/test/org/nse/NSETest.java b/test/org/gnunet/nse/NSETest.java
index 47e4448..c3e6512 100644
--- a/test/org/nse/NSETest.java
+++ b/test/org/gnunet/nse/NSETest.java
@@ -18,9 +18,8 @@
18 Boston, MA 02111-1307, USA. 18 Boston, MA 02111-1307, USA.
19 */ 19 */
20 20
21package org.nse; 21package org.gnunet.nse;
22 22
23import org.gnunet.nse.NetworkSizeEstimation;
24import org.gnunet.testing.TestingSetup; 23import org.gnunet.testing.TestingSetup;
25import org.gnunet.testing.TestingSubsystem; 24import org.gnunet.testing.TestingSubsystem;
26import org.gnunet.util.AbsoluteTime; 25import org.gnunet.util.AbsoluteTime;
@@ -38,8 +37,7 @@ public class NSETest {
38 @Test 37 @Test
39 public void test_nse() { 38 public void test_nse() {
40 final Wrapper<Boolean> gotResult = new Wrapper<Boolean>(false); 39 final Wrapper<Boolean> gotResult = new Wrapper<Boolean>(false);
41 TestingSetup testing = new TestingSetup(); 40 TestingSubsystem ts = new TestingSubsystem("nse");
42 TestingSubsystem ts = testing.startSubsystem("nse");
43 41
44 final NetworkSizeEstimation nse = new NetworkSizeEstimation(ts.getConfiguration()); 42 final NetworkSizeEstimation nse = new NetworkSizeEstimation(ts.getConfiguration());
45 nse.subscribe(new NetworkSizeEstimation.Subscriber() { 43 nse.subscribe(new NetworkSizeEstimation.Subscriber() {
diff --git a/test/org/gnunet/statistics/StatisticsTest.java b/test/org/gnunet/statistics/StatisticsTest.java
index ddba478..780a2e1 100644
--- a/test/org/gnunet/statistics/StatisticsTest.java
+++ b/test/org/gnunet/statistics/StatisticsTest.java
@@ -27,9 +27,6 @@ import org.gnunet.util.*;
27import org.junit.Test; 27import org.junit.Test;
28 28
29public class StatisticsTest { 29public class StatisticsTest {
30 TestingSetup testing = new TestingSetup();
31
32
33 public interface Next { 30 public interface Next {
34 void next(); 31 void next();
35 } 32 }
@@ -64,7 +61,8 @@ public class StatisticsTest {
64 61
65 @Test(timeout = 1000) 62 @Test(timeout = 1000)
66 public void test_simple() { 63 public void test_simple() {
67 final TestingSubsystem ts = testing.startSubsystem("statistics"); 64 Program.configureLogging("DEBUG", null);
65 final TestingSubsystem ts = new TestingSubsystem("statistics");
68 66
69 final Statistics stat = new Statistics(ts.getConfiguration()); 67 final Statistics stat = new Statistics(ts.getConfiguration());
70 68
@@ -97,7 +95,7 @@ public class StatisticsTest {
97 95
98 @Test(timeout = 1000) 96 @Test(timeout = 1000)
99 public void test_statistics_get_set() { 97 public void test_statistics_get_set() {
100 final TestingSubsystem ts = testing.startSubsystem("statistics"); 98 final TestingSubsystem ts = new TestingSubsystem("statistics");
101 99
102 final AssertionList assertions = new AssertionList(); 100 final AssertionList assertions = new AssertionList();
103 101
@@ -149,7 +147,7 @@ public class StatisticsTest {
149 147
150 @Test(timeout = 1000) 148 @Test(timeout = 1000)
151 public void test_watch() { 149 public void test_watch() {
152 final TestingSubsystem ts = testing.startSubsystem("statistics"); 150 final TestingSubsystem ts = new TestingSubsystem("statistics");
153 151
154 final Wrapper<Integer> updates = new Wrapper<Integer>(0); 152 final Wrapper<Integer> updates = new Wrapper<Integer>(0);
155 153
diff --git a/test/org/gnunet/testing/TestingSetupTest.java b/test/org/gnunet/testing/TestingSetupTest.java
index b23b543..2bfe0ae 100644
--- a/test/org/gnunet/testing/TestingSetupTest.java
+++ b/test/org/gnunet/testing/TestingSetupTest.java
@@ -29,8 +29,7 @@ public class TestingSetupTest {
29 @Test(timeout = 1000) 29 @Test(timeout = 1000)
30 public void test_testing() { 30 public void test_testing() {
31 // could be any service, just use statistics 31 // could be any service, just use statistics
32 TestingSetup testing = new TestingSetup(); 32 TestingSubsystem ts = new TestingSubsystem("statistics");
33 TestingSubsystem ts = testing.startSubsystem("statistics");
34 String port = ts.getConfiguration().getValueString("statistics", "PORT"); 33 String port = ts.getConfiguration().getValueString("statistics", "PORT");
35 org.junit.Assert.assertTrue(port != null); 34 org.junit.Assert.assertTrue(port != null);
36 35
@@ -39,16 +38,13 @@ public class TestingSetupTest {
39 38
40 @Test(expected = TestingSetup.SetupException.class) 39 @Test(expected = TestingSetup.SetupException.class)
41 public void test_no_service() { 40 public void test_no_service() {
42 TestingSetup testing = new TestingSetup(); 41 new TestingSubsystem("foobar _ !!!");
43 testing.startSubsystem("foobar _ !!!");
44 } 42 }
45 43
46 @Test(timeout = 1000) 44 @Test(timeout = 1000)
47 public void test_restart() { 45 public void test_restart() {
48 // could be any service, just use statistics 46 TestingSubsystem ts = new TestingSubsystem("statistics");
49 TestingSetup testing = new TestingSetup(); 47 ts.restart();
50 TestingSubsystem ts = testing.startSubsystem("statistics");
51 //ts.restart();
52 ts.destroy(); 48 ts.destroy();
53 } 49 }
54} 50}
diff --git a/test/org/gnunet/util/ClientServerTest.java b/test/org/gnunet/util/ClientServerTest.java
index f073a3c..f8b5d4e 100644
--- a/test/org/gnunet/util/ClientServerTest.java
+++ b/test/org/gnunet/util/ClientServerTest.java
@@ -1,10 +1,16 @@
1package org.gnunet.util; 1package org.gnunet.util;
2 2
3import com.google.common.collect.Lists;
4import org.gnunet.construct.UInt32;
5import org.gnunet.construct.UnionCase;
3import org.gnunet.testing.TestingServer; 6import org.gnunet.testing.TestingServer;
4import org.gnunet.testing.TestingSetup; 7import org.gnunet.testing.TestingSetup;
5import org.junit.Assert; 8import org.junit.Assert;
6import org.junit.Test; 9import org.junit.Test;
7 10
11import java.net.*;
12import java.util.ArrayList;
13
8/** 14/**
9 * ... 15 * ...
10 * 16 *
@@ -12,20 +18,26 @@ import org.junit.Test;
12 */ 18 */
13public class ClientServerTest { 19public class ClientServerTest {
14 20
21 @Test
22 public void test_start_stop() {
23 Program.configureLogging("DEBUG", null);
24 final TestingServer srv = new TestingServer();
25 srv.server.stopListening();
26 }
27
15 /** 28 /**
16 * Test if the server receives a message sent by a client. 29 * Test if the server receives a message sent by a client.
17 */ 30 */
18 @Test(timeout = 1000) 31 @Test
19 public void test_testing_server() { 32 public void test_testing_server() {
20 final TestingSetup setup = new TestingSetup();
21 Program.configureLogging("DEBUG", null); 33 Program.configureLogging("DEBUG", null);
22 34
23 final TestingServer srv = setup.createServer(); 35 final TestingServer srv = new TestingServer();
24 36
25 final Wrapper<Boolean> gotMessage = new Wrapper<Boolean>(false); 37 final Wrapper<Boolean> gotMessage = new Wrapper<Boolean>(false);
26 38
27 srv.server.setHandler(new Server.MessageRunabout() { 39 srv.server.setHandler(new Server.MessageRunabout() {
28 public void visit(TESTMessage tm) { 40 public void visit(TestMessage tm) {
29 gotMessage.set(true); 41 gotMessage.set(true);
30 srv.server.destroy(); 42 srv.server.destroy();
31 } 43 }
@@ -39,7 +51,7 @@ public class ClientServerTest {
39 @Override 51 @Override
40 public void transmit(Connection.MessageSink sink) { 52 public void transmit(Connection.MessageSink sink) {
41 System.out.println("ntr!"); 53 System.out.println("ntr!");
42 sink.send(new TESTMessage()); 54 sink.send(new TestMessage());
43 } 55 }
44 56
45 @Override 57 @Override
@@ -57,13 +69,12 @@ public class ClientServerTest {
57 69
58 /** 70 /**
59 * Test what happens when a client calls notifyTransmitReady, but does not send 71 * Test what happens when a client calls notifyTransmitReady, but does not send
60 * a message in the callback but disconnects. 72 * a message in the callback and disconnects.
61 */ 73 */
62 @Test(timeout = 1000) 74 @Test(timeout = 1000)
63 public void test_premature_disconnect() { 75 public void test_premature_disconnect() {
64 final TestingSetup setup = new TestingSetup();
65 Program.configureLogging("DEBUG", null); 76 Program.configureLogging("DEBUG", null);
66 final TestingServer srv = setup.createServer(); 77 final TestingServer srv = new TestingServer();
67 78
68 srv.server.notifyDisconnect(new Server.DisconnectHandler() { 79 srv.server.notifyDisconnect(new Server.DisconnectHandler() {
69 @Override 80 @Override
@@ -79,7 +90,7 @@ public class ClientServerTest {
79 cli.notifyTransmitReady(RelativeTime.FOREVER,true, 0, new MessageTransmitter() { 90 cli.notifyTransmitReady(RelativeTime.FOREVER,true, 0, new MessageTransmitter() {
80 @Override 91 @Override
81 public void transmit(Connection.MessageSink sink) { 92 public void transmit(Connection.MessageSink sink) {
82 sink.send(new TESTMessage()); 93 sink.send(new TestMessage());
83 cli.disconnect(); 94 cli.disconnect();
84 } 95 }
85 96
@@ -91,4 +102,146 @@ public class ClientServerTest {
91 } 102 }
92 }); 103 });
93 } 104 }
105
106
107 @Test
108 public void test_receiveDone() {
109 Program.configureLogging("DEBUG", null);
110 final TestingServer srv = new TestingServer();
111
112 final Wrapper<Integer> msgCount = new Wrapper<Integer>(0);
113
114 srv.server.setHandler(new Server.MessageRunabout() {
115 public void visit(TestMessage tm) {
116 msgCount.set(msgCount.get() + 1);
117 if (msgCount.get() == 3) {
118 getSender().receiveDone(false);
119 srv.server.stopListening();
120 } else {
121 getSender().receiveDone(true);
122 }
123 }
124 });
125
126 Scheduler.run(new Scheduler.Task() {
127 @Override
128 public void run(Scheduler.RunContext ctx) {
129 final Client cli = srv.createClient();
130
131 cli.transmitWhenReady(RelativeTime.FOREVER, new TestMessage(), new Continuation() {
132 @Override
133 public void cont(boolean success) {
134 cli.transmitWhenReady(RelativeTime.FOREVER, new TestMessage(), new Continuation() {
135 @Override
136 public void cont(boolean success) {
137 cli.transmitWhenReady(RelativeTime.FOREVER, new TestMessage(), null);
138 }
139 });
140 }
141 });
142 }
143 });
144 }
145
146 @Test
147 public void test_acceptFromAddresses() {
148 Program.configureLogging("DEBUG", null);
149
150 InetAddress localhost = null;
151 try {
152 localhost = Inet4Address.getLocalHost();
153 } catch (UnknownHostException e) {
154 Assert.fail();
155 }
156
157 // does this work on all operating systems?
158 SocketAddress addr = new InetSocketAddress(localhost, 0);
159
160 Server server = new Server(Lists.newArrayList(addr), RelativeTime.FOREVER, false);
161
162 server.destroy();
163
164 }
165
166
167 @Test
168 public void test_keep_drop() {
169 Program.configureLogging("DEBUG", null);
170 final TestingServer srv = new TestingServer();
171
172 final Wrapper<Integer> msgCount = new Wrapper<Integer>(0);
173
174
175
176 srv.server.setHandler(new Server.MessageRunabout() {
177 public void visit(TestMessage tm) {
178 srv.server.stopListening();
179 if (msgCount.get() == 0) {
180 getSender().keep();
181 getSender().drop();
182 getSender().receiveDone(true);
183 } else if (msgCount.get() == 1) {
184 getSender().receiveDone(false);
185
186 } else {
187 Assert.fail();
188 }
189
190 msgCount.set(msgCount.get() + 1);
191 }
192 });
193
194 Scheduler.run(new Scheduler.Task() {
195 @Override
196 public void run(Scheduler.RunContext ctx) {
197 final Client cli = srv.createClient();
198 cli.transmitWhenReady(new TestMessage(), new Continuation() {
199 @Override
200 public void cont(boolean success) {
201 cli.transmitWhenReady(new TestMessage(), null);
202 }
203 });
204 }
205 });
206 }
207
208
209
210 /**
211 * test if markMonitor / soft shutdown works.
212 */
213 @Test
214 public void test_monitor_clients() {
215 Program.configureLogging("DEBUG", null);
216 final TestingServer srv = new TestingServer();
217
218 final Wrapper<Integer> msgCount = new Wrapper<Integer>(0);
219
220 srv.server.setHandler(new Server.MessageRunabout() {
221 public void visit(TestMessage tm) {
222 if (msgCount.get() == 0) {
223 getSender().markMonitor();
224 getSender().receiveDone(true);
225 } else if (msgCount.get() == 1) {
226 srv.server.stopListening();
227 getSender().receiveDone(false);
228 } else {
229 Assert.fail();
230 }
231
232 msgCount.set(msgCount.get() + 1);
233 }
234 });
235
236 Scheduler.run(new Scheduler.Task() {
237 @Override
238 public void run(Scheduler.RunContext ctx) {
239 final Client cli1 = srv.createClient();
240 final Client cli2 = srv.createClient();
241
242 cli1.transmitWhenReady(new TestMessage(), null);
243 cli2.transmitWhenReady(new TestMessage(), null);
244 }
245 });
246 }
94} 247}
diff --git a/test/org/gnunet/util/FilePipeExample.java b/test/org/gnunet/util/FilePipeExample.java
index 4b72163..94696c9 100644
--- a/test/org/gnunet/util/FilePipeExample.java
+++ b/test/org/gnunet/util/FilePipeExample.java
@@ -13,8 +13,9 @@ import java.nio.ByteBuffer;
13public class FilePipeExample { 13public class FilePipeExample {
14 public static void main(String... args) { 14 public static void main(String... args) {
15 15
16 Program.configureLogging("DEBUG", null);
16 17
17 final Scheduler.FilePipe fp = Scheduler.createFilePipe(new File("test.pipe")); 18 final Scheduler.FilePipe fp = Scheduler.openFilePipe(new File("test.pipe"));
18 19
19 20
20 Scheduler.addRead(RelativeTime.FOREVER, fp.getSource(), new Scheduler.Task() { 21 Scheduler.addRead(RelativeTime.FOREVER, fp.getSource(), new Scheduler.Task() {
diff --git a/test/org/gnunet/util/MeshTest.java b/test/org/gnunet/util/MeshTest.java
new file mode 100644
index 0000000..919d812
--- /dev/null
+++ b/test/org/gnunet/util/MeshTest.java
@@ -0,0 +1,36 @@
1package org.gnunet.util;
2
3import org.gnunet.mesh.Mesh;
4import org.gnunet.testing.TestingSubsystem;
5import org.junit.Test;
6
7/**
8 * ...
9 *
10 * @author Florian Dold
11 */
12public class MeshTest {
13
14 @Test
15 public void test_tunnel_create() {
16 /*
17 Program.configureLogging("DEBUG", null);
18 TestingSubsystem ts = new TestingSubsystem("mesh");
19
20 Mesh m = new Mesh(ts.getConfiguration(), null, null, new RunaboutMessageReceiver() {
21 public void visit(TestMessage tm) {
22
23 }
24 @Override
25 public void handleError() {
26
27 }
28 });
29
30 m.createTunnel(null, null);
31
32 Sc
33 Sheduler.run();
34 */
35 }
36}
diff --git a/test/org/gnunet/util/ResolverTest.java b/test/org/gnunet/util/ResolverTest.java
index 07f694a..ae56b79 100644
--- a/test/org/gnunet/util/ResolverTest.java
+++ b/test/org/gnunet/util/ResolverTest.java
@@ -43,9 +43,7 @@ public class ResolverTest {
43 final Wrapper<Boolean> finished1 = new Wrapper<Boolean>(true); 43 final Wrapper<Boolean> finished1 = new Wrapper<Boolean>(true);
44 final Wrapper<Boolean> finished2 = new Wrapper<Boolean>(true); 44 final Wrapper<Boolean> finished2 = new Wrapper<Boolean>(true);
45 45
46 TestingSetup testing = new TestingSetup(); 46 TestingSubsystem ts = new TestingSubsystem("resolver");
47
48 TestingSubsystem ts = testing.startSubsystem("resolver");
49 47
50 48
51 Resolver r = Resolver.getInstance(); 49 Resolver r = Resolver.getInstance();
diff --git a/test/org/gnunet/util/ServerExample.java b/test/org/gnunet/util/ServerExample.java
index be74b61..a344e2a 100644
--- a/test/org/gnunet/util/ServerExample.java
+++ b/test/org/gnunet/util/ServerExample.java
@@ -23,7 +23,6 @@ package org.gnunet.util;
23import java.net.InetSocketAddress; 23import java.net.InetSocketAddress;
24import java.net.SocketAddress; 24import java.net.SocketAddress;
25import java.util.Arrays; 25import java.util.Arrays;
26import java.util.LinkedList;
27 26
28import static org.gnunet.util.Server.*; 27import static org.gnunet.util.Server.*;
29 28
@@ -43,13 +42,13 @@ public class ServerExample {
43 RelativeTime.MINUTE, 42 RelativeTime.MINUTE,
44 false); 43 false);
45 s.setHandler(new Server.MessageRunabout() { 44 s.setHandler(new Server.MessageRunabout() {
46 public void visit(TESTMessage tm) { 45 public void visit(TestMessage tm) {
47 System.out.println("got TEST message"); 46 System.out.println("got TEST message");
48 final Server.ClientHandle sender = getSender(); 47 final Server.ClientHandle sender = getSender();
49 sender.notifyTransmitReady(4, RelativeTime.FOREVER, new MessageTransmitter() { 48 sender.notifyTransmitReady(4, RelativeTime.FOREVER, new MessageTransmitter() {
50 @Override 49 @Override
51 public void transmit(Connection.MessageSink sink) { 50 public void transmit(Connection.MessageSink sink) {
52 sink.send(new TESTMessage()); 51 sink.send(new TestMessage());
53 System.out.println("TEST message sent"); 52 System.out.println("TEST message sent");
54 sender.receiveDone(true); 53 sender.receiveDone(true);
55 } 54 }
diff --git a/test/org/gnunet/util/StringsTest.java b/test/org/gnunet/util/StringsTest.java
new file mode 100644
index 0000000..49cbfe9
--- /dev/null
+++ b/test/org/gnunet/util/StringsTest.java
@@ -0,0 +1,20 @@
1package org.gnunet.util;
2
3import org.junit.Assert;
4import org.junit.Test;
5
6/**
7 * ...
8 *
9 * @author Florian Dold
10 */
11public class StringsTest {
12 @Test
13 public void test_inverse() {
14 byte[] data = "asdfgASDD$!123".getBytes();
15 String str = Strings.dataToString(data);
16 byte[] data2 = Strings.stringToData(str, data.length);
17 Assert.assertArrayEquals(data, data2);
18 }
19}
20
diff --git a/test/org/gnunet/util/getopt/GetoptTest.java b/test/org/gnunet/util/getopt/GetoptTest.java
index 81a10a8..e60757e 100644
--- a/test/org/gnunet/util/getopt/GetoptTest.java
+++ b/test/org/gnunet/util/getopt/GetoptTest.java
@@ -25,8 +25,8 @@ import org.junit.Assert;
25import org.junit.Test; 25import org.junit.Test;
26 26
27class Target { 27class Target {
28 @Option( 28 @Argument(
29 action = OptionAction.STORE_STRING, 29 action = ArgumentAction.STORE_STRING,
30 shortname = "s", 30 shortname = "s",
31 longname = "string", 31 longname = "string",
32 argumentName = "SOME_STRING", 32 argumentName = "SOME_STRING",
@@ -34,16 +34,16 @@ class Target {
34 ) 34 )
35 String someString; 35 String someString;
36 36
37 @Option( 37 @Argument(
38 action = OptionAction.SET, 38 action = ArgumentAction.SET,
39 shortname = "y", 39 shortname = "y",
40 longname = "set", 40 longname = "set",
41 description = "enable, default disabled" 41 description = "enable, default disabled"
42 ) 42 )
43 boolean set = false; 43 boolean set = false;
44 44
45 @Option( 45 @Argument(
46 action = OptionAction.RESET, 46 action = ArgumentAction.RESET,
47 shortname = "n", 47 shortname = "n",
48 longname = "reset", 48 longname = "reset",
49 description = "disable, default enabled" 49 description = "disable, default enabled"
@@ -51,21 +51,20 @@ class Target {
51 boolean reset = true; 51 boolean reset = true;
52 52
53 53
54 @Option( 54 @Argument(
55 action = OptionAction.INCREMENT, 55 action = ArgumentAction.STORE_NUMBER,
56 shortname = "i",
57 longname = "inc",
58 description = "increment a counter"
59 )
60 int counter = 0;
61
62 @Option(
63 action = OptionAction.STORE_NUMBER,
64 shortname = "w", 56 shortname = "w",
65 longname = "value", 57 longname = "value",
66 description = "some value" 58 description = "some value"
67 ) 59 )
68 int intVal = 0; 60 int intVal = 0;
61
62 static int someConstant = 42;
63}
64
65class InvalidTarget {
66 @Argument(action = ArgumentAction.SET, shortname = "foo", longname = "bar", description = "bla bla")
67 boolean foo;
69} 68}
70 69
71public class GetoptTest { 70public class GetoptTest {
@@ -74,12 +73,7 @@ public class GetoptTest {
74 Target t = new Target(); 73 Target t = new Target();
75 Parser p = new Parser(t); 74 Parser p = new Parser(t);
76 75
77 t.someString = null;
78 76
79 // argument after shortopt
80 p.parse(new String[]{"-s", "foo"});
81 Assert.assertEquals("foo", t.someString);
82
83 t.someString = null; 77 t.someString = null;
84 78
85 // argument directly with shortopt 79 // argument directly with shortopt
@@ -88,6 +82,12 @@ public class GetoptTest {
88 82
89 t.someString = null; 83 t.someString = null;
90 84
85 // argument after shortopt
86 p.parse(new String[]{"-s", "foo"});
87 Assert.assertEquals("foo", t.someString);
88
89 t.someString = null;
90
91 p.parse(new String[]{"--string=foo"}); 91 p.parse(new String[]{"--string=foo"});
92 Assert.assertEquals("foo", t.someString); 92 Assert.assertEquals("foo", t.someString);
93 93
@@ -186,6 +186,21 @@ public class GetoptTest {
186 Assert.assertArrayEquals(new String[]{"foo", "bar", "--reset", "baz"}, rest); 186 Assert.assertArrayEquals(new String[]{"foo", "bar", "--reset", "baz"}, rest);
187 } 187 }
188 188
189
190 @Test(expected = Parser.ArgumentError.class)
191 public void test_missingLongopt() {
192 Target t = new Target();
193 Parser p = new Parser(t);
194 p.parse(new String[]{"--foobar"});
195 }
196
197 @Test(expected = Parser.ArgumentError.class)
198 public void test_missingShortopt_1() {
199 Target t = new Target();
200 Parser p = new Parser(t);
201 p.parse(new String[]{"-x"});
202 }
203
189 @Test 204 @Test
190 public void test_long() { 205 public void test_long() {
191 Target t = new Target(); 206 Target t = new Target();
@@ -196,6 +211,9 @@ public class GetoptTest {
196 rest = p.parse(new String[]{"-w5"}); 211 rest = p.parse(new String[]{"-w5"});
197 Assert.assertEquals(5, t.intVal); 212 Assert.assertEquals(5, t.intVal);
198 213
214 rest = p.parse(new String[]{"-w", "5"});
215 Assert.assertEquals(5, t.intVal);
216
199 rest = p.parse(new String[]{"--value=6"}); 217 rest = p.parse(new String[]{"--value=6"});
200 Assert.assertEquals(6, t.intVal); 218 Assert.assertEquals(6, t.intVal);
201 219
@@ -213,4 +231,57 @@ public class GetoptTest {
213 } 231 }
214 Assert.assertTrue(thrown); 232 Assert.assertTrue(thrown);
215 } 233 }
234
235
236 @Test(expected = Parser.ArgumentError.class)
237 public void test_missingNumberArgument_short() {
238 Target t = new Target();
239 Parser p = new Parser(t);
240
241 p.parse(new String[]{"-w"});
242 Assert.assertEquals(5, t.intVal);
243 }
244
245 @Test(expected = Parser.ArgumentError.class)
246 public void test_missingNumberArgument_long() {
247 Target t = new Target();
248 Parser p = new Parser(t);
249
250
251 p.parse(new String[]{"--w"});
252 Assert.assertEquals(5, t.intVal);
253 }
254
255
256 @Test(expected = Parser.ArgumentError.class)
257 public void test_invalidNumberFormat() {
258 Target t = new Target();
259 Parser p = new Parser(t);
260
261 String[] rest;
262
263 rest = p.parse(new String[]{"-w", "abc"});
264 Assert.assertEquals(5, t.intVal);
265 }
266
267
268 @Test
269 public void test_dashRest() {
270 Target t = new Target();
271 Parser p = new Parser(t);
272
273 String[] rest;
274
275 rest = p.parse(new String[]{"-w", "123", "-"});
276 Assert.assertArrayEquals(new String[]{"-"}, rest);
277 }
278
279
280 @Test(expected = AssertionError.class)
281 public void test_invalid() {
282 InvalidTarget it = new InvalidTarget();
283 Parser p = new Parser(it);
284
285 p.parse(new String[]{"-foo"});
286 }
216} 287}
diff --git a/tools/build b/tools/build
index 225be8e..998756d 100755
--- a/tools/build
+++ b/tools/build
@@ -12,6 +12,9 @@ set -e
12BASEDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"/.. 12BASEDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"/..
13 13
14 14
15OUTDIR="$BASEDIR/build/"
16
17
15# collect all source files 18# collect all source files
16SOURCES_PROD=`find "$BASEDIR/src/" -name "*.java"` 19SOURCES_PROD=`find "$BASEDIR/src/" -name "*.java"`
17SOURCES_TEST=`find "$BASEDIR/test/" -name "*.java"` 20SOURCES_TEST=`find "$BASEDIR/test/" -name "*.java"`
diff --git a/tools/coverage b/tools/coverage
index 4834adc..8e5afce 100755
--- a/tools/coverage
+++ b/tools/coverage
@@ -6,9 +6,6 @@ INSTRUMENT_CMD="sh $BASEDIR/cobertura/cobertura-instrument.sh --datafile $BASEDI
6 6
7echo $INSTRUMENT_CMD 7echo $INSTRUMENT_CMD
8 8
9set -x
10
11
12case "$1" in 9case "$1" in
13instrument) 10instrument)
14 echo "instrumenteing" 11 echo "instrumenteing"