[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] r28880 - in gnunet-java: . gradle gradle/wrapper src src/ma
From: |
gnunet |
Subject: |
[GNUnet-SVN] r28880 - in gnunet-java: . gradle gradle/wrapper src src/main src/main/java src/main/java/org src/main/java/org/gnunet src/main/java/org/gnunet/consensus src/main/java/org/gnunet/construct src/main/java/org/gnunet/construct/parsers src/main/java/org/gnunet/core src/main/java/org/gnunet/dht src/main/java/org/gnunet/hello src/main/java/org/gnunet/mesh src/main/java/org/gnunet/mq src/main/java/org/gnunet/nse src/main/java/org/gnunet/peerinfo src/main/java/org/gnunet/requests src/main/java/org/gnunet/statistics src/main/java/org/gnunet/testbed src/main/java/org/gnunet/testing src/main/java/org/gnunet/transport src/main/java/org/gnunet/util src/main/java/org/gnunet/util/getopt src/main/java/org/gnunet/voting src/main/java/org/gnunet/voting/simulation src/main/java/org/grothoff src/main/resources src/main/resources/org src/main/resources/org/gnunet src/main/resources/org/gnunet/construct src/test src/test/java src/test/java/org src/test/java/org/gnunet src/test/java/org/gn unet/con struct src/test/java/org/gnunet/core src/test/java/org/gnunet/dht src/test/java/org/gnunet/mesh src/test/java/org/gnunet/nse src/test/java/org/gnunet/peerinfo src/test/java/org/gnunet/statistics src/test/java/org/gnunet/testing src/test/java/org/gnunet/util src/test/java/org/gnunet/util/getopt src/test/java/org/grothoff |
Date: |
Tue, 27 Aug 2013 19:16:18 +0200 |
Author: dold
Date: 2013-08-27 19:16:18 +0200 (Tue, 27 Aug 2013)
New Revision: 28880
Added:
gnunet-java/gradle.properties
gnunet-java/gradle/
gnunet-java/gradle/wrapper/
gnunet-java/gradle/wrapper/gradle-wrapper.jar
gnunet-java/gradle/wrapper/gradle-wrapper.properties
gnunet-java/gradlew
gnunet-java/src/main/
gnunet-java/src/main/java/
gnunet-java/src/main/java/org/
gnunet-java/src/main/java/org/gnunet/
gnunet-java/src/main/java/org/gnunet/consensus/
gnunet-java/src/main/java/org/gnunet/consensus/ConcludeCallback.java
gnunet-java/src/main/java/org/gnunet/consensus/ConcludeDoneMessage.java
gnunet-java/src/main/java/org/gnunet/consensus/ConcludeMessage.java
gnunet-java/src/main/java/org/gnunet/consensus/Consensus.java
gnunet-java/src/main/java/org/gnunet/consensus/ConsensusElement.java
gnunet-java/src/main/java/org/gnunet/consensus/InsertDoneCallback.java
gnunet-java/src/main/java/org/gnunet/consensus/InsertElementMessage.java
gnunet-java/src/main/java/org/gnunet/consensus/NewElementCallback.java
gnunet-java/src/main/java/org/gnunet/consensus/NewElementMessage.java
gnunet-java/src/main/java/org/gnunet/construct/
gnunet-java/src/main/java/org/gnunet/construct/Construct.java
gnunet-java/src/main/java/org/gnunet/construct/DoubleValue.java
gnunet-java/src/main/java/org/gnunet/construct/FillWith.java
gnunet-java/src/main/java/org/gnunet/construct/FixedSizeArray.java
gnunet-java/src/main/java/org/gnunet/construct/FixedSizeIntegerArray.java
gnunet-java/src/main/java/org/gnunet/construct/FrameSize.java
gnunet-java/src/main/java/org/gnunet/construct/Int16.java
gnunet-java/src/main/java/org/gnunet/construct/Int32.java
gnunet-java/src/main/java/org/gnunet/construct/Int64.java
gnunet-java/src/main/java/org/gnunet/construct/Int8.java
gnunet-java/src/main/java/org/gnunet/construct/IntegerFill.java
gnunet-java/src/main/java/org/gnunet/construct/Message.java
gnunet-java/src/main/java/org/gnunet/construct/MessageIdAnnotationProcessor.java
gnunet-java/src/main/java/org/gnunet/construct/MessageLoader.java
gnunet-java/src/main/java/org/gnunet/construct/MessageUnion.java
gnunet-java/src/main/java/org/gnunet/construct/MsgMap.txt
gnunet-java/src/main/java/org/gnunet/construct/NestedMessage.java
gnunet-java/src/main/java/org/gnunet/construct/ProtocolViolationException.java
gnunet-java/src/main/java/org/gnunet/construct/ReflectUtil.java
gnunet-java/src/main/java/org/gnunet/construct/UInt16.java
gnunet-java/src/main/java/org/gnunet/construct/UInt32.java
gnunet-java/src/main/java/org/gnunet/construct/UInt64.java
gnunet-java/src/main/java/org/gnunet/construct/UInt8.java
gnunet-java/src/main/java/org/gnunet/construct/Union.java
gnunet-java/src/main/java/org/gnunet/construct/UnionCase.java
gnunet-java/src/main/java/org/gnunet/construct/VariableSizeArray.java
gnunet-java/src/main/java/org/gnunet/construct/VariableSizeIntegerArray.java
gnunet-java/src/main/java/org/gnunet/construct/ZeroTerminatedString.java
gnunet-java/src/main/java/org/gnunet/construct/package-info.java
gnunet-java/src/main/java/org/gnunet/construct/parsers/
gnunet-java/src/main/java/org/gnunet/construct/parsers/DoubleParser.java
gnunet-java/src/main/java/org/gnunet/construct/parsers/FillParser.java
gnunet-java/src/main/java/org/gnunet/construct/parsers/FixedSizeArrayParser.java
gnunet-java/src/main/java/org/gnunet/construct/parsers/FixedSizeIntegerArrayParser.java
gnunet-java/src/main/java/org/gnunet/construct/parsers/IntegerFillParser.java
gnunet-java/src/main/java/org/gnunet/construct/parsers/IntegerParser.java
gnunet-java/src/main/java/org/gnunet/construct/parsers/IntegerUtil.java
gnunet-java/src/main/java/org/gnunet/construct/parsers/NestedParser.java
gnunet-java/src/main/java/org/gnunet/construct/parsers/Parser.java
gnunet-java/src/main/java/org/gnunet/construct/parsers/SequenceParser.java
gnunet-java/src/main/java/org/gnunet/construct/parsers/StringParser.java
gnunet-java/src/main/java/org/gnunet/construct/parsers/UnionParser.java
gnunet-java/src/main/java/org/gnunet/construct/parsers/VariableSizeArrayParser.java
gnunet-java/src/main/java/org/gnunet/construct/parsers/VariableSizeIntegerArrayParser.java
gnunet-java/src/main/java/org/gnunet/construct/parsers/package-info.java
gnunet-java/src/main/java/org/gnunet/core/
gnunet-java/src/main/java/org/gnunet/core/ConnectHandler.java
gnunet-java/src/main/java/org/gnunet/core/ConnectNotifyMessage.java
gnunet-java/src/main/java/org/gnunet/core/Core.java
gnunet-java/src/main/java/org/gnunet/core/DisconnectHandler.java
gnunet-java/src/main/java/org/gnunet/core/DisconnectNotifyMessage.java
gnunet-java/src/main/java/org/gnunet/core/HeaderNotify.java
gnunet-java/src/main/java/org/gnunet/core/InitCallback.java
gnunet-java/src/main/java/org/gnunet/core/InitMessage.java
gnunet-java/src/main/java/org/gnunet/core/InitReplyMessage.java
gnunet-java/src/main/java/org/gnunet/core/MessageNotify.java
gnunet-java/src/main/java/org/gnunet/core/NotifyInboundTrafficMessage.java
gnunet-java/src/main/java/org/gnunet/core/NotifyOutboundTrafficMessage.java
gnunet-java/src/main/java/org/gnunet/core/RequestIdentification.java
gnunet-java/src/main/java/org/gnunet/core/SendMessage.java
gnunet-java/src/main/java/org/gnunet/core/SendMessageReady.java
gnunet-java/src/main/java/org/gnunet/core/SendMessageRequest.java
gnunet-java/src/main/java/org/gnunet/core/package-info.java
gnunet-java/src/main/java/org/gnunet/dht/
gnunet-java/src/main/java/org/gnunet/dht/BlockType.java
gnunet-java/src/main/java/org/gnunet/dht/ClientGetMessage.java
gnunet-java/src/main/java/org/gnunet/dht/ClientGetStopMessage.java
gnunet-java/src/main/java/org/gnunet/dht/ClientPutConfirmationMessage.java
gnunet-java/src/main/java/org/gnunet/dht/ClientPutMessage.java
gnunet-java/src/main/java/org/gnunet/dht/ClientResultMessage.java
gnunet-java/src/main/java/org/gnunet/dht/DistributedHashTable.java
gnunet-java/src/main/java/org/gnunet/dht/MonitorGetHandler.java
gnunet-java/src/main/java/org/gnunet/dht/MonitorGetMessage.java
gnunet-java/src/main/java/org/gnunet/dht/MonitorGetRespMessage.java
gnunet-java/src/main/java/org/gnunet/dht/MonitorGetResponseHandler.java
gnunet-java/src/main/java/org/gnunet/dht/MonitorPutHandler.java
gnunet-java/src/main/java/org/gnunet/dht/MonitorPutMessage.java
gnunet-java/src/main/java/org/gnunet/dht/MonitorStartStop.java
gnunet-java/src/main/java/org/gnunet/dht/ResultCallback.java
gnunet-java/src/main/java/org/gnunet/dht/RouteOption.java
gnunet-java/src/main/java/org/gnunet/dht/package-info.java
gnunet-java/src/main/java/org/gnunet/hello/
gnunet-java/src/main/java/org/gnunet/hello/HelloMessage.java
gnunet-java/src/main/java/org/gnunet/hello/package-info.java
gnunet-java/src/main/java/org/gnunet/mesh/
gnunet-java/src/main/java/org/gnunet/mesh/ClientConnectMessage.java
gnunet-java/src/main/java/org/gnunet/mesh/ConnectHandler.java
gnunet-java/src/main/java/org/gnunet/mesh/DataMessage.java
gnunet-java/src/main/java/org/gnunet/mesh/DisconnectHandler.java
gnunet-java/src/main/java/org/gnunet/mesh/InboundTunnelHandler.java
gnunet-java/src/main/java/org/gnunet/mesh/LocalAckMessage.java
gnunet-java/src/main/java/org/gnunet/mesh/Mesh.java
gnunet-java/src/main/java/org/gnunet/mesh/MeshRunabout.java
gnunet-java/src/main/java/org/gnunet/mesh/TunnelCreateMessage.java
gnunet-java/src/main/java/org/gnunet/mesh/TunnelDestroyMessage.java
gnunet-java/src/main/java/org/gnunet/mesh/TunnelEndHandler.java
gnunet-java/src/main/java/org/gnunet/mesh/TunnelNotificationMessage.java
gnunet-java/src/main/java/org/gnunet/mesh/package-info.java
gnunet-java/src/main/java/org/gnunet/mq/
gnunet-java/src/main/java/org/gnunet/mq/Envelope.java
gnunet-java/src/main/java/org/gnunet/mq/MessageQueue.java
gnunet-java/src/main/java/org/gnunet/mq/NotifySentHandler.java
gnunet-java/src/main/java/org/gnunet/nse/
gnunet-java/src/main/java/org/gnunet/nse/NetworkSizeEstimation.java
gnunet-java/src/main/java/org/gnunet/nse/StartMessage.java
gnunet-java/src/main/java/org/gnunet/nse/UpdateMessage.java
gnunet-java/src/main/java/org/gnunet/nse/package-info.java
gnunet-java/src/main/java/org/gnunet/peerinfo/
gnunet-java/src/main/java/org/gnunet/peerinfo/InfoEnd.java
gnunet-java/src/main/java/org/gnunet/peerinfo/InfoMessage.java
gnunet-java/src/main/java/org/gnunet/peerinfo/ListAllPeersMessage.java
gnunet-java/src/main/java/org/gnunet/peerinfo/ListPeerMessage.java
gnunet-java/src/main/java/org/gnunet/peerinfo/PeerInfo.java
gnunet-java/src/main/java/org/gnunet/peerinfo/PeerProcessor.java
gnunet-java/src/main/java/org/gnunet/peerinfo/RsaPublicKeyBinaryEncoded.java
gnunet-java/src/main/java/org/gnunet/peerinfo/package-info.java
gnunet-java/src/main/java/org/gnunet/requests/
gnunet-java/src/main/java/org/gnunet/requests/MatchingRequestContainer.java
gnunet-java/src/main/java/org/gnunet/requests/RequestContainer.java
gnunet-java/src/main/java/org/gnunet/requests/SequentialRequestContainer.java
gnunet-java/src/main/java/org/gnunet/requests/package-info.java
gnunet-java/src/main/java/org/gnunet/statistics/
gnunet-java/src/main/java/org/gnunet/statistics/GetMessage.java
gnunet-java/src/main/java/org/gnunet/statistics/GetRequest.java
gnunet-java/src/main/java/org/gnunet/statistics/GetResponseEndMessage.java
gnunet-java/src/main/java/org/gnunet/statistics/GetResponseMessage.java
gnunet-java/src/main/java/org/gnunet/statistics/SetMessage.java
gnunet-java/src/main/java/org/gnunet/statistics/SetRequest.java
gnunet-java/src/main/java/org/gnunet/statistics/Statistics.java
gnunet-java/src/main/java/org/gnunet/statistics/StatisticsReceiver.java
gnunet-java/src/main/java/org/gnunet/statistics/StatisticsWatcher.java
gnunet-java/src/main/java/org/gnunet/statistics/WatchMessage.java
gnunet-java/src/main/java/org/gnunet/statistics/WatchRequest.java
gnunet-java/src/main/java/org/gnunet/statistics/WatchResponseMessage.java
gnunet-java/src/main/java/org/gnunet/statistics/package-info.java
gnunet-java/src/main/java/org/gnunet/testbed/
gnunet-java/src/main/java/org/gnunet/testbed/Controller.java
gnunet-java/src/main/java/org/gnunet/testbed/ControllerEventCallback.java
gnunet-java/src/main/java/org/gnunet/testbed/ControllerInitMessage.java
gnunet-java/src/main/java/org/gnunet/testbed/ControllerProc.java
gnunet-java/src/main/java/org/gnunet/testbed/ControllerStatusCallback.java
gnunet-java/src/main/java/org/gnunet/testbed/HelperInitMessage.java
gnunet-java/src/main/java/org/gnunet/testbed/HelperReplyMessage.java
gnunet-java/src/main/java/org/gnunet/testbed/Host.java
gnunet-java/src/main/java/org/gnunet/testbed/Operation.java
gnunet-java/src/main/java/org/gnunet/testbed/OperationCompletionCallback.java
gnunet-java/src/main/java/org/gnunet/testbed/Peer.java
gnunet-java/src/main/java/org/gnunet/testbed/PeerChurnCallback.java
gnunet-java/src/main/java/org/gnunet/testbed/PeerCreateCallback.java
gnunet-java/src/main/java/org/gnunet/testing/
gnunet-java/src/main/java/org/gnunet/testing/TestingFixture.java
gnunet-java/src/main/java/org/gnunet/testing/TestingServer.java
gnunet-java/src/main/java/org/gnunet/testing/TestingSetup.java
gnunet-java/src/main/java/org/gnunet/testing/TestingSubsystem.java
gnunet-java/src/main/java/org/gnunet/testing/package-info.java
gnunet-java/src/main/java/org/gnunet/transport/
gnunet-java/src/main/java/org/gnunet/transport/AddressIterateMessage.java
gnunet-java/src/main/java/org/gnunet/transport/BlacklistCallback.java
gnunet-java/src/main/java/org/gnunet/transport/BlacklistInitMessage.java
gnunet-java/src/main/java/org/gnunet/transport/HelloUpdateCallback.java
gnunet-java/src/main/java/org/gnunet/transport/PeerIterateCallback.java
gnunet-java/src/main/java/org/gnunet/transport/RequestConnectMessage.java
gnunet-java/src/main/java/org/gnunet/transport/StartMessage.java
gnunet-java/src/main/java/org/gnunet/transport/Transport.java
gnunet-java/src/main/java/org/gnunet/transport/TryConnectCallback.java
gnunet-java/src/main/java/org/gnunet/util/
gnunet-java/src/main/java/org/gnunet/util/ATSInformation.java
gnunet-java/src/main/java/org/gnunet/util/AbsoluteTime.java
gnunet-java/src/main/java/org/gnunet/util/AbsoluteTimeMessage.java
gnunet-java/src/main/java/org/gnunet/util/Cancelable.java
gnunet-java/src/main/java/org/gnunet/util/Client.java
gnunet-java/src/main/java/org/gnunet/util/Configuration.java
gnunet-java/src/main/java/org/gnunet/util/Connection.java
gnunet-java/src/main/java/org/gnunet/util/Continuation.java
gnunet-java/src/main/java/org/gnunet/util/GnunetMessage.java
gnunet-java/src/main/java/org/gnunet/util/HashCode.java
gnunet-java/src/main/java/org/gnunet/util/Helper.java
gnunet-java/src/main/java/org/gnunet/util/MessageReceiver.java
gnunet-java/src/main/java/org/gnunet/util/MessageTransmitter.java
gnunet-java/src/main/java/org/gnunet/util/PeerIdentity.java
gnunet-java/src/main/java/org/gnunet/util/Program.java
gnunet-java/src/main/java/org/gnunet/util/RelativeTime.java
gnunet-java/src/main/java/org/gnunet/util/RelativeTimeMessage.java
gnunet-java/src/main/java/org/gnunet/util/Resolver.java
gnunet-java/src/main/java/org/gnunet/util/RunaboutMessageReceiver.java
gnunet-java/src/main/java/org/gnunet/util/RunaboutUtil.java
gnunet-java/src/main/java/org/gnunet/util/Scheduler.java
gnunet-java/src/main/java/org/gnunet/util/Server.java
gnunet-java/src/main/java/org/gnunet/util/Service.java
gnunet-java/src/main/java/org/gnunet/util/Strings.java
gnunet-java/src/main/java/org/gnunet/util/TestMessage.java
gnunet-java/src/main/java/org/gnunet/util/UnknownMessageBody.java
gnunet-java/src/main/java/org/gnunet/util/getopt/
gnunet-java/src/main/java/org/gnunet/util/getopt/Argument.java
gnunet-java/src/main/java/org/gnunet/util/getopt/ArgumentAction.java
gnunet-java/src/main/java/org/gnunet/util/getopt/Parser.java
gnunet-java/src/main/java/org/gnunet/util/getopt/package-info.java
gnunet-java/src/main/java/org/gnunet/util/package-info.java
gnunet-java/src/main/java/org/gnunet/voting/
gnunet-java/src/main/java/org/gnunet/voting/CertificateAuthorityService.java
gnunet-java/src/main/java/org/gnunet/voting/ElectionCallTool.java
gnunet-java/src/main/java/org/gnunet/voting/ElectionSpecification.java
gnunet-java/src/main/java/org/gnunet/voting/TallyAuthorityService.java
gnunet-java/src/main/java/org/gnunet/voting/VotingTool.java
gnunet-java/src/main/java/org/gnunet/voting/simulation/
gnunet-java/src/main/java/org/gnunet/voting/simulation/Authority.java
gnunet-java/src/main/java/org/gnunet/voting/simulation/Ballot.java
gnunet-java/src/main/java/org/gnunet/voting/simulation/BogusAuthority.java
gnunet-java/src/main/java/org/gnunet/voting/simulation/CallForVoters.java
gnunet-java/src/main/java/org/gnunet/voting/simulation/CryptoUtil.java
gnunet-java/src/main/java/org/gnunet/voting/simulation/Cyphertext.java
gnunet-java/src/main/java/org/gnunet/voting/simulation/ElectionSupervisor.java
gnunet-java/src/main/java/org/gnunet/voting/simulation/GroupPublicKey.java
gnunet-java/src/main/java/org/gnunet/voting/simulation/TallyKeyShare.java
gnunet-java/src/main/java/org/gnunet/voting/simulation/TransmitShareVerification.java
gnunet-java/src/main/java/org/gnunet/voting/simulation/Voter.java
gnunet-java/src/main/java/org/gnunet/voting/simulation/VotingParameters.java
gnunet-java/src/main/java/org/gnunet/voting/simulation/VotingSimulation.java
gnunet-java/src/main/java/org/grothoff/
gnunet-java/src/main/java/org/grothoff/Runabout.java
gnunet-java/src/main/java/org/grothoff/package-info.java
gnunet-java/src/main/resources/
gnunet-java/src/main/resources/org/
gnunet-java/src/main/resources/org/gnunet/
gnunet-java/src/main/resources/org/gnunet/construct/
gnunet-java/src/main/resources/org/gnunet/construct/MsgMap.txt
gnunet-java/src/test/
gnunet-java/src/test/java/
gnunet-java/src/test/java/org/
gnunet-java/src/test/java/org/gnunet/
gnunet-java/src/test/java/org/gnunet/construct/
gnunet-java/src/test/java/org/gnunet/construct/ByteFillMessage.java
gnunet-java/src/test/java/org/gnunet/construct/ConstructTest.java
gnunet-java/src/test/java/org/gnunet/construct/DoubleTest.java
gnunet-java/src/test/java/org/gnunet/construct/FillParserTest.java
gnunet-java/src/test/java/org/gnunet/construct/FixedSizeTest.java
gnunet-java/src/test/java/org/gnunet/construct/FrameSizeTest.java
gnunet-java/src/test/java/org/gnunet/construct/IntMessage.java
gnunet-java/src/test/java/org/gnunet/construct/OptionalUnionTest.java
gnunet-java/src/test/java/org/gnunet/construct/PrivateMemberMessage.java
gnunet-java/src/test/java/org/gnunet/construct/QueryMessage.java
gnunet-java/src/test/java/org/gnunet/construct/SendMessageTest.java
gnunet-java/src/test/java/org/gnunet/construct/StringMessage.java
gnunet-java/src/test/java/org/gnunet/construct/StringTest.java
gnunet-java/src/test/java/org/gnunet/construct/StringTuple.java
gnunet-java/src/test/java/org/gnunet/construct/VariableSizeArrayTest.java
gnunet-java/src/test/java/org/gnunet/construct/VariableSizeMessage.java
gnunet-java/src/test/java/org/gnunet/core/
gnunet-java/src/test/java/org/gnunet/core/CoreTest.java
gnunet-java/src/test/java/org/gnunet/dht/
gnunet-java/src/test/java/org/gnunet/dht/DHTTest.java
gnunet-java/src/test/java/org/gnunet/mesh/
gnunet-java/src/test/java/org/gnunet/mesh/MeshTest.java
gnunet-java/src/test/java/org/gnunet/nse/
gnunet-java/src/test/java/org/gnunet/nse/NSETest.java
gnunet-java/src/test/java/org/gnunet/peerinfo/
gnunet-java/src/test/java/org/gnunet/peerinfo/PeerInfoTest.java
gnunet-java/src/test/java/org/gnunet/statistics/
gnunet-java/src/test/java/org/gnunet/statistics/StatisticsTest.java
gnunet-java/src/test/java/org/gnunet/testing/
gnunet-java/src/test/java/org/gnunet/testing/TestingSetupTest.java
gnunet-java/src/test/java/org/gnunet/util/
gnunet-java/src/test/java/org/gnunet/util/Assertion.java
gnunet-java/src/test/java/org/gnunet/util/AssertionList.java
gnunet-java/src/test/java/org/gnunet/util/ClientServerTest.java
gnunet-java/src/test/java/org/gnunet/util/FilePipeExample.java
gnunet-java/src/test/java/org/gnunet/util/ResolverTest.java
gnunet-java/src/test/java/org/gnunet/util/ServerExample.java
gnunet-java/src/test/java/org/gnunet/util/StringsTest.java
gnunet-java/src/test/java/org/gnunet/util/TimeTest.java
gnunet-java/src/test/java/org/gnunet/util/Wrapper.java
gnunet-java/src/test/java/org/gnunet/util/getopt/
gnunet-java/src/test/java/org/gnunet/util/getopt/GetoptTest.java
gnunet-java/src/test/java/org/grothoff/
gnunet-java/src/test/java/org/grothoff/RunaboutBenchmark.java
Removed:
gnunet-java/src/org/
gnunet-java/test/
Modified:
gnunet-java/ISSUES
gnunet-java/README
gnunet-java/build.gradle
Log:
- adapted source tree structure to gradle/maven conventions
- added gradle wrapper
- fixes to adapt to GNUnet changes (new time unit, ...)
- helper process in util
- started implementing testbed
- skeleton for voting tools
- use new mq api
- implemented some more transport api
- mesh
Modified: gnunet-java/ISSUES
===================================================================
--- gnunet-java/ISSUES 2013-08-27 16:48:59 UTC (rev 28879)
+++ gnunet-java/ISSUES 2013-08-27 17:16:18 UTC (rev 28880)
@@ -1,16 +1,125 @@
-* after loads of nice-to-find bugs, i'm fairly confident consensus and set
work ok now ...
-* gnunet-java needs some work / updating, but that's necessary for voting
anyway
+* gnunet-testing-run-service merged into gnunet-testing
+ * the whole program runs without scheduler ... shouldn't be a problem, right?
+* i'm getting a lot of warnings from the autotools (newer version)
-* multihashmap_create (0) should be allowed ... hard to miss otherwise
-* testBED with java
+* probably found a bug in (openjdk7's) warning suppression
-for voting:
-* how is an 'election' created / published to other peers?
- * who's allowed to vote?
-* setting up the secret shared private key / cooperative decryption (service
of its own?)
-* casting votes
-* tallying and getting the results
+* various issues with time unit change now fixed
+ * test cases timed out ... exponential backoff unit mismatch was the cause
-util-29321 INFO Accepting connection from `<unbound UNIX client>': 0xae2d00
-^^ why is the 'INFO'?
+
+* i found the "correct" way to handle junit4/scheduler: test teardown
annotations (@After/@Before)
+ * tests using the scheduler should inherit org.gnunet.testing.TestingFixture
+ * other test cases are now unaffected
+
+* i experimented around with message / request queues
+ * everything now uses an mq/envelope mechanism very similar to GNUNET_MQ
+ * difference: in gnunet-java, client, mesh tunnel, etc. _are_ message queues
+ * there are request containers
+ * sequential (e.g. statistics set/get) and matching (stat. watch, core ntr)
+
+
+* for testing org.gnunet.mesh.Mesh:
+ * how should the peer's identity accessed from java?
+ GNUNET_CRYPTO_ecc_key_get_public in java?
+ * => java mesh api currently can't be tested without using Core
+ (mesh _used_ to allow peerid=0, but does not anymore)
+
+* core:
+ * the second test case seems to hang for a few seconds sometimes,
+ is this core's key generation?
+ * i just increased the test timeout, works fine no, works fine now ...
+
+
+* transport API:
+ * discuss transport api strangeness
+ * hellos are passed around as message headers in the C API (for
"copyability"?), what should java do?
+ * GnunetMessage or HelloMessage?
+ * I get my own hello (for get_hello) only after I send init => bad?!
+ * currently, a transport handle is required for blacklist/active address
query
+ * should there be a seperate
org.gnunet.transport.(Blacklist|ActiveAddressQuery)?
+ * testing the blacklist api?
+
+
+statistics:
+ * queing etc. now implemented with mq / new requests api
+ * how do I test correct behavior on reconnect automatically?
+ * as statistics refuses to shut down when there's a (non-monitor) connection
+
+configuration:
+* what about newline in config options? they are written as "\\\n", right?
+
+testbed:
+
+
+habitability check ... what's the best way to do this in java?
+ * threads ....
+
+* starting a controller on a host updates the host's config?
+* why do i have to send the controller hostname when connecting to a
controller?
+ *
+in what extent does controller_disconnect block? (see doxygen comment)
+
+
+GNUNET_TESTBED_HelperInit has a very "nice" format, but consensus can handle
it ...
+ * one string is zero terminated, the other not ...
+ * currently the non-zero-terminated string is just implemented as
@VariableSizeIntegerArray
+ * do we need a @VariableSizeString?
+ * java's Deflater has the worst api imaginable ...
+
+* why is the host list an array?
+ * creating a host with a large (e.g. random) id creates huge array
+
+ while (id >= new_size)
+ new_size += HOST_LIST_GROW_STEP;
+ if (new_size != host_list_size)
+ GNUNET_array_grow (host_list, host_list_size, new_size);
+
+* gnunet-java has now org.gnunet.util.Helper, which is needed for testbed
+ * which is "simply" a message queue with some extra methods
+ * java async process IO _requires_ threading (or using e.g. the bloated
apache commons)
+ * Scheduler now is (or should be ;) thread safe
+ * i'm not sure what to do about process stopping/killing in java
+ * only kill is implemented, i'm not sure stop() is possible in java
+
+
+* the latest version of cobertura is very large (~5MB)
+* discuss dependencies in general, discuss maven repositories and classpath
with gradle repos
+ * developer can specfiy custom repositories in the build config
+ * e.g. when the jar is probably available in the local system
+ * see gradle showDeps for getting at the jar's locations
+ * could have a gradle copyDeps/installDeps
+ * make gradle create wrappers with correct classpath, either for development
or
+ shipping
+
+* why not run multiple gnunet-java "applications" in one JVM?
+ * would require changes the the scheduler (non-static)
+ * handy for running larger testbeds and nice for command line tool startup
times
+ * nailgun nails (nailgun is apache2 licensed)
+
+* changed some paths to be more compliant with java (=intellij,gradle,maven)
conventions
+* the gradle wrapper is checked into svn (as recommended by gradle docs)
+
+* should voting stay in the main gnunet-java tree, or be an extension?
+ * being an extension would force me to maintain good compatibility of the
+ extension template
+
+
+voting
+ * what should be used for signatures, voter IDs?
+ * the voting ca could selectively deny voters their permission
+ * is this what we want to have "per default"?
+ * review VotingTool/ElectionCallTool
+
+
+TODO:
+request cancellation, request overlapping
+testbed
+review all existing gnj stuff
+voting
+gnj coverage
+merge testing tool
+fix sam cobertura
+
+
Modified: gnunet-java/README
===================================================================
--- gnunet-java/README 2013-08-27 16:48:59 UTC (rev 28879)
+++ gnunet-java/README 2013-08-27 17:16:18 UTC (rev 28880)
@@ -1,7 +1,7 @@
Building gnunet-java
====================
-For building gnunet-java, gradle>=1.5 is required, see http://gradle.org/.
+For building gnunet-java, gradle>=1.7 is required, see http://gradle.org/.
Extending gnunet-java
Modified: gnunet-java/build.gradle
===================================================================
--- gnunet-java/build.gradle 2013-08-27 16:48:59 UTC (rev 28879)
+++ gnunet-java/build.gradle 2013-08-27 17:16:18 UTC (rev 28880)
@@ -6,41 +6,29 @@
buildDir = "$projectDir/build-gradle"
+// specify where to get jars
repositories {
flatDir {
dirs 'lib'
}
+ mavenCentral()
}
dependencies {
- compile name: 'guava', version: '12.0'
- compile name: 'junit', version: '4.10'
+ compile group: 'com.google.guava', name: 'guava', version: '14.0.1'
+ compile group: 'junit', name: 'junit', version: '4.11'
compile name: 'log4j', version: '1.2.16'
compile name: 'slf4j-api', version: '1.6.4'
compile name: 'slf4j-log4j12', version: '1.6.4'
}
-sourceSets {
- main {
- java {
- srcDir 'src'
- }
- resources {
- srcDir 'src'
- }
- }
- test {
- java {
- srcDir 'test'
- }
- resources {
- srcDir 'test'
- }
- }
+
+task showClasspath << {
+ System.out.println(configurations.compile.asPath);
}
-task install (dependsOn: 'build', type: Copy) {
-
+task showDeps << {
+ configurations.compile.each { File file -> println file.getPath() }
}
@@ -97,20 +85,26 @@
reportCoverage.dependsOn testCoverage
+
+task createResourcesDir << {
+ def myDir = new File('src/main/resources')
+ myDir.mkdirs()
+}
+
/*
TODO: should we really use the compile task for this?
*/
-task msgtypes (type: JavaCompile) {
+task msgtypes (type: JavaCompile, dependsOn: 'createResourcesDir') {
description = "Updates the index of GNUnet message types known to
gnunet-java."
classpath = project.sourceSets.main.runtimeClasspath
source = files(project.sourceSets.main.allJava)
options.setCompilerArgs(["-processor",
"org.gnunet.construct.MessageIdAnnotationProcessor",
"-proc:only",
- "-s", "src"])
+ // generated "source" files should resources, tell
the annotation processor!
+ "-s", "src/main/resources"])
destinationDir = file("$buildDir/classes/main/")
}
-
project.ext.installerFile = "$projectDir/gnunet-java-installer.jar"
task installer (type: Exec) {
@@ -131,3 +125,15 @@
}
installer.commandLine "$izpack", "$projectDir/izpack-installer.xml", "-o",
"$installerFile"
}
+
+
+task wrapper(type: Wrapper) {
+ gradleVersion = '1.7'
+}
+
+if (hasProperty("xlint")) {
+ tasks.withType(Compile) {
+ options.compilerArgs << "-Xlint:unchecked"
+ }
+}
+
Added: gnunet-java/gradle/wrapper/gradle-wrapper.jar
===================================================================
(Binary files differ)
Index: gnunet-java/gradle/wrapper/gradle-wrapper.jar
===================================================================
--- gnunet-java/gradle/wrapper/gradle-wrapper.jar 2013-08-27 16:48:59 UTC
(rev 28879)
+++ gnunet-java/gradle/wrapper/gradle-wrapper.jar 2013-08-27 17:16:18 UTC
(rev 28880)
Property changes on: gnunet-java/gradle/wrapper/gradle-wrapper.jar
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: gnunet-java/gradle/wrapper/gradle-wrapper.properties
===================================================================
--- gnunet-java/gradle/wrapper/gradle-wrapper.properties
(rev 0)
+++ gnunet-java/gradle/wrapper/gradle-wrapper.properties 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,6 @@
+#Thu Aug 22 19:26:08 CEST 2013
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.7-bin.zip
Added: gnunet-java/gradle.properties
===================================================================
--- gnunet-java/gradle.properties (rev 0)
+++ gnunet-java/gradle.properties 2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1 @@
+org.gradle.daemon=true
Added: gnunet-java/gradlew
===================================================================
--- gnunet-java/gradlew (rev 0)
+++ gnunet-java/gradlew 2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to
pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no
'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\"
\"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ###
Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ###
Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5"
"$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5"
"$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5"
"$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the
shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "address@hidden" -classpath "$CLASSPATH"
org.gradle.wrapper.GradleWrapperMain "$@"
Property changes on: gnunet-java/gradlew
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: gnunet-java/src/main/java/org/gnunet/consensus/ConcludeCallback.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/consensus/ConcludeCallback.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/consensus/ConcludeCallback.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,5 @@
+package org.gnunet.consensus;
+
+public interface ConcludeCallback {
+ void onConcludeDone();
+}
Added: gnunet-java/src/main/java/org/gnunet/consensus/ConcludeDoneMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/consensus/ConcludeDoneMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/consensus/ConcludeDoneMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,13 @@
+package org.gnunet.consensus;
+
+
+import org.gnunet.construct.MessageUnion;
+import org.gnunet.construct.UnionCase;
+
+/**
+ * Notify the client that conclude has finished.
+ * Direction: service -> client
+ */
address@hidden(525)
+public class ConcludeDoneMessage implements MessageUnion {
+}
Added: gnunet-java/src/main/java/org/gnunet/consensus/ConcludeMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/consensus/ConcludeMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/consensus/ConcludeMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,19 @@
+package org.gnunet.consensus;
+
+import org.gnunet.construct.FillWith;
+import org.gnunet.construct.UInt16;
+import org.gnunet.construct.UInt8;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+
+/**
+ * Notify the client of a new element.
+ *
+ * Direction: service -> client
+ *
+ * @author Florian Dold
+ */
address@hidden(524)
+public class ConcludeMessage implements GnunetMessage.Body {
+ /* empty body */
+}
\ No newline at end of file
Added: gnunet-java/src/main/java/org/gnunet/consensus/Consensus.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/consensus/Consensus.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/consensus/Consensus.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,128 @@
+package org.gnunet.consensus;
+
+import org.gnunet.mq.Envelope;
+import org.gnunet.mq.MessageQueue;
+import org.gnunet.mq.NotifySentHandler;
+import org.gnunet.util.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Multi-peer set reconciliation.
+ */
+public class Consensus {
+ /**
+ * Class logger.
+ */
+ private static final Logger logger = LoggerFactory
+ .getLogger(Consensus.class);
+
+ /**
+ * Callback for new elements arriving from the service.
+ * Also used to notify of consensus failure.
+ */
+ private final NewElementCallback newElementCallback;
+
+ /**
+ * Client connected to the consensus service.
+ */
+ private Client client;
+
+ /**
+ * Called when conclude has finished.
+ */
+ private ConcludeCallback concludeCallback;
+
+ /**
+ * Message dispatch for messages from the consensus service.
+ */
+ private class ConsensusMessageReceiver extends RunaboutMessageReceiver {
+ public void visit(ConcludeDoneMessage m) {
+ if (null == concludeCallback)
+ {
+ logger.error("unexpected conclude done message");
+ return;
+ }
+ concludeCallback.onConcludeDone();
+ }
+
+ public void visit(NewElementMessage m) {
+ ConsensusElement element = new ConsensusElement();
+ element.element_type = m.element_type;
+ element.data = m.element_data;
+ newElementCallback.onNewElement(element);
+ }
+
+ @Override
+ public void handleError() {
+ newElementCallback.onNewElement(null);
+ }
+ }
+
+ /**
+ * Create a consensus session. The set being reconciled is initially
+ * empty. Only reconcile with other peers after
+ * GNUNET_CONSENSUS_reconcile has been called.
+ *
+ * @param num_peers number of peers in the session
+ * @param peers array of peers participating in this consensus session
+ * Inclusion of the local peer is optional.
+ * @param sessionId session identifier
+ * Allows a group of peers to have more than consensus
session.
+ * @param newElementCallback callback, called when a new element is added
to the set by
+ * another peer
+ */
+ public Consensus(Configuration cfg, int num_peers, PeerIdentity[] peers,
HashCode sessionId,
+ NewElementCallback newElementCallback) {
+ client = new Client("consensus", cfg);
+ client.installReceiver(new ConsensusMessageReceiver());
+ this.newElementCallback = newElementCallback;
+ }
+
+ /**
+ * Insert an element into the consensus set.
+ *
+ * @param element element to insert in the consnesus
+ * @param idc called when the element has been sent to the service
+ */
+ public void insertElement (ConsensusElement element, final
InsertDoneCallback idc) {
+ InsertElementMessage m = new InsertElementMessage();
+ m.element_data = element.data;
+ m.element_type = element.element_type;
+ Envelope ev = new Envelope(m);
+ ev.notifySent(new NotifySentHandler() {
+ @Override
+ public void onSent() {
+ idc.onInsertDone();
+ }
+ });
+ client.send(ev);
+ }
+
+ /**
+ * We are done with inserting new elements into the consensus;
+ * try to conclude the consensus within a given time window.
+ * After conclude has been called, no further elements may be
+ * inserted by the client.
+ * @param concludeCallback called when the consensus has concluded
+ */
+ public void conclude(ConcludeCallback concludeCallback) {
+ if (null == concludeCallback)
+ throw new AssertionError("conclude with empty callback");
+ if (null != this.concludeCallback)
+ throw new AssertionError("called conclude twice");
+ this.concludeCallback = concludeCallback;
+ ConcludeMessage m = new ConcludeMessage();
+ client.send(m);
+ }
+
+ /**
+ * Destroy a consensus handle.
+ * Free all state associated with
+ * it, no longer call any of the callbacks.
+ */
+ public void destroy() {
+ client.disconnect();
+ client = null;
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/consensus/ConsensusElement.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/consensus/ConsensusElement.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/consensus/ConsensusElement.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,16 @@
+package org.gnunet.consensus;
+
+
+public class ConsensusElement {
+ /**
+ * Type of the element.
+ * 0 <= element_type <= 2^16
+ */
+ int element_type;
+
+ /**
+ * Data for the element.
+ * 0 <= data.length <= 2^16
+ */
+ byte[] data;
+}
Added: gnunet-java/src/main/java/org/gnunet/consensus/InsertDoneCallback.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/consensus/InsertDoneCallback.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/consensus/InsertDoneCallback.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,5 @@
+package org.gnunet.consensus;
+
+public interface InsertDoneCallback {
+ void onInsertDone();
+}
Added: gnunet-java/src/main/java/org/gnunet/consensus/InsertElementMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/consensus/InsertElementMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/consensus/InsertElementMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,23 @@
+package org.gnunet.consensus;
+
+import org.gnunet.construct.FillWith;
+import org.gnunet.construct.UInt16;
+import org.gnunet.construct.UInt8;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+
+/**
+ * Send an element to the service, insert it into the consensus set.
+ *
+ * Direction: client -> service
+ *
+ * @author Florian Dold
+ */
address@hidden(521)
+public class InsertElementMessage implements GnunetMessage.Body {
+ @UInt16
+ public int element_type;
+ @FillWith
+ @UInt8
+ public byte[] element_data;
+}
\ No newline at end of file
Added: gnunet-java/src/main/java/org/gnunet/consensus/NewElementCallback.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/consensus/NewElementCallback.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/consensus/NewElementCallback.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,5 @@
+package org.gnunet.consensus;
+
+public interface NewElementCallback {
+ void onNewElement(ConsensusElement element);
+}
Added: gnunet-java/src/main/java/org/gnunet/consensus/NewElementMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/consensus/NewElementMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/consensus/NewElementMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,20 @@
+package org.gnunet.consensus;
+
+import org.gnunet.construct.*;
+import org.gnunet.util.GnunetMessage;
+
+/**
+ * Notify the client of a new element.
+ *
+ * Direction: service -> client
+ *
+ * @author Florian Dold
+ */
address@hidden(523)
+public class NewElementMessage implements GnunetMessage.Body {
+ @UInt16
+ public int element_type;
+ @FillWith
+ @UInt8
+ public byte[] element_data;
+}
\ No newline at end of file
Added: gnunet-java/src/main/java/org/gnunet/construct/Construct.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/Construct.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/Construct.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,482 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+import org.gnunet.construct.parsers.*;
+import org.grothoff.Runabout;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.nio.ByteBuffer;
+import java.util.*;
+
+
+/*
+Wanted syntax (not fully implemented yet)
+- @(U)Int<n> => signed or unsigned fixnum, represented by n bits
+- @NestedMessage => nested message
+- @FillWith @(U)Int<n> => fill the rest of the message with the specified
fixnum, annotation valid on primitive arrays
+- @FillWith @NestedMessage => fill the rest of the message with the specified
fixnum, annotation valid on message arrays
+ of the wanted type
+- @VariableSizeArray(lengthField = "<field>") => same syntax as @FillWith
+- @FixedSizeArray(length = n) => same syntax as @FillWith
+- @DoubleValue / @Float => floating point number, should also work with the
array annotations
+- @FrameSize => specifies the fixnum that determines the containing frame's
size
+- @ZeroTerminatedString => self-explanatory
+- @Constructable => annotation on a class that implements the
ConstructableMessage interface,
+ providing methods to serialize/unserialize itself.
+*/
+
+
+/**
+ * Parse and write the binary representation of java classes, as defined by
org.gnunet.construct.*-annotations
+ * on their members.
+ *
+ * @author Christian Grothoff
+ * @author Florian Dold
+ */
address@hidden("unchecked")
+public class Construct {
+ private static final Logger logger = LoggerFactory
+ .getLogger(Construct.class);
+
+
+ private static Map<Class<? extends Message>, Parser> parserCache = new
HashMap<Class<? extends Message>,
+ Parser>(100);
+
+
+ /**
+ * The class Construct is not intended to be instantiated, this its
constructor is private.
+ */
+ private Construct() {
+
+ }
+
+
+ /**
+ * Given a byte buffer with a message, parse it into an object of type c.
The
+ * fields of the class are expected to be annotated with annotations from
+ * the construct package.
+ *
+ * @param srcBuf buffer with the serialized binary data
+ * @param c desired object type to return
+ * @return instance of the desired object type
+ */
+ public static <T extends Message> T parseAs(ByteBuffer srcBuf, Class<T> c)
{
+ T m = ReflectUtil.justInstantiate(c);
+
+ try {
+ getParser(c).parse(srcBuf, 0, m, m, null);
+ } catch (ProtocolViolationException e) {
+ e.augmentPath("on " + c);
+ }
+
+ return m;
+ }
+
+ /**
+ * Given a byte array with a message, parse it into an object of type c.
The
+ * fields of the class are expected to be annotated with annotations from
+ * the construct package.
+ *
+ * @param srcBuf buffer with the serialized binary data
+ * @param c desired object type to return
+ * @return instance of the desired object type
+ */
+ public static <T extends Message> T parseAs(byte[] srcBuf, Class<T> c) {
+ return parseAs(ByteBuffer.wrap(srcBuf), c);
+ }
+
+ /**
+ * Create a Parser for a sub-class of Message. The result is always cached.
+ *
+ * @param c annotated sub-class of message
+ * @return a parser
+ */
+ public static Parser getParser(Class<? extends Message> c) {
+
+ if (parserCache.containsKey(c)) {
+ return parserCache.get(c);
+ }
+
+ Parser p = getParser(c, new ParserGenerator());
+
+ parserCache.put(c, p);
+
+ return p;
+ }
+
+ private static List<Field> getMessageFields(Class c) {
+ LinkedList<Field> fields = new
LinkedList<Field>(Arrays.asList(c.getDeclaredFields()));
+ while ((c = c.getSuperclass()) != null &&
Message.class.isAssignableFrom(c)) {
+ // fields of the superclass have to be parsed *before* the subclass
+ fields.addAll(0, Arrays.asList(c.getDeclaredFields()));
+ }
+ return fields;
+ }
+
+ private static Parser getParser(Class<? extends Message> c,
+ final ParserGenerator pg) {
+
+
+ SequenceParser parser = new SequenceParser();
+
+ if (!Modifier.isPublic(c.getModifiers())) {
+ throw new AssertionError(String.format("Construct Message %s not
declared public", c));
+ }
+
+ for (Field f : getMessageFields(c)) {
+ pg.c = c;
+ Annotation[] as = f.getAnnotations();
+ if (as.length == 0 || f.isSynthetic() ||
Modifier.isStatic(f.getModifiers())) {
+ continue;
+ }
+ if (!Modifier.isPublic(f.getModifiers())) {
+ throw new AssertionError(String.format("Field %s of Message %s
not declared public", f, c));
+ }
+ pg.field = f;
+ pg.annotations = as;
+ pg.annotationsIdx = 0;
+
+ pg.visitAppropriate(as[0]);
+
+ parser.add(pg.parser);
+ }
+
+ parser.setFrameSizePath(pg.frameSizePath);
+
+ return parser;
+ }
+
+ @SuppressWarnings("UnusedDeclaration")
+ static class ParserGenerator extends Runabout {
+
+ // the field we are currently generating a parser for
+ Field field;
+ // all annotations on the field
+ Annotation[] annotations;
+ // the index of the annotation we are supposed to process right now
+ int annotationsIdx;
+
+ // the message class for which the parser is generated
+ Class c;
+
+ // the parser we are actually generating, used by the caller, set as
+ // return value of
+ // the runabout invocation
+ Parser parser;
+
+ // where are we currently, seen from the root message object
+ List<Field> path = new LinkedList<Field>();
+
+ // path of the object that has a frame size field
+ List<Field> frameSizePath;
+
+ private ParserGenerator() {
+ }
+
+ public void visit(Union u) {
+ parser = new UnionParser(u.optional(), (Class<MessageUnion>)
field.getType(),
+ ReflectUtil.getFieldPathFromString(u.tag(), c), field);
+ }
+
+ public void visit(FrameSize ts) {
+
+ frameSizePath = new LinkedList<Field>(path);
+ frameSizePath.add(field);
+
+ if (annotationsIdx != 0) {
+ throw new AssertionError(
+ "FrameSize must be the first annotation on a Field");
+ }
+
+ annotationsIdx++;
+ if (annotationsIdx >= annotations.length) {
+ throw new AssertionError(
+ "FrameSize must be followed by an numeric parser");
+ }
+ visitAppropriate(annotations[annotationsIdx]);
+
+ }
+
+ public void visit(UInt8 i) {
+ parser = new IntegerParser(1, IntegerParser.UNSIGNED, field);
+ }
+
+ public void visit(UInt16 i) {
+ parser = new IntegerParser(2, IntegerParser.UNSIGNED, field);
+ }
+
+ public void visit(UInt32 i) {
+ parser = new IntegerParser(4, IntegerParser.UNSIGNED, field);
+ }
+
+ public void visit(UInt64 i) {
+ parser = new IntegerParser(8, IntegerParser.UNSIGNED, field);
+ }
+
+ public void visit(Int8 i) {
+ parser = new IntegerParser(1, IntegerParser.SIGNED, field);
+ }
+
+ public void visit(Int16 i) {
+ parser = new IntegerParser(2, IntegerParser.SIGNED, field);
+ }
+
+ public void visit(Int32 i) {
+ parser = new IntegerParser(4, IntegerParser.SIGNED, field);
+ }
+
+ public void visit(Int64 i) {
+ parser = new IntegerParser(8, IntegerParser.SIGNED, field);
+ }
+
+
+ public void visit(ZeroTerminatedString zts) {
+ parser = new StringParser(zts.charset(), zts.optional(), field);
+ }
+
+ public void visit(IntegerFill i) {
+ parser = new IntegerFillParser(field, i.signed(), i.bitSize() / 8);
+ }
+
+ public void visit(NestedMessage n) {
+ if (!Message.class.isAssignableFrom(field.getType())) {
+ throw new AssertionError("@NestedMessage only works on
messages, " + field.getType()
+ + " is not a message (origin: " + c + ")");
+ }
+
+ Field nestedField = field;
+
+ if (n.newFrame()) {
+ Parser p = getParser((Class<Message>) nestedField.getType());
+
+ parser = new NestedParser(p, n.optional(), nestedField, true);
+
+ } else {
+ Field old_f = field;
+ List<Field> old_path = new ArrayList<Field>(path);
+ Class old_c = c;
+
+ path.add(field);
+
+ Parser p = getParser((Class<Message>) nestedField.getType(),
this);
+
+ path = old_path;
+ c = old_c;
+
+ parser = new NestedParser(p, n.optional(), old_f, false);
+ }
+ }
+
+ public void visit(FixedSizeArray fsa) {
+ Field f = field;
+ int elemNumber = fsa.length();
+
+ getParser((Class<? extends Message>) field.getType()
+ .getComponentType(), this);
+
+ parser = new FixedSizeArrayParser(elemNumber, parser, f);
+ }
+
+
+ public void visit(FixedSizeIntegerArray fsa) {
+ Field f = field;
+ int elemNumber = fsa.length();
+ parser = new FixedSizeIntegerArrayParser(elemNumber, fsa.signed(),
fsa.bitSize() / 8, f);
+ }
+
+ public void visit(DoubleValue d) {
+ if (!field.getType().equals(java.lang.Double.TYPE)) {
+ throw new AssertionError("@DoubleValue target must be a
primitive 'double' field");
+ }
+ parser = new DoubleParser(field);
+ }
+
+ public void visit(FillWith fw) {
+ annotationsIdx++;
+ // if there's no further annotation, act like there is @Nested
+ if (annotationsIdx >= annotations.length) {
+ Parser p = getParser((Class<? extends Message>)
field.getType().getComponentType());
+ parser = new FillParser(p, field);
+ } else {
+ FillWithParserRunabout r = new FillWithParserRunabout(field);
+ r.visitAppropriate(annotations[annotationsIdx]);
+ if (r.p == null) {
+ throw new AssertionError();
+ }
+ parser = r.p;
+ }
+ }
+
+ public void visit(VariableSizeArray vsa) {
+ Parser p = getParser((Class<? extends Message>) field.getType()
+ .getComponentType());
+
+ if
(!Message.class.isAssignableFrom(field.getType().getComponentType())) {
+ throw new AssertionError("VariableSizeArray only valid on
arrays of messages.");
+ }
+
+ try {
+ parser = new VariableSizeArrayParser(p, c.getField(vsa
+ .lengthField()), field);
+
+ } catch (SecurityException e) {
+ throw new AssertionError(
+ String.format(
+ "VariableSizeArray: length field '%s' not
declared public",
+ vsa.lengthField()));
+ } catch (NoSuchFieldException e) {
+ throw new AssertionError(String.format(
+ "VariableSizeArray: length field '%s' does not exist
in class %s",
+ vsa.lengthField(), c));
+ }
+ }
+
+
+ public void visit(VariableSizeIntegerArray a) {
+ try {
+ parser = new
VariableSizeIntegerArrayParser(c.getField(a.lengthField()), field, a.signed(),
a.bitSize() / 8);
+ } catch (NoSuchFieldException e) {
+ throw new AssertionError(String.format(
+ "VariableSizeIntegerArray: length field '%s' does not
exist in class %s",
+ a.lengthField(), c));
+ }
+ }
+
+ /*
+ * We override this to improve the error message, otherwise obfuscated
by internal java proxy objects
+ */
+ @Override
+ public void visitDefault(Object obj) {
+ if (obj instanceof Annotation) {
+ Annotation ann = (Annotation) obj;
+ throw new AssertionError("invalid Construct annotation: " +
ann.annotationType().getName());
+ } else {
+ throw new AssertionError();
+ }
+ }
+ }
+
+
+ private static class FillWithParserRunabout extends Runabout {
+ public Parser p;
+ private Field f;
+
+ public FillWithParserRunabout(Field f) {
+ this.f = f;
+ }
+
+ public void visit(Int8 x) {
+ p = new IntegerFillParser(f, true, 1);
+ }
+ public void visit(Int16 x) {
+ p = new IntegerFillParser(f, true, 2);
+ }
+ public void visit(Int32 x) {
+ p = new IntegerFillParser(f, true, 4);
+ }
+ public void visit(UInt8 x) {
+ p = new IntegerFillParser(f, false, 1);
+ }
+ public void visit(UInt16 x) {
+ p = new IntegerFillParser(f, false, 2);
+ }
+ public void visit(UInt32 x) {
+ p = new IntegerFillParser(f, false, 4);
+ }
+ public void visit(NestedMessage n) {
+ Parser componentParser = getParser((Class<? extends Message>)
f.getType().getComponentType());
+ p = new FillParser(componentParser, f);
+ }
+
+ }
+
+ /**
+ * Serialize a given message object to a binary byte array. The fields of
+ * the object are expected to be annotated with annotations from the
+ * construct package.
+ *
+ * @param dstBuf where to write the binary object data
+ * @param msg object to serialize
+ * @return number of bytes written to data, -1 on error
+ */
+ public static int write(ByteBuffer dstBuf, Message msg) {
+ Parser p = getParser(msg.getClass());
+ return p.write(dstBuf, msg);
+ }
+
+ /**
+ * Compute the exact size of a serialized message.
+ *
+ * @param m object to serialize
+ * @return number of bytes required to store the message in binary form
+ */
+ public static int getSize(Message m) {
+ if (m == null) {
+ return 0;
+ }
+ Parser p = getParser(m.getClass());
+ return p.getSize(m);
+ }
+
+
+ /**
+ * Return the binary representation of the message m
+ *
+ * @param m the message to serialize
+ * @return a byte array containing the serialized message
+ */
+ public static byte[] toBinary(Message m) {
+ byte[] a = new byte[getSize(m)];
+ ByteBuffer buf = ByteBuffer.wrap(a);
+ write(buf, m);
+ return a;
+ }
+
+ /**
+ * Fill in all fields of a message that are inferable from existing
information.
+ *
+ * Examples: The size field for variable size arrays, the type of unions,
...
+ *
+ * @param m the message that should be patched
+ */
+ public static void patch(Message m) {
+ Parser p = getParser(m.getClass());
+ p.patch(m, p.getSize(m), null, m);
+ }
+
+ /**
+ * Get the minimum static size for the message, determinable even if the
message's members
+ * are not filled in.
+ *
+ * @param m the message of interest
+ * @return the static minimum size of the message
+ */
+ public static int getStaticSize(Message m) {
+ Parser p = getParser(m.getClass());
+ return p.getStaticSize();
+ }
+
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/DoubleValue.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/DoubleValue.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/DoubleValue.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,34 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A number stored in the IEEE 754 double-precision binary floating-point
format.
+ */
address@hidden(RetentionPolicy.RUNTIME)
address@hidden(ElementType.FIELD)
+public @interface DoubleValue {
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/FillWith.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/FillWith.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/FillWith.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,37 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An array of messages filling the rest of the frame
+ *
+ * @author Florian Dold
+ *
+ */
address@hidden(RetentionPolicy.RUNTIME)
address@hidden(ElementType.FIELD)
+public @interface FillWith {
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/FixedSizeArray.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/FixedSizeArray.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/FixedSizeArray.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,37 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An array of messages with static size.
+ *
+ * @author Florian Dold
+ */
address@hidden(RetentionPolicy.RUNTIME)
address@hidden(ElementType.FIELD)
+public @interface FixedSizeArray {
+ int length();
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/FixedSizeIntegerArray.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/FixedSizeIntegerArray.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/FixedSizeIntegerArray.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,21 @@
+package org.gnunet.construct;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * An array of integers with static size.
+ *
+ * @author Florian Dold
+ */
address@hidden(RetentionPolicy.RUNTIME)
address@hidden(ElementType.FIELD)
+public @interface FixedSizeIntegerArray {
+ int length();
+ int bitSize();
+ boolean signed();
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/FrameSize.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/FrameSize.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/FrameSize.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,34 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+import java.lang.annotation.*;
+
+/**
+ * Marker for the field storing the size of the enclosing frame in bytes.
+ *
+ * @author Florian Dold
+ *
+ */
address@hidden(RetentionPolicy.RUNTIME)
address@hidden(ElementType.FIELD)
+public @interface FrameSize {
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/Int16.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/Int16.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/Int16.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,38 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Signed 16-bit integer value.
+ *
+ * @author Florian Dold
+ *
+ */
address@hidden(RetentionPolicy.RUNTIME)
address@hidden(ElementType.FIELD)
+public @interface Int16 {
+
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/Int32.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/Int32.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/Int32.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,38 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Signed 32-bit integer value.
+ *
+ * @author Florian Dold
+ *
+ */
address@hidden(RetentionPolicy.RUNTIME)
address@hidden(ElementType.FIELD)
+public @interface Int32 {
+
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/Int64.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/Int64.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/Int64.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,37 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Signed 64-bit integer value.
+ *
+ */
+
address@hidden(RetentionPolicy.RUNTIME)
address@hidden(ElementType.FIELD)
+public @interface Int64 {
+
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/Int8.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/Int8.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/Int8.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,40 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * Signed 8-bit integer value.
+ *
+ * @author Florian Dold
+ *
+ */
+
address@hidden(RetentionPolicy.RUNTIME)
address@hidden(ElementType.FIELD)
+public @interface Int8 {
+
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/IntegerFill.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/IntegerFill.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/IntegerFill.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,37 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Fills the rest of the message with integers of the specified kind. The
annotation may only be present on the
+ * last serialized field of message.
+ */
address@hidden(RetentionPolicy.RUNTIME)
address@hidden(ElementType.FIELD)
+public @interface IntegerFill {
+ boolean signed();
+ int bitSize();
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/Message.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/Message.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/Message.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,29 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+/**
+ * Base interface for all messages (anything that 'Construct' can serialize or
+ * deserialize). Really just an annotation, but also for sanity checking by the
+ * compiler.
+ */
+public interface Message {
+}
Added:
gnunet-java/src/main/java/org/gnunet/construct/MessageIdAnnotationProcessor.java
===================================================================
---
gnunet-java/src/main/java/org/gnunet/construct/MessageIdAnnotationProcessor.java
(rev 0)
+++
gnunet-java/src/main/java/org/gnunet/construct/MessageIdAnnotationProcessor.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,137 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.Table;
+
+import javax.annotation.processing.*;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic;
+import javax.tools.FileObject;
+import javax.tools.StandardLocation;
+import java.io.IOException;
+import java.io.Writer;
+import java.lang.Integer;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+
+/**
+ * Creates a resource file 'MsgMap.txt' in the package 'org.gnunet.construct'
of the source tree.
+ */
address@hidden("org.gnunet.construct.UnionCase")
address@hidden(SourceVersion.RELEASE_6)
+public class MessageIdAnnotationProcessor extends AbstractProcessor {
+ private final Table<String, Integer, String> idToMember =
HashBasedTable.create();
+
+ @Override
+ public boolean process(Set<? extends TypeElement> typeElements,
RoundEnvironment roundEnvironment) {
+ if (roundEnvironment.errorRaised()) {
+ return false;
+ }
+
+ Types types = processingEnv.getTypeUtils();
+ Elements elements = processingEnv.getElementUtils();
+
+ if (roundEnvironment.processingOver()) {
+ Filer filer = processingEnv.getFiler();
+ FileObject outfile;
+ try {
+ outfile = filer.createResource(StandardLocation.SOURCE_OUTPUT,
"org.gnunet.construct", "MsgMap.txt");
+ } catch (IOException e) {
+
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Could not
create MsgMap.txt");
+ return false;
+ }
+
+ try {
+ Writer w = outfile.openWriter();
+ for (Table.Cell<String, Integer, String> cell :
idToMember.cellSet()) {
+ w.write(cell.getRowKey() + '|' + cell.getColumnKey() + '='
+ cell.getValue() + '\n');
+ }
+
+ DateFormat fmt = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
+
+ w.write("# generated " + fmt.format(new Date()) + '\n');
+ w.close();
+ } catch (IOException e) {
+
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Could not
write MsgMap.txt");
+ }
+
+ processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,
"message map written to " + outfile.toUri());
+
+ } else {
+ for (Element e :
roundEnvironment.getElementsAnnotatedWith(UnionCase.class)) {
+ UnionCase ann = e.getAnnotation(UnionCase.class);
+ // get the uppermost parent class that implements
MessageUnion. This is the union type.
+ // processingEnv.getElementUtils().
+
//processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "element :" +
e.toString());
+ List<? extends TypeMirror> parents =
processingEnv.getTypeUtils().directSupertypes(e.asType());
+ TypeMirror msg =
elements.getTypeElement("org.gnunet.construct.MessageUnion").asType();
+ TypeMirror unionInterface = null;
+ for (TypeMirror p : parents) {
+ if (types.isSubtype(p, msg)) {
+ unionInterface = p;
+ break;
+ }
+ }
+ if (unionInterface == null) {
+
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, String.format(
+ "class %s annotated with @UnionCase does not
implement an interface inheriting MessageUnion", e.getSimpleName()));
+ return false;
+ }
+ String unionName =
getClassName(types.asElement(unionInterface));
+ idToMember.put(unionName, ann.value(), getClassName(e));
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the fully qualified class name, where packages are seperated with
'.', and
+ * inner classes are separated with '$'
+ *
+ * @param e the Element representing a class
+ * @return the fully qualified class name
+ */
+ private String getClassName(Element e) {
+
+ assert e.getKind().isClass();
+
+ String name = e.getSimpleName().toString();
+ String pkg =
processingEnv.getElementUtils().getPackageOf(e).getQualifiedName().toString() +
'.';
+
+ String outer = "";
+
+ while (((e = e.getEnclosingElement()) != null) &&
e.getKind().isClass()) {
+ outer = String.format("%s$%s", e.getSimpleName(), outer);
+ }
+
+ return pkg + outer + name;
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/MessageLoader.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/MessageLoader.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/MessageLoader.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,215 @@
+/*
+ *
+ * This file is part of GNUnet.
+ * (C) 2011 Christian Grothoff (and other contributing authors)
+ *
+ * GNUnet is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNUnet is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNUnet; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+package org.gnunet.construct;
+
+
+import com.google.common.base.Charsets;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * Load message maps, which contain the information the parse/write unions.
+ */
+public class MessageLoader {
+ private static final Logger logger = LoggerFactory
+ .getLogger(MessageLoader.class);
+
+
+ /**
+ * Thrown when a trying to serialize an object that is not registered as a
union type.
+ */
+ public static class UnknownUnionException extends RuntimeException {
+ public UnknownUnionException(String msg) {
+ super(msg);
+ }
+ }
+
+
+ /**
+ * Thrown when parsing a union whose ID is not known.
+ */
+ public static class UnknownUnionIdException extends RuntimeException {
+
+ }
+
+ /**
+ * Maps a class and tag to the corresponding union case.
+ * <p/>
+ * XXX: how much of generics is too much?
+ */
+ private static Map<Class<? extends MessageUnion>, Map<Integer, Class<?
extends MessageUnion>>> unionmap
+ = new HashMap<Class<? extends MessageUnion>, Map<Integer, Class<?
extends MessageUnion>>>(100);
+
+ /*
+ * Maps a union interface and union case to the corresponding tag.
+ */
+ private static Map<Class<? extends MessageUnion>, Map<Class<? extends
MessageUnion>, Integer>> tagmap
+ = new HashMap<Class<? extends MessageUnion>, Map<Class<? extends
MessageUnion>, Integer>>(100);
+
+
+ static {
+ ClassLoader classLoader = MessageLoader.class.getClassLoader();
+ Enumeration<URL> resources;
+ try {
+ resources =
classLoader.getResources("org/gnunet/construct/MsgMap.txt");
+ } catch (IOException e) {
+ throw new RuntimeException("something went wrong with loading
MsgMap.txt");
+ }
+
+ while (resources.hasMoreElements()) {
+ loadMessageMap(resources.nextElement());
+ }
+
+ if (tagmap.isEmpty()) {
+ logger.warn("message map empty");
+ }
+
+ }
+
+ public static void loadMessageMap(URL loc) {
+ if (loc == null) {
+ throw new RuntimeException("could not load message map");
+ }
+ BufferedReader in = null;
+ try {
+ in = new BufferedReader(new InputStreamReader(loc.openStream(),
Charsets.UTF_8));
+ String line;
+ while ((line = in.readLine()) != null) {
+ // skip empty lines and comments
+ if (line.isEmpty() || line.charAt(0) == '#') {
+ continue;
+ }
+ String[] m = line.split("=");
+ if (m.length != 2) {
+ throw new RuntimeException("invalid message map format
(separation by '=')");
+ }
+ String[] left = m[0].split("[|]");
+ if (left.length != 2) {
+ logger.debug(m[0]);
+ logger.debug(m[1]);
+ logger.debug("split in " + left.length);
+ throw new RuntimeException("invalid message map format
(left hand side)");
+ }
+ int id = java.lang.Integer.parseInt(left[1].trim());
+ String unionCaseName = m[1].trim();
+ String unionInterfaceName = left[0];
+
+ Class<? extends MessageUnion> unionInterface =
loadClass(unionInterfaceName);
+ Class<? extends MessageUnion> unionCase =
loadClass(unionCaseName);
+
+ if (!unionmap.containsKey(unionInterface)) {
+ unionmap.put(unionInterface, new HashMap<Integer, Class<?
extends MessageUnion>>(5));
+ }
+ unionmap.get(unionInterface).put(id, unionCase);
+
+
+ if (!tagmap.containsKey(unionInterface)) {
+ tagmap.put(unionInterface, new HashMap<Class<? extends
MessageUnion>, Integer>(5));
+ }
+ tagmap.get(unionInterface).put(unionCase, id);
+
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("could not read message map");
+ } finally {
+ maybeClose(in);
+ }
+ }
+
+ private static void maybeClose(Closeable in) {
+ try {
+ if (in != null) {
+ in.close();
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("error closing stream: " +
e.getMessage());
+ }
+ }
+
+
+ @SuppressWarnings("unchecked")
+ private static Class<? extends MessageUnion> loadClass(String className) {
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ Class<MessageUnion> msgClass;
+ try {
+ msgClass = (Class<MessageUnion>) cl.loadClass(className);
+ } catch (ClassNotFoundException e) {
+ throw new AssertionError(String.format("message class '%s' not
found in classpath", className));
+ } catch (ClassCastException e) {
+ throw new AssertionError(String.format("Class %s does not inherit
from MessageUnion", className));
+ }
+ return msgClass;
+ }
+
+ public static Class<? extends MessageUnion> getUnionClass(Class<? extends
MessageUnion> unionInterface, int tag) {
+ Map<Integer, Class<? extends MessageUnion>> map =
unionmap.get(unionInterface);
+ if (map == null) {
+ throw new UnknownUnionException("don't know how to handle unions
of type '" + unionInterface + "'");
+ }
+
+ Class<? extends MessageUnion> cls = map.get(tag);
+ if (cls == null) {
+ throw new ProtocolViolationException("don't know how to translate
message of type " + tag);
+ }
+
+ return cls;
+ }
+
+
+ public static int getUnionTag(Class<? extends MessageUnion>
unionInterface, Class<? extends MessageUnion> unionCase) {
+ Map<Class<? extends MessageUnion>, Integer> map =
tagmap.get(unionInterface);
+ if (map == null) {
+ throw new AssertionError(String.format("%s is not a known union
type", unionInterface));
+ }
+ if (!map.containsKey(unionCase)) {
+ throw new AssertionError(String.format("%s is not a known instance
of %s", unionCase, unionInterface));
+ }
+ return map.get(unionCase);
+ }
+
+ public static void registerUnionCase(Class<? extends MessageUnion>
unionInterface,
+ Class<? extends MessageUnion>
unionCase, int tag) {
+ if (!unionmap.containsKey(unionInterface)) {
+ unionmap.put(unionInterface, new HashMap<Integer, Class<? extends
MessageUnion>>(5));
+ }
+ unionmap.get(unionInterface).put(tag, unionCase);
+
+
+ if (!tagmap.containsKey(unionInterface)) {
+ tagmap.put(unionInterface, new HashMap<Class<? extends
MessageUnion>, Integer>(5));
+ }
+ tagmap.get(unionInterface).put(unionCase, tag);
+
+
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/MessageUnion.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/MessageUnion.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/MessageUnion.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,27 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+/**
+ * Marker interface for message unions
+ */
+public interface MessageUnion extends Message {
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/MsgMap.txt
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/MsgMap.txt
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/MsgMap.txt 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,46 @@
+org.gnunet.util.Resolver$Address|0=org.gnunet.util.Resolver$TextualAddress
+org.gnunet.util.Resolver$Address|1=org.gnunet.util.Resolver$NumericAddress
+org.gnunet.util.GnunetMessage$Body|68=org.gnunet.core.DisconnectNotifyMessage
+org.gnunet.util.GnunetMessage$Body|274=org.gnunet.mesh.TunnelDestroyMessage
+org.gnunet.util.GnunetMessage$Body|1=org.gnunet.util.TestMessage
+org.gnunet.util.GnunetMessage$Body|70=org.gnunet.core.NotifyInboundTrafficMessage
+org.gnunet.util.GnunetMessage$Body|273=org.gnunet.mesh.TunnelCreateMessage
+org.gnunet.util.GnunetMessage$Body|71=org.gnunet.core.NotifyOutboundTrafficMessage
+org.gnunet.util.GnunetMessage$Body|272=org.gnunet.mesh.ClientConnectMessage
+org.gnunet.util.GnunetMessage$Body|64=org.gnunet.core.InitMessage
+org.gnunet.util.GnunetMessage$Body|4=org.gnunet.util.Resolver$GetMessage
+org.gnunet.util.GnunetMessage$Body|65=org.gnunet.core.InitReplyMessage
+org.gnunet.util.GnunetMessage$Body|5=org.gnunet.util.Resolver$ResolverResponse
+org.gnunet.util.GnunetMessage$Body|143=org.gnunet.dht.ClientGetMessage
+org.gnunet.util.GnunetMessage$Body|67=org.gnunet.core.ConnectNotifyMessage
+org.gnunet.util.GnunetMessage$Body|142=org.gnunet.dht.ClientPutMessage
+org.gnunet.util.GnunetMessage$Body|76=org.gnunet.core.SendMessage
+org.gnunet.util.GnunetMessage$Body|286=org.gnunet.mesh.LocalAckMessage
+org.gnunet.util.GnunetMessage$Body|74=org.gnunet.core.SendMessageRequest
+org.gnunet.util.GnunetMessage$Body|75=org.gnunet.core.SendMessageReady
+org.gnunet.util.GnunetMessage$Body|153=org.gnunet.dht.MonitorStartStop
+org.gnunet.util.GnunetMessage$Body|155=org.gnunet.dht.ClientPutConfirmationMessage
+org.gnunet.util.GnunetMessage$Body|323=org.gnunet.nse.UpdateMessage
+org.gnunet.util.GnunetMessage$Body|260=org.gnunet.mesh.DataMessage
+org.gnunet.util.GnunetMessage$Body|321=org.gnunet.nse.StartMessage
+org.gnunet.util.GnunetMessage$Body|144=org.gnunet.dht.ClientGetStopMessage
+org.gnunet.util.GnunetMessage$Body|145=org.gnunet.dht.ClientResultMessage
+org.gnunet.util.GnunetMessage$Body|332=org.gnunet.peerinfo.InfoMessage
+org.gnunet.util.GnunetMessage$Body|333=org.gnunet.peerinfo.InfoEnd
+org.gnunet.util.GnunetMessage$Body|149=org.gnunet.dht.MonitorGetMessage
+org.gnunet.util.GnunetMessage$Body|331=org.gnunet.peerinfo.ListAllPeersMessage
+org.gnunet.util.GnunetMessage$Body|150=org.gnunet.dht.MonitorGetRespMessage
+org.gnunet.util.GnunetMessage$Body|151=org.gnunet.dht.MonitorPutMessage
+org.gnunet.util.GnunetMessage$Body|171=org.gnunet.statistics.GetResponseEndMessage
+org.gnunet.util.GnunetMessage$Body|170=org.gnunet.statistics.GetResponseMessage
+org.gnunet.util.GnunetMessage$Body|169=org.gnunet.statistics.GetMessage
+org.gnunet.util.GnunetMessage$Body|168=org.gnunet.statistics.SetMessage
+org.gnunet.util.GnunetMessage$Body|374=org.gnunet.transport.RequestConnectMessage
+org.gnunet.util.GnunetMessage$Body|173=org.gnunet.statistics.WatchResponseMessage
+org.gnunet.util.GnunetMessage$Body|172=org.gnunet.statistics.WatchMessage
+org.gnunet.util.GnunetMessage$Body|524=org.gnunet.consensus.ConcludeMessage
+org.gnunet.util.GnunetMessage$Body|521=org.gnunet.consensus.InsertElementMessage
+org.gnunet.util.GnunetMessage$Body|523=org.gnunet.consensus.NewElementMessage
+org.gnunet.util.GnunetMessage$Body|360=org.gnunet.transport.StartMessage
+org.gnunet.construct.MessageUnion|525=org.gnunet.consensus.ConcludeDoneMessage
+# generated 2013/08/22 21:14:59
Added: gnunet-java/src/main/java/org/gnunet/construct/NestedMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/NestedMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/NestedMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,39 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Embed another constructable message.
+ *
+ * @author Florian Dold
+ *
+ */
address@hidden(RetentionPolicy.RUNTIME)
address@hidden(ElementType.FIELD)
+public @interface NestedMessage {
+ boolean newFrame() default false;
+ boolean optional() default false;
+}
\ No newline at end of file
Added:
gnunet-java/src/main/java/org/gnunet/construct/ProtocolViolationException.java
===================================================================
---
gnunet-java/src/main/java/org/gnunet/construct/ProtocolViolationException.java
(rev 0)
+++
gnunet-java/src/main/java/org/gnunet/construct/ProtocolViolationException.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,40 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+
+import java.util.LinkedList;
+
+/**
+ * Thrown when a received message is invalid.
+ *
+ * @author Florian Dold
+ *
+ */
+public class ProtocolViolationException extends RuntimeException {
+ public ProtocolViolationException(String s) {
+ super(s);
+ }
+
+ public ProtocolViolationException augmentPath(String pathMessage) {
+ return new ProtocolViolationException(this.getMessage() + "\n" +
pathMessage);
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/ReflectUtil.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/ReflectUtil.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/ReflectUtil.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,297 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+
+import java.lang.Integer;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utilities for convenient use of the java reflection API.
+ * All methods only throw non-checked exceptions.
+ */
+public class ReflectUtil {
+ public static <T> T justInstantiate(Class<T> c) {
+ try {
+ return c.getConstructor().newInstance();
+ } catch (InstantiationException e) {
+ throw new AssertionError("Cannot instantiate " + c);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError(
+ String.format("Cannot instantiate Message %s (illegal
access)", c));
+ } catch (NoSuchMethodException e) {
+ if (c.isMemberClass()) {
+ throw new AssertionError(String.format("Can not instantiate
non-static member class %s", c));
+ } else {
+ throw new AssertionError(
+ String.format("No suitable default constructor for
class %s", c));
+ }
+ } catch (InvocationTargetException e) {
+ throw new AssertionError(
+ String.format("Exception thrown while constructing object
of class %s", c));
+ }
+ }
+
+ public static void justSetArray(Object arr, int i, long v) {
+ Class t = arr.getClass().getComponentType();
+ if (t.equals(Long.TYPE)) {
+ Array.setLong(arr, i, v);
+ } else if (t.equals(Integer.TYPE)) {
+ Array.setInt(arr, i, (int) v);
+ } else if (t.equals(Short.TYPE)) {
+ Array.setShort(arr, i, (short) v);
+ } else if (t.equals(Byte.TYPE)) {
+ Array.setByte(arr, i, (byte) v);
+ } else if (t.equals(Character.TYPE)) {
+ Array.setChar(arr, i, (char) v);
+ }
+ }
+
+ public static long justGetArrayLong(Object arr, int i) {
+ return Array.getLong(arr, i);
+ }
+
+ /**
+ * An enumeration of all built-in type that can store integers.
+ */
+ public enum NumFieldType {
+ BIGNUM, BYTE_PRIM, SHORT_PRIM, INT_PRIM, LONG_PRIM, CHAR_PRIM
+ }
+
+ /**
+ * Convenience wrapper for a field that stores a numeric value.
+ */
+ public static class NumField {
+ final private Field targetField;
+ final private NumFieldType targetType;
+
+
+ public NumFieldType getNumFieldType() {
+ return targetType;
+ }
+
+ public NumField(Field f) {
+ this.targetField = f;
+ if (f.getType().equals(Long.TYPE)) {
+ targetType = NumFieldType.LONG_PRIM;
+ } else if (f.getType().equals(Integer.TYPE)) {
+ targetType = NumFieldType.INT_PRIM;
+ } else if (f.getType().equals(Short.TYPE)) {
+ targetType = NumFieldType.SHORT_PRIM;
+ } else if (f.getType().equals(Byte.TYPE)) {
+ targetType = NumFieldType.BYTE_PRIM;
+ } else if (f.getType().equals(Character.TYPE)) {
+ targetType = NumFieldType.CHAR_PRIM;
+ } else if (f.getType().equals(BigInteger.class)) {
+ targetType = NumFieldType.BIGNUM;
+ } else {
+ throw new AssertionError(
+ "expected numeric type, got: " + f.getType());
+ }
+ }
+
+ public void set(Object obj, long val) {
+ try {
+ switch (targetType) {
+ case LONG_PRIM:
+ targetField.setLong(obj, val);
+ break;
+ case INT_PRIM:
+ targetField.setInt(obj, (int) val);
+ break;
+ case SHORT_PRIM:
+ targetField.setShort(obj, (short) val);
+ break;
+ case BYTE_PRIM:
+ targetField.setByte(obj, (byte) val);
+ break;
+ case CHAR_PRIM:
+ targetField.setChar(obj, (char) val);
+ break;
+ case BIGNUM:
+ targetField.set(obj, BigInteger.valueOf(val));
+ break;
+ }
+ } catch (IllegalArgumentException e) {
+ throw new AssertionError("cannot access field");
+ } catch (IllegalAccessException e) {
+ throw new AssertionError("cannot access field");
+ }
+ }
+
+ public void set(Object obj, BigInteger val) {
+ try {
+ targetField.set(obj, val);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError("cannot access field");
+ }
+ }
+
+ public long get(Object obj) {
+ try {
+ switch (targetType) {
+ case LONG_PRIM:
+ return targetField.getLong(obj);
+ case INT_PRIM:
+ return targetField.getInt(obj);
+ case SHORT_PRIM:
+ return targetField.getShort(obj);
+ case BYTE_PRIM:
+ return targetField.getByte(obj);
+ case CHAR_PRIM:
+ return targetField.getChar(obj);
+ case BIGNUM:
+ throw new RuntimeException("get() called on NumField
that is a BigInteger");
+ default:
+ throw new AssertionError("unreachable");
+ }
+ } catch (IllegalAccessException e) {
+ throw new AssertionError("cannot access field");
+ }
+ }
+
+ public BigInteger getBig(Object obj) {
+ if (isBig()) {
+ return (BigInteger) justGet(obj, targetField);
+ } else {
+ return BigInteger.valueOf(this.get(obj));
+ }
+ }
+
+ public boolean isBig() {
+ return targetType.equals(NumFieldType.BIGNUM);
+ }
+ }
+
+
+ public static Object followFieldPath(List<Field> fl, Object obj,
+ int depth) {
+ for (int i = 0; i < depth; ++i) {
+ try {
+ obj = fl.get(i).get(obj);
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError("cannot access field " + fl.get(i)
+ + " of " + obj.getClass());
+ }
+ }
+ return obj;
+ }
+
+ public static Object followFieldPath(List<Field> fl, Object obj) {
+ return followFieldPath(fl, obj, fl.size());
+ }
+
+ public static Object followFieldPathToParent(List<Field> fl, Object obj) {
+ return followFieldPath(fl, obj, fl.size() - 1);
+ }
+
+ public static Object justGet(Object obj, Field f) {
+ try {
+ return f.get(obj);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError(
+ String.format("Cannot access private field '%s' in class
%s", f, obj.getClass()));
+ } catch (IllegalArgumentException e) {
+ throw new AssertionError("Cannot access field '" + f.getName() +
"' in class " + obj.getClass());
+ }
+ }
+
+ public static void justSet(Object obj, Field f, Object val) {
+ try {
+ f.set(obj, val);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError(
+ String.format("Cannot access private field %s in class
%s", f, obj.getClass()));
+ }
+ }
+
+
+ public static int justGetInt(Object obj, List<Field> path) {
+ for (int i = 0; i < path.size() - 1; ++i) {
+ try {
+ obj = path.get(i).get(obj);
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError("cannot access field " + path.get(i)
+ + " of " + obj.getClass());
+ }
+ }
+
+ try {
+ return path.get(path.size() - 1).getInt(obj);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError("cannot access field " +
path.get(path.size() - 1)
+ + " of " + obj.getClass());
+ }
+ }
+
+ public static void justSetInt(Object obj, List<Field> path, int val) {
+ for (int i = 0; i < path.size() - 1; ++i) {
+ try {
+ obj = path.get(i).get(obj);
+
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError("cannot access field " + path.get(i)
+ + " of " + obj.getClass());
+ }
+ }
+
+ try {
+ path.get(path.size() - 1).setInt(obj, val);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError("cannot access field " +
path.get(path.size() - 1)
+ + " of " + obj.getClass());
+ }
+ }
+
+
+ public static List<Field> getFieldPathFromString(final String p, final
Class root) {
+ Class current = root;
+
+ String[] components = p.split("[.]");
+
+ List<Field> fp = new ArrayList<Field>(components.length);
+ for (String member : components) {
+ Field f;
+ try {
+ f = current.getField(member);
+ } catch (NoSuchFieldException e) {
+ throw new AssertionError("invalid field path, component " +
member + " not found");
+ }
+
+ fp.add(f);
+
+ current = f.getType();
+ }
+
+ return fp;
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/UInt16.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/UInt16.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/UInt16.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,40 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * Unsigned 16-bit integer value
+ *
+ * @author Florian Dold
+ *
+ */
+
address@hidden(RetentionPolicy.RUNTIME)
address@hidden(ElementType.FIELD)
+public @interface UInt16 {
+
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/UInt32.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/UInt32.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/UInt32.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,39 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Unsigned 32-bit integer value
+ *
+ * @author Florian Dold
+ *
+ */
+
address@hidden(RetentionPolicy.RUNTIME)
address@hidden(ElementType.FIELD)
+public @interface UInt32 {
+
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/UInt64.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/UInt64.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/UInt64.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,39 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Unsigned 64-bit integer value
+ *
+ * @author Florian Dold
+ *
+ */
+
address@hidden(RetentionPolicy.RUNTIME)
address@hidden(ElementType.FIELD)
+public @interface UInt64 {
+
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/UInt8.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/UInt8.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/UInt8.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,41 @@
+
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * Unsigned 8-bit integer value.
+ *
+ * @author Florian Dold
+ *
+ */
+
address@hidden(RetentionPolicy.RUNTIME)
address@hidden(ElementType.FIELD)
+public @interface UInt8 {
+
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/Union.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/Union.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/Union.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,37 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A field that stores a union, whose cases are discriminated by the field
specified with address@hidden tag}.
+ */
address@hidden(ElementType.FIELD)
address@hidden(RetentionPolicy.RUNTIME)
+public @interface Union {
+ String tag();
+ boolean optional() default false;
+}
\ No newline at end of file
Added: gnunet-java/src/main/java/org/gnunet/construct/UnionCase.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/UnionCase.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/UnionCase.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,39 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for messages that are a case of a union, with a distinct value
to discriminate the case.
+ *
+ * Classes annotated by address@hidden UnionCase} should implement
+ * the marker interface for their respective union type.
+ */
address@hidden(RetentionPolicy.SOURCE)
address@hidden(ElementType.TYPE)
+public @interface UnionCase {
+ int value();
+}
\ No newline at end of file
Added: gnunet-java/src/main/java/org/gnunet/construct/VariableSizeArray.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/VariableSizeArray.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/VariableSizeArray.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,39 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An array of messages, where the length of the array is specified in a
+ * field of the containing message.
+ *
+ * @author Florian Dold
+ *
+ */
address@hidden(RetentionPolicy.RUNTIME)
address@hidden(ElementType.FIELD)
+public @interface VariableSizeArray {
+ String lengthField();
+}
Added:
gnunet-java/src/main/java/org/gnunet/construct/VariableSizeIntegerArray.java
===================================================================
---
gnunet-java/src/main/java/org/gnunet/construct/VariableSizeIntegerArray.java
(rev 0)
+++
gnunet-java/src/main/java/org/gnunet/construct/VariableSizeIntegerArray.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,41 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An array of integers, where the length of the array is specified in a
+ * field of the containing message.
+ *
+ * @author Florian Dold
+ *
+ */
address@hidden(RetentionPolicy.RUNTIME)
address@hidden(ElementType.FIELD)
+public @interface VariableSizeIntegerArray {
+ String lengthField();
+ boolean signed();
+ int bitSize();
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/ZeroTerminatedString.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/ZeroTerminatedString.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/ZeroTerminatedString.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,37 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A zero-terminated string with the specified encoding.
+ * The default encoding is UTF-8.
+ *
+ * @author Florian Dold
+ *
+ */
address@hidden(RetentionPolicy.RUNTIME)
+public @interface ZeroTerminatedString {
+ String charset() default "UTF-8";
+ boolean optional() default false;
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/package-info.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/package-info.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/package-info.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,24 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * Write and read an object's binary representation, as determined by its
members annotations.
+ */
+package org.gnunet.construct;
Added: gnunet-java/src/main/java/org/gnunet/construct/parsers/DoubleParser.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/parsers/DoubleParser.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/parsers/DoubleParser.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,75 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct.parsers;
+
+
+import org.gnunet.construct.Message;
+
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+public class DoubleParser implements Parser {
+
+ private final Field targetField;
+
+ public DoubleParser(Field f) {
+ targetField = f;
+ }
+
+ @Override
+ public int getSize(Message srcObj) {
+ return Double.SIZE / 8;
+ }
+
+ @Override
+ public int parse(ByteBuffer srcBuf, int frameOffset, Message frameObj,
Message dstObj, List<Field> frameSizePath) {
+ double d = srcBuf.getDouble();
+ try {
+ targetField.setDouble(dstObj, d);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError("cannot access field (should have been
caught in Construct)");
+ }
+ return Double.SIZE / 8;
+ }
+
+ @Override
+ public int write(ByteBuffer dstBuf, Message srcObj) {
+ double d;
+ try {
+ d = targetField.getDouble(srcObj);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError("field does not exist (should be caught
in Construct)");
+ }
+ dstBuf.putDouble(d);
+ return 8;
+ }
+
+ @Override
+ public void patch(Message m, int frameSize, List<Field> frameSizePath,
Message frameObj) {
+ // nothing to do here
+ }
+
+ @Override
+ public int getStaticSize() {
+ return Double.SIZE / 8;
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/parsers/FillParser.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/parsers/FillParser.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/parsers/FillParser.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,126 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct.parsers;
+
+import org.gnunet.construct.Message;
+import org.gnunet.construct.ReflectUtil;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Parse an array that takes up all the available space.
+ *
+ * @author Florian Dold
+ */
+public class FillParser implements Parser {
+ private final Parser elemParser;
+
+ private final Field targetField;
+
+ public FillParser(Parser p, Field field) {
+ targetField = field;
+ elemParser = p;
+ }
+
+ @Override
+ public int getSize(final Message src) {
+ int size = 0;
+ final Object arr = ReflectUtil.justGet(src, targetField);
+
+ if (arr == null) {
+ throw new RuntimeException("array not initialized");
+ }
+
+ for (int i = 0; i < Array.getLength(arr); ++i) {
+ size += elemParser.getSize((Message) Array.get(arr, i));
+ }
+ return size;
+ }
+
+ @Override
+ public int parse(ByteBuffer srcBuf, int frameOffset,
+ Message frameObj, final Message dstObj, List<Field>
frameSizePath) {
+
+ if (frameSizePath == null) {
+ throw new AssertionError("FillParser expects a non-null
frameSizePath. Does the message have a @FrameSizePath annotation?");
+ }
+
+
+
+ final int frameSize = ReflectUtil.justGetInt(dstObj, frameSizePath);
+ int remaining = frameOffset + frameSize - srcBuf.position();
+ int size = 0;
+
+ Class<?> elemType = targetField.getType().getComponentType();
+
+
+ ArrayList<Message> list = new ArrayList<Message>(10);
+
+ while (remaining > 0) {
+ @SuppressWarnings("unchecked")
+ Message next = ReflectUtil.justInstantiate((Class<Message>)
targetField.getType().getComponentType());
+ int s = elemParser.parse(srcBuf, frameOffset, frameObj, next,
null);
+ size += s;
+ remaining -= s;
+ list.add(next);
+ }
+
+ Object arr = Array.newInstance(elemType, list.size());
+
+ try {
+ targetField.set(dstObj, list.toArray((Object[]) arr));
+ } catch (IllegalAccessException e) {
+ throw new AssertionError("cannot access field");
+ }
+
+ return size;
+ }
+
+ @Override
+ public int write(final ByteBuffer dstBuf, final Message src) {
+ int size = 0;
+ final Object arr = ReflectUtil.justGet(src, targetField);
+ for (int i = 0; i < Array.getLength(arr); ++i) {
+ size += elemParser.write(dstBuf, (Message) Array.get(arr, i));
+ }
+ return size;
+ }
+
+ @Override
+ public void patch(Message m, int frameSize, List<Field> frameSizePath,
Message frameObj) {
+ if (frameSizePath == null) {
+ throw new AssertionError();
+ }
+ ReflectUtil.justSetInt(frameObj, frameSizePath, frameSize);
+
+ // todo: patch nested messages
+ }
+
+ @Override
+ public int getStaticSize() {
+ // not known
+ return 0;
+ }
+
+}
Added:
gnunet-java/src/main/java/org/gnunet/construct/parsers/FixedSizeArrayParser.java
===================================================================
---
gnunet-java/src/main/java/org/gnunet/construct/parsers/FixedSizeArrayParser.java
(rev 0)
+++
gnunet-java/src/main/java/org/gnunet/construct/parsers/FixedSizeArrayParser.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,106 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct.parsers;
+
+import org.gnunet.construct.Message;
+import org.gnunet.construct.ReflectUtil;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+public class FixedSizeArrayParser implements Parser {
+
+ private final Parser elemParser;
+
+ private final Field targetField;
+
+ private final int elemNumber;
+
+ public FixedSizeArrayParser(final int elemNumber,
+ final Parser elemParser, final Field f) {
+ targetField = f;
+ this.elemNumber = elemNumber;
+ this.elemParser = elemParser;
+ }
+
+ @Override
+ public int getSize(final Message srcObj) {
+ int size = 0;
+ final Object arr = ReflectUtil.justGet(srcObj, targetField);
+
+ if (arr == null) {
+ throw new RuntimeException("array not initialized");
+ }
+
+ for (int i = 0; i < Array.getLength(arr); ++i) {
+ size += elemParser.getSize((Message) Array.get(arr, i));
+ }
+ return size;
+ }
+
+ @Override
+ public int parse(ByteBuffer srcBuf, int frameOffset,
+ Message frameObj, final Message dstObj, List<Field>
frameSizePath) {
+ int size = 0;
+
+ final Object arr =
Array.newInstance(targetField.getType().getComponentType(), elemNumber);
+ ReflectUtil.justSet(dstObj, targetField, arr);
+
+ for (int i = 0; i < elemNumber; ++i) {
+ @SuppressWarnings("unchecked")
+ Message elemObj =
ReflectUtil.justInstantiate((Class<Message>)targetField.getType().getComponentType());
+ Array.set(arr, i, elemObj);
+
+ size += elemParser.parse(srcBuf, frameOffset - size, frameObj,
elemObj, null);
+ }
+
+ return size;
+ }
+
+ @Override
+ public int write(final ByteBuffer dstBuf,
+ final Message srcObj) {
+ int size = 0;
+ final Object arr = ReflectUtil.justGet(srcObj, targetField);
+ if (Array.getLength(arr) != elemNumber) {
+ throw new AssertionError("wrong number of elements");
+ }
+ for (int i = 0; i < Array.getLength(arr); ++i) {
+ size += elemParser.write(dstBuf, (Message) Array.get(arr, i));
+ }
+ return size;
+ }
+
+ @Override
+ public void patch(Message m, int frameSize, List<Field> frameSizePath,
Message frameObj) {
+ final Object arr = ReflectUtil.justGet(m, targetField);
+ for (int i = 0; i < Array.getLength(arr); ++i) {
+ elemParser.patch((Message) Array.get(arr, i), frameSize, null,
frameObj);
+ }
+ }
+
+ @Override
+ public int getStaticSize() {
+ return elemNumber * elemParser.getStaticSize();
+ }
+}
Added:
gnunet-java/src/main/java/org/gnunet/construct/parsers/FixedSizeIntegerArrayParser.java
===================================================================
---
gnunet-java/src/main/java/org/gnunet/construct/parsers/FixedSizeIntegerArrayParser.java
(rev 0)
+++
gnunet-java/src/main/java/org/gnunet/construct/parsers/FixedSizeIntegerArrayParser.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,106 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct.parsers;
+
+import org.gnunet.construct.Message;
+import org.gnunet.construct.ProtocolViolationException;
+import org.gnunet.construct.ReflectUtil;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+public class FixedSizeIntegerArrayParser implements Parser {
+
+ private final int byteSize;
+ private final boolean signed;
+
+ private final Field targetField;
+
+ private final int elemNumber;
+
+ public FixedSizeIntegerArrayParser(final int elemNumber, boolean signed,
int byteSize, final Field f) {
+ targetField = f;
+ this.elemNumber = elemNumber;
+ this.signed = signed;
+ this.byteSize = byteSize;
+ }
+
+ @Override
+ public int getSize(final Message srcObj) {
+ return byteSize * elemNumber;
+ }
+
+ @Override
+ public int parse(ByteBuffer srcBuf, int frameOffset,
+ Message frameObj, final Message dstObj, List<Field>
frameSizePath) {
+ int size = 0;
+
+ @SuppressWarnings("unchecked")
+ final Class<Message> arrayElementType = (Class<Message>)
targetField.getType().getComponentType();
+
+ if (!arrayElementType.isPrimitive()) {
+ throw new AssertionError("IntegerFillParser is expected to be of
primitive type, not " + arrayElementType);
+ }
+
+ final Object arr =
Array.newInstance(targetField.getType().getComponentType(), elemNumber);
+ ReflectUtil.justSet(dstObj, targetField, arr);
+
+ for (int i = 0; i < elemNumber; ++i) {
+ long v;
+ try {
+ v = IntegerUtil.readLong(srcBuf, signed, byteSize);
+ } catch (BufferUnderflowException e) {
+ throw new ProtocolViolationException("fixed size array
underflow: " + targetField.toString());
+ }
+ ReflectUtil.justSetArray(arr, i, v);
+ }
+
+ return size;
+ }
+
+ @Override
+ public int write(final ByteBuffer dstBuf,
+ final Message srcObj) {
+ int size = 0;
+ final Object arr = ReflectUtil.justGet(srcObj, targetField);
+ if (Array.getLength(arr) != elemNumber) {
+ throw new AssertionError("wrong number of elements");
+ }
+ for (int i = 0; i < Array.getLength(arr); ++i) {
+ IntegerUtil.writeLong(Array.getLong(arr, i), dstBuf, signed,
byteSize);
+ size += byteSize;
+ }
+ return size;
+ }
+
+ @Override
+ public void patch(Message m, int frameSize, List<Field> frameSizePath,
Message frameObj) {
+ // nothing to patch!
+ }
+
+ @Override
+ public int getStaticSize() {
+ return elemNumber * byteSize;
+ }
+}
Added:
gnunet-java/src/main/java/org/gnunet/construct/parsers/IntegerFillParser.java
===================================================================
---
gnunet-java/src/main/java/org/gnunet/construct/parsers/IntegerFillParser.java
(rev 0)
+++
gnunet-java/src/main/java/org/gnunet/construct/parsers/IntegerFillParser.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,113 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct.parsers;
+
+import org.gnunet.construct.Message;
+import org.gnunet.construct.ReflectUtil;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+public class IntegerFillParser implements Parser {
+ private final Field targetField;
+ private final boolean signed;
+ private final int byteSize;
+
+ public IntegerFillParser(Field targetField,
+ boolean signed, int byteSize) {
+
+ this.targetField = targetField;
+ this.signed = signed;
+ this.byteSize = byteSize;
+ }
+
+
+ @Override
+ public int getSize(Message srcObj) {
+ final Object arr = ReflectUtil.justGet(srcObj, targetField);
+
+ if (arr == null) {
+ throw new RuntimeException("array not initialized");
+ }
+
+ return byteSize * Array.getLength(arr);
+ }
+
+ @Override
+ public int parse(ByteBuffer srcBuf, int frameStart, Message frameObj,
Message dstObj, List<Field> frameSizePath) {
+ if (frameSizePath == null) {
+ throw new AssertionError("IntegerFillParser expects a non-null
frameSizePath. Did you specify a @FrameSize field?");
+ }
+ final int frameSize = ReflectUtil.justGetInt(frameObj, frameSizePath);
+ int remaining = frameStart + frameSize - srcBuf.position();
+
+ int elemNumber = remaining / byteSize;
+
+ @SuppressWarnings("unchecked")
+ final Class<Message> arrayElementType = (Class<Message>)
targetField.getType().getComponentType();
+
+ if (!arrayElementType.isPrimitive()) {
+ throw new AssertionError("IntegerFillParser is expected to be of
primitive type, not " + arrayElementType);
+ }
+
+ final Object arr = Array.newInstance(arrayElementType, elemNumber);
+ ReflectUtil.justSet(dstObj, targetField, arr);
+
+
+ for (int i = 0; i < elemNumber; ++i) {
+ long v = IntegerUtil.readLong(srcBuf, signed, byteSize);
+ ReflectUtil.justSetArray(arr, i, v);
+ }
+
+ return remaining;
+ }
+
+ @Override
+ public int write(ByteBuffer dstBuf, Message srcObj) {
+ final Object arr = ReflectUtil.justGet(srcObj, targetField);
+
+ if (arr == null) {
+ throw new RuntimeException("array not initialized");
+ }
+
+ for (int i = 0; i < Array.getLength(arr); ++i) {
+ IntegerUtil.writeLong(Array.getLong(arr, i), dstBuf, signed,
byteSize);
+ }
+
+ return getSize(srcObj);
+ }
+
+ @Override
+ public void patch(Message m, int frameSize, List<Field> frameSizePath,
Message frameObj) {
+ if (frameSizePath == null) {
+ throw new AssertionError("IntegerFillParser expects a non-null
frameSizePath. Did you specify a @FrameSize field?");
+ }
+ ReflectUtil.justSetInt(frameObj, frameSizePath, frameSize);
+ }
+
+ @Override
+ public int getStaticSize() {
+ // not known
+ return 0;
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/parsers/IntegerParser.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/parsers/IntegerParser.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/parsers/IntegerParser.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,95 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct.parsers;
+
+import org.gnunet.construct.Message;
+import org.gnunet.construct.ReflectUtil;
+
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+/**
+ *
+ * todo: error checking on numeric overflow
+ */
+public class IntegerParser implements Parser {
+
+ public static final boolean UNSIGNED = false;
+ public static final boolean SIGNED = true;
+
+ private final int byteSize;
+
+ private final boolean isSigned;
+
+ private final ReflectUtil.NumField targetField;
+
+
+ public IntegerParser(final int byteSize, final boolean isSigned,
+ final Field f) {
+ this.byteSize = byteSize;
+ this.isSigned = isSigned;
+
+ targetField = new ReflectUtil.NumField(f);
+ }
+
+ @Override
+ public int getSize(final Message srcObj) {
+ return byteSize;
+ }
+
+ @Override
+ public int parse(final ByteBuffer srcBuf, int frameOffset, Message
frameObj, final Message dstObj, List<Field>
+ frameSizePath) {
+ if (targetField.isBig()) {
+ targetField.set(dstObj, IntegerUtil.readBigInteger(srcBuf,
isSigned, byteSize));
+ } else {
+ targetField.set(dstObj, IntegerUtil.readLong(srcBuf, isSigned,
byteSize));
+ }
+ return byteSize;
+ }
+
+ @Override
+ public int write(final ByteBuffer dstBuf, final Message srcObj) {
+ if (targetField.isBig()) {
+ IntegerUtil.writeBitInteger(targetField.getBig(srcObj), dstBuf,
isSigned, byteSize);
+ } else {
+ // todo: error checking on numeric overflow, if requested
+ IntegerUtil.writeLong(targetField.get(srcObj), dstBuf, isSigned,
byteSize);
+ }
+ return byteSize;
+ }
+
+ @Override
+ public void patch(Message m, int frameSize, List<Field> frameSizePath,
Message frameObj) {
+ // todo: optimize this!
+ /*
+ if (frameSizePath != null) {
+ ReflectUtil.justSetInt(frameObj, frameSizePath, frameSize);
+ }
+ */
+ }
+
+ @Override
+ public int getStaticSize() {
+ return byteSize;
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/parsers/IntegerUtil.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/parsers/IntegerUtil.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/parsers/IntegerUtil.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,92 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct.parsers;
+
+
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+
+public class IntegerUtil {
+ public static long readLong(ByteBuffer srcBuf, boolean isSigned, int
byteSize) {
+ long val = 0;
+
+ final int first = srcBuf.position();
+ final int last = first + byteSize - 1;
+
+ // read all bytes except the last
+ while (srcBuf.position() != last) {
+ byte b = srcBuf.get();
+ // byte b may be signed, if so interpret it as unsigned byte;
store it in an int
+ int s = b >= 0 ? b : (256 + b);
+
+ val |= s;
+ val <<= 8;
+ }
+
+ // read the last byte, we don't have to shift val after that
+ byte b = srcBuf.get();
+ int s = b >= 0 ? b : (256 + b);
+ val |= s;
+
+ if (isSigned) {
+ // explicitly OR sign bit to the right place if the source buffer
is
+ // too large
+ long sign = (srcBuf.get(first) & 0x80);
+ val |= (sign << 7);
+ }
+
+ return val;
+ }
+
+ public static void writeLong(final long val, final ByteBuffer dstBuf,
boolean isSigned, int byteSize) {
+ long myval = val;
+
+ // position of the last byte we are responsible to write
+ int last = dstBuf.position() + byteSize - 1;
+
+ while (last >= dstBuf.position()) {
+ dstBuf.put(last, (byte) (myval & 0xFF));
+ myval >>>= 8;
+ last -= 1;
+ }
+
+ if (isSigned) {
+ // a long has 8 bytes, shift by 7 bytes (non-arithmetically) to
get the sign
+ byte sign = (byte) ((val >>> (7*8)) & 0x80);
+ // remove the sign bit from the buffer
+ dstBuf.put(dstBuf.position() + byteSize - 1, (byte)
(dstBuf.get(dstBuf.position() + byteSize - 1) & ~sign));
+ // ... and put it in the right place (lowest byte)
+ dstBuf.put(dstBuf.position(), (byte)
(dstBuf.get(dstBuf.position()) | sign));
+
+ }
+
+ dstBuf.position(dstBuf.position() + byteSize);
+ }
+
+
+ public static void writeBitInteger(BigInteger big, ByteBuffer dstBuf,
boolean isSigned, int byteSize) {
+ throw new UnsupportedOperationException("not yet implemented");
+ }
+
+ public static BigInteger readBigInteger(final ByteBuffer srcBuf, boolean
isSigned, int byteSize) {
+ throw new UnsupportedOperationException("not yet implemented");
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/parsers/NestedParser.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/parsers/NestedParser.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/parsers/NestedParser.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,119 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct.parsers;
+
+import org.gnunet.construct.Message;
+import org.gnunet.construct.ProtocolViolationException;
+import org.gnunet.construct.ReflectUtil;
+
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+
+public class NestedParser implements Parser {
+ private final Field targetField;
+
+ private final Parser nestedParser;
+ private boolean newFrame;
+
+ boolean optional;
+
+ public NestedParser(final Parser p, boolean optional, final Field f,
boolean newFrame) {
+ targetField = f;
+ this.optional = optional;
+ this.nestedParser = p;
+ this.newFrame = newFrame;
+ }
+
+ @Override
+ public int getSize(final Message src) {
+ Message inner = (Message) ReflectUtil.justGet(src, targetField);
+ if (inner == null) {
+ if (optional)
+ return 0;
+ throw new AssertionError(String.format("empty non-optional nested
message in field '%s'", targetField));
+ }
+ return nestedParser.getSize(inner);
+ }
+
+ @Override
+ public int parse(final ByteBuffer srcBuf, int frameOffset, Message
frameObj, final Message dstObj, List<Field>
+ frameSizePath) {
+ if (newFrame) {
+ frameObj = dstObj;
+ frameOffset = 0;
+ }
+
+ if (optional) {
+ if (frameSizePath == null) {
+ throw new AssertionError("optional nested message needs
@FrameSize");
+ }
+
+ int remaining = frameOffset + ReflectUtil.justGetInt(frameObj,
frameSizePath) - srcBuf.position();
+ if (remaining < 0) {
+ throw new ProtocolViolationException("remaining size
negative");
+ }
+ if (remaining == 0) {
+ if (!optional) {
+ throw new ProtocolViolationException("not optional");
+ }
+ ReflectUtil.justSet(dstObj, targetField, null);
+ return 0;
+ }
+ }
+
+ ReflectUtil.justSet(dstObj, targetField,
ReflectUtil.justInstantiate(targetField.getType()));
+
+ try {
+ return nestedParser.parse(srcBuf, frameOffset,
+ frameObj, (Message) ReflectUtil.justGet(dstObj, targetField),
frameSizePath);
+ } catch (ProtocolViolationException e) {
+ throw e.augmentPath("nested parser on " + targetField.toString());
+ }
+ }
+
+ @Override
+ public int write(final ByteBuffer dstBuf, final Message src) {
+ Object nestedMessage = ReflectUtil.justGet(src, targetField);
+ if (nestedMessage == null) {
+ return 0;
+ }
+ return nestedParser.write(dstBuf, (Message) nestedMessage);
+ }
+
+ @Override
+ public void patch(Message m, int frameSize, List<Field> frameSizePath,
Message frameObj) {
+ Message nestedMessage = (Message) ReflectUtil.justGet(m, targetField);
+
+ if (newFrame) {
+ nestedParser.patch(nestedMessage,
nestedParser.getSize(nestedMessage), null, nestedMessage);
+ } else {
+ nestedParser.patch(nestedMessage, frameSize, frameSizePath,
frameObj);
+ }
+ }
+
+ @Override
+ public int getStaticSize() {
+ return nestedParser.getStaticSize();
+ }
+
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/parsers/Parser.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/parsers/Parser.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/parsers/Parser.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,78 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct.parsers;
+
+import org.gnunet.construct.Message;
+
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+
+public interface Parser {
+ /**
+ * Compute the exact size of the object's binary representation in bytes.
+ *
+ * @param srcObj a message object with all fields filled out appropriately
+ * @return the exact size of the object's binary representation in bytes
+ */
+ public int getSize(Message srcObj);
+
+
+ /**
+ * Parse from a ByteBuffer into a destination object.
+ *
+ * @param srcBuf the buffer containing the binary data to construct this
object
+ * @param frameStart start of the current frame, relative to the beginning
of srcBuf
+ * @param frameObj the object containing the dstObj, dstObj if dstObj
itself is the frame object
+ * @param dstObj the object whose members are written according according
to the data in srcBuf
+ * @param frameSizePath
+ * @return number of byres read from srcBuf
+ */
+ public int parse(ByteBuffer srcBuf, int frameStart, Message frameObj,
Message dstObj, List<Field> frameSizePath);
+
+ /**
+ *
+ * @param dstBuf destination buffer for the binary representation of the
object
+ * @param srcObj object to serialize to binary form
+ * @return number of bytes written to buf (todo: we are using a ByteBuffer
now, this is obsolete)
+ */
+ public int write(ByteBuffer dstBuf, Message srcObj);
+
+ /**
+ * Parser-dependent method; sets members of the Message m (or Messages
nested in m) which are
+ * values inferable by the parser.
+ * Examples: Union tags, size fields.
+ *
+ * @param m the message object to patch
+ * @param frameSize the size of the containing message
+ * @param frameSizePath
+ * @param frameObj the object containing the message (and possibly size
fields)
+ */
+ public void patch(Message m, int frameSize, List<Field> frameSizePath,
Message frameObj);
+
+ /**
+ * Return a lower bound for the size of the message in bytes
+ *
+ * @return minimum static size of the message in bytes
+ */
+ int getStaticSize();
+}
Added:
gnunet-java/src/main/java/org/gnunet/construct/parsers/SequenceParser.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/parsers/SequenceParser.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/parsers/SequenceParser.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,106 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct.parsers;
+
+import org.gnunet.construct.Message;
+import org.gnunet.construct.ProtocolViolationException;
+import org.gnunet.construct.ReflectUtil;
+
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * A Sequence of Parsers that operate on the same object.
+ * @author Florian Dold
+ *
+ */
+public class SequenceParser implements Parser {
+
+ private final List<Parser> childParsers = new LinkedList<Parser>();
+ private List<Field> myFrameSizePath;
+
+ public SequenceParser() {
+ }
+
+ public void add(final Parser p) {
+ childParsers.add(p);
+ }
+
+ @Override
+ public int getSize(final Message src) {
+ int size = 0;
+ for (final Parser p : childParsers) {
+ size += p.getSize(src);
+ }
+ return size;
+ }
+
+ @Override
+ public int parse(final ByteBuffer srcBuf, int frameOffset,
+ Message frameObj, final Message dst, List<Field>
frameSizePath) {
+ int size = 0;
+ for (final Parser p : childParsers) {
+ try {
+ size += p.parse(srcBuf, frameOffset, frameObj, dst,
+ frameSizePath == null ? myFrameSizePath :
frameSizePath);
+ } catch (ProtocolViolationException e) {
+ throw e.augmentPath("(sequence parser)");
+ }
+ }
+ return size;
+ }
+
+ @Override
+ public int write(final ByteBuffer dstBuf, final Message src) {
+ int size = 0;
+ for (final Parser p : childParsers) {
+ size += p.write(dstBuf, src);
+ }
+ return size;
+ }
+
+ @Override
+ public void patch(Message m, int frameSize, List<Field> frameSizePath,
Message frameObj) {
+ // todo: this should be optimized / only be done by the topmost
sequence parse => introduce a boolean parameter
+ if (myFrameSizePath != null) {
+ ReflectUtil.justSetInt(frameObj, myFrameSizePath, frameSize);
+ }
+
+ for (final Parser p : childParsers) {
+ p.patch(m, frameSize, frameSizePath == null ? myFrameSizePath :
frameSizePath, frameObj);
+ }
+ }
+
+ @Override
+ public int getStaticSize() {
+ int accum = 0;
+ for (Parser p : childParsers) {
+ accum += p.getStaticSize();
+ }
+ return accum;
+ }
+
+ public void setFrameSizePath(List<Field> frameSizePath) {
+ this.myFrameSizePath = frameSizePath;
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/parsers/StringParser.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/parsers/StringParser.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/parsers/StringParser.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,145 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct.parsers;
+
+import org.gnunet.construct.Message;
+import org.gnunet.construct.ProtocolViolationException;
+import org.gnunet.construct.ReflectUtil;
+
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+public class StringParser implements Parser {
+
+ private final String cset;
+ private final boolean optional;
+ private final Field targetField;
+
+ public StringParser(final String charset, boolean optional, final Field f)
{
+ this.targetField = f;
+ this.optional = optional;
+ this.cset = charset;
+ }
+
+ @Override
+ public int getSize(final Message srcObj) {
+ final String s = (String) ReflectUtil.justGet(srcObj, targetField);
+ if (s == null) {
+ if (optional) {
+ return 0;
+ } else {
+ throw new AssertionError("non-optional string cannot be null");
+ }
+ }
+ try {
+ final byte[] b = s.getBytes(cset);
+ return b.length + 1;
+ } catch (final UnsupportedEncodingException e) {
+ throw new RuntimeException();
+ }
+ }
+
+ @Override
+ public int parse(final ByteBuffer srcBuf, int frameOffset, Message
frameObj, final Message dstObj, List<Field>
+ frameSizePath) {
+
+ if (optional) {
+ if (frameSizePath == null) {
+ throw new AssertionError("optional string with no length field
in the message!");
+ }
+ final int frameSize = ReflectUtil.justGetInt(dstObj,
frameSizePath);
+ int remaining = frameOffset + frameSize - srcBuf.position();
+
+ if (remaining == 0) {
+ if (!optional) {
+ throw new ProtocolViolationException("no data received for
non-optional string");
+ }
+ ReflectUtil.justSet(dstObj, targetField, null);
+ return 0;
+ }
+ }
+
+ int length = 0;
+
+ while (srcBuf.get(srcBuf.position() + length) != 0) {
+ length++;
+ }
+
+ final byte[] stringData = new byte[length];
+
+ srcBuf.get(stringData);
+
+ if (srcBuf.get() != 0) {
+ throw new AssertionError("programming error");
+ }
+
+ String str;
+ try {
+ str = new String(stringData, cset);
+ } catch (final UnsupportedEncodingException e) {
+ throw new RuntimeException();
+ }
+
+ ReflectUtil.justSet(dstObj, targetField, str);
+
+ return length + 1;
+ }
+
+ @Override
+ public int write(final ByteBuffer dstBuf, final Message srcObj) {
+ String s = (String) ReflectUtil.justGet(srcObj, targetField);
+
+ if (s == null) {
+ if (!optional) {
+ throw new AssertionError("non-optional string cannot be null");
+ }
+ return 0;
+ }
+
+ byte[] b;
+ try {
+ b = s.getBytes(cset);
+ } catch (final UnsupportedEncodingException e) {
+ throw new RuntimeException();
+ }
+
+ dstBuf.put(b);
+ dstBuf.put((byte) 0);
+
+ // +1 for the 0-byte
+ return b.length + 1;
+ }
+
+ @Override
+ public void patch(Message m, int frameSize, List<Field> frameSizePath,
Message frameObj) {
+ if (frameSizePath != null) {
+ ReflectUtil.justSetInt(frameObj, frameSizePath, frameSize);
+ }
+ }
+
+ @Override
+ public int getStaticSize() {
+ return optional ? 0 : 1;
+ }
+
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/parsers/UnionParser.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/parsers/UnionParser.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/parsers/UnionParser.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,143 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct.parsers;
+
+import org.gnunet.construct.*;
+import org.gnunet.construct.ProtocolViolationException;
+
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+
+
+// unchecked casts are necessary
address@hidden("unchecked")
+public class UnionParser implements Parser {
+
+ private final Field targetField;
+
+ private final List<Field> unionTagPath;
+ private final ReflectUtil.NumField unionTagField;
+ private final Class<? extends MessageUnion> unionType;
+
+ boolean optional;
+
+ public UnionParser(boolean optional, Class<? extends MessageUnion>
unionType,
+ List<Field> unionTagPath, Field f) {
+ targetField = f;
+ this.optional = optional;
+ this.unionTagPath = unionTagPath;
+ this.unionTagField = new
ReflectUtil.NumField(unionTagPath.get(unionTagPath.size() - 1));
+ this.unionType = unionType;
+ }
+
+ @Override
+ public int getSize(final Message src) {
+ Object target = ReflectUtil.justGet(src, targetField);
+ if (target == null) {
+ if (optional) {
+ return 0;
+ } else {
+ throw new AssertionError("non-optional union member must not
be null");
+ }
+ }
+ Class cls = ReflectUtil.justGet(src, targetField).getClass();
+
+ Parser parser = Construct.getParser(cls);
+
+ return parser.getSize((Message)ReflectUtil.justGet(src, targetField));
+ }
+
+ @Override
+ public int parse(final ByteBuffer srcBuf, int frameOffset, Message
frameObj, final Message dstObj, List<Field>
+ frameSizePath) {
+ if (optional) {
+ if (frameSizePath == null) {
+ throw new AssertionError("missing @FrameSize");
+ }
+
+ int remaining = frameOffset + ReflectUtil.justGetInt(frameObj,
frameSizePath) - srcBuf.position();
+ if (remaining <= 0) {
+ if (!optional) {
+ throw new ProtocolViolationException("not optional");
+ }
+ ReflectUtil.justSet(dstObj, targetField, null);
+ return 0;
+ }
+ }
+
+ long unionTag =
unionTagField.get(ReflectUtil.followFieldPathToParent(unionTagPath, dstObj));
+
+ final Class cls;
+
+ cls = MessageLoader.getUnionClass(unionType, (int) unionTag);
+
+ ReflectUtil.justSet(dstObj, targetField,
ReflectUtil.justInstantiate(cls));
+
+ final Message theUnion = (Message) ReflectUtil.justGet(dstObj,
targetField);
+
+ Parser parser = Construct.getParser(cls);
+
+ return parser.parse(srcBuf, frameOffset, frameObj, theUnion,
frameSizePath);
+ }
+
+ @Override
+ public int write(final ByteBuffer dstBuf, final Message src) {
+ final Object target = ReflectUtil.justGet(src, targetField);
+
+ if (target == null) {
+ if (optional) {
+ return 0;
+ } else {
+ throw new AssertionError("non-optional union member must not
be null");
+ }
+ }
+
+ final Class currentUnionClass = target.getClass();
+ final Parser p = Construct.getParser(currentUnionClass);
+
+ return p.write(dstBuf, (Message) ReflectUtil.justGet(src,
targetField));
+ }
+
+ @SuppressWarnings("unchecked")
+ public int getTag(Message m) {
+ return MessageLoader.getUnionTag(unionType, (Class<MessageUnion>)
ReflectUtil.justGet(m, targetField).getClass());
+ }
+
+ @Override
+ public void patch(Message m, int frameSize, List<Field> frameSizePath,
Message frameObj) {
+ final Class currentUnionClass = ReflectUtil.justGet(m,
targetField).getClass();
+ final Parser p = Construct.getParser(currentUnionClass);
+
+ p.patch((Message) ReflectUtil.justGet(m, targetField), frameSize,
frameSizePath, frameObj);
+
+ unionTagField.set(ReflectUtil.followFieldPathToParent(unionTagPath, m),
+ getTag(m));
+ }
+
+ @Override
+ public int getStaticSize() {
+ // we can't say anything about the static size
+ // todo: in a more elaborate implementation, try all union members
+ return 0;
+ }
+}
Added:
gnunet-java/src/main/java/org/gnunet/construct/parsers/VariableSizeArrayParser.java
===================================================================
---
gnunet-java/src/main/java/org/gnunet/construct/parsers/VariableSizeArrayParser.java
(rev 0)
+++
gnunet-java/src/main/java/org/gnunet/construct/parsers/VariableSizeArrayParser.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,106 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct.parsers;
+
+import org.gnunet.construct.Message;
+import org.gnunet.construct.ProtocolViolationException;
+import org.gnunet.construct.ReflectUtil;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+public class VariableSizeArrayParser implements Parser {
+ private final Field targetField;
+ private final Parser elemParser;
+ private ReflectUtil.NumField sizeField;
+
+
+ public VariableSizeArrayParser(final Parser elemParser, Field sizeField,
Field arrayField) {
+ targetField = arrayField;
+ this.elemParser = elemParser;
+ this.sizeField = new ReflectUtil.NumField(sizeField);
+ }
+
+ @Override
+ public int getSize(final Message src) {
+ int size = 0;
+ final Object arr = ReflectUtil.justGet(src, targetField);
+
+ if (arr == null) {
+ throw new RuntimeException("array not initialized");
+ }
+
+ for (int i = 0; i < Array.getLength(arr); ++i) {
+ size += elemParser.getSize((Message) Array.get(arr, i));
+ }
+ return size;
+ }
+
+ @Override
+ public int parse(final ByteBuffer srcBuf, int frameOffset, Message
frameObj, final Message dstObj, List<Field>
+ frameSizePath) {
+ final int elemNumber = (int) sizeField.get(dstObj);
+
+ @SuppressWarnings("unchecked")
+ final Class<Message> arrayElementType = (Class<Message>)
targetField.getType().getComponentType();
+
+ int size = 0;
+
+ final Object arr = Array.newInstance(arrayElementType, elemNumber);
+ ReflectUtil.justSet(dstObj, targetField, arr);
+
+ for (int i = 0; i < elemNumber; ++i) {
+ Message elemObj;
+
+ elemObj = ReflectUtil.justInstantiate(arrayElementType);
+
+ Array.set(arr, i, elemObj);
+
+ size += elemParser.parse(srcBuf, frameOffset - size, null,
elemObj, null);
+ }
+
+ return size;
+ }
+
+ @Override
+ public int write(final ByteBuffer dstBuf, final Message src) {
+ int size = 0;
+ final Object arr = ReflectUtil.justGet(src, targetField);
+ for (int i = 0; i < Array.getLength(arr); ++i) {
+ size += elemParser.write(dstBuf, (Message) Array.get(arr, i));
+ }
+ return size;
+ }
+
+ @Override
+ public void patch(Message m, int frameSize, List<Field> frameSizePath,
Message frameObj) {
+ int size = Array.getLength(ReflectUtil.justGet(m, targetField));
+ sizeField.set(m, size);
+ }
+
+ @Override
+ public int getStaticSize() {
+ return 0;
+ }
+
+}
Added:
gnunet-java/src/main/java/org/gnunet/construct/parsers/VariableSizeIntegerArrayParser.java
===================================================================
---
gnunet-java/src/main/java/org/gnunet/construct/parsers/VariableSizeIntegerArrayParser.java
(rev 0)
+++
gnunet-java/src/main/java/org/gnunet/construct/parsers/VariableSizeIntegerArrayParser.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,103 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct.parsers;
+
+import org.gnunet.construct.Message;
+import org.gnunet.construct.ReflectUtil;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+public class VariableSizeIntegerArrayParser implements Parser {
+ private final Field targetField;
+ private ReflectUtil.NumField sizeField;
+ private int byteSize;
+ private boolean signed;
+
+
+ public VariableSizeIntegerArrayParser(Field sizeField, Field arrayField,
+ boolean signed, int byteSize) {
+ targetField = arrayField;
+ this.sizeField = new ReflectUtil.NumField(sizeField);
+ this.signed = signed;
+ this.byteSize = byteSize;
+ }
+
+ @Override
+ public int getSize(final Message src) {
+ final Object arr = ReflectUtil.justGet(src, targetField);
+
+ if (arr == null) {
+ throw new RuntimeException("array not initialized");
+ }
+
+ return Array.getLength(arr) * (byteSize);
+ }
+
+ @Override
+ public int parse(final ByteBuffer srcBuf, int frameOffset, Message
frameObj, final Message dstObj, List<Field>
+ frameSizePath) {
+ final int elemNumber = (int) sizeField.get(dstObj);
+
+
+ @SuppressWarnings("unchecked")
+ final Class<Message> arrayElementType = (Class<Message>)
targetField.getType().getComponentType();
+
+ if (!arrayElementType.isPrimitive()) {
+ throw new AssertionError("VariableSizeIntegerArray is expected to
be of primitive type, not " + arrayElementType);
+ }
+
+ final Object arr = Array.newInstance(arrayElementType, elemNumber);
+ ReflectUtil.justSet(dstObj, targetField, arr);
+
+ for (int i = 0; i < elemNumber; ++i) {
+ long v = IntegerUtil.readLong(srcBuf, signed, byteSize);
+ ReflectUtil.justSetArray(arr, i, v);
+ }
+
+ return byteSize * elemNumber;
+ }
+
+ @Override
+ public int write(final ByteBuffer dstBuf, final Message src) {
+ int size = 0;
+ final Object arr = ReflectUtil.justGet(src, targetField);
+ for (int i = 0; i < Array.getLength(arr); ++i) {
+ IntegerUtil.writeLong(ReflectUtil.justGetArrayLong(arr, i),
dstBuf, signed, byteSize);
+ size += byteSize;
+ }
+ return size;
+ }
+
+ @Override
+ public void patch(Message m, int frameSize, List<Field> frameSizePath,
Message frameObj) {
+ int size = Array.getLength(ReflectUtil.justGet(m, targetField));
+ sizeField.set(m, size);
+ }
+
+ @Override
+ public int getStaticSize() {
+ return 0;
+ }
+
+}
Added: gnunet-java/src/main/java/org/gnunet/construct/parsers/package-info.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/construct/parsers/package-info.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/construct/parsers/package-info.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,25 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+
+/**
+ * The actual parsers for reading and writing annotated messages.
+ */
+package org.gnunet.construct.parsers;
Added: gnunet-java/src/main/java/org/gnunet/core/ConnectHandler.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/core/ConnectHandler.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/core/ConnectHandler.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,30 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.core;
+
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * Called when a new peer (with a compatible set of messages) connects to core
+ */
+public interface ConnectHandler {
+ void onConnect(PeerIdentity peerIdentity);
+}
Added: gnunet-java/src/main/java/org/gnunet/core/ConnectNotifyMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/core/ConnectNotifyMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/core/ConnectNotifyMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,54 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.core;
+
+import org.gnunet.construct.*;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * Message sent by the service to clients to notify them
+ * about a peer connecting.
+ */
address@hidden(67)
+public class ConnectNotifyMessage implements GnunetMessage.Body {
+ /**
+ * Number of ATS key-value pairs that follow this struct
+ * (excluding the 0-terminator).
+ */
+ @UInt32
+ public long atsCount;
+
+ /**
+ * Identity of the connecting peer.
+ */
+ @NestedMessage
+ public PeerIdentity peer;
+
+
+ @FillWith @UInt8
+ public byte[] atsInfo;
+
+
+ //@FillWith
+ //public ATSInformation[] atsInformation;
+
+}
Added: gnunet-java/src/main/java/org/gnunet/core/Core.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/core/Core.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/core/Core.java 2013-08-27 17:16:18 UTC
(rev 28880)
@@ -0,0 +1,347 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.core;
+
+import com.google.common.collect.Maps;
+import org.gnunet.construct.Construct;
+import org.gnunet.construct.MessageLoader;
+import org.gnunet.mq.Envelope;
+import org.gnunet.requests.MatchingRequestContainer;
+import org.gnunet.requests.RequestContainer;
+import org.gnunet.util.*;
+import org.grothoff.Runabout;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+
+
+/**
+ * API for the gnunet core service.
+ * <p/>
+ * Sends messages to connected peers.
+ */
+public class Core {
+ /**
+ * Logger for org.gnunet.Core.
+ */
+ private static final Logger logger = LoggerFactory
+ .getLogger(Core.class);
+
+ /**
+ * Client for connecting to the core service
+ */
+ private final Client client;
+
+ /*
+ * set to null once connected for the first time
+ */
+ private InitCallback initCallback;
+
+ /*
+ * Callback for traffic notifications. null if not interested.
+ */
+ private HeaderNotify notifyOutboundHeaders;
+
+ /*
+ * Callback for traffic notifications. null if not interested.
+ */
+ private HeaderNotify notifyInboundHeaders;
+
+ /*
+ * Callback for traffic notifications. null if not interested.
+ */
+ private MessageNotify notifyOutboundMessages;
+
+ /*
+ * Callback for traffic notifications. null if not interested.
+ */
+ private MessageNotify notifyInboundMessages;
+
+ /*
+ * Callbacks for connect events
+ */
+ private ConnectHandler connectHandler;
+
+ /**
+ * Callback for disconnect events.
+ */
+ private DisconnectHandler disconnectHandler;
+
+ /**
+ * Messages we are interested in.
+ * Per default we are interested in all messages => specific interest set
is empty.
+ */
+ private int[] interested = new int[0];
+
+ /**
+ * Handler for the messages we are interested in.
+ */
+ private Runabout messageHandler;
+
+ /**
+ * Peers that we were notified about being connected to them.
+ * Every connected peer is mapped to a generator for unique request IDs.
+ */
+ private HashMap<PeerIdentity, Integer> connectedPeers = Maps.newHashMap();
+
+ /**
+ * Request container for notify transmit requests.
+ */
+ private MatchingRequestContainer<RequestIdentification,
NotifyTransmitReadyRequest> ntr_requests;
+
+ public static class NotifyTransmitReadyRequest extends
RequestContainer.Request {
+ private final int size;
+ final public PeerIdentity target;
+ final public long priority;
+ public int smrId;
+ final public MessageTransmitter transmitter;
+ final public AbsoluteTime deadline;
+
+ public NotifyTransmitReadyRequest(int priority, int size, PeerIdentity
target, RelativeTime timeout, MessageTransmitter transmitter) {
+ this.deadline = timeout.toAbsolute();
+ this.priority = priority;
+ this.size = size;
+ this.target = target;
+ this.transmitter = transmitter;
+ }
+
+ @Override
+ public Envelope assembleRequest() {
+ SendMessageRequest m = new SendMessageRequest();
+ m.peer = target;
+ m.smrId = smrId;
+ m.priority = priority;
+ m.size = size;
+ m.deadline = deadline.asMessage();
+ return new Envelope(m);
+ }
+
+ public void cancel() {
+ // do nothing
+ }
+ }
+
+
+ public final class CoreReceiver extends RunaboutMessageReceiver {
+ public void visit(InitReplyMessage m) {
+ PeerIdentity myIdentity = m.myIdentity;
+ connectedPeers.put(myIdentity, 1);
+
+ if (initCallback != null) {
+ initCallback.onInit(m.myIdentity);
+ initCallback = null;
+ }
+ }
+
+ public void visit(ConnectNotifyMessage m) {
+ if (connectHandler != null) {
+ connectHandler.onConnect(m.peer);
+ }
+ }
+
+ public void visit(DisconnectNotifyMessage m) {
+ if (disconnectHandler != null) {
+ disconnectHandler.onDisconnect(m.peer);
+ }
+ }
+
+ public void visit(NotifyInboundTrafficMessage m) {
+ boolean found = false;
+ if (notifyInboundHeaders != null) {
+ notifyInboundHeaders.notify(m.payloadHeader);
+ }
+ if (notifyInboundMessages != null) {
+ // todo: call corresponding notify on notifyInboundMessages
+ }
+
+ for (int i : interested) {
+ if (i == m.payloadHeader.messageType) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ Class bodyClass =
MessageLoader.getUnionClass(GnunetMessage.Body.class,
m.payloadHeader.messageType);
+ @SuppressWarnings("unchecked")
+ GnunetMessage.Body b = (GnunetMessage.Body)
Construct.parseAs(m.payloadBody, bodyClass);
+ messageHandler.visitAppropriate(b);
+ }
+ }
+
+ public void visit(NotifyOutboundTrafficMessage m) {
+ if (notifyOutboundHeaders != null) {
+ notifyOutboundHeaders.notify(m.payloadHeader);
+ }
+ if (notifyOutboundMessages != null) {
+ // todo
+ }
+ }
+
+ public void visit(SendMessageReady m) {
+ RequestIdentification rid = new RequestIdentification(m.smrId,
m.peer);
+ NotifyTransmitReadyRequest req = ntr_requests.getRequest(rid);
+
+ final SendMessage sm = new SendMessage();
+ sm.cork = 0;
+ sm.peer = req.target;
+ sm.priority = req.priority;
+ sm.deadline = req.deadline.asMessage();
+
+ req.transmitter.transmit(new Connection.MessageSink() {
+ boolean sent;
+ @Override
+ public void send(GnunetMessage.Body m) {
+ if (sent) {
+ throw new AssertionError("sending multiple messages
not supported");
+ }
+ sm.payloadMessage = GnunetMessage.fromBody(m);
+ sent = true;
+ }
+ });
+
+
+ if (sm.payloadMessage == null)
+ throw new AssertionError();
+
+ client.send(sm);
+ }
+
+ @Override
+ public void visitDefault(Object o) {
+ logger.warn("received unexpected message from core: {}",
o.getClass());
+ }
+
+ @Override
+ public void handleError() {
+ if (disconnectHandler != null) {
+ for (PeerIdentity e : connectedPeers.keySet()) {
+ disconnectHandler.onDisconnect(e);
+ }
+ }
+ connectedPeers.clear();
+ }
+ }
+
+ public Core(Configuration cfg) {
+ client = new Client("core", cfg);
+ client.installReceiver(new CoreReceiver());
+ ntr_requests = new MatchingRequestContainer<RequestIdentification,
NotifyTransmitReadyRequest>(client);
+ }
+
+ /**
+ * Send to the service which messages are we interested in.
+ *
+ * @param initCallback called after the init message has been sent
+ */
+ public void init(InitCallback initCallback) {
+ this.initCallback = initCallback;
+ InitMessage initMessage = new InitMessage();
+
+ initMessage.interested = interested;
+ initMessage.options = 0;
+
+ for (int i : interested) {
+ logger.debug("we are interested in " + i);
+ }
+ client.sendPrefered(initMessage);
+ }
+
+ /**
+ * Ask the core to call "notify" once it is ready to transmit the
+ * given number of bytes to the specified "target". Must only be
+ * called after a connection to the respective peer has been
+ * established (and the client has been informed about this).
+ *
+ * @param priority how important is the message?
+ * @param maxdelay how long can the message wait?
+ * @param target the identity of the receiver
+ * @param size the size of the message we want to transmit
+ * @param transmitter called once the core service is ready to send message
+ * @return a handle to cancel the notification
+ */
+ public Cancelable notifyTransmitReady(int priority, RelativeTime maxdelay,
+ PeerIdentity target, int size, final
MessageTransmitter transmitter) {
+ if (!connectedPeers.containsKey(target)) {
+ throw new AssertionError("notifyTransmitReady called for
unconnected peer");
+ }
+ int id = connectedPeers.get(target);
+ connectedPeers.put(target, id+1);
+ NotifyTransmitReadyRequest notifyRequest = new
NotifyTransmitReadyRequest(priority, size, target, maxdelay, transmitter);
+ notifyRequest.smrId = id;
+ RequestIdentification rid = new
RequestIdentification(notifyRequest.smrId, target);
+ return ntr_requests.addRequest(rid, notifyRequest);
+ }
+
+ /**
+ * Observe outgoing message headers from core.
+ * @param h callback
+ */
+ public void observeOutboundHeaders(HeaderNotify h) {
+ this.notifyOutboundHeaders = h;
+ }
+
+ public void observeInboundHeaders(HeaderNotify h) {
+ this.notifyInboundHeaders = h;
+ }
+
+ public void observeInboundMessages(MessageNotify h) {
+ this.notifyInboundMessages = h;
+ }
+
+ public void observeOutboundMessages(MessageNotify h) {
+ this.notifyOutboundMessages = h;
+ }
+
+ public void observeConnect(ConnectHandler connectHandler) {
+ this.connectHandler = connectHandler;
+ }
+
+ public void observeDisconnect(DisconnectHandler disconnectHandler) {
+ this.disconnectHandler = disconnectHandler;
+ }
+
+ /**
+ * Handle all incoming messages with the specified runabout.
+ * Has to be called before init, as the service has to know which messages
we
+ * are interested in.
+ */
+ public void setMessageHandler(Runabout runabout) {
+ if (messageHandler != null) {
+ throw new AssertionError("Core can have only on message handler");
+ }
+ if (client.isConnected()) {
+ // todo: shouldn't we just reconnect?
+ throw new AssertionError("can set message handler only if not yet
connected");
+ }
+ messageHandler = runabout;
+ interested = RunaboutUtil.getRunaboutMessageTypes(runabout);
+ }
+
+ /**
+ * Disconnect from the core service. This function can only
+ * be called *after* all pending notifyTransmitReady
+ * requests have been explicitly cancelled.
+ */
+ public void disconnect() {
+ client.disconnect();
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/core/DisconnectHandler.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/core/DisconnectHandler.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/core/DisconnectHandler.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,30 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.core;
+
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * Called when a peer disconnects from the core.
+ */
+public interface DisconnectHandler {
+ void onDisconnect(PeerIdentity peerIdentity);
+}
Added: gnunet-java/src/main/java/org/gnunet/core/DisconnectNotifyMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/core/DisconnectNotifyMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/core/DisconnectNotifyMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,46 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.core;
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * Message sent by the service to clients to notify them
+ * about a peer disconnecting.
+ */
address@hidden(68)
+public class DisconnectNotifyMessage implements GnunetMessage.Body {
+ /**
+ * Always zero.
+ */
+ @UInt32
+ public int reserved;
+
+ /**
+ * Identity of the connecting peer.
+ */
+ @NestedMessage
+ public PeerIdentity peer;
+}
Added: gnunet-java/src/main/java/org/gnunet/core/HeaderNotify.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/core/HeaderNotify.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/core/HeaderNotify.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,30 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.core;
+
+import org.gnunet.util.GnunetMessage;
+
+/**
+ *
+ */
+public interface HeaderNotify {
+ void notify(GnunetMessage.Header header);
+}
Added: gnunet-java/src/main/java/org/gnunet/core/InitCallback.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/core/InitCallback.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/core/InitCallback.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,30 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.core;
+
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * Called once the handshake with core was successful.
+ */
+public interface InitCallback {
+ void onInit(PeerIdentity myIdentity);
+}
Added: gnunet-java/src/main/java/org/gnunet/core/InitMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/core/InitMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/core/InitMessage.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,45 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.core;
+
+import org.gnunet.construct.IntegerFill;
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+
+
address@hidden(64)
+public class InitMessage implements GnunetMessage.Body {
+ /*
+ * Options used to tell core what kind of traffic notify messages we are
interested in.
+ */
+ private final static int
+ OPTION_FULL_INBOUND = 8,
+ OPTION_HDR_INBOUND = 16,
+ OPTION_FULL_OUTBOUND = 32,
+ OPTION_HDR_OUTBOUND = 64;
+
+ @UInt32
+ public long options;
+
+ @IntegerFill(signed = false, bitSize = 16)
+ public int[] interested;
+}
Added: gnunet-java/src/main/java/org/gnunet/core/InitReplyMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/core/InitReplyMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/core/InitReplyMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,39 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.core;
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.PeerIdentity;
+
+
address@hidden(65)
+public class InitReplyMessage implements GnunetMessage.Body {
+ @UInt32
+ public int reserved = 0;
+ /**
+ * pubkey of the local peer
+ */
+ @NestedMessage
+ public PeerIdentity myIdentity;
+}
Added: gnunet-java/src/main/java/org/gnunet/core/MessageNotify.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/core/MessageNotify.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/core/MessageNotify.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,28 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.core;
+
+import org.gnunet.util.GnunetMessage;
+
+
+public interface MessageNotify {
+ void notify(GnunetMessage messageBody);
+}
Added:
gnunet-java/src/main/java/org/gnunet/core/NotifyInboundTrafficMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/core/NotifyInboundTrafficMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/core/NotifyInboundTrafficMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,47 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.core;
+
+import org.gnunet.construct.*;
+import org.gnunet.util.ATSInformation;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.PeerIdentity;
+
+
address@hidden(70)
+public class NotifyInboundTrafficMessage implements GnunetMessage.Body {
+ /**
+ * Identity of the receiver or sender.
+ */
+ @NestedMessage
+ public PeerIdentity peer;
+
+ @NestedMessage(newFrame = true)
+ public GnunetMessage.Header payloadHeader;
+
+ /**
+ * The (optional) message body corresponding to payloadHeader.
+ * Not typed as GnunetMessage.Body because the message type may not be
known by this
+ * peer.
+ */
+ @FillWith @UInt8
+ public byte[] payloadBody;
+}
Added:
gnunet-java/src/main/java/org/gnunet/core/NotifyOutboundTrafficMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/core/NotifyOutboundTrafficMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/core/NotifyOutboundTrafficMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,58 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.core;
+
+import org.gnunet.construct.*;
+import org.gnunet.util.ATSInformation;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.PeerIdentity;
+
+
address@hidden(71)
+public class NotifyOutboundTrafficMessage implements GnunetMessage.Body {
+ /**
+ * Number of ATS key-value pairs that follow this struct
+ * (excluding the 0-terminator).
+ */
+ @UInt32
+ public long ats_count;
+
+ /**
+ * Identity of the receiver or sender.
+ */
+ @NestedMessage
+ public PeerIdentity peer;
+
+ @VariableSizeArray(lengthField = "ats_count")
+ public ATSInformation[] atsRest;
+
+ @NestedMessage(newFrame = true)
+ public GnunetMessage.Header payloadHeader;
+
+ /**
+ * The (optional) message body corresponding to payloadHeader.
+ * Not typed as GnunetMessage.Body because the message type may not be
known by this
+ * peer.
+ */
+ @FillWith @UInt8
+ public byte[] payloadBody;
+
+}
Added: gnunet-java/src/main/java/org/gnunet/core/RequestIdentification.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/core/RequestIdentification.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/core/RequestIdentification.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,35 @@
+package org.gnunet.core;
+
+import org.gnunet.peerinfo.PeerInfo;
+import org.gnunet.util.PeerIdentity;
+
+
+final class RequestIdentification {
+ public final int requestIdentifier;
+ public final PeerIdentity peerIdentity;
+
+ public RequestIdentification(int requestIdentifier, PeerIdentity
peerIdentity) {
+ this.requestIdentifier = requestIdentifier;
+ this.peerIdentity = peerIdentity;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ RequestIdentification that = (RequestIdentification) o;
+
+ if (requestIdentifier != that.requestIdentifier) return false;
+ if (!peerIdentity.equals(that.peerIdentity)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = requestIdentifier;
+ result = 31 * result + peerIdentity.hashCode();
+ return result;
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/core/SendMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/core/SendMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/core/SendMessage.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,71 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.core;
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UInt64;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.AbsoluteTimeMessage;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * Client asking core to transmit a particular message to a particular
+ * target (response to GNUNET_MESSAGE_TYPE_CORE_SEND_READY).
+ */
address@hidden(76)
+public class SendMessage implements GnunetMessage.Body {
+ /**
+ * How important is this message?
+ */
+ @UInt32
+ public long priority;
+
+ /**
+ * By what time would the sender really like to see this
+ * message transmitted?
+ */
+ @NestedMessage
+ public AbsoluteTimeMessage deadline;
+
+ /**
+ * Identity of the intended receiver.
+ */
+ @NestedMessage
+ public PeerIdentity peer;
+
+ /**
+ * GNUNET_YES if corking is allowed, GNUNET_NO if not.
+ */
+ @UInt32
+ public int cork;
+
+ /**
+ * Always 0.
+ */
+ @UInt64
+ public int reserved;
+
+ @NestedMessage(newFrame = true)
+ public GnunetMessage payloadMessage;
+
+}
Added: gnunet-java/src/main/java/org/gnunet/core/SendMessageReady.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/core/SendMessageReady.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/core/SendMessageReady.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,56 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.core;
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UInt16;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * Core notifying client that it is allowed to now
+ * transmit a message to the given target
+ * (response to GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST).
+ */
address@hidden(75)
+public class SendMessageReady implements GnunetMessage.Body {
+ /**
+ * How many bytes are allowed for transmission?
+ * Guaranteed to be at least as big as the requested size,
+ * or ZERO if the request is rejected (will timeout,
+ * peer disconnected, queue full, etc.).
+ */
+ @UInt16
+ public int size;
+
+ /**
+ * smrId from the request.
+ */
+ @UInt16
+ public int smrId;
+
+ /**
+ * Identity of the intended target.
+ */
+ @NestedMessage
+ public PeerIdentity peer;
+}
Added: gnunet-java/src/main/java/org/gnunet/core/SendMessageRequest.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/core/SendMessageRequest.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/core/SendMessageRequest.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,73 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.core;
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UInt16;
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.AbsoluteTimeMessage;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * Client notifying core about the maximum-priority
+ * message it has in the queue for a particular target.
+ */
address@hidden(74)
+public class SendMessageRequest implements GnunetMessage.Body {
+ /**
+ * How important is this message?
+ */
+ @UInt32
+ public long priority;
+
+ /**
+ * By what time would the sender really like to see this
+ * message transmitted?
+ */
+ @NestedMessage
+ public AbsoluteTimeMessage deadline;
+
+ /**
+ * Identity of the intended target.
+ */
+ @NestedMessage
+ public PeerIdentity peer;
+
+ /**
+ * How large is the client's message queue for this peer?
+ */
+ @UInt32
+ public byte reserved;
+
+ /**
+ * How large is the message?
+ */
+ @UInt16
+ public int size;
+
+ /**
+ * Counter for this peer to match SMRs to replies.
+ */
+ @UInt16
+ public int smrId;
+}
Added: gnunet-java/src/main/java/org/gnunet/core/package-info.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/core/package-info.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/core/package-info.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,24 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * API for the gnunet core service.
+ */
+package org.gnunet.core;
Added: gnunet-java/src/main/java/org/gnunet/dht/BlockType.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/dht/BlockType.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/dht/BlockType.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,81 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.dht;
+
+/**
+ * Information on how to interpret a block of data.
+ */
+public enum BlockType {
+ /**
+ * Any type of block, used as a wildcard when searching. Should
+ * never be attached to a specific block.
+ */
+ ANY(0),
+ /**
+ * Data block (leaf) in the CHK tree.
+ */
+ DBLOCK(1),
+ /**
+ * Inner block in the CHK tree.
+ */
+ IBLOCK(2),
+ /**
+ * Type of a block representing a keyword search result. Note that
+ * the values for KBLOCK, SBLOCK and NBLOCK must be consecutive.
+ */
+ KBLOCK(3),
+ /**
+ * Type of a block that is used to advertise content in a namespace.
+ */
+ SBLOCK(4),
+ /**
+ * Type of a block that is used to advertise a namespace.
+ */
+ NBLOCK(5),
+ /**
+ * Type of a block representing a block to be encoded on demand from disk.
+ * Should never appear on the network directly.
+ */
+ FS_ONDEMAND(6),
+ /**
+ * Type of a block that contains a HELLO for a peer (for
+ * DHT find-peer operations).
+ */
+ DHT_HELLO(7),
+ /**
+ * Block for testing.
+ */
+ TEST(8),
+ /**
+ * Block for storing .gnunet-domains
+ */
+ DNS(10),
+ /**
+ * Block for storing record data
+ */
+ NAMERECORD(11);
+
+ public final int val;
+
+ BlockType(int val) {
+ this.val = val;
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/dht/ClientGetMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/dht/ClientGetMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/dht/ClientGetMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,51 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.dht;
+
+import org.gnunet.construct.*;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.HashCode;
+
+/**
+* Created with IntelliJ IDEA.
+* User: dold
+* Date: 5/2/12
+* Time: 7:05 PM
+* To change this template use File | Settings | File Templates.
+*/
address@hidden(143)
+public class ClientGetMessage implements GnunetMessage.Body {
+ /**
+ * Combination of RouteOption.*
+ */
+ @UInt32
+ public int options;
+ @UInt32
+ public int desiredReplicationLevel;
+ @UInt32
+ public int type;
+ @NestedMessage
+ public HashCode key;
+ @UInt64
+ public long uniqueId;
+ @FillWith @UInt8
+ public byte[] xquery;
+}
Added: gnunet-java/src/main/java/org/gnunet/dht/ClientGetStopMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/dht/ClientGetStopMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/dht/ClientGetStopMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,45 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.dht;
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UInt64;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.HashCode;
+
+/**
+* Created with IntelliJ IDEA.
+* User: dold
+* Date: 5/2/12
+* Time: 7:05 PM
+* To change this template use File | Settings | File Templates.
+*/
address@hidden(144)
+public class ClientGetStopMessage implements GnunetMessage.Body {
+ @UInt32
+ public int reserved = 0;
+ @UInt64
+ public long unique_id;
+ @NestedMessage
+ public HashCode key;
+}
Added:
gnunet-java/src/main/java/org/gnunet/dht/ClientPutConfirmationMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/dht/ClientPutConfirmationMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/dht/ClientPutConfirmationMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,38 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.dht;
+
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UInt64;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+
+
address@hidden(155)
+public class ClientPutConfirmationMessage implements GnunetMessage.Body {
+ @UInt32
+ public int reserved;
+ /**
+ * UID used to identify request with the response
+ */
+ @UInt64
+ public long uid;
+}
Added: gnunet-java/src/main/java/org/gnunet/dht/ClientPutMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/dht/ClientPutMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/dht/ClientPutMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,54 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.dht;
+
+import org.gnunet.construct.*;
+import org.gnunet.util.AbsoluteTimeMessage;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.HashCode;
+
+
address@hidden(142)
+public class ClientPutMessage implements GnunetMessage.Body {
+ /**
+ * Type of data to insert, one of BlockType.*
+ */
+ @UInt32
+ public int type;
+ /**
+ * Combination of RouteOption.*
+ */
+ @UInt32
+ public int options;
+ @UInt32
+ public int desiredReplicationLevel;
+ /**
+ * UID used to identify request with the response
+ */
+ @UInt64
+ public long uid;
+ @NestedMessage
+ public AbsoluteTimeMessage expiration;
+ @NestedMessage
+ public HashCode hash;
+ @FillWith @UInt8
+ public byte[] data;
+}
Added: gnunet-java/src/main/java/org/gnunet/dht/ClientResultMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/dht/ClientResultMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/dht/ClientResultMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,56 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.dht;
+
+import org.gnunet.construct.*;
+import org.gnunet.util.AbsoluteTimeMessage;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.HashCode;
+import org.gnunet.util.PeerIdentity;
+
+/**
+* Created with IntelliJ IDEA.
+* User: dold
+* Date: 5/2/12
+* Time: 7:06 PM
+* To change this template use File | Settings | File Templates.
+*/
address@hidden(145)
+public class ClientResultMessage implements GnunetMessage.Body {
+ @UInt32
+ public int type;
+ @UInt32
+ public int putPathLength;
+ @UInt32
+ public int getPathLength;
+ @UInt64
+ public long uid;
+ @NestedMessage
+ public AbsoluteTimeMessage expiration;
+ @NestedMessage
+ public HashCode key;
+ @VariableSizeArray(lengthField = "putPathLength")
+ public PeerIdentity[] putPath;
+ @VariableSizeArray(lengthField = "getPathLength")
+ public PeerIdentity[] getPath;
+ @FillWith @UInt8
+ public byte[] data;
+}
Added: gnunet-java/src/main/java/org/gnunet/dht/DistributedHashTable.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/dht/DistributedHashTable.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/dht/DistributedHashTable.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,449 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.dht;
+
+import com.google.common.base.Charsets;
+import org.gnunet.mq.Envelope;
+import org.gnunet.requests.MatchingRequestContainer;
+import org.gnunet.requests.RequestContainer;
+import org.gnunet.requests.SequentialRequestContainer;
+import org.gnunet.util.*;
+import org.gnunet.util.getopt.Argument;
+import org.gnunet.util.getopt.ArgumentAction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+
+/**
+ * API for the gnunet dht service.
+ * <p/>
+ * Stores data under a key, distributed across the network.
+ * <p/>
+ */
+public class DistributedHashTable {
+ private static final Logger logger = LoggerFactory
+ .getLogger(DistributedHashTable.class);
+
+ private Client client;
+
+ /**
+ * next UID used on get/monitor requests, incremented after each use.
+ */
+ private long nextUID = 1;
+
+ private MatchingRequestContainer<Long, PutRequest> putRequests;
+ private MatchingRequestContainer<Long, GetRequest> getRequests;
+ private SequentialRequestContainer<MonitorRequest> monitorRequests;
+
+ private class PutRequest extends RequestContainer.Request {
+ public byte[] data;
+ public HashCode key;
+ public int replicationLevel;
+ public AbsoluteTime expiration;
+ public int type;
+ public Continuation cont;
+ public long uid;
+
+ public PutRequest() {
+ this.uid = nextUID++;
+ }
+
+ @Override
+ public Envelope assembleRequest() {
+ final ClientPutMessage cpm = new ClientPutMessage();
+ cpm.data = data;
+ cpm.hash = key;
+ cpm.desiredReplicationLevel = replicationLevel;
+ cpm.expiration = expiration.asMessage();
+ cpm.type = type;
+ cpm.uid = uid;
+ return new Envelope(cpm);
+ }
+
+ public void cancel() {
+ }
+ }
+
+
+ private class GetRequest extends RequestContainer.Request {
+ public long uid;
+ public HashCode key;
+ public ResultCallback cb;
+ public int type;
+ public int replication;
+ public byte[] xquery;
+
+ public GetRequest() {
+ uid = DistributedHashTable.this.nextUID++;
+ }
+
+ @Override
+ public Envelope assembleRequest() {
+ ClientGetMessage gm = new ClientGetMessage();
+ gm.desiredReplicationLevel = replication;
+ gm.type = type;
+ gm.xquery = xquery == null ? new byte[0] : xquery;
+ gm.key = key;
+ gm.uniqueId = uid;
+ return new Envelope(gm);
+ }
+ public void cancel() {
+
+ }
+ }
+
+ private class MonitorRequest extends RequestContainer.Request {
+ public int blockType;
+ public HashCode key;
+ public MonitorGetHandler getHandler;
+ public MonitorGetResponseHandler getResponseHandler;
+ public MonitorPutHandler putHandler;
+
+ @Override
+ public Envelope assembleRequest() {
+ MonitorStartStop mss = new MonitorStartStop();
+ if (key != null) {
+ mss.filter_key = 1;
+ mss.key = key;
+ } else {
+ mss.key = new HashCode();
+ }
+ if (getHandler != null) {
+ mss.get = 1;
+ }
+ if (getResponseHandler != null) {
+ mss.getResp = 1;
+ }
+ if (putHandler != null) {
+ mss.put = 1;
+ }
+ mss.type = blockType;
+ return new Envelope(mss);
+ }
+
+ public void cancel() {
+ // todo: use priority requests
+ MonitorRequest cancelRequest = new MonitorRequest();
+ cancelRequest.getHandler = null;
+ cancelRequest.getResponseHandler = null;
+ cancelRequest.putHandler = null;
+ monitorRequests.addRequest(cancelRequest);
+
+ monitorRequests.addRequest(cancelRequest);
+ }
+ }
+
+ private class DHTMessageReceiver extends RunaboutMessageReceiver {
+ public void visit(ClientPutConfirmationMessage pcm) {
+ PutRequest thePutRequest = putRequests.getRequest(pcm.uid);
+ if (thePutRequest == null) {
+ logger.warn("request UID not found");
+ return;
+ }
+ if (thePutRequest.cont != null) {
+ thePutRequest.cont.cont(true);
+ }
+ }
+
+ public void visit(ClientResultMessage rm) {
+ GetRequest theGetRequest = getRequests.getRequest(rm.uid);
+ if (theGetRequest == null) {
+ logger.warn("request UID not found");
+ return;
+ }
+
theGetRequest.cb.handleResult(AbsoluteTime.fromNetwork(rm.expiration), rm.key,
null, null,
+ BlockType.TEST,
+ rm.data);
+ }
+
+ public void visit(MonitorGetMessage monitorGetMessage) {
+ for (MonitorRequest monitorRequest : monitorRequests.iter()) {
+ boolean type_ok = (monitorGetMessage.type == BlockType.ANY.val)
+ || (monitorGetMessage.type ==
monitorRequest.blockType);
+ boolean key_ok = monitorGetMessage.key.isAllZero()
+ || monitorGetMessage.key.equals(monitorRequest.key);
+
+ if (key_ok && type_ok && monitorRequest.getHandler != null) {
+ monitorRequest.getHandler.onGet(monitorGetMessage.options,
monitorGetMessage.type,
+ monitorGetMessage.hop_count,
monitorGetMessage.desired_replication_level, monitorGetMessage.getPath,
+ monitorGetMessage.key);
+ }
+ }
+ }
+
+ public void visit(MonitorGetRespMessage monitorGetRespMessage) {
+ for (MonitorRequest monitorRequest : monitorRequests.iter()) {
+ boolean type_ok = (monitorGetRespMessage.type ==
BlockType.ANY.val)
+ || (monitorGetRespMessage.type ==
monitorRequest.blockType);
+ boolean key_ok = monitorGetRespMessage.key.isAllZero()
+ ||
monitorGetRespMessage.key.equals(monitorRequest.key);
+
+ if (key_ok && type_ok && monitorRequest.getResponseHandler !=
null) {
+ monitorRequest.getResponseHandler.onGetResponse(
+ monitorGetRespMessage.type,
+ monitorGetRespMessage.getPath,
+ monitorGetRespMessage.putPath,
+ monitorGetRespMessage.expiration,
+ monitorGetRespMessage.key,
+ monitorGetRespMessage.data);
+ }
+ }
+
+ }
+
+ public void visit(MonitorPutMessage monitorPutMessage) {
+ for (MonitorRequest monitorRequest : monitorRequests.iter()) {
+ boolean type_ok = (monitorPutMessage.type == BlockType.ANY.val)
+ || (monitorPutMessage.type ==
monitorRequest.blockType);
+ boolean key_ok = monitorPutMessage.key.isAllZero()
+ || monitorPutMessage.key.equals(monitorRequest.key);
+
+ if (key_ok && type_ok && monitorRequest.putHandler != null) {
+ monitorRequest.putHandler.onPut(monitorPutMessage.options,
monitorPutMessage.type,
+ monitorPutMessage.hop_count,
monitorPutMessage.expirationTime,
+ monitorPutMessage.putPath, monitorPutMessage.key,
monitorPutMessage.data);
+ }
+ }
+ }
+
+ @Override
+ public void handleError() {
+ }
+ }
+
+
+ /**
+ * Create a connection with the DHT service.
+ *
+ * @param cfg the configuration to use
+ */
+ public DistributedHashTable(Configuration cfg) {
+ client = new Client("dht", cfg);
+ client.installReceiver(new DHTMessageReceiver());
+ putRequests = new MatchingRequestContainer<Long, PutRequest>(client);
+ getRequests = new MatchingRequestContainer<Long, GetRequest>(client);
+ monitorRequests = new
SequentialRequestContainer<MonitorRequest>(client);
+ }
+
+ /**
+ * Put data into the dht.
+ *
+ * @param key key key to store the data under
+ * @param data data data to store
+ * @param replicationLevel how many peers should store this value
+ * @param routeOptions additional options
+ * @param type type of the data to store
+ * @param expiration how long should the value be stored? TODO: what
is the maximum?
+ * @param timeout how long after we give up on storing the value?
+ * @param cont called after the put operation failed or
succeeded
+ */
+ public void put(HashCode key, byte[] data, int replicationLevel,
Set<RouteOption> routeOptions,
+ int type, AbsoluteTime expiration,
+ RelativeTime timeout, final Continuation cont) {
+ PutRequest pr = new PutRequest();
+ pr.key = key;
+ pr.data = data;
+ pr.replicationLevel = replicationLevel;
+ pr.expiration = expiration;
+ pr.type = type;
+ pr.cont = cont;
+
+ putRequests.addRequest(pr.uid, pr);
+ }
+
+
+ /**
+ * Request results from the DHT.
+ *
+ * @param timeout timeout for the request
+ * @param type which type of data do we want to query for? (the
DHT does not support TYPE_ANY)
+ * @param key the key we want to query
+ * @param replication how many peers do we want to ask?
+ * @param routeOptions extra routing options, null for default
+ * @param xquery extra query parameters, defaults to null
+ * @param cb the callback object for results or failure
indication
+ * @return a handle to cancel the request
+ */
+ public Cancelable startGet(RelativeTime timeout, int type, HashCode key,
+ int replication, EnumSet<RouteOption>
routeOptions,
+ byte[] xquery, ResultCallback cb) {
+
+ final GetRequest getRequest = new GetRequest();
+ getRequest.key = key;
+ getRequest.cb = cb;
+ getRequest.type = type;
+ getRequest.replication = type;
+ getRequest.xquery = xquery;
+
+ return getRequests.addRequest(getRequest.uid, getRequest);
+ }
+
+ public Cancelable startMonitor(int blockType, HashCode key,
MonitorGetHandler getHandler,
+ MonitorGetResponseHandler
getResponseHandler,
+ MonitorPutHandler putHandler) {
+ MonitorRequest monitorRequest = new MonitorRequest();
+ monitorRequest.blockType = blockType;
+ monitorRequest.key = key;
+ monitorRequest.getHandler = getHandler;
+ monitorRequest.getResponseHandler = getResponseHandler;
+ monitorRequest.putHandler = putHandler;
+
+ return monitorRequests.addRequest(monitorRequest);
+ }
+
+
+ /**
+ * Destroy the connection to the service.
+ */
+ public void destroy() {
+ // there's nothing to sync, just destroy!
+ client.disconnect();
+ }
+
+ public static void main(String[] args) {
+ new Program(args) {
+ @Argument(action = ArgumentAction.SET,
+ shortname = "p",
+ longname = "put",
+ description = "set a value in the DHT; default is get")
+ boolean modePut = false;
+
+ @Argument(action = ArgumentAction.SET,
+ shortname = "m",
+ longname = "monitor",
+ description = "monitor requests going to the local DHT")
+ boolean monitor = false;
+
+
+ @Argument(action = ArgumentAction.STORE_STRING,
+ shortname = "d",
+ longname = "data",
+ description = "data (only used with --put)")
+ String data = null;
+
+ @Argument(action = ArgumentAction.STORE_STRING,
+ shortname = "k",
+ longname = "key",
+ description = "key used for the operation")
+ String key = null;
+
+
+ // todo: implement the following options
+ /*
+ @Argument(action = ArgumentAction.STORE_STRING,
+ shortname = "t",
+ longname = "type",
+ description = "type of data used in this operation")
+ String type = null;
+
+ @Argument(action = ArgumentAction.STORE_STRING,
+ shortname = "e",
+ longname = "expire",
+ description = "expiration (ony use with --put)")
+ String expiration = null;
+ */
+
+
+ @Argument(action = ArgumentAction.STORE_NUMBER,
+ shortname = "r",
+ longname = "replication",
+ description = "desired replication (only used with --put)")
+ int replication = 5;
+
+
+ public void run() {
+ if (modePut) {
+
+ if (key == null) {
+ System.out.println("key required");
+ return;
+ }
+
+ if (data == null) {
+ System.out.println("data required on put");
+ return;
+ }
+ final DistributedHashTable dht = new
DistributedHashTable(cfg);
+
+ dht.put(new HashCode(key), data.getBytes(), replication,
EnumSet.of(RouteOption.NONE),
+ BlockType.TEST.val,
AbsoluteTime.now().add(RelativeTime.HOUR),
+ RelativeTime.SECOND, new Continuation() {
+ @Override
+ public void cont(boolean success) {
+ if (success) {
+ System.out.println("put request sent");
+ } else {
+ System.out.println("error");
+ }
+ dht.destroy();
+ }
+ });
+ } else if (monitor) {
+ final DistributedHashTable dht = new
DistributedHashTable(cfg);
+ dht.startMonitor(BlockType.TEST.val, null,
+ new MonitorGetHandler() {
+ @Override
+ public void onGet(int options, int type, int
hop_count,
+ int
desired_replication_level, PeerIdentity[] getPath, HashCode key) {
+ System.out.println("get monitored");
+ }
+ },
+ new MonitorGetResponseHandler() {
+ @Override
+ public void onGetResponse(int type,
PeerIdentity[] getPath, PeerIdentity[] putPath,
+ AbsoluteTimeMessage
expiration, HashCode key, byte[] data) {
+ System.out.println("get response
monitored");
+ }
+ },
+ new MonitorPutHandler() {
+ @Override
+ public void onPut(int options, int type, int
hop_count, AbsoluteTimeMessage
+ expirationTime, PeerIdentity[]
putPath, HashCode key, byte[] data) {
+ System.out.println("put monitored");
+ }
+ });
+ } else { // get
+ if (key == null) {
+ System.out.println("key required");
+ return;
+ }
+ if (data != null) {
+ System.out.println("get does not take data as an
option");
+ return;
+ }
+
+ final DistributedHashTable dht = new
DistributedHashTable(cfg);
+
+ dht.startGet(RelativeTime.SECOND, BlockType.TEST.val, new
HashCode(key), replication, null,
+ new byte[0], new ResultCallback() {
+ @Override
+ public void handleResult(AbsoluteTime expiration,
HashCode key, List<PeerIdentity>
+ getPath, List<PeerIdentity> putPath, BlockType
type, byte[] data) {
+ System.out.println("got result:");
+ System.out.println(new String(data,
Charsets.UTF_8));
+ }
+ });
+ }
+ }
+ }.start();
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/dht/MonitorGetHandler.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/dht/MonitorGetHandler.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/dht/MonitorGetHandler.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,30 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.dht;
+
+import org.gnunet.util.HashCode;
+import org.gnunet.util.PeerIdentity;
+
+
+public interface MonitorGetHandler {
+ void onGet(int options, int type, int hop_count, int
desired_replication_level, PeerIdentity[] getPath,
+ HashCode key);
+}
Added: gnunet-java/src/main/java/org/gnunet/dht/MonitorGetMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/dht/MonitorGetMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/dht/MonitorGetMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,75 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.dht;
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.construct.VariableSizeArray;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.HashCode;
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * Message to monitor get requests going through peer, DHT service -> clients.
+ */
address@hidden(149)
+public class MonitorGetMessage implements GnunetMessage.Body {
+ /**
+ * Message options, actually an 'enum GNUNET_DHT_RouteOption' value.
+ */
+ @UInt32
+ public int options;
+
+ /**
+ * The type of data in the request.
+ */
+ @UInt32
+ public int type;
+
+ /**
+ * Hop count
+ */
+ @UInt32
+ public int hop_count;
+
+ /**
+ * Replication level for this message
+ */
+ @UInt32
+ public int desired_replication_level;
+
+ /**
+ * Number of peers recorded in the outgoing path from source to the
+ * storage location of this message.
+ */
+ @UInt32
+ public int get_path_length;
+
+ /**
+ * The key to store the value under.
+ */
+ @NestedMessage
+ public HashCode key;
+
+ @VariableSizeArray(lengthField = "get_path_length")
+ public PeerIdentity[] getPath;
+}
Added: gnunet-java/src/main/java/org/gnunet/dht/MonitorGetRespMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/dht/MonitorGetRespMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/dht/MonitorGetRespMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,72 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.dht;
+
+import org.gnunet.construct.*;
+import org.gnunet.util.AbsoluteTimeMessage;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.HashCode;
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * Message to monitor get results going through peer, DHT service --> clients.
+ */
address@hidden(150)
+public class MonitorGetRespMessage implements GnunetMessage.Body {
+ /**
+ * Content type.
+ */
+ @UInt32
+ int type;
+
+ /**
+ * Length of the PUT path that follows (if tracked).
+ */
+ @UInt32
+ int put_path_length;
+
+ /**
+ * Length of the GET path that follows (if tracked).
+ */
+ @UInt32
+ int get_path_length;
+
+ /**
+ * When does the content expire?
+ */
+ @NestedMessage
+ public AbsoluteTimeMessage expiration;
+
+ /**
+ * The key of the corresponding GET request.
+ */
+ @NestedMessage
+ public HashCode key;
+
+ @VariableSizeArray(lengthField = "put_path_length")
+ public PeerIdentity[] putPath;
+
+ @VariableSizeArray(lengthField = "get_path_length")
+ public PeerIdentity[] getPath;
+
+ @FillWith @UInt8
+ public byte[] data;
+}
Added: gnunet-java/src/main/java/org/gnunet/dht/MonitorGetResponseHandler.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/dht/MonitorGetResponseHandler.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/dht/MonitorGetResponseHandler.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,31 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.dht;
+
+import org.gnunet.util.AbsoluteTimeMessage;
+import org.gnunet.util.HashCode;
+import org.gnunet.util.PeerIdentity;
+
+
+public interface MonitorGetResponseHandler {
+ void onGetResponse(int type, PeerIdentity[] getPath, PeerIdentity[]
putPath, AbsoluteTimeMessage expiration,
+ HashCode key, byte[] data);
+}
Added: gnunet-java/src/main/java/org/gnunet/dht/MonitorPutHandler.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/dht/MonitorPutHandler.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/dht/MonitorPutHandler.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,31 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.dht;
+
+import org.gnunet.util.AbsoluteTimeMessage;
+import org.gnunet.util.HashCode;
+import org.gnunet.util.PeerIdentity;
+
+
+public interface MonitorPutHandler {
+ void onPut(int options, int type, int hop_count, AbsoluteTimeMessage
expirationTime, PeerIdentity[] putPath,
+ HashCode key, byte[] data);
+}
Added: gnunet-java/src/main/java/org/gnunet/dht/MonitorPutMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/dht/MonitorPutMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/dht/MonitorPutMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,82 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.dht;
+
+import org.gnunet.construct.*;
+import org.gnunet.util.AbsoluteTimeMessage;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.HashCode;
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * Message to monitor put requests going through peer, DHT service --> clients.
+ */
address@hidden(151)
+public class MonitorPutMessage implements GnunetMessage.Body {
+ /**
+ * Message options, actually an 'enum GNUNET_DHT_RouteOption' value.
+ */
+ @UInt32
+ public int options;
+
+ /**
+ * The type of data in the request.
+ */
+ @UInt32
+ public int type;
+
+ /**
+ * Hop count so far.
+ */
+ @UInt32
+ public int hop_count;
+
+ /**
+ * Replication level for this message
+ */
+ @UInt32
+ public int desired_replication_level;
+
+ /**
+ * Number of peers recorded in the outgoing path from source to the
+ * storage location of this message.
+ */
+ @UInt32
+ public int put_path_length;
+
+ /**
+ * How long should this data persist?
+ */
+ @NestedMessage
+ public AbsoluteTimeMessage expirationTime;
+
+ /**
+ * The key to store the value under.
+ */
+ @NestedMessage
+ public HashCode key;
+
+ @VariableSizeArray(lengthField = "put_path_length")
+ public PeerIdentity[] putPath;
+
+ @FillWith @UInt8
+ public byte[] data;
+}
Added: gnunet-java/src/main/java/org/gnunet/dht/MonitorStartStop.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/dht/MonitorStartStop.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/dht/MonitorStartStop.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,70 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.dht;
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UInt16;
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.HashCode;
+
+/**
+ * Message to request monitoring messages, clients --> DHT service.
+ */
address@hidden(153)
+public class MonitorStartStop implements GnunetMessage.Body {
+ /**
+ * The type of data desired, GNUNET_BLOCK_TYPE_ANY for all.
+ */
+ @UInt32
+ public int type;
+
+ /**
+ * Flag whether to notify about GET messages.
+ */
+ @UInt16
+ public int get;
+
+ /**
+ * Flag whether to notify about GET_REPONSE messages.
+ */
+ @UInt16
+ public int getResp;
+
+ /**
+ * Flag whether to notify about PUT messages.
+ */
+ @UInt16
+ public int put;
+
+ /**
+ * Flag whether to use the provided key to filter messages.
+ */
+ @UInt16
+ public int filter_key;
+
+ /*
+ The key to filter messages by.
+ */
+ @NestedMessage
+ public HashCode key;
+}
Added: gnunet-java/src/main/java/org/gnunet/dht/ResultCallback.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/dht/ResultCallback.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/dht/ResultCallback.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,46 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.dht;
+
+import org.gnunet.util.AbsoluteTime;
+import org.gnunet.util.HashCode;
+import org.gnunet.util.PeerIdentity;
+
+import java.util.List;
+
+/**
+ * Callback object for requests to the dht
+ */
+public interface ResultCallback {
+ /**
+ * Called when the dht returns a result
+ *
+ * @param expiration expiration of the returned entry
+ * @param key key of the returned entry
+ * @param getPath put path of the returned entry
+ * @param putPath put path of the returned entry
+ * @param type type of data in the entry
+ * @param data data of the returned entry
+ */
+ public void handleResult(AbsoluteTime expiration, HashCode key,
+ List<PeerIdentity> getPath, List<PeerIdentity>
putPath,
+ BlockType type, byte[] data);
+}
Added: gnunet-java/src/main/java/org/gnunet/dht/RouteOption.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/dht/RouteOption.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/dht/RouteOption.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,55 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.dht;
+
+/**
+ * Options passed to the dht service for routing requests.
+ */
+enum RouteOption {
+ /**
+ * Default. Do nothing special.
+ */
+ NONE(0),
+ /**
+ * Each peer along the way should look at 'enc' (otherwise
+ * only the k-peers closest to the key should look at it).
+ */
+ DEMULTIPLEX_EVERYWHERE(1),
+ /**
+ * We should keep track of the route that the message
+ * took in the P2P network.
+ */
+ RECORD_ROUTE(2),
+ /**
+ * This is a 'FIND-PEER' request, so approximate results are fine.
+ */
+ FIND_PEER(4),
+ /**
+ * Possible message option for query key randomization.
+ */
+ BART(8);
+
+ private int val;
+
+ RouteOption(int val) {
+ this.val = val;
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/dht/package-info.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/dht/package-info.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/dht/package-info.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,24 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * API for the gnunet dht service.
+ */
+package org.gnunet.dht;
Added: gnunet-java/src/main/java/org/gnunet/hello/HelloMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/hello/HelloMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/hello/HelloMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,50 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.hello;
+
+import org.gnunet.construct.*;
+import org.gnunet.peerinfo.RsaPublicKeyBinaryEncoded;
+
+/**
+ * A HELLO message is used to exchange information about
+ * transports with other peers. This struct is always
+ * followed by the actual network addresses which have
+ * the format:
+ *
+ * 1) transport-name (0-terminated)
+ * 2) address-length (uint16_t, network byte order; possibly
+ * unaligned!)
+ * 3) address expiration (GNUNET_TIME_AbsoluteNBO); possibly
+ * unaligned!)
+ * 4) address (address-length bytes; possibly unaligned!)
+ *
+ * @author Florian Dold
+ */
+public class HelloMessage implements Message {
+ @UInt32
+ public int reserved;
+
+ @NestedMessage
+ public RsaPublicKeyBinaryEncoded publicKey;
+
+ @FillWith @UInt8
+ public byte[] addresses;
+}
Added: gnunet-java/src/main/java/org/gnunet/hello/package-info.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/hello/package-info.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/hello/package-info.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,25 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+
+/**
+ * Management of hello-messages from peers.
+ */
+package org.gnunet.hello;
Added: gnunet-java/src/main/java/org/gnunet/mesh/ClientConnectMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/mesh/ClientConnectMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/mesh/ClientConnectMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,17 @@
+package org.gnunet.mesh;
+
+import org.gnunet.construct.*;
+import org.gnunet.util.GnunetMessage;
+
+/**
+ * Allows a client to register with the service.
+ *
+ * Direction: client -> service
+ *
+ * @author Florian Dold
+ */
address@hidden(272)
+public class ClientConnectMessage implements GnunetMessage.Body {
+ @IntegerFill(signed = false, bitSize = 32)
+ public int[] apps_list;
+}
Added: gnunet-java/src/main/java/org/gnunet/mesh/ConnectHandler.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/mesh/ConnectHandler.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/mesh/ConnectHandler.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,13 @@
+package org.gnunet.mesh;
+
+import org.gnunet.peerinfo.PeerInfo;
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public interface ConnectHandler {
+ public void onConnect(Mesh.Tunnel tunnel, PeerIdentity peer);
+}
Added: gnunet-java/src/main/java/org/gnunet/mesh/DataMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/mesh/DataMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/mesh/DataMessage.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,19 @@
+package org.gnunet.mesh;
+
+import org.gnunet.construct.*;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
address@hidden(260)
+public class DataMessage implements GnunetMessage.Body {
+ @UInt32
+ public int tid;
+ @FillWith
+ @UInt8
+ public byte[] payload;
+}
Added: gnunet-java/src/main/java/org/gnunet/mesh/DisconnectHandler.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/mesh/DisconnectHandler.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/mesh/DisconnectHandler.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,12 @@
+package org.gnunet.mesh;
+
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public interface DisconnectHandler {
+ void onDisconnect(PeerIdentity peer);
+}
Added: gnunet-java/src/main/java/org/gnunet/mesh/InboundTunnelHandler.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/mesh/InboundTunnelHandler.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/mesh/InboundTunnelHandler.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,12 @@
+package org.gnunet.mesh;
+
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public interface InboundTunnelHandler {
+ void onInboundTunnel(Mesh.Tunnel tunnel, PeerIdentity initiator);
+}
Added: gnunet-java/src/main/java/org/gnunet/mesh/LocalAckMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/mesh/LocalAckMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/mesh/LocalAckMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,18 @@
+package org.gnunet.mesh;
+
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
address@hidden(286)
+public class LocalAckMessage implements GnunetMessage.Body {
+ @UInt32
+ public int tid;
+ @UInt32
+ public int maxPid;
+}
Added: gnunet-java/src/main/java/org/gnunet/mesh/Mesh.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/mesh/Mesh.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/mesh/Mesh.java 2013-08-27 17:16:18 UTC
(rev 28880)
@@ -0,0 +1,309 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.mesh;
+
+import org.gnunet.construct.Construct;
+import org.gnunet.mq.Envelope;
+import org.gnunet.mq.MessageQueue;
+import org.gnunet.mq.NotifySentHandler;
+import org.gnunet.util.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Mesh API
+ *
+ * @author Florian Dold
+ */
+public class Mesh {
+ /**
+ * Class logger.
+ */
+ private static final Logger logger = LoggerFactory
+ .getLogger(Mesh.class);
+
+ /**
+ * For tunnels created by the client, the bit in this
+ * mask is always set.
+ */
+ private static final int TUNNEL_ID_CLI = 0x80000000;
+
+ /**
+ * For tunnels created by the server, the bit in this
+ * mask is always set.
+ */
+ private static final int TUNNEL_ID_SERV = 0xB0000000;
+
+ /**
+ * Disable buffering on intermediate nodes (for minimum latency).
+ * Yes/No.
+ */
+ private static final int OPTION_NOBUFFER = 1;
+
+ /**
+ * Enable tunnel reliability, lost messages will be retransmitted.
+ * Yes/No.
+ */
+ private static final int OPTION_RELIABLE = 2;
+
+ /**
+ * Client connected to the mesh service
+ */
+ private final Client client;
+
+ /**
+ * Called whenever a tunnel was destroyed.
+ */
+ private TunnelEndHandler tunnelEndHandler;
+
+ /**
+ * Message handler for messages received through
+ * a tunnel.
+ */
+ private MeshRunabout messageReceiver;
+
+ /**
+ * Ports that we listen on.
+ */
+ private int[] ports;
+
+ /**
+ * Handler for inbound tunnels.
+ */
+ private InboundTunnelHandler inboundTunnelHandler;
+
+ /**
+ * Mapping from the tunnel's ID to the tunnel object.
+ */
+ private Map<Integer,Tunnel> tunnelMap = new HashMap<Integer,Tunnel>();
+
+ /**
+ * Counter for generating fresh tunnel ID's
+ * when creating new tunnels.
+ */
+ private int next_tid = 1;
+
+ /**
+ * A tunnel to a remote peer.
+ * @param <T> type of context data for the tunnel
+ */
+ public class Tunnel<T> extends MessageQueue {
+ private T context;
+ private final int opt;
+ public final PeerIdentity peer;
+ public final int port;
+ protected int tunnelId;
+ private boolean receive_done_expected = false;
+ int ack_count = 1;
+
+ /**
+ * Canceler for the currently submitted envelope.
+ */
+ public Cancelable envelopeCanceler;
+
+ /**
+ * Create a new tunnel (we're initiator and will be allowed to
add/remove peers
+ * and to broadcast).
+ *
+ * @param context tunnel context
+ * @param peer peer identity the tunnel should go to
+ * @param port Port number.
+ * @param nobuffer Flag for disabling buffering on relay nodes.
+ * @param reliable Flag for end-to-end reliability.
+ */
+ public Tunnel(PeerIdentity peer, int port, boolean nobuffer, boolean
reliable, T context)
+ {
+ this(peer, 0, port, nobuffer, reliable);
+ TunnelCreateMessage tcm = new TunnelCreateMessage();
+ tcm.otherEnd = peer;
+ tcm.opt = opt;
+ tcm.port = port;
+ tcm.tunnel_id = tunnelId;
+ client.send(tcm);
+ }
+
+ /**
+ * Private tunnel constructor, for creating tunnel objects for
+ * incoming tunnels.
+ *
+ * @param peer
+ * @param tunnelId
+ * @param port
+ * @param nobuffer
+ * @param reliable
+ */
+ public Tunnel(PeerIdentity peer, int tunnelId, int port, boolean
nobuffer, boolean reliable) {
+ int my_opt = 0;
+ if (reliable)
+ my_opt |= OPTION_RELIABLE;
+ if (nobuffer)
+ my_opt |= OPTION_NOBUFFER;
+ if (0 == tunnelId)
+ this.tunnelId = ((next_tid++) | TUNNEL_ID_CLI) &
~TUNNEL_ID_SERV;
+ else
+ this.tunnelId = tunnelId;
+ this.peer = peer;
+ this.port = port;
+ this.opt = my_opt;
+ }
+
+ public void receiveDone() {
+ if (!receive_done_expected)
+ throw new AssertionError("unexpected call to receiveDone");
+ LocalAckMessage am = new LocalAckMessage();
+ am.tid = tunnelId;
+ client.send(am);
+ receive_done_expected = false;
+ }
+
+ public void destroy() {
+ TunnelDestroyMessage m = new TunnelDestroyMessage();
+ m.tunnel_id = tunnelId;
+ client.send(m);
+ }
+
+ @Override
+ protected void submit(Envelope ev) {
+ if (ack_count <= 0)
+ throw new AssertionError();
+ DataMessage m = new DataMessage();
+ m.payload = Construct.toBinary(GnunetMessage.fromBody(ev.message));
+ Envelope mesh_ev = new Envelope(m);
+ mesh_ev.notifySent(new NotifySentHandler() {
+ @Override
+ public void onSent() {
+ envelopeCanceler = null;
+ }
+ });
+ client.send(mesh_ev);
+ envelopeCanceler = mesh_ev;
+ ack_count -= 1;
+ }
+
+ @Override
+ protected void retract() {
+ if (envelopeCanceler == null)
+ throw new AssertionError();
+ envelopeCanceler.cancel();
+ envelopeCanceler = null;
+ }
+
+ public T getContext() {
+ return context;
+ }
+
+ public void setContext(T newContext) {
+ context = newContext;
+ }
+
+ }
+
+ private class MeshMessageReceiver extends RunaboutMessageReceiver {
+ public void visit(TunnelCreateMessage m) {
+ Tunnel t = new Tunnel(m.otherEnd, m.tunnel_id, m.port,
+ (m.opt & OPTION_NOBUFFER) != 0, (m.opt & OPTION_NOBUFFER)
!= 0);
+ if (inboundTunnelHandler != null) {
+ inboundTunnelHandler.onInboundTunnel(t, m.otherEnd);
+ }
+ }
+
+ public void visit(DataMessage m) {
+ Tunnel t = tunnelMap.get(m.tid);
+ if (t != null)
+ {
+ if (t.receive_done_expected)
+ logger.warn("got unexpected message from service");
+ t.receive_done_expected = true;
+ messageReceiver.visitAppropriate(Construct.parseAs(m.payload,
GnunetMessage.class).body);
+ }
+ }
+
+ public void visit(LocalAckMessage m) {
+ Tunnel t = tunnelMap.get(m.tid);
+ if (t != null)
+ t.ack_count += 1;
+ }
+
+ public void visit(TunnelDestroyMessage m) {
+ Tunnel t = tunnelMap.get(m.tunnel_id);
+ if (t == null) {
+ logger.warn("server got confused with tunnel IDs on destroy,
ignoring message");
+ return;
+ }
+ t.destroy();
+ tunnelEndHandler.onTunnelEnd(t);
+ }
+
+ @Override
+ public void handleError() {
+ if (tunnelEndHandler != null) {
+ for (Tunnel t : tunnelMap.values()) {
+ tunnelEndHandler.onTunnelEnd(t);
+ }
+ }
+ tunnelMap.clear();
+ client.reconnect();
+ ClientConnectMessage ccm = new ClientConnectMessage();
+ ccm.apps_list = ports;
+ client.send(ccm);
+ }
+ }
+
+ /**
+ * Connect to the mesh service.
+ *
+ * @param cfg configuration to use
+ * @param inboundTunnelHandler function called when an *inbound* tunnel is
created
+ * @param tunnelEndHandler function called when an *inbound* tunnel is
destroyed by the
+ * remote peer, it is *not* called if
Tunnel.destroy
+ * is called on the tunnel
+ */
+ public Mesh(Configuration cfg, InboundTunnelHandler inboundTunnelHandler,
+ TunnelEndHandler tunnelEndHandler, MeshRunabout
messageReceiver, int... ports) {
+ this.tunnelEndHandler = tunnelEndHandler;
+ this.messageReceiver = messageReceiver;
+ this.ports = ports;
+ this.inboundTunnelHandler = inboundTunnelHandler;
+
+ client = new Client("mesh", cfg);
+ client.installReceiver(new MeshMessageReceiver());
+ ClientConnectMessage ccm = new ClientConnectMessage();
+ ccm.apps_list = ports;
+ client.send(ccm);
+ }
+
+ public <T> Tunnel<T> createTunnel(PeerIdentity peer, int port, boolean
nobuffer, boolean reliable, T initialContext) {
+ return new Tunnel<T>(peer, port, nobuffer, reliable, initialContext);
+ }
+
+ /**
+ * Disconnect from the mesh service.
+ * All tunnels will be destroyed.
+ * All tunnel disconnect callbacks will be called on any still connected
peers, notifying
+ * about their disconnection.
+ */
+ public void destroy() {
+ client.disconnect();
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/mesh/MeshRunabout.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/mesh/MeshRunabout.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/mesh/MeshRunabout.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,19 @@
+package org.gnunet.mesh;
+
+import org.gnunet.util.PeerIdentity;
+import org.grothoff.Runabout;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class MeshRunabout extends Runabout {
+ private PeerIdentity sender;
+ /* package private */ void setSender(PeerIdentity sender) {
+ this.sender = sender;
+ }
+ public PeerIdentity getSender() {
+ return sender;
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/mesh/TunnelCreateMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/mesh/TunnelCreateMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/mesh/TunnelCreateMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,27 @@
+package org.gnunet.mesh;
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * FIXME
+ *
+ * @author Florian Dold
+ */
address@hidden(273)
+public class TunnelCreateMessage implements GnunetMessage.Body {
+ @UInt32
+ public int tunnel_id;
+
+ @NestedMessage(optional = false)
+ public PeerIdentity otherEnd;
+
+ @UInt32
+ public int port;
+
+ @UInt32
+ public int opt;
+}
Added: gnunet-java/src/main/java/org/gnunet/mesh/TunnelDestroyMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/mesh/TunnelDestroyMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/mesh/TunnelDestroyMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,16 @@
+package org.gnunet.mesh;
+
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
address@hidden(274)
+public class TunnelDestroyMessage implements GnunetMessage.Body {
+ @UInt32
+ public int tunnel_id;
+}
Added: gnunet-java/src/main/java/org/gnunet/mesh/TunnelEndHandler.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/mesh/TunnelEndHandler.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/mesh/TunnelEndHandler.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,10 @@
+package org.gnunet.mesh;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public interface TunnelEndHandler {
+ void onTunnelEnd(Mesh.Tunnel tunnel);
+}
Added: gnunet-java/src/main/java/org/gnunet/mesh/TunnelNotificationMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/mesh/TunnelNotificationMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/mesh/TunnelNotificationMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,22 @@
+package org.gnunet.mesh;
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UInt32;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class TunnelNotificationMessage implements GnunetMessage.Body {
+ @UInt32
+ public int tunnel_id;
+ /**
+ * Peer at the other end, if any
+ * TODO: ask bart what 'if any' means here
+ */
+ @NestedMessage
+ public PeerIdentity peer;
+}
Added: gnunet-java/src/main/java/org/gnunet/mesh/package-info.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/mesh/package-info.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/mesh/package-info.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,25 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+
+/**
+ * Create tunnels for packet-based communication to distant peers.
+ */
+package org.gnunet.mesh;
Added: gnunet-java/src/main/java/org/gnunet/mq/Envelope.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/mq/Envelope.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/mq/Envelope.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,36 @@
+package org.gnunet.mq;
+
+import org.gnunet.util.Cancelable;
+import org.gnunet.util.GnunetMessage;
+
+/**
+ * Container for a message to be sent by a message queue.
+ */
+public class Envelope implements Cancelable {
+ public final GnunetMessage.Body message;
+ private MessageQueue parent_queue;
+ private NotifySentHandler notify_sent_handler;
+
+ public Envelope(GnunetMessage.Body message) {
+ this.message = message;
+ }
+
+ public void notifySent(NotifySentHandler h) {
+ this.notify_sent_handler = h;
+ }
+
+ public void injectSent() {
+ if (notify_sent_handler != null)
+ notify_sent_handler.onSent();
+ }
+
+ public void cancel() {
+ if (parent_queue == null)
+ throw new AssertionError("can not cancel an unqueued message");
+ }
+
+ /* pkg-private */ void invokeSentNotification() {
+ if (null != notify_sent_handler)
+ notify_sent_handler.onSent();
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/mq/MessageQueue.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/mq/MessageQueue.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/mq/MessageQueue.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,84 @@
+package org.gnunet.mq;
+
+
+import org.gnunet.util.GnunetMessage;
+
+import java.util.LinkedList;
+
+/**
+ * General-purpose message queue
+ */
+public abstract class MessageQueue {
+ private LinkedList<Envelope> queued_envelopes = new LinkedList<Envelope>();
+ private LinkedList<Envelope> prefered_queued_envelopes = new
LinkedList<Envelope>();
+ protected Envelope current_envelope;
+
+ protected abstract void submit(Envelope ev);
+
+ protected abstract void retract();
+
+ public void send(GnunetMessage.Body body) {
+ send(new Envelope(body));
+ }
+
+ public void sendPrefered(GnunetMessage.Body body) {
+ sendPrefered(new Envelope(body));
+ }
+
+ private Envelope pollNextEnvelope() {
+ if (!prefered_queued_envelopes.isEmpty())
+ return prefered_queued_envelopes.removeFirst();
+ if (!queued_envelopes.isEmpty())
+ return queued_envelopes.removeFirst();
+ return null;
+ }
+
+ public void send(Envelope ev) {
+ if (null == current_envelope) {
+ current_envelope = ev;
+ submit(current_envelope);
+ } else {
+ queued_envelopes.addLast(ev);
+ }
+ }
+
+ public void sendPrefered(Envelope ev) {
+ if (null == current_envelope) {
+ current_envelope = ev;
+ submit(current_envelope);
+ } else {
+ prefered_queued_envelopes.addLast(ev);
+ }
+ }
+
+ protected void reportMessageSent() {
+ if (null == current_envelope)
+ throw new AssertionError();
+ current_envelope.invokeSentNotification();
+ next();
+ }
+
+ private void next() {
+ current_envelope = pollNextEnvelope();
+ if (current_envelope == null)
+ return;
+ submit(current_envelope);
+ }
+
+ /**
+ * Cancel sending an envelope. The envelope must be queued in this message
queue.
+ *
+ * @param ev the envelope to cancel
+ */
+ /* pkg-private */ void cancelEnvelope(Envelope ev) {
+ if (null == current_envelope)
+ throw new AssertionError();
+ if (ev == current_envelope) {
+ retract();
+ next();
+ } else {
+ queued_envelopes.remove(ev);
+ prefered_queued_envelopes.remove(ev);
+ }
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/mq/NotifySentHandler.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/mq/NotifySentHandler.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/mq/NotifySentHandler.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,6 @@
+package org.gnunet.mq;
+
+
+public interface NotifySentHandler {
+ void onSent();
+}
Added: gnunet-java/src/main/java/org/gnunet/nse/NetworkSizeEstimation.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/nse/NetworkSizeEstimation.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/nse/NetworkSizeEstimation.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,167 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.nse;
+
+
+import org.gnunet.util.*;
+import org.gnunet.util.getopt.Argument;
+import org.gnunet.util.getopt.ArgumentAction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+
+/**
+ * An API for the network size estimation service.
+ *
+ * @author Florian Dold
+ */
+public class NetworkSizeEstimation {
+ private static final Logger logger = LoggerFactory
+ .getLogger(NetworkSizeEstimation.class);
+
+ private Collection<Subscriber> subscribers = new HashSet<Subscriber>(1);
+ private boolean disconnected = false;
+
+ private Client client;
+
+ private class NSE_Receiver extends RunaboutMessageReceiver {
+ public void visit(UpdateMessage uMsg) {
+ for (Subscriber s : subscribers) {
+ s.update(AbsoluteTime.fromNetwork(uMsg.timestamp),
uMsg.sizeEstimate, uMsg.stdDeviation);
+ }
+
+ if (!disconnected) {
+ client.receiveOne(RelativeTime.FOREVER, this);
+ }
+ }
+
+ @Override
+ public void handleError() {
+ logger.warn("NSE connection lost - trying to reconnect");
+ client.reconnect();
+ requestUpdate();
+ }
+ }
+
+ private class NSE_Transmitter implements MessageTransmitter {
+ @Override
+ public void transmit(Connection.MessageSink sink) {
+ StartMessage m = new StartMessage();
+ sink.send(m);
+ client.receiveOne(RelativeTime.FOREVER, new NSE_Receiver());
+ }
+
+ @Override
+ public void handleError() {
+ logger.warn("NSE connection lost - trying to reconnect");
+ client.reconnect();
+ requestUpdate();
+
+ }
+ }
+
+
+ /**
+ * A handle for a subscription to the network size estimation service, may
be used to cancel the
+ * subscription.
+ */
+ public class Subscription implements Cancelable {
+ private Subscriber sub;
+
+ private Subscription(Subscriber sub) {
+ this.sub = sub;
+ }
+
+ /**
+ * Cancel the subscription.
+ */
+ public void cancel() {
+ subscribers.remove(sub);
+ }
+ }
+
+ /**
+ * A NSE_Subscriber receives updates from the service.
+ */
+ public interface Subscriber {
+ public void update(AbsoluteTime timestamp, double estimate, double
deviation);
+ }
+
+ /**
+ * Subscribe for updates from the service.
+ *
+ * @param s callback for updates
+ * @return a subscription handle that may be used to cancel the
subscription
+ */
+ public Cancelable subscribe(Subscriber s) {
+ subscribers.add(s);
+ requestUpdate();
+ return new Subscription(s);
+ }
+
+ /**
+ * Create a connection to the network size estimation service.
+ *
+ * @param cfg the configuration to use for connecting with the service
+ */
+ public NetworkSizeEstimation(Configuration cfg) {
+ client = new Client("nse", cfg);
+ }
+
+ private void requestUpdate() {
+ client.notifyTransmitReady(RelativeTime.FOREVER, true, 0, new
NSE_Transmitter());
+ }
+
+ /**
+ * Cancel all subscriptions and disconnect from the service.
+ */
+ public void disconnect() {
+ disconnected = true;
+ }
+
+ public static void main(String[] args) {
+ new Program(args) {
+ @Argument(action = ArgumentAction.SET,
+ shortname = "w",
+ longname = "watch",
+ description = "wait and watch for more NSE updates")
+ boolean cont = false;
+
+ public void run() {
+ final NetworkSizeEstimation svc = new
NetworkSizeEstimation(cfg);
+
+ Subscriber subscriber = new Subscriber() {
+ @Override
+ public void update(AbsoluteTime timestamp, double
estimate, double deviation) {
+ System.out.println("est: " + estimate + " dev: " +
deviation + " t: " + timestamp.toDate());
+ if (!cont) {
+ svc.disconnect();
+ }
+ }
+ };
+ svc.subscribe(subscriber);
+ }
+ }.start();
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/nse/StartMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/nse/StartMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/nse/StartMessage.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,12 @@
+package org.gnunet.nse;
+
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+
+/**
+* ...
+*
+* @author Florian Dold
+*/
address@hidden(321)
+public class StartMessage implements GnunetMessage.Body {}
Added: gnunet-java/src/main/java/org/gnunet/nse/UpdateMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/nse/UpdateMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/nse/UpdateMessage.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,26 @@
+package org.gnunet.nse;
+
+import org.gnunet.construct.*;
+import org.gnunet.construct.DoubleValue;
+import org.gnunet.util.AbsoluteTimeMessage;
+import org.gnunet.util.GnunetMessage;
+
+/**
+* ...
+*
+* @author Florian Dold
+*/
address@hidden(323)
+public class UpdateMessage implements GnunetMessage.Body {
+ @UInt32
+ public int reserved;
+
+ @NestedMessage
+ public AbsoluteTimeMessage timestamp;
+
+ @DoubleValue
+ public double sizeEstimate;
+
+ @DoubleValue
+ public double stdDeviation;
+}
Added: gnunet-java/src/main/java/org/gnunet/nse/package-info.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/nse/package-info.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/nse/package-info.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,24 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * API for the gnunet nse service.
+ */
+package org.gnunet.nse;
Added: gnunet-java/src/main/java/org/gnunet/peerinfo/InfoEnd.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/peerinfo/InfoEnd.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/peerinfo/InfoEnd.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,14 @@
+package org.gnunet.peerinfo;
+
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
address@hidden(333)
+public class InfoEnd implements GnunetMessage.Body {
+
+}
Added: gnunet-java/src/main/java/org/gnunet/peerinfo/InfoMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/peerinfo/InfoMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/peerinfo/InfoMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,50 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.peerinfo;
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.hello.HelloMessage;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * @author Florian Dold
+ */
address@hidden(332)
+public class InfoMessage implements GnunetMessage.Body {
+ /**
+ * Always zero.
+ */
+ @UInt32
+ public int reserved;
+ /**
+ * About which peer are we talking here?
+ */
+ @NestedMessage
+ public PeerIdentity peerIdentity;
+ /**
+ * HELLO of the peer, null if no HELLO present.
+ */
+ @NestedMessage(optional = true)
+ public HelloMessage hello;
+}
Added: gnunet-java/src/main/java/org/gnunet/peerinfo/ListAllPeersMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/peerinfo/ListAllPeersMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/peerinfo/ListAllPeersMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,39 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.peerinfo;
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * Message requesting a listing of all known peers,
+ * possibly restricted to the specified peer identity.
+ *
+ * @author Florian Dold
+ */
address@hidden(331)
+public class ListAllPeersMessage implements GnunetMessage.Body {
+ @UInt32
+ public int include_friend_only;
+}
Added: gnunet-java/src/main/java/org/gnunet/peerinfo/ListPeerMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/peerinfo/ListPeerMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/peerinfo/ListPeerMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,39 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.peerinfo;
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UInt32;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * Message requesting a listing of all known peers,
+ * possibly restricted to the specified peer identity.
+ *
+ * @author Florian Dold
+ */
+public class ListPeerMessage implements GnunetMessage.Body {
+ @UInt32
+ public int reserved;
+ @NestedMessage
+ public PeerIdentity peer;
+}
Added: gnunet-java/src/main/java/org/gnunet/peerinfo/PeerInfo.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/peerinfo/PeerInfo.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/peerinfo/PeerInfo.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,159 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.peerinfo;
+
+import org.gnunet.hello.HelloMessage;
+import org.gnunet.mq.Envelope;
+import org.gnunet.mq.MessageQueue;
+import org.gnunet.requests.RequestContainer;
+import org.gnunet.requests.SequentialRequestContainer;
+import org.gnunet.util.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Interface to the service that maintains all known hosts.
+ *
+ * @author Florian Dold
+ */
+public class PeerInfo {
+ private static final Logger logger = LoggerFactory
+ .getLogger(AbsoluteTime.class);
+
+ /**
+ * Client that connects to the peerinfo service.
+ */
+ private final Client client;
+
+ /**
+ * All currently active iterate requests.
+ */
+ private SequentialRequestContainer<PeerIterateRequest> iterate_requests;
+
+ private class PeerIterateRequest extends RequestContainer.Request {
+ public PeerIdentity peer;
+ public PeerProcessor peerProcessor;
+ public boolean friend_only;
+ public boolean canceled;
+
+ public PeerIterateRequest(PeerIdentity peer, boolean friend_only,
PeerProcessor peerProcessor) {
+ this.peer = peer;
+ this.peerProcessor = peerProcessor;
+ this.friend_only = friend_only;
+ }
+
+ @Override
+ public Envelope assembleRequest() {
+ if (peer == null) {
+ ListAllPeersMessage m = new ListAllPeersMessage();
+ m.include_friend_only = friend_only ? 1 : 0;
+ return new Envelope(m);
+ } else {
+ ListPeerMessage m = new ListPeerMessage();
+ m.peer = peer;
+ return new Envelope(m);
+ }
+ }
+
+ public void cancel() {
+ canceled = true;
+ }
+ }
+
+ private class PeerInfoMessageReceiver extends RunaboutMessageReceiver {
+ public void visit(InfoEnd infoEnd) {
+ PeerIterateRequest r = iterate_requests.getRequest();
+ if (!r.canceled)
+ r.peerProcessor.onEnd();
+ iterate_requests.next();
+ }
+ public void visit(InfoMessage infoMessage) {
+ PeerIterateRequest r = iterate_requests.getRequest();
+ if (!r.canceled)
+ r.peerProcessor.onPeer(infoMessage.peerIdentity,
infoMessage.hello);
+ }
+
+ @Override
+ public void handleError() {
+ client.reconnect();
+ iterate_requests.restart();
+ }
+ }
+
+
+ public PeerInfo(Configuration cfg) {
+ client = new Client("peerinfo", cfg);
+ client.installReceiver(new PeerInfoMessageReceiver());
+ iterate_requests = new
SequentialRequestContainer<PeerIterateRequest>(client);
+ // Make sure that new requests are only sent once the old request has
finished.
+ // Otherwise, the peerinfo service would send the answers interleaved.
+ iterate_requests.setOverlap(false);
+ }
+
+ /**
+ * Iterates over the HELLOs of all peers.
+ *
+ * @param timeout
+ * @param processor
+ * @return
+ */
+ public Cancelable iterate(RelativeTime timeout, boolean friend_only,
PeerProcessor processor) {
+ return iterate(timeout, null, friend_only, processor);
+ }
+
+ /**
+ * Iterates over the HELLOs of the given peer.
+ * Can be called with peer=null to iterate over all peers.
+ * @param timeout
+ * @param peer
+ * @param processor
+ * @return
+ */
+ public Cancelable iterate(RelativeTime timeout, PeerIdentity peer, boolean
friend_only, PeerProcessor processor) {
+ PeerIterateRequest r = new PeerIterateRequest(peer, friend_only,
processor);
+ return iterate_requests.addRequest(r);
+ }
+
+ public void disconnect() {
+ client.disconnect();
+ }
+
+ public static void main(String... args) {
+ new Program(args) {
+ @Override
+ public void run() {
+ final PeerInfo peerInfo = new PeerInfo(getConfiguration());
+ peerInfo.iterate(RelativeTime.FOREVER, false, new
PeerProcessor() {
+ @Override
+ public void onPeer(PeerIdentity peerIdentity, HelloMessage
hello) {
+ System.out.println("peer " + peerIdentity.toString());
+ }
+
+ @Override
+ public void onEnd() {
+ System.out.println("got peer end");
+ peerInfo.disconnect();
+ }
+ });
+ }
+ }.start();
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/peerinfo/PeerProcessor.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/peerinfo/PeerProcessor.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/peerinfo/PeerProcessor.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,12 @@
+package org.gnunet.peerinfo;
+
+import org.gnunet.hello.HelloMessage;
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * Callback class to receive known peers and their HELLOs.
+ */
+public interface PeerProcessor {
+ public void onPeer(PeerIdentity peerIdentity, HelloMessage hello);
+ public void onEnd();
+}
Added:
gnunet-java/src/main/java/org/gnunet/peerinfo/RsaPublicKeyBinaryEncoded.java
===================================================================
---
gnunet-java/src/main/java/org/gnunet/peerinfo/RsaPublicKeyBinaryEncoded.java
(rev 0)
+++
gnunet-java/src/main/java/org/gnunet/peerinfo/RsaPublicKeyBinaryEncoded.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,56 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.peerinfo;
+
+import org.gnunet.construct.FixedSizeIntegerArray;
+import org.gnunet.construct.Message;
+import org.gnunet.construct.UInt16;
+import org.gnunet.construct.UInt8;
+
+/**
+ * @author Florian Dold
+ */
+public class RsaPublicKeyBinaryEncoded implements Message {
+ public static final int GNUNET_CRYPTO_RSA_KEY_LENGTH = 258;
+
+ /**
+ * In big-endian, must be GNUNET_CRYPTO_RSA_KEY_LENGTH+4
+ */
+ @UInt16
+ public int len;
+ /**
+ * Size of n in key; in big-endian!
+ */
+ @UInt16
+ public int sizen;
+
+ /**
+ * The key itself, contains n followed by e.
+ */
+ @FixedSizeIntegerArray(length =
RsaPublicKeyBinaryEncoded.GNUNET_CRYPTO_RSA_KEY_LENGTH, signed = false, bitSize
= 8)
+ public byte[] key;
+
+ /**
+ * Padding.
+ */
+ @UInt8
+ public byte reserved;
+}
Added: gnunet-java/src/main/java/org/gnunet/peerinfo/package-info.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/peerinfo/package-info.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/peerinfo/package-info.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,25 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+
+/**
+ * Access to information about known hosts.
+ */
+package org.gnunet.peerinfo;
Added:
gnunet-java/src/main/java/org/gnunet/requests/MatchingRequestContainer.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/requests/MatchingRequestContainer.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/requests/MatchingRequestContainer.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,51 @@
+package org.gnunet.requests;
+
+import com.google.common.collect.Maps;
+import org.gnunet.mq.MessageQueue;
+import org.gnunet.util.Cancelable;
+
+import java.util.Map;
+
+
+public class MatchingRequestContainer<K, T extends RequestContainer.Request>
extends RequestContainer {
+ private Map<K,T> requests = Maps.newHashMap();
+ private final MessageQueue mq;
+
+ public MatchingRequestContainer(MessageQueue mq) {
+ this.mq = mq;
+ }
+
+ public Cancelable addRequest(K key, final T request) {
+ if (requests.containsKey(key))
+ throw new AssertionError("key already present in request
container");
+ requests.put(key, request);
+ mq.send(request.assembleRequest());
+ return new Cancelable() {
+ @Override
+ public void cancel() {
+ setRequestCancelled(request);
+ if (isRequestTransmitting(request)) {
+ cancelRequestTransmission(request);
+ } else {
+ request.cancel();
+ }
+ }
+ };
+ }
+
+ @Override
+ public void restart() {
+ Map<K,T> requestsOld = requests;
+ requests = Maps.newHashMap();
+ for (Map.Entry<K,T> e : requestsOld.entrySet()) {
+ if (!isRequestCancelled(e.getValue())) {
+ setRequestTransmitting(e.getValue(), false);
+ addRequest(e.getKey(), e.getValue());
+ }
+ }
+ }
+
+ public T getRequest(K key) {
+ return requests.get(key);
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/requests/RequestContainer.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/requests/RequestContainer.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/requests/RequestContainer.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,59 @@
+package org.gnunet.requests;
+
+
+import org.gnunet.mq.Envelope;
+import org.gnunet.util.Cancelable;
+
+public abstract class RequestContainer {
+ protected boolean overlap = true;
+
+ public abstract static class Request {
+ private boolean transmitting;
+ private boolean canceled;
+ private Cancelable cancelRequest;
+ public abstract Envelope assembleRequest();
+ public void cancel() {
+ throw new AssertionError("request of type " + this.getClass() + "
can not be canceled (not implemented)");
+ }
+ }
+
+ /**
+ * Re-send all requests in the queue that have not been canceled.
+ */
+ public abstract void restart();
+
+ /**
+ * Allow or disallow requests to be send while other requests in the queue
have not been completed.
+ *
+ * @param overlap true to allow overlapped requests, false to disallow them
+ */
+ public void setOverlap(boolean overlap) {
+ this.overlap = overlap;
+ }
+
+ protected boolean isRequestTransmitting(Request r) {
+ return r.transmitting;
+ }
+
+ protected void setRequestTransmitting(Request r, boolean transmitting) {
+ r.transmitting = transmitting;
+ }
+
+ protected void setRequestTransmissionCancel(Request request, Cancelable
cancel) {
+ request.cancelRequest = cancel;
+ }
+
+ protected void cancelRequestTransmission(Request r) {
+ r.cancelRequest.cancel();
+ r.cancelRequest = null;
+ }
+
+ protected void setRequestCancelled(Request r) {
+ r.canceled = true;
+ }
+
+ protected boolean isRequestCancelled(Request r) {
+ return r.canceled;
+ }
+
+}
Added:
gnunet-java/src/main/java/org/gnunet/requests/SequentialRequestContainer.java
===================================================================
---
gnunet-java/src/main/java/org/gnunet/requests/SequentialRequestContainer.java
(rev 0)
+++
gnunet-java/src/main/java/org/gnunet/requests/SequentialRequestContainer.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,86 @@
+package org.gnunet.requests;
+
+import org.gnunet.mq.Envelope;
+import org.gnunet.mq.MessageQueue;
+import org.gnunet.mq.NotifySentHandler;
+import org.gnunet.util.Cancelable;
+
+import java.util.LinkedList;
+
+/**
+ * Container for requests that are responded to in sequential order.
+ */
+public class SequentialRequestContainer<T extends RequestContainer.Request>
extends RequestContainer {
+ private LinkedList<T> requests = new LinkedList<T>();
+ private MessageQueue mq;
+
+ int requestsActive = 0;
+
+ public SequentialRequestContainer(MessageQueue mq) {
+ this.mq = mq;
+ }
+
+ public T getRequest() {
+ return requests.getFirst();
+ }
+
+ public void next() {
+ if (requestsActive == 0 || requests.isEmpty())
+ throw new AssertionError();
+ requestsActive--;
+ requests.removeFirst();
+ if (requestsActive == 0 && !requests.isEmpty()) {
+ Request r = requests.getFirst();
+ setRequestTransmitting(r, true);
+ Envelope ev = r.assembleRequest();
+ setRequestTransmissionCancel(r, ev);
+ mq.send(r.assembleRequest());
+ requestsActive++;
+ }
+ }
+
+ public Cancelable addRequest(final T request) {
+ requests.addLast(request);
+ if (overlap || requestsActive == 0) {
+ requestsActive++;
+ setRequestTransmitting(request, true);
+ Envelope ev = request.assembleRequest();
+ ev.notifySent(new NotifySentHandler() {
+ @Override
+ public void onSent() {
+ setRequestTransmitting(request, false);
+ }
+ });
+ setRequestTransmissionCancel(request, ev);
+ mq.send(request.assembleRequest());
+ }
+ return new Cancelable() {
+ @Override
+ public void cancel() {
+ setRequestCancelled(request);
+ if (isRequestTransmitting(request)) {
+ cancelRequestTransmission(request);
+ } else {
+ request.cancel();
+ }
+ }
+ };
+ }
+
+ @Override
+ public void restart() {
+ LinkedList<T> requestsOld = requests;
+ requests = new LinkedList<T>();
+ for (T r : requestsOld) {
+ if (!isRequestCancelled(r)) {
+ setRequestTransmitting(r, false);
+ addRequest(r);
+ }
+ }
+ }
+
+
+ public Iterable<T> iter() {
+ return requests;
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/requests/package-info.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/requests/package-info.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/requests/package-info.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,25 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+
+/**
+ * General mechanism for queueing requests to a service.
+ */
+package org.gnunet.requests;
Added: gnunet-java/src/main/java/org/gnunet/statistics/GetMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/statistics/GetMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/statistics/GetMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,43 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.statistics;
+
+import org.gnunet.construct.UnionCase;
+import org.gnunet.construct.ZeroTerminatedString;
+import org.gnunet.util.GnunetMessage;
+
+/**
+ * Client --> Service
+ *
+ */
address@hidden(169)
+public class GetMessage implements GnunetMessage.Body {
+ /**
+ * Subsystem of interest, empty string for all subsystems.
+ */
+ @ZeroTerminatedString
+ public String subsystemName;
+ /**
+ * Statistics value name of interest, empty string for all values.
+ */
+ @ZeroTerminatedString
+ public String statisticsName;
+}
Added: gnunet-java/src/main/java/org/gnunet/statistics/GetRequest.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/statistics/GetRequest.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/statistics/GetRequest.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,31 @@
+package org.gnunet.statistics;
+
+import org.gnunet.mq.Envelope;
+import org.gnunet.mq.MessageQueue;
+import org.gnunet.requests.RequestContainer;
+
+/**
+ */
+public class GetRequest extends RequestContainer.Request {
+ private final String subsystem;
+ private final String name;
+ public final StatisticsReceiver receiver;
+ private RequestContainer parent;
+
+ public GetRequest(String subsystem, String name, StatisticsReceiver
receiver) {
+ this.subsystem = subsystem;
+ this.name = name;
+ this.receiver = receiver;
+ }
+
+ @Override
+ public Envelope assembleRequest() {
+ GetMessage m = new GetMessage();
+ m.subsystemName = subsystem;
+ m.statisticsName = name;
+ return new Envelope(m);
+ }
+
+ public void cancel() {
+ }
+}
Added:
gnunet-java/src/main/java/org/gnunet/statistics/GetResponseEndMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/statistics/GetResponseEndMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/statistics/GetResponseEndMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,32 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.statistics;
+
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+
+/**
+ * ...
+*/
address@hidden(171)
+public class GetResponseEndMessage implements GnunetMessage.Body {
+ // empty
+}
Added: gnunet-java/src/main/java/org/gnunet/statistics/GetResponseMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/statistics/GetResponseMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/statistics/GetResponseMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,49 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.statistics;
+
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UInt64;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.construct.ZeroTerminatedString;
+import org.gnunet.util.GnunetMessage;
+
+/**
+ * service --> client
+ *
+ *
+ */
address@hidden(170)
+public class GetResponseMessage implements GnunetMessage.Body {
+ /**
+ * Unique numerical identifier for the value (will
+ * not change during the same client-session). Highest
+ * bit will be set for persistent values.
+ */
+ @UInt32
+ public long uid;
+ @UInt64
+ public long value;
+ @ZeroTerminatedString
+ public String subsystemName;
+ @ZeroTerminatedString
+ public String statisticName;
+}
Added: gnunet-java/src/main/java/org/gnunet/statistics/SetMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/statistics/SetMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/statistics/SetMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,43 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.statistics;
+
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UInt64;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.construct.ZeroTerminatedString;
+import org.gnunet.util.GnunetMessage;
+
+
+/**
+ * Sent to the service by the client to set a statistics value.
+ */
address@hidden(168)
+public class SetMessage implements GnunetMessage.Body {
+ @UInt32
+ public int flags;
+ @UInt64
+ public long value;
+ @ZeroTerminatedString
+ public String subsystemName;
+ @ZeroTerminatedString
+ public String statisticName;
+}
Added: gnunet-java/src/main/java/org/gnunet/statistics/SetRequest.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/statistics/SetRequest.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/statistics/SetRequest.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,48 @@
+package org.gnunet.statistics;
+
+import org.gnunet.mq.Envelope;
+import org.gnunet.mq.MessageQueue;
+import org.gnunet.requests.RequestContainer;
+import org.gnunet.util.RelativeTime;
+
+
+public class SetRequest extends RequestContainer.Request {
+ /**
+ * Time after we give up on setting values in statistics
+ */
+ private static final RelativeTime SET_TIMEOUT =
RelativeTime.SECOND.multiply(10);
+
+ private final static int SETFLAG_RELATIVE = 1;
+ private final static int SETFLAG_PERSIST = 2;
+ private final String subsystem;
+ private final String name;
+ private final boolean persist;
+ private final long value;
+ private final boolean relative;
+
+ public SetRequest(String subsystem, String name, long value, boolean
relative, boolean persist) {
+ this.subsystem = subsystem;
+ this.name = name;
+ this.persist = persist;
+ this.value = value;
+ this.relative = relative;
+
+ }
+
+ @Override
+ public Envelope assembleRequest() {
+ SetMessage m = new SetMessage();
+ m.statisticName = name;
+ m.subsystemName = subsystem;
+ m.value = value;
+ if (relative)
+ m.flags |= SETFLAG_RELATIVE;
+ if (persist)
+ m.flags |= SETFLAG_PERSIST;
+ return new Envelope(m);
+ }
+
+ public void cancel() {
+ //To change body of implemented methods use File | Settings | File
Templates.
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/statistics/Statistics.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/statistics/Statistics.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/statistics/Statistics.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,310 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * The stuff below does nothing whatsoever, first milestone of
+ * this project is to implement the StatisticsService api
+ *
+ */
+
+package org.gnunet.statistics;
+
+import org.gnunet.requests.MatchingRequestContainer;
+import org.gnunet.requests.SequentialRequestContainer;
+import org.gnunet.util.*;
+import org.gnunet.util.getopt.Argument;
+import org.gnunet.util.getopt.ArgumentAction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * API for the GNUnet statistics service.
+ * <p/>
+ * Set, get and monitor statistics values, represented as unsigned 64bit
integer.
+ * Note that address@hidden long}, java's largest primitive type, can only
store signed 64bit integers.
+ * With absolute operation, its negative values are interpreted as large
numbers by the statistics api.
+ */
+public class Statistics {
+ private static final Logger logger = LoggerFactory
+ .getLogger(Statistics.class);
+
+ /**
+ * Client connecting us to the statistics service.
+ */
+ private final Client client;
+
+ SequentialRequestContainer<SetRequest> set_requests;
+ SequentialRequestContainer<GetRequest> get_requests;
+ MatchingRequestContainer<Long,WatchRequest> watch_requests;
+
+ private boolean destroy_requested;
+
+ private long wid = 0;
+
+ public class StatisticsMessageReceiver extends RunaboutMessageReceiver {
+ public void visit(GetResponseMessage m) {
+ GetRequest r = get_requests.getRequest();
+ if (r != null)
+ r.receiver.onReceive(m.subsystemName, m.statisticName,
m.value);
+ }
+
+ public void visit(GetResponseEndMessage m) {
+ GetRequest r = get_requests.getRequest();
+ if (r != null)
+ r.receiver.onDone();
+ //noinspection ConstantConditions
+ if (get_requests != null)
+ get_requests.next();
+ }
+
+ public void visit(TestMessage m) {
+ System.out.println("got back TEST message");
+ client.disconnect();
+ }
+
+ public void visit(WatchResponseMessage wrm) {
+ WatchRequest r = watch_requests.getRequest((long) wrm.wid);
+ if (r != null) {
+ r.watcher.onReceive(r.subsystem, r.name, wrm.value);
+ }
+ }
+
+ @Override
+ public void handleError() {
+ if (!destroy_requested) {
+ client.reconnect();
+ get_requests.restart();
+ set_requests.restart();
+ watch_requests.restart();
+ }
+ }
+ }
+
+ public Statistics(Configuration cfg) {
+ client = new Client("statistics", cfg);
+ client.installReceiver(new StatisticsMessageReceiver());
+ get_requests = new SequentialRequestContainer<GetRequest>(client);
+ set_requests = new SequentialRequestContainer<SetRequest>(client);
+ watch_requests = new MatchingRequestContainer<Long,
WatchRequest>(client);
+ }
+
+ /**
+ * Retrieve values from statistics.
+ * Only one instance of this request may be active simultaneously.
+ * Upon cancellation
+ *
+ * @param timeout time after we give up and call receiver.onTimeout
+ * @param subsystem the subsystem of interest
+ * @param name name of the statistics value belongs to
+ * @param receiver callback
+ * @return handle to cancel the request
+ */
+ public Cancelable get(RelativeTime timeout, final String subsystem, final
String name,
+ final StatisticsReceiver receiver) {
+ if (destroy_requested)
+ throw new AssertionError("already destroyed");
+ return get_requests.addRequest(new GetRequest(subsystem, name,
receiver));
+ }
+
+ /**
+ * Sets a statistics value asynchronously.
+ *
+ * @param name name of the entry
+ * @param value desired value
+ * @param persist keep value even if the statistics service restarts
+ * @return a handle to cancel the request
+ */
+ public Cancelable set(final String subsystem, final String name, final
long value, boolean persist) {
+ if (destroy_requested)
+ throw new AssertionError("already destroyed");
+ return set_requests.addRequest(new SetRequest(subsystem, name, value,
false, persist));
+ }
+
+ /**
+ * Changes a statistics value asynchronously.
+ *
+ * @param name name of the entry
+ * @param delta relative difference to the old value
+ * @param persist keep value even if the statistics service restarts
+ * @return a handle to cancel the request
+ */
+ public Cancelable update(final String subsystem, final String name, final
long delta, boolean persist) {
+ if (destroy_requested)
+ throw new AssertionError("already destroyed");
+ return set_requests.addRequest(new SetRequest(subsystem, name, delta,
true, persist));
+ }
+
+ /**
+ * Receive updates about changing statistics values.
+ *
+ * @param subsystem the subsystem to watch
+ * @param name the value to watch
+ * @param watcher the object that receives the updates
+ * @return a handle to cancel the request
+ */
+ public Cancelable watch(final String subsystem, final String name,
StatisticsWatcher watcher) {
+ if (destroy_requested)
+ throw new AssertionError("already destroyed");
+ WatchRequest r = new WatchRequest(subsystem, name, watcher);
+ return watch_requests.addRequest(wid++, r);
+ }
+
+ /**
+ * Destroy handle to the statistics service. Always finishes writing
pending values.
+ */
+ public void destroy() {
+ destroy_requested = true;
+ client.send(new TestMessage());
+ // wait until the service responds
+ // TODO: or timeout
+ System.out.println("destroying statistics");
+ }
+
+
+ /**
+ * Statistics command line utility entry point
+ *
+ * @param args command line arguments
+ */
+ public static void main(String[] args) {
+ new Program(args) {
+ @Argument(
+ shortname = "x",
+ longname = "set",
+ action = ArgumentAction.SET,
+ description = "watch a value")
+ boolean set;
+ @Argument(
+ shortname = "w",
+ longname = "watch",
+ action = ArgumentAction.SET,
+ description = "set a value")
+ boolean watch;
+ @Argument(
+ shortname = "n",
+ longname = "name",
+ action = ArgumentAction.STORE_STRING,
+ argumentName = "NAME",
+ description = "statistics name")
+ String statisticsName = "";
+ @Argument(
+ shortname = "s",
+ longname = "subsystem",
+ argumentName = "SUBSYS",
+ action = ArgumentAction.STORE_STRING,
+ description = "subsystem name")
+ String subsystemName = "";
+ @Argument(
+ shortname = "p",
+ longname = "persistent",
+ action = ArgumentAction.SET,
+ description = "set value persistently (used with -x)")
+ boolean persistent = false;
+ @Argument(
+ shortname = "r",
+ longname = "relative",
+ action = ArgumentAction.SET,
+ description = "set value relative to old value (used with
-x)")
+ boolean relative = false;
+
+ @Override
+ protected String makeHelpText() {
+ return "Get, set and watch GNUnet's statistics.";
+ }
+
+ public void run() {
+ final Statistics statistics = new Statistics(cfg);
+
+ if (set && watch) {
+ System.err.println("--watch/-w and --set/-s cannot be used
together");
+ return;
+ }
+
+ if (set) {
+ if (subsystemName.isEmpty() || statisticsName.isEmpty()) {
+ System.err.println("both subsystem and name must be
given for --set/-x");
+ return;
+ }
+ if (unprocessedArgs.length != 1) {
+ System.err.println("must specify exactly one value to
set");
+ return;
+ }
+ long value;
+ try {
+ value = Long.parseLong(unprocessedArgs[0]);
+ } catch (NumberFormatException e) {
+ System.err.println("invalid value (not a long)");
+ return;
+ }
+ if (relative)
+ statistics.update(subsystemName, statisticsName,
value, persistent);
+ else
+ statistics.set(subsystemName, statisticsName, value,
persistent);
+ statistics.destroy();
+ return;
+ }
+
+ if (unprocessedArgs.length != 0) {
+ System.err.println("dumping statistics does not take any
positional parameters");
+ return;
+ }
+
+ if (watch) {
+ if (subsystemName.isEmpty() || statisticsName.isEmpty()) {
+ System.err.println("both subsystem and name must be
given for --watch/-w");
+ return;
+ }
+ statistics.watch(subsystemName, statisticsName,
+ new StatisticsWatcher() {
+ @Override
+ public void onReceive(String subsystem, String
name, long value) {
+ System.out.println(subsystem + "(" + name
+ ") = " + value);
+ }
+
+ @Override
+ public void onTimeout() {
+ System.err.println("timeout");
+ }
+ }
+ );
+ } else {
+ statistics.get(RelativeTime.SECOND, subsystemName,
statisticsName,
+ new StatisticsReceiver() {
+ @Override
+ public void onReceive(String subsystem, String
name, long value) {
+ System.out.println(subsystem + "(" + name
+ ") = " + value);
+ }
+
+ @Override
+ public void onTimeout() {
+ System.err.println("timeout");
+ }
+
+ @Override
+ public void onDone() {
+ statistics.destroy();
+ }
+ }
+ );
+ }
+ }
+ }.start();
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/statistics/StatisticsReceiver.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/statistics/StatisticsReceiver.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/statistics/StatisticsReceiver.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,29 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.statistics;
+
+
+
+public interface StatisticsReceiver {
+ public void onReceive(String subsystem, String name, long value);
+ public void onTimeout();
+ public void onDone();
+}
Added: gnunet-java/src/main/java/org/gnunet/statistics/StatisticsWatcher.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/statistics/StatisticsWatcher.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/statistics/StatisticsWatcher.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,13 @@
+package org.gnunet.statistics;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: dold
+ * Date: 8/24/13
+ * Time: 5:56 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public interface StatisticsWatcher {
+ public void onReceive(String subsystem, String name, long value);
+ public void onTimeout();
+}
Added: gnunet-java/src/main/java/org/gnunet/statistics/WatchMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/statistics/WatchMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/statistics/WatchMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,40 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.statistics;
+
+
+import org.gnunet.construct.UnionCase;
+import org.gnunet.construct.ZeroTerminatedString;
+import org.gnunet.util.GnunetMessage;
+
address@hidden(172)
+public class WatchMessage implements GnunetMessage.Body {
+ /**
+ * Subsystem of interest, may not be empty.
+ */
+ @ZeroTerminatedString
+ public String subsystemName;
+ /**
+ * Statistics value name of interest, may not be empty.
+ */
+ @ZeroTerminatedString
+ public String statisticsName;
+}
Added: gnunet-java/src/main/java/org/gnunet/statistics/WatchRequest.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/statistics/WatchRequest.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/statistics/WatchRequest.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,31 @@
+package org.gnunet.statistics;
+
+import org.gnunet.mq.Envelope;
+import org.gnunet.mq.MessageQueue;
+import org.gnunet.requests.RequestContainer;
+
+/**
+ */
+public class WatchRequest extends RequestContainer.Request {
+ public String subsystem;
+ public String name;
+ public StatisticsWatcher watcher;
+
+ public WatchRequest(String subsystem, String name, StatisticsWatcher
watcher) {
+ this.subsystem = subsystem;
+ this.name = name;
+ this.watcher = watcher;
+ }
+
+ @Override
+ public Envelope assembleRequest() {
+ WatchMessage m = new WatchMessage();
+ m.statisticsName = name;
+ m.subsystemName = subsystem;
+ return new Envelope(m);
+ }
+
+ public void cancel() {
+
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/statistics/WatchResponseMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/statistics/WatchResponseMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/statistics/WatchResponseMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,39 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.statistics;
+
+
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UInt64;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+
address@hidden(173)
+public class WatchResponseMessage implements GnunetMessage.Body {
+ @UInt32
+ public int flags;
+ @UInt32
+ public int wid;
+ @UInt32
+ public int reserved ;
+ @UInt64
+ public long value;
+}
Added: gnunet-java/src/main/java/org/gnunet/statistics/package-info.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/statistics/package-info.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/statistics/package-info.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,24 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * API for the gnunet statistics service.
+ */
+package org.gnunet.statistics;
Added: gnunet-java/src/main/java/org/gnunet/testbed/Controller.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/Controller.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/testbed/Controller.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,84 @@
+package org.gnunet.testbed;
+
+import org.gnunet.util.Client;
+import org.gnunet.util.Configuration;
+
+/**
+ * Handle to interact with a GNUnet testbed controller. Each
+ * controller has at least one master handle which is created when the
+ * controller is created; this master handle interacts with the
+ * controller process, destroying it destroys the controller (by
+ * closing stdin of the controller process). Additionally,
+ * controllers can interact with each other (in a P2P fashion); those
+ * links are established via TCP/IP on the controller's service port.
+ */
+public class Controller {
+
+ /**
+ * Client connecting to the testbed service.
+ */
+ Client client;
+
+ /**
+ * Connect to a controller process. The configuration to use for the
connection
+ * is retreived from the given host where a controller is started using
+ * GNUNET_TESTBED_controller_start().
+ *
+ * @param host host to run the controller on; This should be the same host
if
+ * the controller was previously started with
+ * GNUNET_TESTBED_controller_start()
+ * @param event_mask bit mask with set of events to call 'cc' for;
+ * or-ed values of "1LL" shifted by the
+ * respective 'enum GNUNET_TESTBED_EventType'
+ * (i.e. "(1LL << GNUNET_TESTBED_ET_CONNECT) | ...")
+ * @param cb controller callback to invoke on events
+ */
+ public Controller(Host host, long event_mask, ControllerEventCallback cb) {
+ client = new Client("testbed", host.cfg);
+ }
+
+
+ /**
+ * Create the given peer at the specified host using the given
+ * controller. If the given controller is not running on the target
+ * host, it should find or create a controller at the target host and
+ * delegate creating the peer. Explicit delegation paths can be setup
+ * using 'GNUNET_TESTBED_controller_link'. If no explicit delegation
+ * path exists, a direct link with a subordinate controller is setup
+ * for the first delegated peer to a particular host; the subordinate
+ * controller is then destroyed once the last peer that was delegated
+ * to the remote host is stopped.
+ *
+ * Creating the peer only creates the handle to manipulate and further
+ * configure the peer; use "GNUNET_TESTBED_peer_start" and
+ * "GNUNET_TESTBED_peer_stop" to actually start/stop the peer's
+ * processes.
+ *
+ * Note that the given configuration will be adjusted by the
+ * controller to avoid port/path conflicts with other peers.
+ * The "final" configuration can be obtained using
+ * 'GNUNET_TESTBED_peer_get_information'.
+ *
+ * @param host host to run the peer on; cannot be NULL
+ * @param cfg Template configuration to use for the peer. Should exist
until
+ * operation is cancelled or GNUNET_TESTBED_operation_done() is
called
+ * @param cb the callback to call when the peer has been created
+ * @return the operation handle
+ */
+
+ public Operation createPeer(Host host, Configuration cfg,
PeerCreateCallback cb) {
+ return null;
+ }
+
+
+ /**
+ * Stop the given controller (also will terminate all peers and
+ * controllers dependent on this controller). This function
+ * blocks until the testbed has been fully terminated (!).
+ */
+ public void disconnect () {
+
+ }
+
+
+}
Added: gnunet-java/src/main/java/org/gnunet/testbed/ControllerEventCallback.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/ControllerEventCallback.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/testbed/ControllerEventCallback.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,21 @@
+package org.gnunet.testbed;
+
+
+
+public abstract class ControllerEventCallback {
+ void onPeerStart() {
+ throw new AssertionError("event not handled");
+ }
+ void onPeerStop() {
+ throw new AssertionError("event not handled");
+ }
+ void onPeerConnect() {
+ throw new AssertionError("event not handled");
+ }
+ void onPeerDisconnect() {
+ throw new AssertionError("event not handled");
+ }
+ void onOperationFinished() {
+ throw new AssertionError("event not handled");
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/testbed/ControllerInitMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/ControllerInitMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/testbed/ControllerInitMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,30 @@
+package org.gnunet.testbed;
+
+
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UInt64;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.construct.ZeroTerminatedString;
+import org.gnunet.util.GnunetMessage;
+
address@hidden(460)
+public class ControllerInitMessage implements GnunetMessage.Body {
+ /**
+ * Host ID that the controller is either given (if this is the
+ * dominating client) or assumed to have (for peer-connections
+ * between controllers). A controller must check that all
+ * connections make consistent claims...
+ */
+ @UInt32
+ public int host_id;
+
+ /**
+ * Event mask that specifies which events this client is interested in.
+ */
+ @UInt64
+ public long event_mask;
+
+ @ZeroTerminatedString
+ public String controler_hostname;
+
+}
Added: gnunet-java/src/main/java/org/gnunet/testbed/ControllerProc.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/ControllerProc.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/testbed/ControllerProc.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,89 @@
+package org.gnunet.testbed;
+
+import com.google.common.base.Charsets;
+import org.gnunet.util.Helper;
+import org.gnunet.util.RunaboutMessageReceiver;
+
+import java.io.ByteArrayOutputStream;
+import java.util.zip.Deflater;
+
+/**
+ * A controller process.
+ * The controller process is either a local helper process, or an ssh process
that starts and controls
+ * the testbed helper on a remote machine.
+ */
+public class ControllerProc {
+ final Helper helper;
+
+
+ public class ControllerProcReceiver extends RunaboutMessageReceiver {
+ public void visit(HelperReplyMessage m) {
+
+ }
+ @Override
+ public void handleError() {
+
+ }
+ }
+
+ /**
+ * Starts a controller process at the given host. The given host's
configration
+ * is used as a Template configuration to use for the remote controller;
the
+ * remote controller will be started with a slightly modified configuration
+ * (port numbers, unix domain sockets and service home values are changed
as per
+ * TESTING library on the remote host). The modified configuration
replaces the
+ * host's existing configuration before signalling success through the
+ * GNUNET_TESTBED_ControllerStatusCallback()
+ *
+ * @param trustedIP the ip address of the controller which will be set as
TRUSTED
+ * HOST(all connections form this ip are permitted by the
testbed) when
+ * starting testbed controller at host. This can either be a
single ip
+ * address or a network address in CIDR notation.
+ * @param host the host where the controller has to be started. CANNOT be
NULL.
+ * @param cb function called when the controller is successfully started or
+ * dies unexpectedly; GNUNET_TESTBED_controller_stop shouldn't be
+ * called if cb is called with GNUNET_SYSERR as status. Will
never be
+ * called in the same task as 'GNUNET_TESTBED_controller_start'
+ * (synchronous errors will be signalled by returning NULL). This
+ * parameter cannot be NULL.
+ */
+ public ControllerProc(String trustedIP, Host host,
ControllerStatusCallback cb) {
+ if (host.isLocal()) {
+ helper = new Helper(false, "gnunet-testbed-helper", null, new
ControllerProcReceiver());
+ } else {
+ throw new AssertionError("not implemented yet");
+ }
+ }
+
+
+ private HelperInitMessage makeHelperInitMessage(String trustedIP, Host
host) {
+ HelperInitMessage m = new HelperInitMessage();
+ if (host.hostname == null) {
+ m.hostname = null;
+ m.hostname_size = 0;
+ } else {
+ m.hostname_size = host.hostname.length();
+ m.hostname = host.hostname.getBytes(Charsets.UTF_8);
+ }
+ m.trusted_ip_size = trustedIP.length();
+ m.trusted_ip = trustedIP;
+
+ byte[] serialized_config = host.cfg.serialize().getBytes();
+
+ Deflater compresser = new Deflater();
+ compresser.setInput(serialized_config);
+ compresser.finish();
+
+ ByteArrayOutputStream s = new ByteArrayOutputStream();
+ byte[] buf = new byte[1024];
+ while (!compresser.finished()) {
+ int n = compresser.deflate(buf);
+ s.write(buf, 0, n);
+ }
+
+ m.compressed_config = s.toByteArray();
+ m.config_size = serialized_config.length;
+
+ return m;
+ }
+}
Added:
gnunet-java/src/main/java/org/gnunet/testbed/ControllerStatusCallback.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/ControllerStatusCallback.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/testbed/ControllerStatusCallback.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,9 @@
+package org.gnunet.testbed;
+
+
+import org.gnunet.util.Configuration;
+
+public interface ControllerStatusCallback {
+ void onStartupSuccess(Configuration cfg);
+ void onStartupFailure();
+}
Added: gnunet-java/src/main/java/org/gnunet/testbed/HelperInitMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/HelperInitMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/testbed/HelperInitMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,37 @@
+package org.gnunet.testbed;
+
+import org.gnunet.construct.*;
+import org.gnunet.util.GnunetMessage;
+
+/**
+ * Initialization message for gnunet-helper-testbed to start testbed service
+ */
address@hidden(495)
+public class HelperInitMessage implements GnunetMessage.Body {
+ /**
+ * The controller hostname size excluding the NULL termination character -
+ * strlen (hostname); cannot be zero
+ */
+ @UInt16
+ int trusted_ip_size;
+ /**
+ * The hostname size excluding the NULL termination character - strlen
+ * (hostname); cannot be zero
+ */
+ @UInt16
+ int hostname_size;
+ /**
+ * The size of the uncompressed configuration
+ */
+ @UInt16
+ public int config_size;
+
+ @ZeroTerminatedString(optional = true)
+ public String trusted_ip;
+
+ @VariableSizeIntegerArray(signed = true, bitSize = 8, lengthField =
"hostname_size")
+ public byte[] hostname;
+
+ @FillWith @UInt8
+ public byte[] compressed_config;
+}
Added: gnunet-java/src/main/java/org/gnunet/testbed/HelperReplyMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/HelperReplyMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/testbed/HelperReplyMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,17 @@
+package org.gnunet.testbed;
+
+
+import org.gnunet.construct.FillWith;
+import org.gnunet.construct.UInt16;
+import org.gnunet.construct.UInt8;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+
address@hidden(496)
+public class HelperReplyMessage implements GnunetMessage.Body {
+ @UInt16
+ int uncompressed_config_size;
+
+ @FillWith @UInt8
+ byte[] compressed_config;
+}
Added: gnunet-java/src/main/java/org/gnunet/testbed/Host.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/Host.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/testbed/Host.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,51 @@
+package org.gnunet.testbed;
+
+import org.gnunet.util.Configuration;
+
+/**
+ * Opaque handle to a host running experiments managed by the testing
framework.
+ * The master process must be able to SSH to this host without password (via
+ * ssh-agent).
+ */
+public class Host {
+ static int nextUID = 1;
+ final Configuration cfg;
+ final String hostname;
+ final String username;
+ final int port;
+
+ private boolean controllerStarted;
+
+ /**
+ * Create a host to run peers and controllers on.
+ *
+ * @param hostname name of the host, use "NULL" for localhost
+ * @param username username to use for the login; may be NULL
+ * @param cfg the configuration to use as a template while starting a
controller
+ * on this host. Operation queue sizes specific to a host are
also
+ * read from this configuration handle
+ * @param port port number to use for ssh; use 0 to let ssh decide
+ */
+ public Host(String hostname, String username, Configuration cfg, int port)
{
+ this.port = (port == 0) ? 22 : port;
+ this.hostname = hostname;
+ this.username = username;
+ this.cfg = cfg;
+ }
+
+ /**
+ * Create a host handle for the local machine.
+ *
+ * @param cfg the configuration to use as a template while starting a
controller
+ * on this host. Operation queue sizes specific to a host are
also
+ * read from this configuration handle
+ * @param port port number to use for ssh; use 0 to let ssh decide
+ */
+ public Host(Configuration cfg, int port) {
+ this(null, null, cfg, port);
+ }
+
+ public boolean isLocal() {
+ return hostname == null;
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/testbed/Operation.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/Operation.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/testbed/Operation.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,11 @@
+package org.gnunet.testbed;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: dold
+ * Date: 8/25/13
+ * Time: 1:26 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public interface Operation {
+}
Added:
gnunet-java/src/main/java/org/gnunet/testbed/OperationCompletionCallback.java
===================================================================
---
gnunet-java/src/main/java/org/gnunet/testbed/OperationCompletionCallback.java
(rev 0)
+++
gnunet-java/src/main/java/org/gnunet/testbed/OperationCompletionCallback.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,11 @@
+package org.gnunet.testbed;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: dold
+ * Date: 8/25/13
+ * Time: 1:35 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public interface OperationCompletionCallback {
+}
Added: gnunet-java/src/main/java/org/gnunet/testbed/Peer.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/Peer.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/testbed/Peer.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,57 @@
+package org.gnunet.testbed;
+
+import org.gnunet.util.Configuration;
+
+/**
+ * Opaque handle to a peer controlled by the testbed framework. A peer runs
+ * at a particular host.
+ */
+public class Peer {
+ public Operation start(PeerChurnCallback peerChurnCallback) {
+ return null;
+ }
+
+ public Operation stop(PeerChurnCallback peerChurnCallback) {
+ return null;
+ }
+
+ public Operation getInformation() {
+ return null;
+ }
+
+ /*
+ * Change peer configuration. Must only be called while the
+ * peer is stopped. Ports and paths cannot be changed this
+ * way.
+ */
+ public Operation updateConfiguration(Configuration cfg) {
+ return null;
+ }
+
+ /*
+ * Change peer configuration. Must only be called while the
+ * peer is stopped. Ports and paths cannot be changed this
+ * way.
+ */
+ public Operation destroy() {
+ return null;
+ }
+
+ public Operation manageService(String serviceName, boolean start) {
+ return null;
+ }
+
+ /**
+ * Both peers must have been started before calling this function.
+ * This function then obtains a HELLO from this peer, gives it to
'otherPeer'
+ * and asks 'otherPeer' to connect to this peer..
+ */
+ public Operation connectOverlay(OperationCompletionCallback cb, Peer
otherPeer) {
+ return null;
+ }
+
+ public Operation getServiceConnection(String serviceName /*,... */) {
+ return null;
+ }
+
+}
Added: gnunet-java/src/main/java/org/gnunet/testbed/PeerChurnCallback.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/PeerChurnCallback.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/testbed/PeerChurnCallback.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,7 @@
+package org.gnunet.testbed;
+
+
+public interface PeerChurnCallback {
+ void onChurnSuccess();
+ void onChurnError(String emsg);
+}
Added: gnunet-java/src/main/java/org/gnunet/testbed/PeerCreateCallback.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testbed/PeerCreateCallback.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/testbed/PeerCreateCallback.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,7 @@
+package org.gnunet.testbed;
+
+
+public interface PeerCreateCallback {
+ void onPeerCreated(Peer peer);
+ void onError(String errorMessage);
+}
Added: gnunet-java/src/main/java/org/gnunet/testing/TestingFixture.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testing/TestingFixture.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/testing/TestingFixture.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,21 @@
+package org.gnunet.testing;
+
+import org.gnunet.util.Scheduler;
+import org.junit.After;
+import org.junit.Before;
+
+/**
+ * Default JUnit4 fixture methods for gnunet-java tests.
+ * Resets the scheduler properly.
+ */
+public class TestingFixture {
+ @Before
+ public void beginGNJTest() {
+ Scheduler.forceReset();
+ }
+
+ @After
+ public void endGNJTest() {
+ Scheduler.forceReset();
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/testing/TestingServer.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testing/TestingServer.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/testing/TestingServer.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,65 @@
+package org.gnunet.testing;
+
+import org.gnunet.util.Client;
+import org.gnunet.util.RelativeTime;
+import org.gnunet.util.Server;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.nio.channels.ServerSocketChannel;
+
+/**
+ * Server with an ephemeral port.
+ * Can spawn clients connected to the server for testing.
+ *
+ * @author Florian Dold
+ */
+public class TestingServer {
+ public final Server server;
+ private final ServerSocketChannel srvChan;
+
+ public TestingServer() {
+ this(RelativeTime.FOREVER, true);
+ }
+
+ public TestingServer(RelativeTime idleTimeout, boolean requireFound) {
+ try {
+ srvChan = ServerSocketChannel.open();
+ srvChan.configureBlocking(false);
+
+ // bind to ephemeral port
+ srvChan.socket().bind(null);
+ } catch (IOException e) {
+ throw new RuntimeException("TestingServer creation failed");
+ }
+
+ server = new Server(idleTimeout, requireFound);
+ server.addAcceptSocket(srvChan);
+
+ }
+
+ /**
+ * Create a client connected to this server.
+ *
+ * @return a client connected to this server
+ */
+ public Client createClient() {
+ SocketAddress socketAddress = srvChan.socket().getLocalSocketAddress();
+
+ if (!(socketAddress instanceof InetSocketAddress)) {
+ throw new RuntimeException("unknown type of socket address");
+ }
+ InetSocketAddress saddr = (InetSocketAddress) socketAddress;
+
+ String hostname = saddr.getHostName();
+
+ if (hostname == null) {
+ throw new RuntimeException("localhost SocketAddress has no
hostname");
+ }
+
+ return new Client(hostname, srvChan.socket().getLocalPort());
+ }
+
+}
Added: gnunet-java/src/main/java/org/gnunet/testing/TestingSetup.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testing/TestingSetup.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/testing/TestingSetup.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,56 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.testing;
+
+import org.gnunet.util.Program;
+import org.gnunet.util.RelativeTime;
+
+/**
+ * A testing setup is responsible for configuring the loggers during testing,
and can
+ * start gnunet subsystems (like statistics, core, etc.).
+ *
+ * @author Florian Dold
+ */
+public final class TestingSetup {
+
+ private TestingSetup() {
+
+ }
+
+ public static class SetupException extends RuntimeException {
+ public SetupException(Exception e) {
+ super(e);
+ }
+ public SetupException(String msg) {
+ super(msg);
+ }
+
+ }
+
+ public static void setup() {
+ String log = System.getenv("GNJ_LOGLEVEL");
+ if (log != null) {
+ Program.configureLogging(log, null);
+ } else {
+ Program.configureLogging("WARN", null);
+ }
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/testing/TestingSubsystem.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testing/TestingSubsystem.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/testing/TestingSubsystem.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,133 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.testing;
+
+import com.google.common.base.Charsets;
+import org.gnunet.util.Configuration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+
+/**
+ * Handle to a GNUnet subsystem that has been started for testing purposes.
+ *
+ * @author Florian Dold
+*/
+public class TestingSubsystem {
+ private static final Logger logger = LoggerFactory
+ .getLogger(TestingSubsystem.class);
+
+
+ private Process p;
+ private BufferedReader reader;
+ private OutputStreamWriter writer;
+ private Configuration cfg;
+
+ public Configuration getConfiguration() {
+ return cfg;
+ }
+
+ public TestingSubsystem(String service) {
+ try {
+ p = Runtime.getRuntime().exec(new String[]{"gnunet-testing", "-r",
service});
+ } catch (IOException e) {
+ throw new TestingSetup.SetupException(e);
+ }
+
+ reader = new BufferedReader(new InputStreamReader(p.getInputStream(),
Charsets.UTF_8));
+
+ writer = new OutputStreamWriter(p.getOutputStream(), Charsets.UTF_8);
+
+ String started;
+ try {
+ started = reader.readLine();
+ } catch (IOException e) {
+ throw new TestingSetup.SetupException(e);
+ }
+
+ if (started == null || !started.equals("ok")) {
+ throw new TestingSetup.SetupException("could not start service ('"
+ started + "')");
+ }
+
+
+ String cfgFileName;
+ try {
+ cfgFileName = reader.readLine();
+ } catch (IOException e) {
+ throw new TestingSetup.SetupException(e);
+ }
+
+ if (cfgFileName == null) {
+ throw new TestingSetup.SetupException("could not start subsystem
for testing: no config file received from helper");
+ }
+
+ cfg = new Configuration();
+ cfg.parse(cfgFileName);
+
+ try {
+ if (p.getErrorStream().available() != 0) {
+ throw new TestingSetup.SetupException("error starting
service");
+ }
+ } catch (IOException e) {
+ throw new TestingSetup.SetupException(e);
+ }
+ }
+ public void destroy() {
+ try {
+ writer.write("q\n");
+ writer.flush();
+ } catch (IOException e) {
+ throw new TestingSetup.SetupException(e);
+ }
+ try {
+ p.waitFor();
+ } catch (InterruptedException e) {
+ throw new TestingSetup.SetupException(e);
+ }
+ if (p.exitValue() != 0) {
+ throw new TestingSetup.SetupException("gnunet-testing exit value
unsuccessful");
+ }
+ }
+
+ public void restart() {
+ try {
+ writer.write("r\n");
+ writer.flush();
+ } catch (IOException e) {
+ throw new TestingSetup.SetupException(e);
+ }
+ String response;
+ logger.debug("waiting for gnunet-testing to respond to restart");
+ try {
+ response = reader.readLine();
+ } catch (IOException e) {
+ throw new TestingSetup.SetupException(e);
+ }
+ if (response == null || !response.equals("restarted")) {
+ throw new TestingSetup.SetupException("wrapper did not cooperate");
+ }
+ logger.debug("restart successful");
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/testing/package-info.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/testing/package-info.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/testing/package-info.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,27 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+
+/**
+ * Various utilities for testing.
+ *
+ * This is in the main source code location, as the testing package itself has
unit tests.
+ */
+package org.gnunet.testing;
Added: gnunet-java/src/main/java/org/gnunet/transport/AddressIterateMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/transport/AddressIterateMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/transport/AddressIterateMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,34 @@
+package org.gnunet.transport;
+
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.AbsoluteTime;
+import org.gnunet.util.PeerIdentity;
+
+
+/**
+ * Message from the client to the transport service
+ * asking for binary addresses known for a peer.
+ */
address@hidden(380)
+public class AddressIterateMessage {
+ /**
+ * One shot call or continous replies?
+ */
+ @UInt32
+ public int one_shot;
+
+ /**
+ * FIXME: This field seems to be deprecated in the C API?
+ */
+ @NestedMessage
+ public AbsoluteTime timeout;
+
+ /**
+ * The identity of the peer to look up.
+ */
+ @NestedMessage
+ public PeerIdentity peer;
+}
Added: gnunet-java/src/main/java/org/gnunet/transport/BlacklistCallback.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/transport/BlacklistCallback.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/transport/BlacklistCallback.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,12 @@
+package org.gnunet.transport;
+
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public interface BlacklistCallback {
+ boolean isAllowed(PeerIdentity peerIdentity);
+}
Added: gnunet-java/src/main/java/org/gnunet/transport/BlacklistInitMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/transport/BlacklistInitMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/transport/BlacklistInitMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,9 @@
+package org.gnunet.transport;
+
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+
address@hidden(369)
+public class BlacklistInitMessage implements GnunetMessage.Body {
+ // message body is empty
+}
Added: gnunet-java/src/main/java/org/gnunet/transport/HelloUpdateCallback.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/transport/HelloUpdateCallback.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/transport/HelloUpdateCallback.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,9 @@
+package org.gnunet.transport;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class HelloUpdateCallback {
+}
Added: gnunet-java/src/main/java/org/gnunet/transport/PeerIterateCallback.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/transport/PeerIterateCallback.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/transport/PeerIterateCallback.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,12 @@
+package org.gnunet.transport;
+
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public interface PeerIterateCallback {
+ void processPeerAddress(PeerIdentity peer, Object hello);
+}
Added: gnunet-java/src/main/java/org/gnunet/transport/RequestConnectMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/transport/RequestConnectMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/transport/RequestConnectMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,24 @@
+package org.gnunet.transport;
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
address@hidden(374)
+public class RequestConnectMessage implements GnunetMessage.Body {
+ @UInt32
+ public int reserved;
+
+ /**
+ * Identity of the peer we would like to connect to.
+ */
+ @NestedMessage
+ public PeerIdentity peer;
+}
Added: gnunet-java/src/main/java/org/gnunet/transport/StartMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/transport/StartMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/transport/StartMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,32 @@
+package org.gnunet.transport;
+
+import org.gnunet.construct.NestedMessage;
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.PeerIdentity;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
address@hidden(360)
+public class StartMessage implements GnunetMessage.Body {
+ /**
+ * 0: no options
+ * 1: The 'self' field should be checked
+ * 2: this client is interested in payload traffic
+ */
+ @UInt32
+ public int options;
+
+ /**
+ * Identity we think we have. If it does not match, the
+ * receiver should print out an error message and disconnect.
+ */
+ @NestedMessage
+ public PeerIdentity self;
+
+
+}
Added: gnunet-java/src/main/java/org/gnunet/transport/Transport.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/transport/Transport.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/transport/Transport.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,156 @@
+package org.gnunet.transport;
+
+import org.gnunet.hello.HelloMessage;
+import org.gnunet.mq.Envelope;
+import org.gnunet.mq.NotifySentHandler;
+import org.gnunet.util.*;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class Transport {
+
+ /**
+ * Client that connects to the transport service,
+ */
+ private final Client client;
+
+ boolean init_requested;
+
+ /**
+ * Blacklist callback, null if there is no active blacklist
+ * for this handle.
+ */
+ BlacklistCallback blacklistCallback;
+
+ private final class TransportReceiver extends RunaboutMessageReceiver {
+ @Override
+ public void handleError() {
+ client.reconnect();
+ // FIXME: complete
+ }
+ }
+
+ /**
+ * Create a handle to the transport service.
+ *
+ * @param cfg configuration to use for connecting
+ */
+ public Transport(Configuration cfg) {
+ client = new Client("transport", cfg);
+ client.installReceiver(new TransportReceiver());
+ }
+
+ /**
+ * Ask the transport service to establish a connection to
+ * the given peer.
+ *
+ * @param target who we should try to connect to
+ * @param cb callback to be called when request was transmitted to
transport
+ * service
+ * @return a handle to cancel the operation
+ */
+ Cancelable tryConnect(PeerIdentity target, final TryConnectCallback cb) {
+ RequestConnectMessage m = new RequestConnectMessage();
+ m.peer = target;
+ m.reserved = 0;
+ final Envelope ev = new Envelope(m);
+ ev.notifySent(new NotifySentHandler() {
+ @Override
+ public void onSent() {
+ cb.onDone();
+ }
+ });
+ client.send(ev);
+
+ return new Cancelable() {
+ @Override
+ public void cancel() {
+ ev.cancel();
+ }
+ };
+ }
+
+ /**
+ * ... (discuss first)
+ */
+ public void init(Object receiveCallback, Object notifyConnect, Object
notifyDisconnect) {
+
+ }
+
+
+ /**
+ * Obtain the HELLO message for this peer.
+ *
+ * @param rec function to call with the HELLO, sender will be our peer
+ * identity; message and sender will be NULL on timeout
+ * (handshake with transport service pending/failed).
+ * cost estimate will be 0.
+ * @return handle to cancel the operation
+ */
+ Cancelable getHello(HelloUpdateCallback rec) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Offer the transport service the HELLO of another peer. Note that
+ * the transport service may just ignore this message if the HELLO is
+ * malformed or useless due to our local configuration.
+ *
+ * @param hello the hello message
+ * @param cont continuation to call when HELLO has been sent,
+ * tc reason GNUNET_SCHEDULER_REASON_TIMEOUT for fail
+ * tc reasong GNUNET_SCHEDULER_REASON_READ_READY for success
+ * @return a GNUNET_TRANSPORT_OfferHelloHandle handle or NULL on failure,
+ * in case of failure cont will not be called
+ */
+
+ Cancelable offerHello(HelloMessage hello,
+ Scheduler.Task cont) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Install a blacklist callback. The service will be queried for all
+ * existing connections as well as any fresh connections to check if
+ * they are permitted.
+ * The blacklist is active until the Transport handle is destroyed.
+ * When the transport handle that installed the blacklist is destroyed,
+ * all hosts that were denied in the past will automatically be
+ * whitelisted again. This is the only way to re-enable
+ * connections from peers that were previously blacklisted.
+ *
+ * @param blacklistCallback callback to invoke to check if connections
are allowed
+ */
+ public void blacklist(BlacklistCallback blacklistCallback) {
+ if (this.blacklistCallback != null)
+ throw new AssertionError("there is already a blacklist");
+ if (blacklistCallback == null)
+ throw new AssertionError("blacklist callback may not be null");
+ this.blacklistCallback = blacklistCallback;
+ client.send(new BlacklistInitMessage());
+ }
+
+ /**
+ * Return all the known addresses for a specific peer or all peers.
+ * Returns continuously all address if one_shot is set to false
+ * <p/>
+ * Returns the address(es) that we are currently using for this
+ * peer. Upon completion, the 'AddressLookUpCallback' is called one more
+ * time with 'NULL' for the address and the peer. After this, the
operation must no
+ * longer be explicitly canceled.
+ *
+ * @param peer peer identity to look up the addresses
of, CHANGE: allow NULL for all (connected) peers
+ * @param one_shot GNUNET_YES to return the current state
and then end (with NULL+NULL),
+ * GNUNET_NO to monitor the set of
addresses used (continuously, must be explicitly canceled)
+ * @param timeout how long is the lookup allowed to take
at most (irrelevant if one_shot is set to GNUNET_NO)
+ * @param peer_address_callback function to call with the results
+ */
+ Cancelable getActiveAddresses(PeerIdentity peer, int one_shot,
+ RelativeTime timeout, PeerIterateCallback
peer_address_callback) {
+ throw new UnsupportedOperationException();
+ }
+}
+
Added: gnunet-java/src/main/java/org/gnunet/transport/TryConnectCallback.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/transport/TryConnectCallback.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/transport/TryConnectCallback.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,10 @@
+package org.gnunet.transport;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public interface TryConnectCallback {
+ void onDone();
+}
Added: gnunet-java/src/main/java/org/gnunet/util/ATSInformation.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/ATSInformation.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/ATSInformation.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,37 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+
+import org.gnunet.construct.Message;
+import org.gnunet.construct.UInt32;
+
+
+/**
+ * Information related to Automatic Transport Selection.
+ */
+public class ATSInformation implements Message {
+ @UInt32
+ public long type;
+
+ @UInt32
+ public long value;
+}
Added: gnunet-java/src/main/java/org/gnunet/util/AbsoluteTime.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/AbsoluteTime.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/AbsoluteTime.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,269 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Date;
+
+/**
+ * A specific point in time.
+ *
+ * @author Florian Dold
+ */
+public class AbsoluteTime implements Comparable<AbsoluteTime> {
+ private static final Logger logger = LoggerFactory
+ .getLogger(AbsoluteTime.class);
+
+ /**
+ * Constant for 'the beginning of time' in our frame.
+ */
+ public final static AbsoluteTime ZERO = new AbsoluteTime(0);
+ public final static AbsoluteTime FOREVER = new
AbsoluteTime(Long.MAX_VALUE);
+
+ /**
+ * Absolute time value in microseconds.
+ */
+ private final long abs_value_us;
+
+ /**
+ * Gets the current time.
+ *
+ * @return the current time
+ */
+ public static AbsoluteTime now() {
+ return new AbsoluteTime(System.currentTimeMillis() * 1000);
+ }
+
+ public AbsoluteTime(final long abs_value_us) {
+ this.abs_value_us = abs_value_us;
+ }
+
+ /**
+ * Adds a relative time value to an absolute time.
+ *
+ * @param duration duration to add to address@hidden this}
+ * @return address@hidden this + duration}
+ */
+ public AbsoluteTime add(RelativeTime duration) {
+ if (abs_value_us == Long.MAX_VALUE
+ || duration.isForever()) {
+ return AbsoluteTime.FOREVER;
+ }
+ if (abs_value_us + duration.getMicroseconds() < abs_value_us) {
+ return AbsoluteTime.FOREVER;
+ }
+ return new AbsoluteTime(abs_value_us + duration.getMicroseconds());
+ }
+
+ /**
+ * Calculates the estimate time of arrival/completion for an operation.
+ *
+ * @param start
+ * when did the operation start?
+ * @param finished
+ * how much has been done?
+ * @param total
+ * how much must be done overall (same unit as for "finished")
+ * @return remaining duration for the operation, assuming it continues at
+ * the same speed
+ */
+ public static RelativeTime calculateETA(final AbsoluteTime start,
+ final long finished, final long total) {
+ if (finished >= total) {
+ return RelativeTime.ZERO;
+ }
+ if (finished == 0) {
+ return RelativeTime.FOREVER;
+ }
+ final RelativeTime dur = start.getDuration();
+ final double exp = dur.getMicroseconds() * total
+ / (double) finished;
+ return new RelativeTime((long) exp);
+ }
+
+
+ /**
+ * address@hidden
+ */
+ @Override
+ public boolean equals(Object other) {
+ return other instanceof AbsoluteTime && compareTo((AbsoluteTime)
other) == 0;
+ }
+
+ /**
+ * address@hidden
+ */
+ @Override
+ public int hashCode() {
+ return (int) this.abs_value_us;
+ }
+
+ /**
+ * address@hidden
+ */
+ @Override
+ public int compareTo(AbsoluteTime other) {
+ if (this.abs_value_us < other.abs_value_us) {
+ return -1;
+ }
+ if (this.abs_value_us > other.abs_value_us) {
+ return 1;
+ }
+ return 0;
+ }
+
+ /**
+ * address@hidden
+ */
+ @Override
+ public String toString() {
+ if (this.isForever()) {
+ return "AbsoluteTime(FOREVER)";
+ }
+ return "AbsoluteTime("+this.abs_value_us +")";
+ }
+
+
+ /**
+ * Check if a deadline is due.
+ * @return true if NOW is greater than the given time, false otherwise
+ */
+ public boolean isDue() {
+ return this.abs_value_us < now().abs_value_us;
+ }
+
+ /**
+ * Does this AbsoluteTime value represent forever?
+ *
+ * @return this==FOREVER
+ */
+ public boolean isForever() {
+ return this.abs_value_us == Long.MAX_VALUE;
+ }
+
+ /**
+ * Calculates the difference between two absolute times.
+ *
+ * @param other ...
+ * @return this - other
+ */
+ public RelativeTime getDifference(final AbsoluteTime other) {
+ if (other.abs_value_us == Long.MAX_VALUE) {
+ return RelativeTime.FOREVER;
+ }
+ return new RelativeTime(abs_value_us - other.abs_value_us);
+ }
+
+ /**
+ * Gets the duration of an operation as the difference of the current time
+ * and address@hidden this}.
+ *
+ * @return this - now
+ */
+ public RelativeTime getDuration() {
+ assert abs_value_us != Long.MAX_VALUE;
+ return getDifference(AbsoluteTime.now());
+ }
+
+ /**
+ * Returns the milliseconds since some fixed point of reference.
+ *
+ * @return the absolute time in milliseconds
+ */
+ public long getMicroseconds() {
+ return abs_value_us;
+ }
+
+ /**
+ * Calculates the remaining time relative to now.
+ *
+ * @return this - now
+ */
+ public RelativeTime getRemaining() {
+ if (abs_value_us == Long.MAX_VALUE) {
+ return RelativeTime.FOREVER;
+ }
+ return getDifference(AbsoluteTime.now());
+ }
+
+ /**
+ * Returns the maximum of two time values.
+ *
+ * @param other ...
+ * @return max(this,other)
+ */
+ public AbsoluteTime max(final AbsoluteTime other) {
+ return abs_value_us >= other.abs_value_us ? this : other;
+
+ }
+
+ /**
+ * Returns the minimum of two time values.
+ *
+ * @param other ...
+ * @return min(this,other)
+ */
+ public AbsoluteTime min(final AbsoluteTime other) {
+ return abs_value_us <= other.abs_value_us ? this : other;
+ }
+
+ /**
+ * Subtracts a relative time value to an absolute time
+ *
+ * @param duration ...
+ * @return this - duration
+ */
+ public AbsoluteTime subtract(final RelativeTime duration) {
+ if (abs_value_us <= duration.getMicroseconds()) {
+ return AbsoluteTime.ZERO;
+ }
+ if (abs_value_us == Long.MAX_VALUE) {
+ return this;
+ }
+ return new AbsoluteTime(abs_value_us - duration.getMicroseconds());
+ }
+
+ /**
+ * Get a serializable message corresponding to this AbsoluteTime.
+ *
+ * @return a serializable message corresponding to this AbsoluteTime
+ */
+ public AbsoluteTimeMessage asMessage() {
+ return new AbsoluteTimeMessage(this);
+ }
+
+ /**
+ * Get the AbsoluteTime from a AbsoluteTimeMessage.
+ *
+ * @param m serializable representation of an AbsoluteTime
+ *
+ * @return the real AbsoluteTime associated with m
+ */
+ public static AbsoluteTime fromNetwork(AbsoluteTimeMessage m) {
+ return m.value__ < 0 ? AbsoluteTime.FOREVER : new
AbsoluteTime(m.value__);
+ }
+
+ public Date toDate() {
+ return new Date(abs_value_us / 1000);
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/util/AbsoluteTimeMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/AbsoluteTimeMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/AbsoluteTimeMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,47 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+import org.gnunet.construct.Message;
+import org.gnunet.construct.UInt64;
+
+
+
+/**
+ * Representation of an AbsoluteTime object, to be sent over the network.
+ */
+public class AbsoluteTimeMessage implements Message {
+ @UInt64
+ public long value__;
+
+ public AbsoluteTimeMessage() {
+
+ }
+
+
+ public AbsoluteTimeMessage(final AbsoluteTime t) {
+ if (t.equals(AbsoluteTime.FOREVER)) {
+ this.value__ = -1;
+ } else {
+ this.value__ = t.getMicroseconds();
+ }
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/util/Cancelable.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/Cancelable.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/Cancelable.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,28 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+/**
+ * Any asynchronous operation that can be canceled should implement this
interface.
+ */
+public interface Cancelable {
+ public void cancel();
+}
Added: gnunet-java/src/main/java/org/gnunet/util/Client.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/Client.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/Client.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,329 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+package org.gnunet.util;
+
+import com.google.common.base.Optional;
+import org.gnunet.mq.Envelope;
+import org.gnunet.mq.MessageQueue;
+import org.gnunet.statistics.Statistics;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A connection to a GNUnet service.
+ *
+ * Wraps a Connection, and is responsible for waiting until the underlying
connection has been made
+ * and allows reconnects.
+ */
+public class Client extends MessageQueue {
+ private static final Logger logger = LoggerFactory
+ .getLogger(Client.class);
+
+ /**
+ * Underlying connection to the service.
+ * May be NULL if the client is currently not connected.
+ */
+ private Connection connection;
+
+ /**
+ * Host this client should be connected to.
+ */
+ private final String hostname;
+
+ /**
+ * Port of the host the client should connect to.
+ */
+ private final int port;
+
+ /**
+ * Initial value for connectBackoff.
+ */
+ private static final RelativeTime INITAL_BACKOFF =
RelativeTime.MILLISECOND.multiply(5);
+
+ /**
+ * Maximum value for connectBackoff.
+ */
+ private static final RelativeTime MAX_BACKOFF =
RelativeTime.SECOND.multiply(5);
+
+ /**
+ * The time to wait after an error occured while connecting.
+ * Every time an error occurs while connecting, this value is doubled
until its maximum
+ * value (MAX_BACKOFF) has been reached. This strategy is called
exponential backoff.
+ */
+ private RelativeTime connectBackoff = INITAL_BACKOFF;
+
+ /**
+ * True if we are waiting for the client to connect before we can ask it
to do
+ * notifyTransmitReady.
+ */
+ private boolean notifyTransmitReadyDelayed;
+
+ /**
+ * When notifyTransmitReadyDelayed is true, This can be used to cancel the
task
+ * waiting for the connection to be established.
+ */
+ private Cancelable delayedNotifyTransmitHandle;
+
+ /**
+ * Currently installed persistent receiver.
+ * Will receive all messages sent to the client.
+ */
+ private RunaboutMessageReceiver receiver;
+
+ private boolean receiver_active;
+
+ /**
+ * Handle to cancel the message currently submitted in the queue,
+ */
+ private Cancelable currentSubmit;
+
+ /**
+ * Create a connection to a service.
+ *
+ * @param serviceName name of the service
+ * @param cfg configuration to use
+ */
+ public Client(String serviceName, Configuration cfg) {
+ if (cfg == null) {
+ throw new AssertionError("Configuration may not be null");
+ }
+ if (!cfg.haveValue(serviceName, "PORT")) {
+ throw new Configuration.ConfigurationException(String.format("PORT
of service '%s' not specified", serviceName));
+ }
+ if (!cfg.haveValue(serviceName, "HOSTNAME")) {
+ throw new
Configuration.ConfigurationException(String.format("HOSTNAME of service '%s'
not specified", serviceName));
+ }
+
+ // get port of this service from the configuration
+ Optional<Long> portOption = cfg.getValueNumber(serviceName, "PORT");
+ port = portOption.get().intValue();
+ // get the hostname from the configuration
+ hostname = cfg.getValueString(serviceName, "HOSTNAME").get();
+ if (hostname == null || hostname.isEmpty()) {
+ throw new
Configuration.ConfigurationException(String.format("hostname of service '%s'
empty", serviceName));
+ }
+ reconnect();
+ }
+
+ /**
+ * Create a connection to a service with the specified hostname and port.
+ *
+ * @param hostname hostname of the service
+ * @param port port of the service
+ */
+ public Client(String hostname, int port) {
+ this.hostname = hostname;
+ this.port = port;
+ reconnect();
+ }
+
+
+ /**
+ * Receive one message from the service. Can only be called after sending
a message to the server.
+ *
+ * @param timeout deadline after which MessageReceiver.deadline will be
called
+ * @param receiver MessageReceiver that is responsible for the received
message
+ */
+ public Cancelable receiveOne(RelativeTime timeout, MessageReceiver
receiver) {
+ return connection.receive(timeout, receiver);
+ }
+
+ /**
+ * Ask the client to call us once it is able to send a message.
+ *
+ *
+ * @param timeout after how long should we give up (and call
transmitter.transmit(null))
+ * @param autoRetry if the connection to the service dies, should we
+ * automatically reconnect and retry (within the
deadline period)
+ * or should we immediately fail in this case? Pass
true
+ * if the caller does not care about temporary
connection errors,
+ * for example because the protocol is stateless
+ * @param size size of the message we want to transmit, can be an
upper bound
+ * @param transmitter the MessageTransmitter object to call once the
client is ready to transmit or
+ * 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
+ *
+ * @return a handle to cancel the notification
+ */
+ public Cancelable notifyTransmitReady(final RelativeTime timeout,
+ final boolean autoRetry, int size,
final MessageTransmitter transmitter) {
+ if (notifyTransmitReadyDelayed) {
+ throw new AssertionError("notifyTransmitReady called twice!");
+ }
+ if (connection == null) {
+ throw new AssertionError("notifyTransmitReady called on
disconnected client");
+ }
+ if (connection.isConnected()) {
+ return connection.notifyTransmitReady(0, timeout, transmitter);
+ } else {
+ notifyTransmitReadyDelayed = true;
+ final AbsoluteTime deadline = timeout.toAbsolute();
+ delayedNotifyTransmitHandle =
connection.notifyConnected(connectBackoff, new Continuation() {
+ @Override
+ public void cont(boolean success) {
+ delayedNotifyTransmitHandle = null;
+ if (success) {
+ activateReceiver();
+ notifyTransmitReadyDelayed = false;
+ delayedNotifyTransmitHandle =
connection.notifyTransmitReady(0, timeout, new MessageTransmitter() {
+ @Override
+ public void transmit(Connection.MessageSink sink) {
+ delayedNotifyTransmitHandle = null;
+ transmitter.transmit(sink);
+ }
+
+ @Override
+ public void handleError() {
+ delayedNotifyTransmitHandle = null;
+ transmitter.handleError();
+ }
+ });
+ } else {
+ logger.debug("connect timed out, trying again");
+ if (deadline.isDue()) {
+ transmitter.handleError();
+ } else {
+ RelativeTime timeout = deadline.getRemaining();
+ connectBackoff = RelativeTime.min(timeout,
RelativeTime.min(connectBackoff.multiply(2), MAX_BACKOFF));
+ reconnect();
+ delayedNotifyTransmitHandle =
connection.notifyConnected(connectBackoff, this);
+ }
+ }
+ }
+ });
+ return new Cancelable() {
+ @Override
+ public void cancel() {
+ if (delayedNotifyTransmitHandle != null) {
+ delayedNotifyTransmitHandle.cancel();
+ }
+ }
+ };
+ }
+ }
+
+ /**
+ * Convenience method for sending messages.
+ *
+ * @param timeout when should we give up sending the message, and call
cont.cont(false)
+ * @param message the message to send
+ * @param cont called when the message has been sent successfully or on
error
+ * @return a handle to cancel sending the message
+ */
+ public Cancelable transmitWhenReady(final RelativeTime timeout, final
GnunetMessage.Body message, final Continuation cont) {
+ return notifyTransmitReady(timeout, false, 0, new MessageTransmitter()
{
+ @Override
+ public void transmit(Connection.MessageSink sink) {
+ sink.send(message);
+ if (cont != null) {
+ cont.cont(true);
+ }
+ }
+
+ @Override
+ public void handleError() {
+ if (cont != null) {
+ cont.cont(false);
+ }
+ }
+ });
+ }
+
+ /**
+ * Convenience method for sending messages. Timeout defaults to FOREVER.
+ *
+ * @param message the message to send
+ * @param cont called when the message has been sent successfully or on
error
+ * @return a handle to cancel sending the message
+ */
+ public Cancelable transmitWhenReady(final GnunetMessage.Body message,
final Continuation cont) {
+ return transmitWhenReady(RelativeTime.FOREVER, message, cont);
+ }
+
+ public final void reconnect() {
+ if (connection != null) {
+ connection.disconnect();
+ }
+ connection = new Connection(hostname, port);
+ }
+
+ /**
+ * Disconnect from the service. Cancel all pending receive/transmit
requests.
+ */
+ public void disconnect() {
+ if (notifyTransmitReadyDelayed) {
+ logger.error("disconnecting while notifyTransmitReady is pending");
+ }
+ connection.disconnect();
+ connection = null;
+ }
+
+ public boolean isConnected() {
+ return (connection != null) && connection.isConnected();
+ }
+
+ @Override
+ protected void submit(Envelope ev) {
+ currentSubmit = transmitWhenReady(RelativeTime.FOREVER, ev.message,
new Continuation() {
+ @Override
+ public void cont(boolean success) {
+ currentSubmit = null;
+ reportMessageSent();
+ }
+ });
+ }
+
+ @Override
+ protected void retract() {
+ if (currentSubmit == null)
+ throw new AssertionError();
+ currentSubmit.cancel();
+ currentSubmit = null;
+ }
+
+ private void activateReceiver() {
+ if (receiver_active || receiver == null)
+ return;
+ final MessageReceiver proxyReceiver = new MessageReceiver() {
+ @Override
+ public void process(GnunetMessage.Body msg) {
+ Client.this.receiver.process(msg);
+ if (connection != null && connection.isConnected())
+ connection.receive(RelativeTime.FOREVER, this);
+ else
+ receiver_active = false;
+ }
+
+ @Override
+ public void handleError() {
+ Client.this.receiver.handleError();
+ receiver_active = false;
+ }
+ };
+ connection.receive(RelativeTime.FOREVER, proxyReceiver);
+ receiver_active = true;
+ }
+
+ public void installReceiver(RunaboutMessageReceiver receiver) {
+ this.receiver = receiver;
+ if (connection != null && connection.isConnected())
+ activateReceiver();
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/util/Configuration.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/Configuration.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/Configuration.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,389 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.Table;
+import com.google.common.io.Files;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Configuration management.
+ *
+ * @author Florian Dold
+ */
+public class Configuration {
+ public static class ParsingError extends RuntimeException {
+ ParsingError(String msg) {
+ super(msg);
+ }
+
+ ParsingError(String msg, final Throwable t) {
+ super(msg, t);
+ }
+ }
+
+ private static final Logger logger = LoggerFactory
+ .getLogger(Configuration.class);
+
+ private static Pattern section = Pattern.compile("\\[(.*?)\\]");
+ private static Pattern tag = Pattern.compile("\\s*(\\S+?)\\s*=(.*?)");
+ private static Pattern whitspace = Pattern.compile("\\s*");
+
+ // rows are sections, colums are options
+ private final Table<String, String, String> sections =
HashBasedTable.create();
+
+ private final Map<String, Set<String>> sectionSources = new
HashMap<String, Set<String>>(20);
+
+ /**
+ * Start with an empty configuration.
+ */
+ public Configuration() {
+ }
+
+
+ /**
+ * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR" where
+ * either in the "PATHS" section or the environment "FOO" is set to
+ * "DIRECTORY".
+ *
+ * @param orig string to $-expand
+ * @return $-expanded string
+ */
+ public String expandDollar(String orig) {
+ Map<String, String> env = System.getenv();
+ for (final Map.Entry<String, String> e : env.entrySet()) {
+ orig = orig.replace("$" + e.getKey(), e.getValue());
+ }
+
+ for (final Map.Entry<String, String> e :
sections.row("PATHS").entrySet()) {
+ orig = orig.replace("$" + e.getKey(), e.getValue());
+ }
+ return orig;
+ }
+
+ /**
+ * Returns all configuration options in a section.
+ *
+ * @param s the section of interest
+ * @return an unmodifiable view of the section.
+ */
+ public Map<String, String> getSection(String s) {
+ Map<String, String> m = sections.row(s);
+ return Collections.unmodifiableMap(m);
+ }
+
+ /**
+ * Returns the names of all non-empty sections
+ *
+ * @return set of non-empty section names
+ */
+ public Set<String> getSections() {
+ return sections.rowKeySet();
+ }
+
+ /**
+ * Get a configuration value that should be in a set of predefined strings
+ *
+ * @param section section of interest
+ * @param option option of interest
+ * @param choices list of legal values
+ * @return matching value from choices
+ */
+ public Optional<String> getValueChoice(String section, String option,
+ Iterable<String> choices) {
+ Optional<String> value = getValueString(section, option);
+ if (!value.isPresent()) {
+ return value;
+ }
+ for (String c : choices) {
+ if (c.equals(value.get())) {
+ return value;
+ }
+ }
+ logger.error("Failure in configuration section {}: invalid value",
section);
+ return Optional.absent();
+ }
+
+
+ /**
+ * Get a configuration value that should be a number
+ *
+ * @param section section of interest
+ * @param option option of interest
+ * @return null if value not in configuration, the option's value otherwise
+ */
+ public Optional<Long> getValueNumber(String section, String option) {
+ Optional<String> num_str = getValueString(section, option);
+ if (!num_str.isPresent()) {
+ logSectionSources(section);
+ return Optional.absent();
+ }
+ try {
+ return Optional.of(Long.parseLong(num_str.get()));
+ } catch (NumberFormatException e) {
+ logger.error("Failure in configuration section "
+ + section + " option " + option + ": " + e.getMessage(),
e);
+ return Optional.absent();
+ }
+ }
+
+ private void logSectionSources(String section) {
+ Set<String> sources = sectionSources.get(section);
+ if (sources == null) {
+ logger.info("No sources for section '{}'", section);
+ } else {
+ logger.info("Sources for section '{}': {}", section, sources);
+ }
+ }
+
+ /**
+ * Set an option to a string value in a section.
+ *
+ * @param section section of interest
+ * @param option option of interest
+ * @return value
+ */
+ public Optional<String> getValueString(String section, String option) {
+ if (haveValue(section, option)) {
+ return Optional.of(sections.get(section, option));
+ }
+ return Optional.absent();
+ }
+
+ /**
+ * Gets a configuration value that should be in a set of {"YES","NO"}.
+ *
+ * @param section section of interest
+ * @param option option of interest
+ * @return true, false, null
+ */
+ public Optional<Boolean> getValueYesNo(String section, String option) {
+ final Optional<String> v = getValueChoice(section, option,
+ Arrays.asList("YES", "NO"));
+ if (!v.isPresent()) {
+ Set<String> sources = sectionSources.get(section);
+ if (sources == null) {
+ logger.info("No sources for section '{}'", section);
+ } else {
+ logger.info("Sources for section '{}': {}", section, sources);
+ }
+ logger.error(String.format(
+ "Failure in configuration section '%s': option '%s' not
found",
+ section, option));
+ return Optional.absent();
+ }
+ if (v.get().equalsIgnoreCase("YES")) {
+ return Optional.of(true);
+ }
+ if (v.get().equalsIgnoreCase("NO")) {
+ return Optional.of(false);
+ }
+
+ logger.error(String.format("Configuration error: section '%s', option
'%s' not recognized as YES or NO", section, option));
+
+ return Optional.absent();
+ }
+
+ /**
+ * Tests if we have a value for a particular option.
+ *
+ * @param section section of interest
+ * @param option option of interest
+ * @return true if so, false of not
+ */
+ public boolean haveValue(String section, String option) {
+ return sections.contains(section, option);
+ }
+
+ /**
+ * Parse a configuration file, add all of the options in the file to the
+ * configuration environment.
+ *
+ * @param filename name of the configuration file
+ */
+ public void parse(String filename) {
+ filename = replaceHome(filename);
+
+ String current_section = "";
+
+ Iterator<String> it;
+
+ try {
+ List<String> lines = Files.readLines(new File(filename),
Charset.defaultCharset());
+ it = lines.iterator();
+ } catch (IOException e) {
+ throw new ParsingError("Cannot read configuration file '" +
filename + "'");
+ }
+
+ int lineNumer = 1;
+
+ while (it.hasNext()) {
+ String line = it.next();
+ String[] split_line = line.split("#");
+ if (split_line.length == 0)
+ continue;
+
+ // strip comment
+ line = split_line[0];
+ Matcher m;
+
+ if ((m = tag.matcher(line)).matches()) {
+ String option = m.group(1).trim();
+ String value = m.group(2).trim();
+
+ if (value.length() != 0 && value.charAt(0) == '"') {
+ int pos = value.indexOf('"', 1);
+ if (pos == -1) {
+ logger.warn("incorrecly quoted config value");
+ continue;
+ }
+ value = value.substring(1, pos);
+ }
+ setValueString(current_section, option, value);
+ } else if ((m = section.matcher(line)).matches()) {
+ current_section = m.group(1).trim();
+ if (sectionSources.containsKey(current_section)) {
+ sectionSources.get(current_section).add(filename);
+ } else {
+ sectionSources.put(current_section, new
HashSet<String>(Collections.singleton(filename)));
+ }
+ } else if (whitspace.matcher(line).matches()) {
+ // whitespace is ok
+ } else {
+ logger.warn(String.format("skipped unreadable line %s in
configuration file '%s': '%s'", lineNumer,
+ filename, line));
+ }
+
+ lineNumer++;
+ }
+ }
+
+ private String replaceHome(String filename) {
+ String home = System.getenv("HOME");
+ return home != null ? filename.replace("~", home) : filename;
+ }
+
+ /**
+ * Remove the given section and all options in it.
+ */
+ public void removeSection(String section) {
+ sections.row(section).clear();
+ }
+
+ /**
+ * Set an option to a string value in a section.
+ *
+ * @param section section of interest
+ * @param option option of interest
+ * @param value value to set
+ */
+ public void setValueNumber(String section, String option,
+ long value) {
+ setValueString(section, option, "" + value);
+ }
+
+ /**
+ * Set an option to a string value in a section.
+ *
+ * @param section section of interest
+ * @param option option of interest
+ * @param value value to set
+ */
+ public void setValueString(String section, String option,
+ String value) {
+ sections.put(section, option, value);
+ }
+
+ /**
+ * Write configuration file.
+ *
+ * @param filename where to write the configuration
+ */
+ public void write(String filename) throws IOException {
+ BufferedWriter w = Files.newWriter(new File(filename), Charsets.UTF_8);
+ try {
+ for (String section : sections.rowKeySet()) {
+ w.write("["+section+"]");
+ w.newLine();
+ for (Map.Entry<String,String> e :
sections.row(section).entrySet()) {
+ w.write(e.getKey() + " = " + e.getValue());
+ w.newLine();
+ }
+ }
+ } finally {
+ w.close();
+ }
+ }
+
+ public String serialize() {
+ StringBuffer buf = new StringBuffer();
+ for (Map.Entry<String, Map<String,String>> section :
sections.rowMap().entrySet()) {
+ buf.append("[" + section.getKey() + "]\n");
+ for (Map.Entry<String, String> option :
section.getValue().entrySet()) {
+ buf.append(option.getKey() + " = " + option.getValue() + "\n");
+ }
+ }
+ return buf.toString();
+ }
+
+
+ public void loadDefaults() {
+ Collection<File> dirs = new ArrayList<File>(5);
+ dirs.add(new File("/usr/share/gnunet/config.d/"));
+ dirs.add(new File("/usr/local/share/gnunet/config.d/"));
+ String pfx = System.getenv("GNUNET_PREFIX");
+ if (pfx != null) {
+ dirs.add(new File(pfx, "share/gnunet/config.d/"));
+ dirs.add(new File(pfx, "config.d/"));
+ dirs.add(new File(pfx, "gnunet/config.d/"));
+ }
+ for (File dir : dirs) {
+ if (dir.exists() && dir.isDirectory()) {
+ File[] files = dir.listFiles();
+ if (files == null) {
+ continue;
+ }
+ for (File f : files) {
+ parse(f.getAbsolutePath());
+ }
+ }
+ }
+ }
+
+ public static class ConfigurationException extends RuntimeException {
+ public ConfigurationException(String string) {
+ super(string);
+ }
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/util/Connection.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/Connection.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/Connection.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,696 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+import org.gnunet.construct.Construct;
+import org.gnunet.construct.MessageLoader;
+import org.gnunet.construct.ProtocolViolationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOError;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Integrates sockets with the gnunet-java message loop / the scheduler.
+ */
+public class Connection {
+ private static final Logger logger = LoggerFactory
+ .getLogger(Connection.class);
+
+ /**
+ * The underlying socket the client is using to talk with the service.
+ */
+ private SocketChannel connectionChannel = null;
+
+ /**
+ * The list of all address probes.
+ * Each address probe tries to connect via a different address.
+ */
+ private List<AddressProbe> addressProbes = null;
+
+ /**
+ * The task that is currently used by the resolve mechanism.
+ */
+ private Cancelable resolveHandle = null;
+
+ /**
+ * The task that is responsible for establishing the connection to the
server.
+ */
+ private Cancelable connectHandle = null;
+
+ /**
+ * The ReceiveHelper responsible for receiving a whole message from the
service
+ * and calling the respective MessageReceiver.
+ */
+ private ReceiveHelper currentReceiveHelper = null;
+
+ /**
+ * The buffer with the (partial) message received from the service.
+ * Initially, this buffer has the size of the smallest possible messages,
but grows when
+ * receiving larger messages.
+ */
+ private ByteBuffer recvBuffer =
ByteBuffer.allocate(GnunetMessage.Header.SIZE);
+
+ /**
+ * The handle for the current transmission. Writes data to the socket.
+ */
+ private TransmitHelper currentTransmitHelper = null;
+
+ /**
+ * The handle for the next transmission. The next transmission will become
the current
+ * transmission once the current transmission has completed.
+ * While nextTransmitHelper is not null, no new transmit requests may be
scheduled.
+ */
+ private TransmitHelper nextTransmitHelper = null;
+
+ /**
+ * The transmitters passed to transmitReadyNotify(...) write to this
buffer by calling
+ * methods on the MessageSink passed to the
Transmitter.transmit(MessageSink s) method.
+ * Initially, this buffer has the size of the smallest possible messages,
but grows when
+ * transmitting larger messages.
+ */
+ private ByteBuffer transmitBuffer =
ByteBuffer.allocate(GnunetMessage.Header.SIZE);
+ private boolean disconnected = false;
+
+ /**
+ * Timeout task for the connect notify.
+ */
+ private Scheduler.TaskConfiguration notifyConnectedTimeout;
+
+ /**
+ * Continuation to call when connected
+ */
+ private Continuation notifyConnectedContinuation;
+
+
+ /**
+ * An address probe is a connection to a socket that may succeed or not.
+ * The first address probe that succeeded is used for this connection.
+ */
+ private static class AddressProbe {
+ Cancelable connectTask;
+ SocketChannel channel;
+
+ public void cancel() {
+ if (connectTask != null) {
+ connectTask.cancel();
+ }
+ if (channel != null) {
+ try {
+ channel.close();
+ } catch (IOException e) {
+ // nothing we can do here
+ }
+ }
+ }
+ }
+
+ /**
+ * Represents a request for transmission.
+ */
+ public interface TransmitHandle extends Cancelable {
+ /**
+ * Cancel a request for the transmit ready notification.
+ * This does *not* cancel a transmission that already has been started.
+ */
+ public void cancel();
+ }
+
+ /**
+ * An interface that allows the Transmitter.transmit method to deliver
their messages
+ * to the client, which sends them to the service.
+ */
+ public interface MessageSink {
+ public void send(GnunetMessage.Body m);
+ }
+
+ /**
+ * The ReceiveHelper is responsible for receiving a whole
+ * GnunetMessage and call the respective MessageReceiver with the message
on success,
+ * and null on failure or timeout.
+ */
+ private class ReceiveHelper implements Scheduler.Task {
+ private MessageReceiver receiver;
+ private RelativeTime timeout;
+ private GnunetMessage.Header msgh = null;
+ private Scheduler.TaskConfiguration recvTask = null;
+ private boolean finished = false;
+ // is this receiver actively working? if not, the connection process
has to kick off the receiver
+ // (or select behaves badly)
+ private boolean working = false;
+
+ public ReceiveHelper(MessageReceiver receiver, RelativeTime timeout) {
+ this.receiver = receiver;
+ this.timeout = timeout;
+ }
+
+ public void dispatchMessage() {
+ assert msgh != null;
+ currentReceiveHelper = null;
+ finished = true;
+ recvBuffer.flip();
+
+ boolean found = true;
+ Class unionClass = null;
+
+ try {
+ unionClass =
MessageLoader.getUnionClass(GnunetMessage.Body.class, msgh.messageType);
+ } catch (ProtocolViolationException e) {
+ found = false;
+ }
+
+ logger.debug("dispatching received message");
+ if (found) {
+ GnunetMessage msg;
+ try {
+ msg = Construct.parseAs(recvBuffer, GnunetMessage.class);
+ } catch (OutOfMemoryError e) {
+ throw new OutOfMemoryError("oom while parsing " +
unionClass);
+ }
+ receiver.process(msg.body);
+ } else {
+ UnknownMessageBody b = new UnknownMessageBody();
+ b.id = msgh.messageType;
+
+ // may throw exception, doesn't matter as it's the last call
+ receiver.process(b);
+ }
+ }
+
+ @Override
+ public void run(Scheduler.RunContext ctx) {
+ recvTask = null;
+ if (ctx.reasons.contains(Scheduler.Reason.TIMEOUT)) {
+ currentReceiveHelper = null;
+ receiver.handleError();
+ } else if (ctx.reasons.contains(Scheduler.Reason.READ_READY)) {
+ try {
+ int n = connectionChannel.read(recvBuffer);
+ if (n == -1) {
+ currentReceiveHelper = null;
+ logger.warn("lost connection to service");
+ connectionChannel.close();
+ connectionChannel = null;
+ if (Connection.this.currentTransmitHelper != null) {
+ Connection.this.currentTransmitHelper.cancel();
+ Connection.this.currentTransmitHelper = null;
+ }
+ try {
+ receiver.handleError();
+ } finally {
+ return;
+ }
+ }
+ logger.debug(String.format("read %s bytes from %s", n,
connectionChannel.socket().toString()));
+ } catch (IOException e) {
+ logger.error("read failed:", e);
+ try {
+ receiver.handleError();
+ } finally {
+ return;
+ }
+ }
+ if (recvBuffer.remaining() == 0) {
+ if (msgh != null) {
+ dispatchMessage();
+ } else {
+ recvBuffer.rewind();
+ msgh = Construct.parseAs(recvBuffer,
GnunetMessage.Header.class);
+
+ logger.debug("expecting message of size {}, type {}",
msgh.messageSize, msgh.messageType);
+ if (msgh.messageSize > GnunetMessage.Header.SIZE) {
+ if (recvBuffer.capacity() < msgh.messageSize) {
+ ByteBuffer buf =
ByteBuffer.allocate(msgh.messageSize);
+ recvBuffer.flip();
+ buf.put(recvBuffer);
+ recvBuffer = buf;
+ }
+ recvBuffer.limit(msgh.messageSize);
+ schedule();
+ } else {
+ dispatchMessage();
+ }
+ }
+ } else {
+ schedule();
+ }
+ } else if (ctx.reasons.contains(Scheduler.Reason.SHUTDOWN)) {
+ // nothing to do!
+ } else {
+ // XXX: what to do here?
+ throw new RuntimeException("receive failed");
+ }
+ }
+
+ private void schedule() {
+ working = true;
+ recvTask = Scheduler.addRead(timeout, connectionChannel, this);
+ }
+
+ public void cancel() {
+ if (finished) {
+ throw new AssertionError("canceling finished receive");
+ }
+ if (recvTask != null) {
+ recvTask.cancel();
+ recvTask = null;
+ }
+ }
+ }
+
+
+ private class TransmitHelper implements Scheduler.Task, MessageSink {
+ private final MessageTransmitter transmitter;
+
+ private Cancelable notifyTimeoutTask;
+
+ private Cancelable transmitTask = null;
+
+ public TransmitHelper(final MessageTransmitter transmitter,
RelativeTime notifyTimeout) {
+ this.transmitter = transmitter;
+
+ Scheduler.TaskConfiguration tc = new
Scheduler.TaskConfiguration(notifyTimeout,
+ new Scheduler.Task() {
+ @Override
+ public void run(Scheduler.RunContext ctx) {
+ transmitter.handleError();
+ }
+ });
+
+ notifyTimeoutTask = tc.schedule();
+ }
+
+ public void cancel() {
+ if (transmitTask != null) {
+ transmitTask.cancel();
+ transmitTask = null;
+ }
+ if (notifyTimeoutTask != null) {
+ notifyTimeoutTask.cancel();
+ notifyTimeoutTask = null;
+ }
+ }
+
+ @Override
+ public void run(Scheduler.RunContext ctx) {
+ this.transmitTask = null;
+ if (connectionChannel == null) {
+ logger.error("could not write to channel (null)");
+ return;
+ }
+ try {
+ int n = connectionChannel.write(transmitBuffer);
+ // logger.debug("connectionChannel has written " + n + " bytes
to " + connectionChannel.socket().toString());
+ } catch (IOException e) {
+ throw new IOError(e);
+ }
+ if (transmitBuffer.remaining() == 0) {
+ //logger.debug("sent " + transmitBuffer.position() + "bytes
complete message");
+ if (nextTransmitHelper == null) {
+ currentTransmitHelper = null;
+ } else {
+ currentTransmitHelper = nextTransmitHelper;
+ // we need to to this so the transmit callback can do
notifyTransmitReady
+ TransmitHelper tmpTransmitHelper = nextTransmitHelper;
+ nextTransmitHelper = null;
+ tmpTransmitHelper.start();
+
+ }
+ } else {
+ schedule();
+ }
+ }
+
+ /**
+ * called to notify when we are ready to put new messages in the
transmit buffer
+ */
+ public void start() {
+ notifyTimeoutTask.cancel();
+ notifyTimeoutTask = null;
+ transmitBuffer.clear();
+ transmitter.transmit(TransmitHelper.this);
+ transmitBuffer.flip();
+ schedule();
+ }
+
+ private void schedule() {
+ if (disconnected) {
+ return;
+ }
+ // timeout is forever, because there is no way to directly limit
the transmission time
+ // of a message, only the max. wait time before transmission.
+ // cancel must be called on the transmitTask if we disconnect
+ Scheduler.TaskConfiguration tc = new
Scheduler.TaskConfiguration(RelativeTime.FOREVER, this);
+ tc.selectWrite(connectionChannel);
+ this.transmitTask = tc.schedule();
+ }
+
+ @Override
+ public void send(final GnunetMessage.Body m) {
+ final GnunetMessage gm = new GnunetMessage();
+ gm.header = new GnunetMessage.Header();
+ gm.body = m;
+ Construct.patch(gm);
+ gm.header.messageSize = Construct.getSize(gm);
+ byte[] b = Construct.toBinary(gm);
+ if (b.length != gm.header.messageSize) {
+ throw new AssertionError(
+ String.format("tried to send message with binary size
%s but size in header %s",
+ b.length, gm.header.messageSize));
+ }
+ logger.debug("sending message (size={},type={})", b.length,
gm.header.messageType);
+ if (transmitBuffer.remaining() < b.length) {
+ ByteBuffer buf = ByteBuffer.allocate(b.length +
transmitBuffer.capacity());
+ transmitBuffer.flip();
+ buf.put(transmitBuffer);
+ transmitBuffer = buf;
+ }
+ transmitBuffer.put(b);
+ }
+ }
+
+ /**
+ * Create a connection to the given hostname/port.
+ *
+ * @param hostname name of the host to connect to
+ * @param port port of the host to connect to
+ */
+ public Connection(String hostname, int port) {
+ addressProbes = new LinkedList<AddressProbe>();
+ ConnectionResolveHandler addressHandler = new
ConnectionResolveHandler(port);
+ resolveHandle = Resolver.getInstance().resolveHostname(hostname,
RelativeTime.FOREVER, addressHandler);
+ }
+
+ public Connection(SocketChannel sock) {
+ assert sock != null;
+ this.connectionChannel = sock;
+ }
+
+
+ class ConnectionResolveHandler implements Resolver.AddressCallback {
+ private final int port;
+
+ public ConnectionResolveHandler(int port) {
+ this.port = port;
+ }
+
+ @Override
+ public void onAddress(InetAddress addr) {
+ final SocketChannel channel = createChannel();
+ try {
+ channel.connect(new InetSocketAddress(addr, port));
+ } catch (IOException e) {
+ logger.error("could not connect to host");
+ return;
+ }
+
+ final AddressProbe addressProbe = new AddressProbe();
+ addressProbe.channel = channel;
+ Scheduler.TaskConfiguration tc = new
Scheduler.TaskConfiguration(RelativeTime.FOREVER,
+ new Scheduler.Task() {
+ @Override
+ public void run(Scheduler.RunContext ctx) {
+ addressProbe.connectTask = null;
+ if
(ctx.reasons.contains(Scheduler.Reason.SHUTDOWN)) {
+ return;
+ }
+ Connection.this.finishConnect(addressProbe);
+ }
+ });
+
+ // our channel has already disconnected
+ if (!channel.isOpen()) {
+ return;
+ }
+
+ tc.selectConnect(channel);
+
+ addressProbe.connectTask = tc.schedule();
+ }
+
+ @Override
+ public void onFinished() {
+ resolveHandle = null;
+ }
+
+ @Override
+ public void onTimeout() {
+ // do nothing
+ // todo: is this correct?
+ }
+ }
+
+
+ private void finishConnect(AddressProbe probe) {
+ // can happen if the addres probe task was already scheduled
+ if (connectionChannel != null) {
+ try {
+ probe.channel.close();
+ } catch (IOException e) {
+ logger.error("could not close channel", e);
+ }
+ return;
+ }
+
+ SocketChannel channel = probe.channel;
+ boolean connected;
+ try {
+ connected = channel.finishConnect();
+ } catch (IOException e) {
+ logger.debug("finishConnect() was not successful: {}", (Object) e);
+ return;
+ }
+
+ if (!connected) {
+ logger.error("socket reported OP_CONNECT but is not connected");
+ return;
+ }
+
+ for (AddressProbe addressProbe : addressProbes) {
+ if (addressProbe != probe && addressProbe.connectTask != null) {
+ addressProbe.connectTask.cancel();
+ try {
+ addressProbe.channel.close();
+ } catch (IOException e) {
+ logger.error("could not close channel", e);
+ }
+ }
+ }
+
+ addressProbes.clear();
+
+ connectionChannel = channel;
+
+ if (currentTransmitHelper != null) {
+ currentTransmitHelper.start();
+ }
+ if (currentReceiveHelper != null && !currentReceiveHelper.working) {
+ currentReceiveHelper.schedule();
+ }
+ Continuation c = notifyConnectedContinuation;
+ notifyConnectedContinuation = null;
+ if (notifyConnectedTimeout != null) {
+ notifyConnectedTimeout.cancel();
+ notifyConnectedTimeout = null;
+ }
+ if (c != null) {
+ c.cont(true);
+ }
+ }
+
+ /**
+ * Open a channel for this connection in non-blocking mode
+ */
+ private SocketChannel createChannel() {
+ try {
+ SocketChannel channel =
SelectorProvider.provider().openSocketChannel();
+ channel.configureBlocking(false);
+ return channel;
+ } catch (IOException e) {
+ // this is fatal, no retry necessary
+ throw new IOError(e);
+ }
+ }
+
+ public boolean isConnected() {
+ return connectionChannel != null && connectionChannel.isConnected();
+ }
+
+
+ public interface ReceiveHandle extends Cancelable {
+ }
+
+ /**
+ * Receive one message from the network.
+ *
+ * @param timeout deadline after which receiver.onError() will be called
+ * @param receiver MessageReceiver that is responsible for the received
message
+ */
+ public ReceiveHandle receive(RelativeTime timeout, final MessageReceiver
receiver) {
+ if (currentReceiveHelper != null) {
+ throw new AssertionError("receive must not be called while
receiving");
+ }
+
+ if (!isConnected()) {
+ throw new AssertionError("cannot receive if not connected");
+ }
+
+ recvBuffer.clear();
+ recvBuffer.limit(GnunetMessage.Header.SIZE);
+ final ReceiveHelper rh = new ReceiveHelper(receiver, timeout);
+ currentReceiveHelper = rh;
+
+ // we can only schedule the receive helper if we are sure the
connection is made, otherwise
+ // select will misbehave!
+ if (connectionChannel.isConnected()) {
+ currentReceiveHelper.schedule();
+ }
+
+ return new ReceiveHandle() {
+ @Override
+ public void cancel() {
+ rh.cancel();
+ }
+ };
+ }
+
+ /**
+ * Call the transmitter once the we are ready to transmit data.
+ *
+ * @param size number of bytes to send
+ * @param timeout after how long should we give up (and call
transmitter.transmit(null))
+ * @param transmitter the MessageTransmitter object to call once the
client is ready to transmit or
+ * 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, null
if request could be satisfied immediately
+ */
+ public TransmitHandle notifyTransmitReady(int size, RelativeTime timeout,
final MessageTransmitter transmitter) {
+ if (disconnected) {
+ throw new AssertionError("notifyTransmitReady called on a closed
connection");
+ }
+ if (nextTransmitHelper != null) {
+ throw new AssertionError(
+ "previous transmit request must have completed before
calling notifyTransmitReady again");
+ }
+
+ if (timeout.getMicroseconds() <= 0) {
+ throw new AssertionError("notifyTransmitReady timeout must be
positive");
+ }
+
+ if (!isConnected()) {
+ throw new AssertionError("notifyTransmitHandle can only be called
once connected");
+ }
+
+ final TransmitHelper transmit = new TransmitHelper(transmitter,
timeout);
+
+ if (currentTransmitHelper == null) {
+ currentTransmitHelper = transmit;
+ currentTransmitHelper.start();
+ return null;
+ }
+
+ nextTransmitHelper = transmit;
+
+ return new TransmitHandle() {
+ @Override
+ public void cancel() {
+ transmit.cancel();
+ }
+ };
+ }
+
+
+ /**
+ * Call cont after establishing the connection or when the timeout has
occured.
+ *
+ * @param timeout timeout
+ * @param cont continuation to call
+ * @return
+ */
+ /* package-protected */ Cancelable notifyConnected(RelativeTime timeout,
final Continuation cont) {
+ if (notifyConnectedTimeout != null) {
+ throw new AssertionError();
+ }
+ this.notifyConnectedContinuation = cont;
+ this.notifyConnectedTimeout = Scheduler.addDelayed(timeout, new
Scheduler.Task() {
+ @Override
+ public void run(Scheduler.RunContext ctx) {
+ Continuation c = notifyConnectedContinuation;
+ notifyConnectedContinuation = null;
+ Connection.this.notifyConnectedTimeout = null;
+ if (c != null) {
+ c.cont(false);
+ }
+ }
+ });
+ return this.notifyConnectedTimeout;
+ }
+
+ /**
+ * Disconnect. There must not be any pending transmit/receive requests.
+ * Any buffered data scheduled for writing is discarded.
+ */
+ public void disconnect() {
+ if (disconnected) {
+ logger.error("disconnect called twice");
+ }
+ disconnected = true;
+
+ if (currentTransmitHelper != null) {
+ currentTransmitHelper.cancel();
+ currentTransmitHelper = null;
+ }
+
+ if (nextTransmitHelper != null) {
+ nextTransmitHelper.cancel();
+ nextTransmitHelper = null;
+ }
+
+ if (currentReceiveHelper != null) {
+ currentReceiveHelper.cancel();
+ currentReceiveHelper = null;
+ }
+
+ if (resolveHandle != null) {
+ resolveHandle.cancel();
+ resolveHandle = null;
+ }
+ if (connectHandle != null) {
+ connectHandle.cancel();
+ connectHandle = null;
+ }
+ if (connectionChannel != null) {
+ try {
+ connectionChannel.close();
+ } catch (IOException e) {
+ throw new IOError(e);
+ }
+ connectionChannel = null;
+ }
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/util/Continuation.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/Continuation.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/Continuation.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,25 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+public interface Continuation {
+ void cont(boolean success);
+}
Added: gnunet-java/src/main/java/org/gnunet/util/GnunetMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/GnunetMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/GnunetMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,81 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+
+import org.gnunet.construct.*;
+
+
+/**
+ * Every message used to communicate between gnunet components uses this
format.
+ * First, a header is sent, containing the size of the overall message
(including the header), as
+ * well as the type of the message. After that the message body is sent, whose
format is specified
+ * by the message type.
+ *
+ */
+public final class GnunetMessage implements Message {
+ public static final int MINIMAL_SIZE = Header.SIZE;
+
+
+ /**
+ * The header of every gnunet message.
+ */
+ public static final class Header implements Message {
+ public static final int SIZE = 4;
+
+ @FrameSize
+ @UInt16
+ public int messageSize;
+
+ @UInt16
+ public int messageType;
+ }
+
+ /**
+ * The common interface for every message body.
+ *
+ */
+ public static interface Body extends MessageUnion {
+ }
+
+
+ /**
+ * Create a GnunetMessage from its body only. The header is added and
filled with the relevant information
+ * automatically.
+ *
+ * @param b the message body to convert
+ * @return a complete and valid gnunet message
+ */
+ public static GnunetMessage fromBody(Body b) {
+ GnunetMessage msg = new GnunetMessage();
+ msg.header = new Header();
+ msg.header.messageSize = Header.SIZE + Construct.getSize(b);
+ msg.header.messageType =
MessageLoader.getUnionTag(GnunetMessage.Body.class, b.getClass());
+ msg.body = b;
+ return msg;
+ }
+
+ @NestedMessage
+ public Header header;
+
+ @Union(tag = "header.messageType")
+ public Body body;
+}
Added: gnunet-java/src/main/java/org/gnunet/util/HashCode.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/HashCode.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/HashCode.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,94 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+
+import com.google.common.base.Charsets;
+import org.gnunet.construct.FixedSizeIntegerArray;
+import org.gnunet.construct.Message;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+
+/**
+ * 512-bit hash code
+ */
+public class HashCode implements Message {
+
+ @FixedSizeIntegerArray(length = 64, signed = false, bitSize = 8)
+ public byte[] data; // should be immutable, final, can't be due to
construct
+
+
+ public HashCode() {
+ // construct needs a default c'tor
+ }
+
+ public HashCode(byte[] hash) {
+ if (hash.length != 64) {
+ throw new AssertionError("HashCode has to have length 64");
+ }
+ data = Arrays.copyOf(hash, hash.length);
+ }
+
+ /**
+ * Create the HashCode of an UTF-8 String using SHA-512.
+ *
+ * @param s the string to hash
+ */
+ public HashCode(String s) {
+ MessageDigest digest;
+ try {
+ digest = MessageDigest.getInstance("SHA-512");
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("crypto algorithm required but not
provided");
+ }
+ byte[] data = digest.digest(s.getBytes(Charsets.UTF_8));
+ if (data.length != 64) {
+ throw new RuntimeException("error in SHA512 algorithm");
+ }
+ this.data = data;
+ }
+
+ public boolean isAllZero() {
+ for (byte aData : data) {
+ if (aData != 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof HashCode)) {
+ return false;
+ }
+ HashCode hashCode = (HashCode) other;
+ return Arrays.equals(this.data, hashCode.data);
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(this.data);
+ }
+}
\ No newline at end of file
Added: gnunet-java/src/main/java/org/gnunet/util/Helper.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/Helper.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/Helper.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,208 @@
+package org.gnunet.util;
+
+import org.gnunet.construct.Construct;
+import org.gnunet.construct.Message;
+import org.gnunet.construct.MessageLoader;
+import org.gnunet.construct.ProtocolViolationException;
+import org.gnunet.mq.Envelope;
+import org.gnunet.mq.MessageQueue;
+
+import java.io.IOError;
+import java.io.IOException;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.util.EnumSet;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Process that we can communicate with standard GNUnet messages over
stdin/stdout.
+ */
+public class Helper extends MessageQueue {
+
+ private final ProcessBuilder processBuilder;
+ private final RunaboutMessageReceiver receiver;
+ private Process process;
+
+ private volatile GnunetMessage.Body writeMessage;
+
+ private final class WriteThread implements Runnable {
+ @Override
+ public void run() {
+ GnunetMessage.Body msg;
+ while (true) {
+ synchronized (Helper.this) {
+ while (writeMessage == null) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ // do nothing
+ }
+ }
+ // we now have a message we can send
+ msg = writeMessage;
+ writeMessage = null;
+ // somebody can set the next send message
+ }
+ byte[] data = Construct.toBinary(GnunetMessage.fromBody(msg));
+ try {
+ process.getOutputStream().write(data);
+ } catch (IOException e) {
+ // fixme: what now?
+ }
+ Scheduler.addContinuation(new Scheduler.Task() {
+ @Override
+ public void run(Scheduler.RunContext ctx) {
+ reportMessageSent();
+ }
+ }, EnumSet.noneOf(Scheduler.Reason.class));
+ }
+ }
+ }
+
+ private final class ReadThread implements Runnable {
+ private ByteBuffer buffer;
+ ReadableByteChannel channel;
+
+ private void fillBuffer() {
+ while (buffer.hasRemaining()) {
+ try {
+ channel.read(buffer);
+ } catch (IOException e) {
+ // FIXME
+ return;
+ }
+ }
+ }
+
+ private void scheduleInvokeReceiver(final GnunetMessage.Body body) {
+ Scheduler.addContinuation(new Scheduler.Task() {
+ @Override
+ public void run(Scheduler.RunContext ctx) {
+ receiver.process(body);
+ }
+ }, EnumSet.noneOf(Scheduler.Reason.class));
+
+ }
+
+ @Override
+ public void run() {
+ // allocate just enough for the message header
+ buffer = ByteBuffer.allocate(4);
+ channel = Channels.newChannel(process.getInputStream());
+ while (true) {
+ buffer.clear();
+ buffer.limit(4);
+ fillBuffer();
+ buffer.rewind();
+ GnunetMessage.Header msgh = Construct.parseAs(buffer,
GnunetMessage.Header.class);
+ if (msgh.messageSize > GnunetMessage.Header.SIZE) {
+ if (buffer.capacity() < msgh.messageSize) {
+ ByteBuffer newBuf =
ByteBuffer.allocate(msgh.messageSize);
+ buffer.flip();
+ newBuf.put(buffer);
+ buffer = newBuf;
+ }
+ buffer.limit(msgh.messageSize);
+ fillBuffer();
+ }
+ // we now have a complete message
+ // prepare for reading again
+ buffer.flip();
+
+ boolean found = true;
+ Class unionClass = null;
+
+ try {
+ unionClass =
MessageLoader.getUnionClass(GnunetMessage.Body.class, msgh.messageType);
+ } catch (ProtocolViolationException e) {
+ found = false;
+ }
+ if (found) {
+ GnunetMessage msg;
+ msg = Construct.parseAs(buffer, GnunetMessage.class);
+ scheduleInvokeReceiver(msg.body);
+ } else {
+ UnknownMessageBody b = new UnknownMessageBody();
+ b.id = msgh.messageType;
+ scheduleInvokeReceiver(b);
+ }
+ }
+ }
+ }
+
+
+ public Helper(boolean withControlPipe, String binaryName, List<String>
argv,
+ RunaboutMessageReceiver receiver) {
+ this.receiver = receiver;
+ List<String> command = new LinkedList<String>();
+ if (binaryName == null) {
+ throw new AssertionError();
+ }
+ command.add(binaryName);
+ if (argv != null)
+ command.addAll(argv);
+ processBuilder = new ProcessBuilder(command);
+ try {
+ process = processBuilder.start();
+ } catch (IOException e) {
+ throw new IOError(e);
+ }
+ }
+
+ /**
+ * Sends termination signal to the helper process. The helper process is
not
+ * reaped; call GNUNET_HELPER_wait() for reaping the dead helper process.
+ *
+ * @param softkill if GNUNET_YES, signals termination by closing the
helper's
+ * stdin; GNUNET_NO to signal termination by sending SIGTERM to
helper
+ * @return true on success, false on failure
+ */
+ public boolean kill(boolean softkill) {
+ if (softkill) {
+ try {
+ process.getInputStream().close();
+ } catch (IOException e) {
+ return false;
+ }
+ return true;
+ }
+ process.destroy();
+ return true;
+ }
+
+ /**
+ * Reap the helper process. This call is blocking(!). The helper process
+ * should either be sent a termination signal before or should be dead
before
+ * calling this function
+ *
+ * @return true on success, false on failure
+ */
+ public boolean waitFor() {
+ try {
+ process.waitFor();
+ } catch (InterruptedException e) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ protected void submit(Envelope ev) {
+ synchronized (this) {
+ if (writeMessage != null)
+ throw new AssertionError("message queue not implemented
correctly");
+ writeMessage = ev.message;
+ notifyAll();
+ }
+ }
+
+ @Override
+ protected void retract() {
+ synchronized (this) {
+ writeMessage = null;
+ }
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/util/MessageReceiver.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/MessageReceiver.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/MessageReceiver.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,41 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+/**
+ * Callback object for receiving messages.
+ *
+ */
+public interface MessageReceiver {
+
+ /**
+ * Called when a message is received
+ *
+ * @param msg message received, null on deadline or fatal error
+ */
+ public void process(GnunetMessage.Body msg);
+
+
+ /**
+ * Called when an error (timeout, loss of connection) occured before
receiving the message.
+ */
+ public void handleError();
+}
Added: gnunet-java/src/main/java/org/gnunet/util/MessageTransmitter.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/MessageTransmitter.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/MessageTransmitter.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,43 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+
+/**
+ * Callback object for transmitting messages.
+ */
+public interface MessageTransmitter {
+ /**
+ * Called when the client is ready to transmit messages, or on
timeout/error.
+ *
+ * @param sink A message sink that receives messages to be transmitted by
the client,
+ * or null on timeout/error.
+ */
+ public void transmit(Connection.MessageSink sink);
+
+
+ /**
+ * Called when the transmit request could not be fullfilled.
+ *
+ * After transmit has been called, handleError will not be called anymore
(until the next transmit request)
+ */
+ void handleError();
+}
Added: gnunet-java/src/main/java/org/gnunet/util/PeerIdentity.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/PeerIdentity.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/PeerIdentity.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,69 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+
+import org.gnunet.construct.FixedSizeIntegerArray;
+import org.gnunet.construct.Message;
+
+import java.util.Arrays;
+
+
+/**
+ * Identity of a peer, stored as 512-bit public key.
+ */
+public class PeerIdentity implements Message {
+
+ @FixedSizeIntegerArray(length = 64, signed = false, bitSize = 8)
+ public byte[] data;
+
+ static final String HEXES = "0123456789ABCDEF";
+
+ /**
+ * Creates a zero-filled peer identity
+ */
+ public PeerIdentity() {
+ data = new byte[64];
+ }
+
+ public String getHex() {
+ final StringBuilder hex = new StringBuilder( 2 * data.length );
+ for (final byte b : data) {
+ hex.append(HEXES.charAt((b & 0xF0) >> 4))
+ .append(HEXES.charAt((b & 0x0F)));
+ }
+ return hex.toString();
+ }
+
+ public String toString() {
+ return Strings.dataToString(data);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj != null && obj instanceof PeerIdentity &&
Arrays.equals(((PeerIdentity) obj).data, this.data);
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(data);
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/util/Program.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/Program.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/Program.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,229 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+import org.apache.log4j.*;
+import org.gnunet.util.getopt.Argument;
+import org.gnunet.util.getopt.ArgumentAction;
+import org.gnunet.util.getopt.Parser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+
+/**
+ * Program is the entry point class for everything that uses gnunet services
or APIs.
+ *
+ * Also specifies the default command line arguments using the
org.gnunet.util.getopt annotations.
+ *
+ * @see Service
+ */
+public abstract class Program {
+ private static final Logger logger = LoggerFactory
+ .getLogger(Program.class);
+
+
+ protected final Configuration cfg = new Configuration();
+
+ @Argument(shortname = "c", longname = "config",
+ description = "Path of the configuration file",
+ argumentName = "FILENAME",
+ action = ArgumentAction.STORE_STRING)
+ public String cfgFileName;
+
+ @Argument(shortname = "h", longname = "help",
+ description = "print this help message",
+ action = ArgumentAction.SET)
+ public boolean printHelp;
+
+ @Argument(shortname = "v", longname = "version",
+ description = "print version",
+ action = ArgumentAction.SET)
+ public boolean showVersion;
+
+
+ @Argument(shortname = "L", longname = "log",
+ description = "configure logging to use LOGLEVEL",
+ argumentName = "LOGLEVEL",
+ action = ArgumentAction.STORE_STRING)
+ public String logLevel;
+
+ @Argument(shortname = "l", longname = "logfile",
+ description = "configure logging to write logs to LOGFILE",
+ argumentName = "LOGFILE",
+ action = ArgumentAction.STORE_STRING)
+ public String logFile;
+
+
+ protected String[] unprocessedArgs;
+
+ private final String[] args;
+
+ private int returnValue = 0;
+
+
+ /**
+ * A program with the desired environment for a gnunet utility.
+ * While executing, the scheduler is guaranteed to run, command arguments
are parsed,
+ * the default configuration is loaded and the DNS Resolver is initialized.
+ *
+ * @param args array of command line arguments to parse. used to
automatically load additional settings
+ * and configure log levels.
+ */
+ public Program(String... args) {
+ this.args = args;
+
+ /*
+ * Remember: We can't parse command line arguments here, as java's
initialization order
+ * dictates that member variables of subclasses are initialized
*after* the superclass constructor (here).
+ */
+ }
+
+ /**
+ * Configure logging with the given log level and log file.
+ *
+ * @param logLevel one of DEBUG,INFO,WARN,ERROR,OFF
+ * @param logFile logfile, absolute or relative to the current working
directory
+ */
+ public static void configureLogging(String logLevel, String logFile) {
+ org.apache.log4j.Logger rootLogger = LogManager.getRootLogger();
+
+ rootLogger.removeAllAppenders();
+
+ // %c{2}: category 2 levels
+ Layout layout = new PatternLayout("%d{dd MMM yyyy HH:mm:ss-SSS} %c{2}
%p: %m%n");
+
+ if (logFile == null) {
+ rootLogger.addAppender(new ConsoleAppender(layout,
ConsoleAppender.SYSTEM_OUT));
+ } else {
+ Appender appender = null;
+ try {
+ appender = new FileAppender(layout, logFile);
+ } catch (IOException e) {
+ logger.warn("could not open log file {}", logFile);
+ }
+ if (appender!= null) {
+ rootLogger.removeAllAppenders();
+ rootLogger.addAppender(appender);
+ }
+ }
+ if (logLevel == null) {
+ rootLogger.setLevel(Level.INFO);
+ } else if (logLevel.equalsIgnoreCase("debug")) {
+ rootLogger.setLevel(Level.DEBUG);
+ } else if (logLevel.equalsIgnoreCase("info")) {
+ rootLogger.setLevel(Level.INFO);
+ } else if (logLevel.equalsIgnoreCase("warn") ||
logLevel.equalsIgnoreCase("warning")) {
+ rootLogger.setLevel(Level.WARN);
+ } else if (logLevel.equalsIgnoreCase("error")) {
+ rootLogger.setLevel(Level.ERROR);
+ } else if (logLevel.equalsIgnoreCase("off")) {
+ rootLogger.setLevel(Level.OFF);
+ } else {
+ rootLogger.setLevel(Level.INFO);
+ logger.info("unknown log level '{}'; defaulting to INFO",
logLevel);
+ }
+ }
+
+ public static void configureLogging(String logLevel) {
+ configureLogging(logLevel, null);
+ }
+
+ public static void configureLogging() {
+ configureLogging(null, null);
+ }
+
+
+ /**
+ * Override to display a different help text on "-h/--help"
+ *
+ * @return the help text
+ */
+ protected String makeHelpText() {
+ return "gnunet-java tool";
+ }
+
+ /**
+ * Override to display a different version description on "-h/--help"
+ *
+ * @return version description
+ */
+ protected String makeVersionDescription() {
+ return "development version of gnunet-java";
+ }
+
+ final protected void setReturnValue(int x) {
+ returnValue = x;
+ }
+
+ /**
+ * Start the Program as the initial task of the Scheduler.
+ */
+ public final void start() {
+ Parser optParser = new Parser(this);
+ unprocessedArgs = optParser.parse(args);
+
+ configureLogging(logLevel, logFile);
+
+ cfg.loadDefaults();
+
+ if (cfgFileName != null) {
+ cfg.parse(cfgFileName);
+ }
+
+ Resolver.getInstance().setConfiguration(cfg);
+
+ if (showVersion) {
+ System.out.println(makeVersionDescription());
+ } else if (printHelp) {
+ System.out.println(makeHelpText());
+ System.out.print(optParser.getHelp());
+ } else {
+ Scheduler.run(new Scheduler.Task() {
+ public void run(Scheduler.RunContext c) {
+ Program.this.runHook();
+ }
+ });
+ }
+
+ System.exit(returnValue);
+ }
+
+ /**
+ * Overridden by specializations of Program, like Service.
+ *
+ * Allows for start() to be final.
+ */
+ /* package-private */
+ void runHook() {
+ run();
+ }
+
+ /**
+ * Override to implement the behavior of the Program.
+ */
+ public abstract void run();
+
+ public final Configuration getConfiguration() {
+ return cfg;
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/util/RelativeTime.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/RelativeTime.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/RelativeTime.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,231 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Positive amount of time with no point of reference.
+ *
+ * @author Florian Dold
+ */
+public final class RelativeTime implements Comparable<RelativeTime> {
+ private static final Logger logger = LoggerFactory
+ .getLogger(RelativeTime.class);
+
+ public static final RelativeTime MICROSECOND = new RelativeTime(1);
+ public static final RelativeTime MILLISECOND = MICROSECOND.multiply(1000);
+ public static final RelativeTime SECOND = MILLISECOND.multiply(1000);
+ public static final RelativeTime MINUTE = SECOND.multiply(60);
+ public static final RelativeTime HOUR = MINUTE.multiply(60);
+ public static final RelativeTime DAY = HOUR.multiply(24);
+ public static final RelativeTime WEEK = DAY.multiply(7);
+ public static final RelativeTime MONTH = DAY.multiply(30);
+ public static final RelativeTime YEAR = DAY.multiply(365);
+
+ public static final RelativeTime ZERO = new RelativeTime(0);
+ public static final RelativeTime FOREVER = new
RelativeTime(Long.MAX_VALUE);
+
+ /**
+ * Time offset in microseconds.
+ */
+ private final long rel_value_us;
+
+ /**
+ * Create a new RelativeTime value, with a given time in milliseconds.
+ *
+ * @param abs_value time in milliseconds
+ */
+ public RelativeTime(final long abs_value) {
+ this.rel_value_us = abs_value;
+ }
+
+ public static RelativeTime fromMilliseconds(final long ms) {
+ return new RelativeTime(ms * 1000);
+ }
+
+ public static RelativeTime fromMicroseconds(final long us) {
+ return new RelativeTime(us);
+ }
+
+ /**
+ * Add relative times together.
+ *
+ * @param other
+ * the other timestamp
+ *
+ * @return this + other
+ */
+ public RelativeTime add(final RelativeTime other) {
+ if (this.rel_value_us == Long.MAX_VALUE
+ || other.rel_value_us == Long.MAX_VALUE) {
+ return RelativeTime.FOREVER;
+ }
+ final long new_rel_value = this.rel_value_us + other.rel_value_us;
+ // check for numeric overflow
+ if (new_rel_value < this.rel_value_us) {
+ logger.warn("time overflow");
+ return RelativeTime.FOREVER;
+ }
+ return new RelativeTime(new_rel_value);
+ }
+
+ /**
+ * Divide relative time by a given factor.
+ *
+ * @param factor
+ * integer to divide by
+ * @return FOREVER if this=FOREVER or factor=0; otherwise this/factor
+ */
+ public RelativeTime divide(final int factor) {
+ if (factor == 0 || this.rel_value_us == Long.MAX_VALUE) {
+ return RelativeTime.FOREVER;
+ }
+ return new RelativeTime(this.rel_value_us / factor);
+ }
+
+ /**
+ * Returns the amount of time in milliseconds.
+ *
+ * @return the amount of time in milliseconds
+ */
+ public long getMicroseconds() {
+ return rel_value_us;
+ }
+
+ /**
+ * Return the maximum of two relative time values.
+ *
+ * @return max(t1, t2)
+ */
+ public static RelativeTime max(RelativeTime t1, RelativeTime t2) {
+ return t1.rel_value_us >= t2.rel_value_us ? t1 : t2;
+ }
+
+ /**
+ * Return the minimum of two relative time values.
+ *
+ * @return min(this, other)
+ */
+ public static RelativeTime min(RelativeTime t1, RelativeTime t2) {
+ return t1.rel_value_us <= t2.rel_value_us ? t1 : t2;
+ }
+
+ /**
+ * Multiply relative time by a given factor.
+ *
+ * @return FOREVER if this=FOREVER or on overflow; otherwise this*factor
+ */
+ public RelativeTime multiply(final int factor) {
+ if (factor == 0) {
+ return RelativeTime.ZERO;
+ }
+ final long ret = this.rel_value_us * factor;
+ // check for numeric overflow
+ if (ret / factor != rel_value_us) {
+ logger.warn("time overflow");
+ return RelativeTime.FOREVER;
+ }
+ return new RelativeTime(ret);
+ }
+
+ /**
+ * Subtract relative timestamp from the other.
+ *
+ * @param other
+ * second timestamp
+ * @return ZERO if other>=this (including both FOREVER), FOREVER if
+ * this=FOREVER, this-other otherwise
+ */
+ public RelativeTime subtract(final RelativeTime other) {
+ if (this.rel_value_us >= other.rel_value_us) {
+ return RelativeTime.ZERO;
+ } else if (this.rel_value_us == Long.MAX_VALUE) {
+ return this;
+ } else {
+ return new RelativeTime(this.rel_value_us - other.rel_value_us);
+ }
+ }
+
+ /**
+ * Converts relative time to an absolute time in the future.
+ *
+ * @return timestamp that is in the future, or FOREVER if this=FOREVER (or
+ * if we would overflow)
+ */
+ public AbsoluteTime toAbsolute() {
+ return AbsoluteTime.now().add(this);
+ }
+
+ public boolean isForever() {
+ return rel_value_us == FOREVER.rel_value_us;
+ }
+
+ public boolean equals(Object o) {
+ return (o instanceof RelativeTime) && ((RelativeTime) o).rel_value_us
== rel_value_us;
+ }
+
+ @Override
+ public int hashCode() {
+ return (int) this.rel_value_us;
+ }
+
+ @Override
+ public int compareTo(RelativeTime other) {
+ if (this.rel_value_us < other.rel_value_us) {
+ return -1;
+ }
+ if (this.rel_value_us > other.rel_value_us) {
+ return 1;
+ }
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ if (this.isForever()) {
+ return "RelativeTime(FOREVER)";
+ }
+ return "RelativeTime("+this.rel_value_us +")";
+ }
+
+
+
+
+ public RelativeTimeMessage toNetwork() {
+ long rval = this.rel_value_us;
+ assert rval >= 0;
+ if (rval == FOREVER.rel_value_us) {
+ rval = -1L; /* 0xFFFFFFFFFFFFFFFF for network format! */
+ }
+ return new RelativeTimeMessage(rval);
+ }
+
+ public static RelativeTime fromNetwork(RelativeTimeMessage m) {
+ if (m.value__ < 0) {
+ return RelativeTime.FOREVER;
+ } else {
+ return new RelativeTime(m.value__);
+ }
+ }
+
+}
Added: gnunet-java/src/main/java/org/gnunet/util/RelativeTimeMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/RelativeTimeMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/RelativeTimeMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,55 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+import org.gnunet.construct.Message;
+import org.gnunet.construct.UInt64;
+
+
+/**
+ * Representation of a RelativeTime object, to be sent over the network.
+ */
+public class RelativeTimeMessage implements Message {
+
+ /**
+ * Value__ still in Java-byte order, needs to be converted to Network byte
+ * order by the Construct class.
+ */
+ @UInt64
+ public long value__;
+
+ public RelativeTimeMessage(final long value) {
+ this.value__ = value;
+ }
+
+ public RelativeTimeMessage() {
+ // default constructor needed for Construct
+ }
+
+ public RelativeTimeMessage(final RelativeTime t) {
+ if (t.equals(RelativeTime.FOREVER)) {
+ this.value__ = -1;
+ } else {
+ this.value__ = t.getMicroseconds();
+ }
+ }
+
+}
Added: gnunet-java/src/main/java/org/gnunet/util/Resolver.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/Resolver.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/Resolver.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,421 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+import com.google.common.net.InetAddresses;
+import org.gnunet.construct.*;
+import org.gnunet.construct.ProtocolViolationException;
+import org.gnunet.util.getopt.Argument;
+import org.gnunet.util.getopt.ArgumentAction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.LinkedList;
+
+/**
+ * Resolve hostnames asynchronously, using the gnunet resolver service if
necessary.
+ * <p/>
+ * TODO: implement reverse lookup (already done in the C-API)
+ */
+public class Resolver {
+ private static final Logger logger = LoggerFactory
+ .getLogger(Resolver.class);
+
+ private static Resolver singletonInstance;
+
+ private Configuration cfg;
+
+ private Client client;
+
+ public static InetAddress getInetAddressFromString(String ipString) {
+ try {
+ return InetAddresses.forString(ipString);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ }
+
+ @UnionCase(4)
+ public static class GetMessage implements GnunetMessage.Body {
+ static final int DIRECTION_GET_IP = 0;
+ static final int DIRECTION_GET_NAME = 1;
+ static final int AF_UNSPEC = 0;
+ static final int AF_INET = 2;
+ static final int AF_INET6 = 10;
+
+ @UInt32
+ public int direction;
+ @UInt32
+ public int domain;
+
+ @Union(tag = "direction", optional = true)
+ public Address addr;
+ }
+
+ public interface Address extends MessageUnion {
+ }
+
+ @UnionCase(GetMessage.DIRECTION_GET_IP)
+ public static class TextualAddress implements Address {
+ @ZeroTerminatedString
+ public String addr;
+ }
+
+ @UnionCase(GetMessage.DIRECTION_GET_NAME)
+ public static class NumericAddress implements Address {
+ @FillWith @UInt8
+ public byte[] addr;
+ }
+
+
+ @UnionCase(5)
+ public static class ResolverResponse implements GnunetMessage.Body {
+ @NestedMessage(optional = true)
+ public ResponseBody responseBody;
+ }
+
+
+ public static class ResponseBody implements Message {
+ @FillWith @UInt8
+ public byte[] addr;
+ }
+
+ /**
+ * Callback object for hostname resolution.
+ */
+ public interface AddressCallback {
+ /**
+ * Called for every address the requested hostname resolves to.
+ *
+ * @param addr address for the resolved name
+ */
+ public void onAddress(InetAddress addr);
+
+ /**
+ * Called after every result (if any) has been passed to onAddress.
+ */
+ public void onFinished();
+
+ /**
+ * Called when the resolve operation times out before returning every
result.
+ */
+ void onTimeout();
+ }
+
+
+ /**
+ * Configuration to use with the Resolver.
+ * <p/>
+ * Usually called by the entry points Program/Service.
+ *
+ * @param cfg configuration to use
+ */
+ public void setConfiguration(Configuration cfg) {
+ this.cfg = cfg;
+ }
+
+ private void lazyConnect() {
+ if (client == null) {
+ if (cfg == null) {
+ throw new AssertionError("Resolver has no Configuration");
+ }
+ client = new Client("resolver", cfg);
+ }
+ }
+
+
+ private InetAddress getInet4Localhost() {
+ try {
+ return InetAddress.getByAddress(new byte[]{127, 0, 0, 1});
+ } catch (UnknownHostException e) {
+ throw new RuntimeException();
+ }
+ }
+
+ private InetAddress getInet6Localhost() {
+ try {
+ return InetAddress.getByAddress(new byte[]{0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1});
+ } catch (UnknownHostException e) {
+ throw new RuntimeException();
+ }
+ }
+
+ public class ResolveHandle implements Cancelable {
+ private String hostname;
+ private AbsoluteTime deadline;
+ private AddressCallback cb;
+ private boolean finished = false;
+ private boolean canceled = false;
+ private Cancelable transmitTask = null;
+ private Cancelable receiveTask = null;
+
+ public void cancel() {
+ if (finished) {
+ throw new AssertionError("Resolve already finished");
+ }
+ if (canceled) {
+ throw new AssertionError("ResolveHandle canceled twice");
+ }
+ if (queuedRequests.contains(this)) {
+ queuedRequests.remove(this);
+ } else {
+ if (receiveTask != null) {
+ receiveTask.cancel();
+ }
+ if (transmitTask != null) {
+ transmitTask.cancel();
+ }
+ }
+ canceled = true;
+ }
+ }
+
+ private LinkedList<ResolveHandle> queuedRequests = new
LinkedList<ResolveHandle>();
+
+ private boolean resolveActive = false;
+
+ /**
+ * Resolve the hostname 'hostname'.
+ *
+ * @param hostname hostname to resolve
+ * @param timeout timeout, calls cb.onTimeout on expiratoin
+ * @param cb callback
+ * @return a handle to cancel the request, null if request could be
satisfied immediately
+ */
+ public Cancelable resolveHostname(String hostname, RelativeTime timeout,
final AddressCallback cb) {
+ // try if hostname is numeric IP or loopback
+ if (hostname.equalsIgnoreCase("localhost")) {
+ logger.debug("resolving address locally");
+ cb.onAddress(getInet6Localhost());
+ cb.onAddress(getInet4Localhost());
+ cb.onFinished();
+ return null;
+ }
+ if (hostname.equalsIgnoreCase("ip6-localhost")) {
+ cb.onAddress(getInet6Localhost());
+ cb.onFinished();
+ return null;
+ }
+ InetAddress inetAddr = getInetAddressFromString(hostname);
+
+ if (inetAddr != null) {
+ cb.onAddress(inetAddr);
+ cb.onFinished();
+ return null;
+ }
+
+ final ResolveHandle rh = new ResolveHandle();
+ rh.hostname = hostname;
+ rh.deadline = timeout.toAbsolute();
+ rh.cb = cb;
+
+ queuedRequests.addLast(rh);
+ handleNextRequest();
+ return rh;
+ }
+
+ private void handleNextRequest() {
+ if (!resolveActive && !queuedRequests.isEmpty()) {
+ ResolveHandle rh = queuedRequests.pollFirst();
+ handleRequest(rh);
+ }
+ }
+
+ private void handleRequest(final ResolveHandle rh) {
+ if (resolveActive) {
+ throw new AssertionError("resolveActive but new resolve started");
+ }
+
+ resolveActive = true;
+
+ lazyConnect();
+
+ final GetMessage req = new GetMessage();
+ req.direction = GetMessage.DIRECTION_GET_IP;
+ req.domain = GetMessage.AF_UNSPEC;
+
+ TextualAddress textAddr = new TextualAddress();
+ textAddr.addr = rh.hostname;
+
+ req.addr = textAddr;
+
+ final AbsoluteTime deadline = rh.deadline;
+
+ logger.debug("deadline is " + deadline + " | now is " +
AbsoluteTime.now());
+
+ logger.debug("remaining is " + deadline.getRemaining());
+
+ rh.transmitTask = client.notifyTransmitReady(
+ deadline.getRemaining(), true,
+ 0, new MessageTransmitter() {
+ @Override
+ public void transmit(Connection.MessageSink sink) {
+ if (sink == null) {
+ onTimeout(rh);
+ return;
+ }
+ sink.send(req);
+ rh.transmitTask = null;
+
+ logger.debug("recv in notifyTransmitReady cb");
+ rh.receiveTask = client.receiveOne(deadline.getRemaining(),
new MessageReceiver() {
+ @Override
+ public void process(GnunetMessage.Body msg) {
+ rh.receiveTask = null;
+ ResolverResponse gmsg = (ResolverResponse) msg;
+ if (gmsg.responseBody != null) {
+ try {
+ InetAddress in_addr;
+ int len = gmsg.responseBody.addr.length;
+ if (len == 4 || len == 16) {
+ in_addr =
InetAddress.getByAddress(gmsg.responseBody.addr);
+ } else {
+ throw new
ProtocolViolationException("malformed address message");
+ }
+
+ rh.cb.onAddress(in_addr);
+ rh.receiveTask =
client.receiveOne(deadline.getRemaining(), this);
+ } catch (UnknownHostException e) {
+ throw new
ProtocolViolationException("malformed address");
+ }
+ } else {
+ resolveActive = false;
+ rh.cb.onFinished();
+ handleNextRequest();
+ }
+ }
+
+ @Override
+ public void handleError() {
+ onTimeout(rh);
+ }
+ });
+
+ }
+
+ @Override
+ public void handleError() {
+ rh.cb.onTimeout();
+ }
+ });
+ }
+
+
+ private void onTimeout(ResolveHandle h) {
+ resolveActive = false;
+ h.cb.onTimeout();
+ handleNextRequest();
+ }
+
+
+ public static Resolver getInstance() {
+ if (singletonInstance == null) {
+ singletonInstance = new Resolver();
+ }
+ return singletonInstance;
+ }
+
+
+ /**
+ * Return a textual representation of an InetAddress. Shortens IPv6
addresses.
+ *
+ * @param addr the address to convert
+ * @return textual representation of the address
+ */
+ public static String ipToString(InetAddress addr) {
+ byte[] a = addr.getAddress();
+ if (a.length == 4) {
+ return addr.getHostAddress();
+ } else if (a.length == 16) {
+ String s = addr.getHostAddress();
+ // replace the first group of zeroes (not the longest) with ::
+ return s.replaceFirst("[:]?0[:](0[:])+0?", "::");
+ } else {
+ throw new RuntimeException("unknown InetAddress format");
+ }
+ }
+
+
+ public static void main(final String[] argv) {
+ new Program(argv) {
+ @Argument(shortname = "r", longname = "reverse",
+ description = "do reverse dns lookup",
+ action = ArgumentAction.SET)
+ boolean isReverse;
+
+ @Override
+ public void run() {
+ if (isReverse) {
+ System.out.println("reverse lookup not supported");
+ } else {
+ resolve();
+ }
+ }
+
+ public void resolve() {
+ final RelativeTime timeout = RelativeTime.SECOND;
+
+ if (unprocessedArgs.length == 0) {
+ logger.warn("no hostname(s) given");
+ } else {
+ logger.info("resolving hostname '" + unprocessedArgs[0] +
"'");
+ Resolver.getInstance().resolveHostname(unprocessedArgs[0],
timeout, new AddressCallback() {
+ int next = 1;
+
+ @Override
+ public void onAddress(InetAddress addr) {
+ System.out.println(ipToString(addr));
+ }
+
+ @Override
+ public void onFinished() {
+ logger.info("resolve finished");
+ next();
+ }
+
+ @Override
+ public void onTimeout() {
+ logger.warn("resolve timed out");
+ next();
+
+ }
+
+ public void next() {
+ if (unprocessedArgs.length > next) {
+ logger.info("resolving hostname '" +
unprocessedArgs[next] + "'");
+
Resolver.getInstance().resolveHostname(unprocessedArgs[next], timeout, this);
+ next++;
+ }
+ }
+ });
+ }
+
+ }
+
+ @Override
+ protected String makeHelpText() {
+ return "tool for forward and reverse DNS lookup";
+ }
+ }.start();
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/util/RunaboutMessageReceiver.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/RunaboutMessageReceiver.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/RunaboutMessageReceiver.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,33 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+import org.grothoff.Runabout;
+
+/**
+ * An abstract base class for message receivers that want to use the runabout,
dispatches
+ * messages to the appropriate visit method.
+ */
+public abstract class RunaboutMessageReceiver extends Runabout implements
MessageReceiver {
+ public void process(GnunetMessage.Body msg) {
+ this.visitAppropriate(msg);
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/util/RunaboutUtil.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/RunaboutUtil.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/RunaboutUtil.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,55 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+import org.gnunet.construct.MessageLoader;
+import org.grothoff.Runabout;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+
+
+/**
+ * Utility methods for the runabout.
+ */
+public class RunaboutUtil {
+ public static ArrayList<Class> getRunaboutVisitees(Runabout r) {
+ Class rc = r.getClass();
+ ArrayList<Class> ret = new ArrayList<Class>(5);
+ for (Method m : rc.getMethods()) {
+ if (!(m.getName().equals("visit") && m.getParameterTypes().length
== 1)) {
+ continue;
+ }
+ ret.add(m.getParameterTypes()[0]);
+ }
+ return ret;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static int[] getRunaboutMessageTypes(Runabout r) {
+ ArrayList<Class> visitees = getRunaboutVisitees(r);
+ int[] msgtypes = new int[visitees.size()];
+ for (int i = 0; i < visitees.size(); ++i) {
+ msgtypes[i] = MessageLoader.getUnionTag(GnunetMessage.Body.class,
visitees.get(i));
+ }
+ return msgtypes;
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/util/Scheduler.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/Scheduler.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/Scheduler.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,678 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.*;
+
+/**
+ * Schedule computations using continuation passing style.
+ *
+ * @author Florian Dold
+ */
+public class Scheduler {
+ private static final Logger logger = LoggerFactory
+ .getLogger(Scheduler.class);
+
+ // only valid while a task is executing
+ private static TaskConfiguration activeTask = null;
+
+ // cumulative number of tasks in the ready lists
+ private static volatile int readyCount = 0;
+
+ // for every priority, there is a list of tasks that is definitely ready
to run
+ @SuppressWarnings("unchecked")
+ final private static LinkedList<TaskConfiguration>[] readyLists = new
LinkedList[Priority.numberOfPriorities];
+
+ static {
+ for (int i = 0; i < Priority.numberOfPriorities; ++i) {
+ readyLists[i] = new LinkedList<TaskConfiguration>();
+ }
+ }
+
+ private static final int EVENT_READ = 0, EVENT_WRITE = 1, EVENT_ACCEPT =
2, EVENT_CONNECT = 3;
+ private static final int[] eventToInterestOp = new
int[]{SelectionKey.OP_READ, SelectionKey.OP_WRITE,
+ SelectionKey.OP_ACCEPT, SelectionKey.OP_CONNECT};
+ private static final Reason[] eventToReason = new
Reason[]{Reason.READ_READY, Reason.WRITE_READY,
+ Reason.ACCEPT_READY, Reason.CONNECT_READY};
+
+
+ /**
+ * Selector, used to check file descriptors for readiness.
+ */
+ private static Selector selector = null;
+
+ static {
+ try {
+ selector = SelectorProvider.provider().openSelector();
+ } catch (final IOException e) {
+ // what to do here?
+ logger.error("fatal: cannot create selector");
+ System.exit(-1);
+ }
+ }
+
+ /**
+ * true iff the scheduler is currently running.
+ */
+ private static boolean scheduler_running = false;
+
+
+ // tasks that are waiting for an event, which are executed anyway after
the deadline has occurred
+ final private static Queue<TaskConfiguration> pending = new
PriorityQueue<TaskConfiguration>(5, new Comparator
+ <TaskConfiguration>() {
+ @Override
+ public int compare(TaskConfiguration a, TaskConfiguration b) {
+ return a.deadline.compareTo(b.deadline);
+ }
+ });
+
+
+ /**
+ * Reset the scheduler forcefully.
+ * Intended to be used internally in the Scheduler, as well as in test
teardown.
+ */
+ public static void forceReset() {
+ scheduler_running = false;
+ readyCount = 0;
+ activeTask = null;
+ for (int i = 0; i < Priority.numberOfPriorities; ++i) {
+ readyLists[i] = new LinkedList<TaskConfiguration>();
+ }
+ pending.clear();
+ }
+
+
+ /**
+ * Priority for Tasks.
+ */
+ public enum Priority {
+ IDLE, BACKGROUND, DEFAULT, HIGH, UI, URGENT, SHUTDOWN;
+
+ // how many different priorities do we have?
+ private static final int numberOfPriorities = Priority.values().length;
+ }
+
+ /**
+ * Reasons for executing a task.
+ */
+ public enum Reason {
+ STARTUP, SHUTDOWN, TIMEOUT, READ_READY, WRITE_READY, ACCEPT_READY,
CONNECT_READY
+ }
+
+ /**
+ * The context of a task that is ready to run.
+ */
+ public static class RunContext {
+ /**
+ * The reason this task has been called by the scheduler.
+ */
+ Set<Reason> reasons = EnumSet.noneOf(Reason.class);
+
+ public RunContext() {
+ }
+ }
+
+ /**
+ * A task is the basic unit of work that is managed by the scheduler.
+ */
+ public static interface Task {
+ public void run(RunContext ctx);
+ }
+
+ /**
+ * A TaskConfiguration represents a Task that will execute or has already
been executed.
+ */
+ public static class TaskConfiguration implements Cancelable {
+ private final Task task;
+ private RunContext ctx = new RunContext();
+ private boolean lifeness = true;
+ private Priority priority;
+ private final AbsoluteTime deadline;
+
+ private ArrayList<SelectableChannel> eventChannels = null;
+ private ArrayList<Integer> eventTypes = null;
+
+ private boolean hasRun = false;
+ private boolean isCanceled = false;
+
+ /**
+ * Create a TaskIdentifier.
+ *
+ * @param delay when will the task be run?
+ * may be null to indicate that this task may not be run
+ * (but only queued directly)
+ * @param task task to run with this TaskIdentifier
+ */
+ TaskConfiguration(RelativeTime delay, Task task) {
+ this.task = task;
+ if (delay == null)
+ this.deadline = null;
+ else
+ this.deadline = delay.toAbsolute();
+ }
+
+ private void addChannelEvent(SelectableChannel channel, int eventType)
{
+ if (channel == null) {
+ throw new AssertionError("channel must be non-null");
+ }
+ if (eventChannels == null) {
+ eventChannels = new ArrayList<SelectableChannel>();
+ eventTypes = new ArrayList<Integer>();
+ }
+ eventChannels.add(channel);
+ eventTypes.add(eventType);
+
+ int interestOp = eventToInterestOp[eventType];
+
+ SelectionKey key = channel.keyFor(selector);
+ if (key == null || !key.isValid()) {
+ try {
+ key = channel.register(selector, interestOp, new
TaskConfiguration[4]);
+ } catch (ClosedChannelException e) {
+ throw new IOError(e);
+ }
+ } else {
+ if ((key.interestOps() & interestOp) != 0) {
+ throw new AssertionError("interest op registered twice");
+ }
+ key.interestOps(key.interestOps() | interestOp);
+ }
+
+ TaskConfiguration[] subscribers = (TaskConfiguration[])
key.attachment();
+ if (subscribers[eventType] != null) {
+ throw new AssertionError("subscriber registered twice");
+ }
+ subscribers[eventType] = this;
+
+ if (subscribers[EVENT_CONNECT] != null && subscribers[EVENT_READ]
!= null) {
+ throw new AssertionError("OP_CONNECT and OP_READ are
incompatible in java");
+ }
+ }
+
+ private void run() {
+ if (hasRun) {
+ throw new AssertionError("same task ran twice");
+ }
+ if (isCanceled) {
+ return;
+ }
+ TaskConfiguration old = activeTask;
+ activeTask = this;
+ task.run(ctx);
+ hasRun = true;
+ activeTask = old;
+ }
+
+ public void cancel() {
+ if (isCanceled) {
+ throw new AssertionError("task canceled twice");
+ }
+ isCanceled = true;
+ pending.remove(this);
+ }
+
+ public Cancelable schedule() {
+ if (this.deadline == null)
+ throw new AssertionError("a task without deadline may not be
scheduled");
+ if (priority == null) {
+ if (activeTask != null) {
+ priority = activeTask.priority;
+ } else {
+ priority = Priority.DEFAULT;
+ }
+ }
+ pending.add(this);
+ return this;
+ }
+
+ private void deregister() {
+ if (eventChannels == null) {
+ return;
+ }
+ for (int i = 0; i < eventChannels.size(); ++i) {
+ SelectionKey key = eventChannels.get(i).keyFor(selector);
+ TaskConfiguration[] subscribers = (TaskConfiguration[])
key.attachment();
+ int interestOp = eventToInterestOp[eventTypes.get(i)];
+ if (subscribers[eventTypes.get(i)] == null ||
(key.interestOps() | interestOp) == 0) {
+ throw new AssertionError("deregistering event that has not
been registered");
+ }
+ subscribers[eventTypes.get(i)] = null;
+ key.interestOps(key.interestOps() & (~interestOp));
+ }
+ }
+
+ public void selectRead(SelectableChannel channel) {
+ addChannelEvent(channel, EVENT_READ);
+ }
+
+ public void selectWrite(SelectableChannel channel) {
+ addChannelEvent(channel, EVENT_WRITE);
+ }
+
+ public void selectConnect(SelectableChannel channel) {
+ addChannelEvent(channel, EVENT_CONNECT);
+ }
+
+ public void selectAccept(SelectableChannel channel) {
+ addChannelEvent(channel, EVENT_ACCEPT);
+ }
+ }
+
+ /**
+ * Run the task regardless of any prerequisites, before any other task of
+ * the same priority.
+ */
+ public static synchronized void addContinuation(Task task, EnumSet<Reason>
reasons) {
+ TaskConfiguration t = new TaskConfiguration(null, task);
+ t.ctx.reasons = reasons;
+ t.priority = Priority.DEFAULT;
+ queueReady(t);
+ }
+
+ /**
+ * Schedule a new task to be run as soon as possible. The task will be run
+ * with the priority of the calling task.
+ *
+ * @param task main function of the task
+ * @return unique task identifier for the job only valid until "task" is
+ * started!
+ */
+ public static Cancelable add(Task task) {
+ return addDelayed(RelativeTime.ZERO, task);
+ }
+
+ /**
+ * Add a task to run after the specified delay.
+ *
+ * @param delay time to wait until running the task
+ * @param task the task to run after delay
+ * @return the TaskIdentifier, can be used to cancel the task until it has
been executed.
+ */
+ public static TaskConfiguration addDelayed(RelativeTime delay, Task task) {
+ TaskConfiguration tid = new TaskConfiguration(delay, task);
+ tid.schedule();
+ return tid;
+ }
+
+ public static TaskConfiguration addRead(RelativeTime timeout,
+ SelectableChannel chan, Task task)
{
+ TaskConfiguration tid = new TaskConfiguration(timeout, task);
+ tid.addChannelEvent(chan, EVENT_READ);
+ tid.schedule();
+ return tid;
+ }
+
+ public static TaskConfiguration addWrite(RelativeTime timeout,
+ SelectableChannel chan, Task
task) {
+ TaskConfiguration tid = new TaskConfiguration(timeout, task);
+ tid.addChannelEvent(chan, EVENT_WRITE);
+ tid.schedule();
+ return tid;
+ }
+
+ /**
+ * Check if the system is still life. Trigger disconnect if we have tasks,
but
+ * none of them give us lifeness.
+ *
+ * @return true to continue the main loop, false to exit
+ */
+ private static boolean checkLiveness() {
+ if (readyCount > 0) {
+ return true;
+ }
+ for (TaskConfiguration t : pending) {
+ if (t.lifeness) {
+ return true;
+ }
+ }
+ // trigger shutdown if we still have pending tasks, but none of them
has lifeness
+ if (!pending.isEmpty()) {
+ logger.debug("tasks pending but not alive -- disconnect");
+ shutdown();
+ return true;
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Queue a Task for execution.
+ *
+ * @param tid TaskIdentifier of the ready task
+ */
+ private static synchronized void queueReady(TaskConfiguration tid) {
+ int idx = tid.priority.ordinal();
+ readyLists[idx].add(tid);
+ readyCount++;
+ pending.remove(tid);
+ }
+
+
+ /**
+ * Queue all tasks with expired timeout.
+ *
+ * @return the minimum time to wait until the next timeout expiry
+ */
+ private static RelativeTime handleTimeouts() {
+ RelativeTime timeout = RelativeTime.FOREVER;
+
+ // check if any timeouts occurred
+ while (true) {
+ TaskConfiguration t = pending.peek();
+ if (t == null) {
+ break;
+ }
+ RelativeTime remaining = t.deadline.getRemaining();
+ if (remaining.getMicroseconds() <= 0) {
+ t.deregister();
+ t.ctx.reasons = EnumSet.of(Reason.TIMEOUT);
+ queueReady(t);
+ } else {
+ timeout = remaining;
+ break;
+ }
+ }
+ return timeout;
+ }
+
+ private static void addSubscriberTask(Collection<TaskConfiguration>
executableTasks,
+ TaskConfiguration[] subscribers, int
eventType) {
+ if (subscribers[eventType] == null) {
+ return;
+ }
+ executableTasks.add(subscribers[eventType]);
+ subscribers[eventType].ctx.reasons.add(eventToReason[eventType]);
+ }
+
+ /**
+ * Select on channels and queue tasks that become executable.
+ *
+ * @param timeout timeout for select
+ */
+ private static void handleSelect(RelativeTime timeout) {
+ long timeout_ms = timeout.getMicroseconds() / 1000;
+ try {
+ // selector.select(0) would block indefinitely (counter-intuitive,
java's fault)
+ if (timeout_ms == 0) {
+ selector.selectNow();
+ } else if (timeout.isForever()) {
+ selector.select(0);
+ } else {
+ selector.select(timeout_ms);
+ }
+ } catch (IOException e) {
+ throw new IOError(e);
+ }
+
+ // we have to do this so we don't execute any task twice
+ Collection<TaskConfiguration> executableTasks = new
HashSet<TaskConfiguration>();
+ for (SelectionKey sk : selector.selectedKeys()) {
+ TaskConfiguration[] subscribers = (TaskConfiguration[])
sk.attachment();
+
+ if (sk.isReadable()) {
+ addSubscriberTask(executableTasks, subscribers, EVENT_READ);
+ }
+ if (sk.isWritable()) {
+ addSubscriberTask(executableTasks, subscribers, EVENT_WRITE);
+ }
+ if (sk.isAcceptable()) {
+ addSubscriberTask(executableTasks, subscribers, EVENT_ACCEPT);
+ }
+ if (sk.isConnectable()) {
+ addSubscriberTask(executableTasks, subscribers, EVENT_CONNECT);
+ }
+
+ }
+ for (TaskConfiguration tt : executableTasks) {
+ // cancel subscriptions to other events, we can execute now!
+ tt.deregister();
+ queueReady(tt);
+ }
+ }
+
+
+ /**
+ * Initialize and run scheduler. This function will return when all tasks
+ * have completed.
+ */
+ public static void run() {
+ run(null);
+ }
+
+ /**
+ * Initialize and run scheduler. This function will return when all tasks
+ * have completed.
+ *
+ * @param initialTask the initial task to run immediately
+ */
+ public static void run(Task initialTask) {
+ logger.info("running scheduler");
+ if (scheduler_running) {
+ throw new AssertionError("Scheduler already running");
+ }
+ scheduler_running = true;
+ try {
+ run_unchecked(initialTask);
+ } finally {
+ logger.info("cleaning up after scheduler ran");
+ // ensure that after run returns, the scheduler is in its initial
state,
+ // even though there was an exception (e.g. after a test case that
expects an exception)
+ forceReset();
+ }
+ }
+
+
+ /**
+ * Initialize and run scheduler. This function will return when all tasks
+ * have completed. Don't check if the scheduler is already running or not.
+ *
+ * @param initialTask the initial task to run immediately
+ */
+ private static void run_unchecked(Task initialTask) {
+ if (initialTask != null) {
+ addContinuation(initialTask, EnumSet.of(Reason.STARTUP));
+ }
+
+ // the gnunet main loop
+ while (true) {
+ synchronized (Scheduler.class) {
+ if (checkLiveness() == false)
+ break;
+ RelativeTime nextTimeout = handleTimeouts();
+ if (nextTimeout.getMicroseconds() < 0) {
+ logger.warn("negative timeout for select");
+ }
+
+ // don't select if there are no tasks; we are done!
+ if (readyCount == 0 && pending.isEmpty()) {
+ return;
+ }
+
+ // don't block in select if we have tasks ready to run!
+ if (readyCount > 0) {
+ handleSelect(RelativeTime.ZERO);
+ } else {
+ handleSelect(nextTimeout);
+ }
+
+ runReady();
+ }
+ }
+
+ if (readyCount != 0) {
+ throw new AssertionError("tasks ready after scheduler ran
(count)");
+ }
+
+ for (List readyList : Scheduler.readyLists) {
+ if (!readyList.isEmpty()) {
+ throw new AssertionError("tasks ready after scheduler ran
(list)");
+ }
+ }
+
+ if (pending.size() != 0) {
+ throw new AssertionError("pending tasks after scheduler ran");
+ }
+
+ if (activeTask != null) {
+ throw new AssertionError("active task after scheduler ran");
+ }
+ }
+
+
+ /**
+ * Execute tasks until there either
+ * <ul>
+ * <li>there are no ready tasks</li>
+ * <li>there is a pending task (which may be of higher priority)</li>
+ * </ul>
+ */
+ private static void runReady() {
+ do {
+ if (readyCount == 0) {
+ return;
+ }
+ // start executing from the highest priority down to 0
+ for (int p = Priority.numberOfPriorities - 1; p >= 0; p--) {
+ // execute all tasks with priority p
+ LinkedList<TaskConfiguration> queue = readyLists[p];
+ while (!queue.isEmpty()) {
+ TaskConfiguration tid = queue.removeFirst();
+ readyCount--;
+ tid.run();
+ }
+ }
+ } while (pending.size() == 0);
+
+ }
+
+ /**
+ * Request the shutdown of the scheduler. Marks all currently pending
tasks as
+ * ready because of disconnect. This will cause all tasks to run (as soon
as
+ * possible, respecting priorities and prerequisite tasks). Note that tasks
+ * scheduled AFTER this call may still be delayed arbitrarily.
+ */
+ public static void shutdown() {
+ // queueReady() while iterating would yield concurrent modification
exn otherwise
+ for (TaskConfiguration tid : new
ArrayList<TaskConfiguration>(pending)) {
+ tid.ctx.reasons.add(Reason.SHUTDOWN);
+ queueReady(tid);
+ }
+ pending.clear();
+ }
+
+
+ /**
+ * A handle to a file system object that can be selected on.
+ */
+ public static class FilePipe {
+ private FilePipeThread filePipeThread;
+
+ private FilePipe(FilePipeThread filePipeThread) {
+ this.filePipeThread = filePipeThread;
+ }
+
+ public Pipe.SourceChannel getSource() {
+ return filePipeThread.pipe.source();
+ }
+
+ }
+
+ /**
+ * A thread that reads from a file pipe.
+ */
+ private static class FilePipeThread extends Thread {
+ public File file;
+ public Pipe pipe;
+
+ FilePipeThread(File file) {
+ this.file = file;
+ try {
+ pipe = SelectorProvider.provider().openPipe();
+ pipe.source().configureBlocking(false);
+ pipe.sink().configureBlocking(false);
+ } catch (IOException e) {
+ throw new RuntimeException("selector provider has no pipes");
+ }
+ }
+
+ @Override
+ public void run() {
+ // has to be done in thread, blocks if file is a fifo
+ FileChannel fileChannel;
+
+ try {
+ FileInputStream stream;
+ stream = new FileInputStream(file);
+ fileChannel = stream.getChannel();
+ } catch (FileNotFoundException e) {
+ throw new IOError(e);
+ }
+
+ // we have such a small buffer so that the pipe will not buffer
+ ByteBuffer buffer = ByteBuffer.allocate(1);
+
+ boolean quit = false;
+
+ while (!quit) {
+ try {
+ buffer.clear();
+ fileChannel.read(buffer);
+ buffer.flip();
+ pipe.sink().write(buffer);
+ } catch (IOException e) {
+ quit = true;
+ try {
+ fileChannel.close();
+ } catch (IOException ex) {
+ // nothing we can do here
+ }
+ try {
+ pipe.sink().close();
+ } catch (IOException ex) {
+ // nothing we can do here
+ }
+ try {
+ pipe.source().close();
+ } catch (IOException ex) {
+ // nothing we can do here
+ }
+ }
+ }
+
+ }
+ }
+
+ public static FilePipe openFilePipe(File file) {
+ FilePipeThread fpt = new FilePipeThread(file);
+ fpt.setDaemon(true);
+ fpt.start();
+ return new FilePipe(fpt);
+ }
+}
+
Added: gnunet-java/src/main/java/org/gnunet/util/Server.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/Server.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/Server.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,509 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+import org.gnunet.construct.Construct;
+import org.grothoff.Runabout;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.SocketAddress;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * A server allows to wait for incoming connections from clients and
respectively communicate with those clients.
+ */
+public class Server {
+ private static final Logger logger = LoggerFactory
+ .getLogger(Server.class);
+
+ /**
+ * Default idle timeout for new clients.
+ */
+ private final RelativeTime idleTimeout;
+
+ /**
+ * If true, disconnect a client when it sends a message we do not expect
to receive. Otherwise, the unexpected
+ * message will just be discarded.
+ */
+ private final boolean requireFound;
+
+ /**
+ * The sockets this server accepts new connections on.
+ */
+ private List<ServerSocketChannel> listenSockets = new
ArrayList<ServerSocketChannel>();
+
+ /**
+ * The list of all clients connected to this server.
+ */
+ private List<ClientHandle> clientHandles = new LinkedList<ClientHandle>();
+
+ /**
+ * The runabout that receives received messages, as well as information
about the sender of the last
+ * received message.
+ */
+ private MessageRunabout receivedMessageHandler;
+
+ /**
+ * Whenever a client is disconnected all disconnect handlers are informed.
+ */
+ private List<DisconnectHandler> disconnectHandlers = new
LinkedList<DisconnectHandler>();
+
+ /**
+ * Classes of the messages we expect to receive. If a received message is
not in this list, the client
+ * will be disconnected, otherwise the message is just ignored.
+ */
+ private List<Class> expectedMessages = Collections.emptyList();
+
+ /**
+ * If true, shut down as soon as all non-monitor clients have finished,
and do not allow new connections
+ * to be made to this server.
+ */
+ private boolean inSoftShutdown;
+
+ /**
+ * Task that is executed as soon as a connection is ready to be accepted.
+ */
+ private Cancelable acceptTask;
+
+ /**
+ * True if we are destroyed, or in the process of being destroyed with no
way back.
+ */
+ private boolean destroyed;
+
+
+ /**
+ * Interface implemented by disconnect handlers, whose onDisconnect method
is called whenever a client
+ * is disconnected from the server.
+ */
+ public interface DisconnectHandler {
+ /**
+ * Called whenever a client is disconnected from the server.
+ *
+ * @param clientHandle the handle for the client that was disconnected
+ */
+ void onDisconnect(ClientHandle clientHandle);
+ }
+
+ /**
+ * A handle to a (remote) client connected to this server.
+ * <p/>
+ * Every client handle keeps a reference count..
+ * Whenever a part of the programs saves a client handle for further
interaction with it, keep() should be called.
+ * This prevents the server from disconnecting the client when it is idle.
+ * Once this interaction is over, drop() will decrement the reference
count and eventually disconnect the client
+ * after being idle for long enough.
+ */
+ public class ClientHandle {
+ /**
+ * The underlying connection to the client-
+ */
+ private Connection connection;
+
+ /**
+ * When referenceCount==0, the server is allowed to drop the client
after a timeout.
+ */
+ private int referenceCount = 0;
+
+ /**
+ * Handle for canceling the receive process of this client, null if no
receive is currently going on.
+ */
+ private Cancelable currentReceive;
+
+ /**
+ * Set to true if the connection to this client should not prevent the
server from shutting down.
+ */
+ private boolean isMonitor;
+
+ /**
+ * Iff true, disconnect the client as soon as possible.
+ * Disconnecting may sometimes not be possible immediately, for
example when the reference count is not zero.
+ */
+ private boolean disconnectRequested;
+
+ /**
+ * Create a client handle.
+ *
+ * @param sock
+ */
+ private ClientHandle(SocketChannel sock) {
+ connection = new Connection(sock);
+ // start receiving
+ receiveDone(true);
+ }
+
+ /**
+ * Notify us when the server has enough space to transmit
+ * a message of the given size to the given client.
+ *
+ * @param size requested amount of buffer space
+ * @param timeout after how long should we give up (and call
+ * notify with buf NULL and size 0)?
+ * @param transmitter callback
+ * @return a handle to cancel the notification
+ */
+ public Cancelable notifyTransmitReady(int size, RelativeTime timeout,
MessageTransmitter transmitter) {
+ return connection.notifyTransmitReady(size, timeout, transmitter);
+ }
+
+ /**
+ * Convenience method for sending messages.
+ *
+ * @param timeout when should we give up sending the message, and call
cont.cont(false)
+ * @param message the message to send
+ * @param cont called when the message has been sent successfully or
on error
+ * @return a handle to cancel sending the message
+ */
+ public Cancelable transmitWhenReady(final RelativeTime timeout, final
GnunetMessage.Body message, final Continuation cont) {
+ return notifyTransmitReady(0, timeout, new MessageTransmitter() {
+ @Override
+ public void transmit(Connection.MessageSink sink) {
+ sink.send(message);
+ if (cont != null) {
+ cont.cont(true);
+ }
+ }
+
+ @Override
+ public void handleError() {
+ if (cont != null) {
+ cont.cont(false);
+ }
+ }
+ });
+ }
+
+ /**
+ * Resume receiving from this client, we are done processing the
+ * current request. This function must be called from within each
+ * message handler (or its respective continuations).
+ * <p/>
+ * The server does not automatically continue to receive messages to
+ * support flow control.
+ *
+ * @param stayConnected false if connection to the client should be
closed
+ */
+ public void receiveDone(boolean stayConnected) {
+ if (currentReceive != null) {
+ throw new AssertionError("receiveDone() called, but still
waiting for message");
+ }
+ if (stayConnected) {
+ currentReceive = connection.receive(RelativeTime.FOREVER, new
MessageReceiver() {
+ @Override
+ public void process(GnunetMessage.Body msg) {
+ currentReceive = null;
+ if ((msg instanceof UnknownMessageBody) ||
!expectedMessages.contains(msg.getClass())) {
+ if (requireFound) {
+ logger.info("disconnecting client sending
unknown message");
+ disconnect();
+ }
+ // otherwise, just ignore it
+ }
+ if (receivedMessageHandler == null) {
+ throw new AssertionError("received message, but no
handler installed");
+ }
+ receivedMessageHandler.setSender(ClientHandle.this);
+ receivedMessageHandler.visitAppropriate(msg);
+ }
+
+ @Override
+ public void handleError() {
+ logger.warn("error receiving from client");
+ disconnect();
+ }
+ });
+ } else {
+ if (referenceCount > 0) {
+ this.disconnectRequested = true;
+ } else {
+ System.out.println("disconnecting " + this.isMonitor);
+ disconnect();
+ }
+ }
+
+ }
+
+ /**
+ * Ask the server to disconnect from the given client.
+ * <p/>
+ * The client will be disconnected from the server, no matter what the
current reference count is.
+ */
+ public void disconnect() {
+ connection.disconnect();
+ // if we are in the process of destruction, to not remove, the
destruction function will do this,
+ // removing the client handle while in destruction would yield a
concurrent modification exception
+ if (!destroyed) {
+ Server.this.clientHandles.remove(this);
+ }
+ for (DisconnectHandler dh : disconnectHandlers) {
+ dh.onDisconnect(this);
+ }
+ Server.this.testForSoftShutdown();
+ }
+
+ /**
+ * Prevent the client from being disconnected.
+ * For every keep, there should be an additional matching drop.
+ */
+ public void keep() {
+ referenceCount++;
+ }
+
+
+ /**
+ * Allow to disconnect this client, if not prevented by previous calls
to keep.
+ * <p/>
+ * A call to drop should be executed for every call to keep.
+ * After drop() has been executed for every matching keep(), the next
call to drop()
+ * allows the server to disconnect the client after a timeout.
+ */
+ public void drop() {
+ assert referenceCount > 0;
+ referenceCount--;
+ if (referenceCount == 0 && disconnectRequested) {
+ disconnect();
+ }
+ }
+
+
+ /**
+ * Set the 'monitor' flag on this client. Clients which have been
+ * marked as 'monitors' won't prevent the server from shutting down
+ * once 'GNUNET_SERVER_stop_listening' has been invoked. The idea is
+ * that for "normal" clients we likely want to allow them to process
+ * their requests; however, monitor-clients are likely to 'never'
+ * disconnect during shutdown and thus will not be considered when
+ * determining if the server should continue to exist after
+ * 'GNUNET_SERVER_destroy' has been called.
+ */
+ public void markMonitor() {
+ this.isMonitor = true;
+ }
+
+ public boolean isMonitor() {
+ return isMonitor;
+ }
+ }
+
+
+ /**
+ * All handlers for receiving messages from clients have to inherit this
class.
+ * <p/>
+ * MessageRunabout is a standard runabout with the added possibility of
getting the sender of the message.
+ * This is necessary as the runabout's visit methods can have only one
parameter.
+ */
+ public abstract static class MessageRunabout extends Runabout {
+ private ClientHandle currentSender;
+
+ /**
+ * Allows implementors of MessageRunabout to get the Client that sent
the message
+ * currently visited.
+ * <p/>
+ * The return value of getSender() is only valid while executing a
visit method.
+ *
+ * @return handle of the client whose message is currently being
visited
+ */
+ public final ClientHandle getSender() {
+ return currentSender;
+ }
+
+ /**
+ * Private method used to set the sender for the getSender() method.
+ *
+ * @param clientHandle the client handle to set as the sender
+ */
+ private void setSender(ClientHandle clientHandle) {
+ currentSender = clientHandle;
+ }
+ }
+
+ /**
+ * Create a server listening on all specified addresses.
+ *
+ * @param addresses addresses to bind on
+ * @param idleTimeout time after a client will be disconnected if idle
+ * @param requireFound allow unknown messages to be received without
disconnecting the client in response
+ */
+ public Server(List<SocketAddress> addresses, RelativeTime idleTimeout,
boolean requireFound) {
+ this.idleTimeout = idleTimeout;
+ this.requireFound = requireFound;
+ try {
+ for (SocketAddress addr : addresses) {
+ ServerSocketChannel socket = ServerSocketChannel.open();
+ socket.configureBlocking(false);
+ socket.socket().bind(addr);
+ logger.debug("socket listening on {}", addr.toString());
+ listenSockets.add(socket);
+ addAcceptSocket(socket);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("could not bind", e);
+ }
+ }
+
+ /**
+ * Create a server, not listening on any sockets yet for new connections.
+ *
+ * @param idleTimeout time after a client will be disconnected if idle
+ * @param requireFound allow unknown messages to be received without
disconnecting the client in response
+ */
+ public Server(RelativeTime idleTimeout, boolean requireFound) {
+ this.idleTimeout = idleTimeout;
+ this.requireFound = requireFound;
+ }
+
+ /**
+ * Accept new connections from the given server socket.
+ *
+ * @param sock the new socket to accept connections from
+ */
+ public final void addAcceptSocket(final ServerSocketChannel sock) {
+ Scheduler.TaskConfiguration b = new
Scheduler.TaskConfiguration(RelativeTime.FOREVER,
+ new Scheduler.Task() {
+ @Override
+ public void run(Scheduler.RunContext ctx) {
+ acceptTask = null;
+ try {
+ SocketChannel cli = sock.accept();
+
+ if (cli != null) {
+ logger.debug("client connected");
+ cli.configureBlocking(false);
+ ClientHandle clientHandle = new
ClientHandle(cli);
+ clientHandles.add(clientHandle);
+ }
+
+ } catch (IOException e) {
+ throw new RuntimeException("accept failed", e);
+ }
+ addAcceptSocket(sock);
+ }
+ });
+ b.selectAccept(sock);
+ acceptTask = b.schedule();
+ }
+
+ /**
+ * Pass messages that the runabout can handle to it.
+ * There can only be one runabout per message type.
+ * (Discrepancy with the C-API, could be changed in the future)
+ *
+ * @param msgRunabout handler
+ */
+ public void setHandler(MessageRunabout msgRunabout) {
+ receivedMessageHandler = msgRunabout;
+ expectedMessages = RunaboutUtil.getRunaboutVisitees(msgRunabout);
+ }
+
+ /**
+ * Ask the server to notify us whenever a client disconnects.
+ * This handler is called whenever the actual network connection
+ * is closed; the reference count may be zero or larger than zero
+ * at this point. Note that the disconnect handler is also called when
+ *
+ * @param disconnectHandler handler to call on disconnect
+ */
+ public Cancelable notifyDisconnect(final DisconnectHandler
disconnectHandler) {
+ this.disconnectHandlers.add(disconnectHandler);
+ return new Cancelable() {
+ @Override
+ public void cancel() {
+ Server.this.disconnectHandlers.remove(disconnectHandler);
+ }
+ };
+ }
+
+ /**
+ * Stop the listen socket destroy the server as soon as only monitor
clients are left.
+ */
+ public void stopListening() {
+ inSoftShutdown = true;
+ if (acceptTask != null) {
+ acceptTask.cancel();
+ acceptTask = null;
+ }
+ testForSoftShutdown();
+ }
+
+ /**
+ * Disconnect all clients forcefully from the server and stop listening.
+ * <p/>
+ * No methods should be called on a server and its client handles after
destroy() has been called.
+ */
+ public void destroy() {
+ if (destroyed) {
+ return;
+ }
+ destroyed = true;
+ for (ClientHandle h : clientHandles) {
+ h.disconnect();
+ }
+ clientHandles.clear();
+ if (acceptTask != null) {
+ acceptTask.cancel();
+ acceptTask = null;
+ }
+ for (ServerSocketChannel ssc : listenSockets) {
+ try {
+ ssc.close();
+ } catch (IOException e) {
+ logger.error("closing listen socket failed", e);
+ }
+ }
+ }
+
+ /**
+ * Test if we should destroy outselves.
+ */
+ private void testForSoftShutdown() {
+ // do this so we don't have many recursive calls to
testForSoftShutdown when shutting down
+ if (destroyed) {
+ return;
+ }
+ if (inSoftShutdown) {
+ System.out.println(""+clientHandles.size());
+ boolean done = true;
+ for (ClientHandle clientHandle : this.clientHandles) {
+ if (!clientHandle.isMonitor) {
+ done = false;
+ }
+ }
+ if (done) {
+ destroy();
+ }
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+ if (!destroyed) {
+ logger.warn("Server instance not destroyed, but finalizer called");
+ }
+ destroy();
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/util/Service.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/Service.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/Service.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,154 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.*;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.Pipe;
+import java.util.LinkedList;
+
+/**
+ * Server the entry point class for every gnunet-java component providing
services
+ * to other components.
+ *
+ * The configuration for the server (i.e. ports/interfaces) is loaded with the
standard configuration system.
+ *
+ * Note that other processes can send signals to the service via a pipe, whose
name has to be given in the
+ * environment variable GNUNET_OS_CONTROL_PIPE
+ */
+public abstract class Service extends Program {
+ private static final Logger logger = LoggerFactory
+ .getLogger(Service.class);
+
+ private Server s;
+ private String serviceName;
+ private RelativeTime idleTimeout;
+ private boolean requireFound;
+
+
+ private Cancelable sigpipeTask;
+ private Pipe.SourceChannel sigpipeChannel;
+
+ public Service(String serviceName, RelativeTime idleTimeout, boolean
requireFound, String[] args) {
+ super(args);
+ this.serviceName = serviceName;
+ this.idleTimeout = idleTimeout;
+ this.requireFound = requireFound;
+ }
+
+ /**
+ * Obtain the server used by a service. Note that the server must NOT
+ * be destroyed by the caller.
+ *
+ * @return handle to the server for this service, NULL if there is none
+ */
+ public final Server getServer() {
+ return s;
+ }
+
+ /**
+ * Stop the service.
+ */
+ public void stop() {
+ s.stopListening();
+ }
+
+ public void runHook() {
+ String ip4AddrList = getConfiguration().getValueString(serviceName,
"ACCEPT_FROM").orNull();
+ String ip6AddrList = getConfiguration().getValueString(serviceName,
"ACCEPT_FROM6").orNull();
+ int port = getConfiguration().getValueNumber(serviceName,
"PORT").get().intValue();
+
+ LinkedList<SocketAddress> addrs = new LinkedList<SocketAddress>();
+
+ if (ip4AddrList != null) {
+ for (String ip4Addr : ip4AddrList.split("[;]")) {
+ InetAddress addr = Resolver.getInetAddressFromString(ip4Addr);
+ addrs.add(new InetSocketAddress(addr, port));
+ }
+ }
+
+ if (ip6AddrList != null) {
+ for (String ip6Addr : ip6AddrList.split("[;]")) {
+ InetAddress addr = Resolver.getInetAddressFromString(ip6Addr);
+ addrs.add(new InetSocketAddress(addr, port));
+ }
+ }
+
+ s = new Server(addrs, idleTimeout, requireFound);
+
+ String pipeName = System.getenv("GNUNET_OS_CONTROL_PIPE");
+ if (pipeName != null && !pipeName.isEmpty()) {
+ Scheduler.FilePipe p = Scheduler.openFilePipe(new File(pipeName));
+
+ Scheduler.TaskConfiguration t = new
Scheduler.TaskConfiguration(RelativeTime.FOREVER,
+ new SigpipeTask());
+ t.selectRead(p.getSource());
+ sigpipeTask = t.schedule();
+ sigpipeChannel = p.getSource();
+ }
+
+ run();
+ }
+
+ private class SigpipeTask implements Scheduler.Task {
+ @Override
+ public void run(Scheduler.RunContext ctx) {
+ ByteBuffer b = ByteBuffer.allocate(1);
+ int n;
+ try {
+ n = sigpipeChannel.read(b);
+ } catch (IOException e) {
+ logger.error("error reading signal pipe", e);
+ return;
+ }
+ b.flip();
+ boolean stopped = false;
+
+ if (n == 1) {
+ byte sig = b.get();
+ // 15=sigterm
+ if (sig == 15) {
+ logger.info("service shutting down");
+ getServer().stopListening();
+ stopped = true;
+ }
+ }
+ if (!stopped) {
+ Scheduler.TaskConfiguration t = new
Scheduler.TaskConfiguration(RelativeTime.FOREVER, this);
+ sigpipeTask = t.schedule();
+ } else {
+ try {
+ sigpipeChannel.close();
+ } catch (IOException e) {
+ logger.error("could not close sigpipe channel, quitting");
+ }
+ System.exit(2);
+ }
+ }
+ }
+}
\ No newline at end of file
Added: gnunet-java/src/main/java/org/gnunet/util/Strings.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/Strings.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/Strings.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,138 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+/**
+ * Common functions on Strings, specific to gnunet-java
+ */
+public class Strings {
+ private static final String encTable = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
+
+
+ /**
+ * Convert binary data to ASCII encoding. The ASCII encoding is rather
+ * GNUnet specific. It was chosen such that it only uses characters
+ * in [0-9A-V], can be produced without complex arithmetics and uses a
+ * small number of characters.
+ * Does not append 0-terminator, but returns a pointer to the place where
+ * it should be placed, if needed.
+ *
+ * returned string has length ((size*8) + (((size*8) % 5) > 0 ? 5 -
((size*8) % 5) : 0)) / 5 bytes
+ *
+ * @param data data to encode
+ * @return pointer to the next byte in 'out' or NULL on error.
+ */
+
+ public static String dataToString(byte[] data) {
+ StringBuilder sb = new StringBuilder();
+
+ long rpos = 0;
+ long bits = 0;
+ long vbit = 0;
+ long size = data.length;
+
+ while ((rpos < size) || (vbit > 0)) {
+ if ((rpos < size) && (vbit < 5)) {
+ byte b = data[(int) rpos++];
+ // convert double to int without sign extension
+ int s = b >= 0 ? b : (256 + b);
+ // eat 8 more bits
+ bits = (bits << 8) | s;
+ vbit += 8;
+ }
+ if (vbit < 5) {
+ // zero-padding
+ bits <<= (5 - vbit);
+ vbit = 5;
+ }
+ sb.append(encTable.charAt((int) (bits >>> (vbit - 5)) & 31));
+ vbit -= 5;
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Convert ASCII encoding back to data
+ * out_size must match exactly the size of the data before it was encoded.
+ *
+ * @param string the string to decode
+ * @param outSize size of the output buffer
+ * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong
encoding
+ */
+
+ public static byte[] stringToData(String string, int outSize) {
+ long rpos;
+ long wpos;
+ long bits;
+ long vbit;
+ long ret;
+ long shift;
+ int enclen = string.length();
+ int encoded_len = outSize * 8;
+ byte[] out = new byte[outSize];
+ if (encoded_len % 5 > 0) {
+ // padding!
+ vbit = encoded_len % 5;
+ shift = 5 - vbit;
+ } else {
+ vbit = 0;
+ shift = 0;
+ }
+ if ((encoded_len + shift) / 5 != enclen) {
+ throw new AssertionError();
+ }
+
+ wpos = outSize;
+ rpos = enclen;
+ bits = (ret = getValue__(string.charAt((int) (--rpos)))) >> (5 -
encoded_len % 5);
+ if (-1 == ret) {
+ throw new AssertionError();
+ }
+ while (wpos > 0) {
+ assert rpos > 0;
+ bits = ((ret = getValue__(string.charAt((int) (--rpos)))) << vbit)
| bits;
+ if (-1 == ret) {
+ throw new AssertionError();
+ }
+ vbit += 5;
+ if (vbit >= 8) {
+ out[(int)--wpos] = (byte)((char) bits);
+ bits >>= 8;
+ vbit -= 8;
+ }
+ }
+ assert(rpos == 0);
+ assert(vbit == 0);
+ return out;
+ }
+
+
+ private static int getValue__ (char a) {
+ if ((a >= '0') && (a <= '9')) {
+ return a - '0';
+ }
+ if ((a >= 'A') && (a <= 'V')) {
+ return (a - 'A' + 10);
+ }
+ return -1;
+ }
+
+}
Added: gnunet-java/src/main/java/org/gnunet/util/TestMessage.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/TestMessage.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/TestMessage.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,31 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+import org.gnunet.construct.UnionCase;
+
+/**
+ * Sent back when a client sends this message to a service.
+ */
address@hidden(1)
+public class TestMessage implements GnunetMessage.Body {
+ // empty
+}
Added: gnunet-java/src/main/java/org/gnunet/util/UnknownMessageBody.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/UnknownMessageBody.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/UnknownMessageBody.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,35 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+/**
+ * Special GnunetMessage body, used to signal that the message containing the
body
+ * is not understood, and therefore no real message body could be constructed.
+ *
+ * Note that this class implements GnunetMessage.Body but does not have a
MessageID associated.
+ * This message should not, and can not, be sent/received over the network
directly as a message body.
+ *
+ * @author Florian Dold
+ */
+public class UnknownMessageBody implements GnunetMessage.Body {
+ public int id;
+ public byte[] data;
+}
Added: gnunet-java/src/main/java/org/gnunet/util/getopt/Argument.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/getopt/Argument.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/getopt/Argument.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,47 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util.getopt;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for fields receiving an argument from the command line.
+ */
address@hidden(RetentionPolicy.RUNTIME)
address@hidden(ElementType.FIELD)
+public @interface Argument {
+ public String shortname();
+ public String longname();
+ /**
+ * Possible values: "store-string", "set", "reset", "count", "store-int"
+ */
+ public ArgumentAction action();
+ /*
+ * Name of the Option's argument(s), empty string of option takes no
arguments
+ *
+ */
+ public String argumentName() default "";
+ public String description();
+}
Added: gnunet-java/src/main/java/org/gnunet/util/getopt/ArgumentAction.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/getopt/ArgumentAction.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/getopt/ArgumentAction.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,29 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util.getopt;
+
+
+/**
+ * Possibilities for what should happen when an argument is read from the
command line
+ */
+public enum ArgumentAction {
+ SET, RESET, STORE_STRING, STORE_NUMBER
+}
Added: gnunet-java/src/main/java/org/gnunet/util/getopt/Parser.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/getopt/Parser.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/getopt/Parser.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,294 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util.getopt;
+
+import org.gnunet.construct.ReflectUtil;
+import java.lang.reflect.Field;
+import java.util.*;
+
+/**
+ * Parser for command line options, in the format indicated by the
+ * annotated members of the target object's class.
+ */
+public class Parser {
+
+ /**
+ * An ArgumentError is thrown if the command line parameters do not match
their
+ * specification in the target object's class.
+ */
+ public static class ArgumentError extends RuntimeException {
+ public ArgumentError(String s) {
+ super(s);
+ }
+ }
+
+ /**
+ * An option together with its target field.
+ */
+ static class OptionField {
+ Argument opt;
+ Field f;
+
+ public OptionField(Argument opt, Field f) {
+ this.opt = opt;
+ this.f = f;
+ }
+ }
+
+ // todo: unify with Construct.getMessageFields
+ private List<Field> getFields(Class c) {
+ LinkedList<Field> fields = new
LinkedList<Field>(Arrays.asList(c.getDeclaredFields()));
+ while ((c = c.getSuperclass()) != null) {
+ fields.addAll(0, Arrays.asList(c.getDeclaredFields()));
+ }
+ return fields;
+ }
+
+ private Map<String, OptionField> longOpt = new HashMap<String,
OptionField>();
+ private Map<String, OptionField> shortOpt = new HashMap<String,
OptionField>();
+
+ private Collection<Argument> arguments = new LinkedList<Argument>();
+
+ private Object targetObject;
+
+
+ public Parser(Object targetObject) {
+ this.targetObject = targetObject;
+ // gather option annotations
+ for (Field f : getFields(targetObject.getClass())) {
+ Argument opt = f.getAnnotation(Argument.class);
+ if (opt != null) {
+ if (opt.shortname().length() != 1) {
+ throw new AssertionError("short name must be of length 1");
+ }
+
+ f.setAccessible(true);
+
+ longOpt.put(opt.longname(), new OptionField(opt, f));
+ shortOpt.put(opt.shortname(), new OptionField(opt, f));
+ arguments.add(opt);
+ }
+ }
+ }
+
+ public String getHelp() {
+ StringBuilder helpString = new StringBuilder();
+ for (Argument opt : arguments) {
+ StringBuilder line = new StringBuilder();
+ line.append(" -");
+ line.append(opt.shortname());
+ line.append(" --");
+ line.append(opt.longname());
+ if (!opt.argumentName().isEmpty()) {
+ line.append("=");
+ line.append(opt.argumentName());
+ }
+ while (line.length() < 30) {
+ line.append(" ");
+ }
+ helpString.append(line);
+ helpString.append(" ");
+ helpString.append(opt.description());
+ helpString.append("\n");
+
+ }
+ return helpString.toString();
+ }
+
+ private void doLongOpt(final LinkedList<String> argsList, Field
targetField, Argument argument, String right) {
+ try {
+ Class targetFieldType = targetField.getType();
+ switch (argument.action()) {
+ case SET:
+ if (!targetFieldType.equals(Boolean.TYPE)) {
+ throw new AssertionError("action SET only valid on
boolean member");
+ }
+ targetField.set(targetObject, true);
+ break;
+ case RESET:
+ if (!targetFieldType.equals(Boolean.TYPE)) {
+ throw new AssertionError("action RESET only valid on
boolean member");
+ }
+ targetField.set(targetObject, false);
+ break;
+ case STORE_STRING:
+ if (!targetFieldType.equals(String.class)) {
+ throw new AssertionError("action STORE_STRING only
valid on boolean member");
+ }
+ if (right == null) {
+ argsList.removeFirst();
+ if (argsList.isEmpty()) {
+ throw new ArgumentError("missing string argument
to option " + argument.longname());
+ }
+ targetField.set(targetObject, argsList.getFirst());
+ } else {
+ targetField.set(targetObject, right);
+ }
+ break;
+ case STORE_NUMBER:
+ ReflectUtil.NumField nf = new
ReflectUtil.NumField(targetField);
+ String numString;
+ if (right == null) {
+ argsList.removeFirst();
+ if (argsList.isEmpty()) {
+ throw new ArgumentError("missing number argument
to option " + argument.longname());
+ }
+ numString = argsList.getFirst();
+ } else {
+ numString = right;
+ }
+ try {
+ nf.set(targetObject, Long.parseLong(numString));
+ } catch (NumberFormatException e) {
+ throw new ArgumentError("error in number format to
option " + argument.longname());
+ }
+ break;
+ }
+ } catch (IllegalAccessException e) {
+ throw new AssertionError(
+ String.format("cannot acces member %s with @Option
annotation", targetField.getName()));
+ }
+ }
+
+ /**
+ * returns true if we processed a shortopt with a parameter, and thus have
to discard the rest
+ * of the current argument string (that is, stop scanning for more
shortopts)
+ */
+ private boolean doShortOpt(final LinkedList<String> argsList, Field
targetField, Argument argument, String shortName) {
+ try {
+ switch (argument.action()) {
+ case SET:
+ if (!targetField.getType().equals(Boolean.TYPE)) {
+ throw new AssertionError("action SET only valid on
boolean member");
+ }
+ targetField.set(targetObject, true);
+ break;
+ case RESET:
+ if (!targetField.getType().equals(Boolean.TYPE)) {
+ throw new AssertionError("action RESET only valid on
boolean field");
+ }
+ targetField.set(targetObject, false);
+ break;
+ case STORE_STRING:
+ if (!targetField.getType().equals(String.class)) {
+ throw new AssertionError("action STORE_STRING only
valid on 'String' field");
+ }
+ if (argsList.getFirst().length() == 2) { // -P xxx (with
space)
+ argsList.removeFirst();
+ if (argsList.isEmpty()) {
+ throw new ArgumentError(String.format("no argument
for short option '%s'",
+ shortName));
+ }
+ targetField.set(targetObject, argsList.getFirst());
+ } else {
+ targetField.set(targetObject,
argsList.getFirst().substring(2)); // -Pxxx...
+ }
+ return true;
+ case STORE_NUMBER:
+ ReflectUtil.NumField nf = new
ReflectUtil.NumField(targetField);
+ String numString;
+ if (argsList.getFirst().length() == 2) { // -X
+ argsList.removeFirst();
+ if (argsList.isEmpty()) {
+ throw new ArgumentError("missing number argument
to option " + argument.longname());
+ }
+ numString = argsList.getFirst();
+ } else {
+ numString = argsList.getFirst().substring(2);
+ }
+ try {
+ nf.set(targetObject, Long.parseLong(numString));
+ } catch (NumberFormatException e) {
+ throw new ArgumentError("error in number format to
option " + argument.longname());
+ }
+ return true;
+ }
+ } catch (IllegalAccessException e) {
+ throw new ArgumentError(
+ String.format("cannot acces member %s with @Option
annotation", targetField.getName()));
+ }
+ return false; // did not consume entire shortopt -Xxxxxx
+ }
+
+ /**
+ * Parses the given arguments, and sets the target object's fields
+ * according to its annotations.
+ *
+ * @param args array with the program arguments
+ * @return positional arguments
+ */
+ public String[] parse(String[] args) {
+ // unprocessed positional args
+ Deque<String> positionalArgs = new LinkedList<String>();
+
+ LinkedList<String> argsList = new
LinkedList<String>(Arrays.asList(args));
+
+ while (!argsList.isEmpty()) {
+ // arguments after single "--" are all positional
+ if (argsList.getFirst().equals("--")) {
+ argsList.removeFirst();
+ positionalArgs.addAll(argsList);
+ break;
+ }
+ // long args
+ if (argsList.getFirst().startsWith("--")) {
+ // remove leading slashes
+ String longOptionString = argsList.getFirst().substring(2);
+ // maybe it is in the format --opt=val
+ String[] components = longOptionString.split("=", 2);
+ OptionField of = longOpt.get(components[0]);
+ if (of == null) {
+ throw new ArgumentError(String.format("unknown long
option: '%s'", components[0]));
+ }
+ String right = (components.length == 2) ? components[1] : null;
+ doLongOpt(argsList, of.f, of.opt, right);
+ } else if ((argsList.getFirst().length() > 1) &&
argsList.getFirst().startsWith("-")) {
+ // handle each flag after the "-"
+ for (int i = 1; i < argsList.getFirst().length(); ++i) {
+ String optShortName = argsList.getFirst().substring(i, i +
1);
+ OptionField of = shortOpt.get(optShortName);
+ if (of == null) {
+ throw new ArgumentError(
+ String.format("unknown short option: -%s",
argsList.getFirst().charAt(i)));
+ }
+
+ boolean discard = doShortOpt(argsList, of.f, of.opt,
optShortName);
+
+ if (discard && (i != 1)) {
+ throw new ArgumentError("short options with argument
must be seperate");
+ }
+
+ if (discard) {
+ break;
+ }
+
+ }
+ } else {
+ positionalArgs.add(argsList.getFirst());
+ }
+
+ argsList.removeFirst();
+ }
+
+ return positionalArgs.toArray(new String[positionalArgs.size()]);
+ }
+
+}
Added: gnunet-java/src/main/java/org/gnunet/util/getopt/package-info.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/getopt/package-info.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/getopt/package-info.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,24 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * Command line option parsing
+ */
+package org.gnunet.util.getopt;
Added: gnunet-java/src/main/java/org/gnunet/util/package-info.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/util/package-info.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/util/package-info.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,24 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * Common utilities for gnunet components.
+ */
+package org.gnunet.util;
Added:
gnunet-java/src/main/java/org/gnunet/voting/CertificateAuthorityService.java
===================================================================
---
gnunet-java/src/main/java/org/gnunet/voting/CertificateAuthorityService.java
(rev 0)
+++
gnunet-java/src/main/java/org/gnunet/voting/CertificateAuthorityService.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,7 @@
+package org.gnunet.voting;
+
+/**
+ * Permits or denies a voter to participate in an election.
+ */
+public class CertificateAuthorityService {
+}
Added: gnunet-java/src/main/java/org/gnunet/voting/ElectionCallTool.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/ElectionCallTool.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/voting/ElectionCallTool.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,50 @@
+package org.gnunet.voting;
+
+
+import org.gnunet.util.Program;
+import org.gnunet.util.getopt.Argument;
+import org.gnunet.util.getopt.ArgumentAction;
+
+public class ElectionCallTool {
+
+ public static void main(String[] args) {
+ new Program(args) {
+ @Argument(
+ shortname = "t",
+ longname = "template",
+ action = ArgumentAction.SET,
+ description = "output election template")
+ boolean template = false;
+ @Argument(
+ shortname = "o",
+ longname = "outfile",
+ argumentName = "FILE",
+ action = ArgumentAction.STORE_STRING,
+ description = "write spec to FILE instead of standard
output")
+ String outfilename = null;
+ @Argument(
+ shortname = "V",
+ longname = "verify",
+ action = ArgumentAction.SET,
+ description = "verify that the ESPEC is valid")
+ boolean verify = false;
+ @Argument(
+ shortname = "a",
+ longname = "authorize",
+ action = ArgumentAction.SET,
+ description = "authorize the ESPEC with the authorities")
+ boolean authorize = false;
+
+ @Override
+ protected String makeHelpText() {
+ return "gnunet-vote-call [OPTIONS]... ESPEC\n" +
+ "Create, authorize and verify an election
specification";
+ }
+
+ @Override
+ public void run() {
+ }
+
+ }.start();
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/voting/ElectionSpecification.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/ElectionSpecification.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/voting/ElectionSpecification.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,5 @@
+package org.gnunet.voting;
+
+public class ElectionSpecification {
+
+}
Added: gnunet-java/src/main/java/org/gnunet/voting/TallyAuthorityService.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/TallyAuthorityService.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/voting/TallyAuthorityService.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,5 @@
+package org.gnunet.voting;
+
+
+public class TallyAuthorityService {
+}
Added: gnunet-java/src/main/java/org/gnunet/voting/VotingTool.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/VotingTool.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/voting/VotingTool.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,49 @@
+package org.gnunet.voting;
+
+
+import org.gnunet.util.Program;
+import org.gnunet.util.getopt.Argument;
+import org.gnunet.util.getopt.ArgumentAction;
+
+public class VotingTool {
+ public static void main(String[] args) {
+ new Program(args) {
+ @Argument(
+ shortname = "q",
+ longname = "query",
+ action = ArgumentAction.SET,
+ description = "query election result")
+ boolean query = false;
+
+ @Argument(
+ shortname = "s",
+ longname = "submit",
+ action = ArgumentAction.STORE_STRING,
+ argumentName = "CHOICE",
+ description = "submit vote to the election")
+ String vote = null;
+
+ @Argument(
+ shortname = "p",
+ longname = "certificate",
+ action = ArgumentAction.STORE_STRING,
+ argumentName = "FILE",
+ description = "certificate file with the permission to
vote")
+ String certfile = null;
+
+ @Override
+ protected String makeHelpText() {
+ return "gnunet-vote [OPTIONS]... ESPEC\n" +
+ "Submit a vote or query an election's result.\n" +
+ "The election is identified in the ESPEC file.";
+ }
+
+ @Override
+ public void run() {
+
+ }
+ }.start();
+
+ }
+
+}
Added: gnunet-java/src/main/java/org/gnunet/voting/simulation/Authority.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/simulation/Authority.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/voting/simulation/Authority.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,266 @@
+package org.gnunet.voting.simulation;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import java.math.BigInteger;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class Authority {
+ private BigInteger privateKeyShare;
+ private BigInteger[] secretPolynomial;
+ private TransmitShareVerification shareVerification;
+
+ private int authorityId;
+
+ private BigInteger receivedShare = BigInteger.ZERO;
+
+ private VotingParameters parameters;
+ private List<Authority> participatingAuthorities;
+
+ private List<Ballot> ballots = Lists.newLinkedList();
+
+ private Map<Integer, TallyKeyShare> specializedKeyShares =
Maps.newTreeMap();
+
+ private Cyphertext encryptedTally;
+ private BigInteger tallyBaseG;
+
+
+ /**
+ * The commitments of each authority to it's share of the group secret.
+ */
+ Map<Integer, BigInteger> shareCommitments = Maps.newTreeMap();
+
+ private GroupPublicKey groupPublicKey;
+
+
+ public Authority() {
+ }
+
+ public BigInteger getPublicKeyShare() {
+ return parameters.g.modPow(privateKeyShare, parameters.p);
+ }
+
+ public BigInteger createShareForAuthority(int j) {
+ return CryptoUtil.evaluatePolynomial(secretPolynomial,
BigInteger.valueOf(j), parameters.q);
+ }
+
+ public void verifyShare(BigInteger distributionShare,
TransmitShareVerification senderVerification) {
+ BigInteger v = parameters.g.modPow(distributionShare, parameters.p);
+ BigInteger prod = BigInteger.ONE;
+ for (int l = 0; l < parameters.authorityThreshold; ++l) {
+ BigInteger exp = BigInteger.valueOf(this.getId()).pow(l);
+ BigInteger coeff = senderVerification.coeffs[l];
+ prod = prod.multiply(coeff.modPow(exp,
parameters.p)).mod(parameters.p);
+ }
+ if (!v.equals(prod)) {
+ throw new AssertionError("verification of transmitted shared
failed");
+ }
+ }
+
+ public void acceptShareFromAuthority(BigInteger distributionShare,
TransmitShareVerification senderVerification, Authority sender) {
+ verifyShare(distributionShare, senderVerification);
+ receivedShare = receivedShare.add(distributionShare);
+ }
+
+ public int getId() {
+ return authorityId;
+ }
+
+ /**
+ * Supervisor -> Authority
+ *
+ * @param authorityId
+ * @param parameters
+ * @return
+ */
+ public BigInteger inviteAuthority(int authorityId, VotingParameters
parameters) {
+ this.authorityId = authorityId;
+ this.parameters = parameters;
+
+ this.privateKeyShare = parameters.generateZq();
+ this.secretPolynomial = new BigInteger[parameters.authorityThreshold];
+
+ this.secretPolynomial[0] = privateKeyShare;
+ for (int i = 1; i < parameters.authorityThreshold; ++i) {
+ secretPolynomial[i] = parameters.generateZq();
+ }
+
+ shareVerification = new TransmitShareVerification(secretPolynomial,
parameters);
+
+ return getPublicKeyShare();
+ }
+
+ /**
+ * Supervisor -> Authority.
+ *
+ * @param participatingAuthorities
+ */
+ public void generateKeyWithAuthorities(List<Authority>
participatingAuthorities) {
+ this.participatingAuthorities = participatingAuthorities;
+
+ for (Authority otherAuthority : participatingAuthorities) {
+
otherAuthority.acceptShareFromAuthority(createShareForAuthority(otherAuthority.getId()),
shareVerification, this);
+ }
+ }
+
+ public void acceptBallot(Ballot ballot) {
+ verifyBallot(ballot);
+ // todo: check duplicates
+ ballots.add(ballot);
+
+ }
+
+ public void acceptGroupPublicKey(GroupPublicKey key) {
+ groupPublicKey = key;
+ }
+
+ public void acceptSpecializedKeyShare(TallyKeyShare share, Authority
sender) {
+ specializedKeyShares.put(sender.getId(), share);
+ verifyTallyKeyShare(share);
+ }
+
+ public void distributeTallyKey() {
+ computeEncryptedTally();
+
+ for (Authority other : participatingAuthorities) {
+ TallyKeyShare tallyKeyShare = new TallyKeyShare(encryptedTally.c1,
receivedShare, parameters);
+ other.acceptSpecializedKeyShare(tallyKeyShare, this);
+ }
+ }
+
+ private void computeEncryptedTally() {
+ BigInteger votesX = BigInteger.ONE;
+ BigInteger votesY = BigInteger.ONE;
+ for (Ballot ballot : ballots) {
+ votesX = votesX.multiply(ballot.x).mod(parameters.p);
+ votesY = votesY.multiply(ballot.y).mod(parameters.p);
+ }
+
+ encryptedTally = new Cyphertext(votesX, votesY);
+ }
+
+ private void decryptTallyToBaseG() {
+ Map<Integer, BigInteger> lagrangeCoefficients = Maps.newTreeMap();
+ for (int j : specializedKeyShares.keySet()) {
+ BigInteger n = BigInteger.ONE;
+ BigInteger d = BigInteger.ONE;
+ for (int l : specializedKeyShares.keySet()) {
+ if (l != j) {
+ n = n.multiply(BigInteger.valueOf(l));
+ d =
d.multiply(BigInteger.valueOf(l).subtract(BigInteger.valueOf(j)));
+ }
+ }
+ lagrangeCoefficients.put(j,
n.multiply(d.modInverse(parameters.q)).mod(parameters.q));
+ }
+
+ BigInteger prod = BigInteger.ONE;
+ for (int authorityIndex : specializedKeyShares.keySet()) {
+ BigInteger wp =
specializedKeyShares.get(authorityIndex).w.modPow(lagrangeCoefficients.get(authorityIndex),
parameters.p);
+ prod = prod.multiply(wp).mod(parameters.p);
+ }
+
+ tallyBaseG =
encryptedTally.c2.multiply(prod.modInverse(parameters.p)).mod(parameters.p);
+ }
+
+ public int decryptTally() {
+ decryptTallyToBaseG();
+
+ int resultRestored = 0;
+ boolean success = false;
+
+ for (int l = -ballots.size(); l <= ballots.size(); ++l) {
+ if (tallyBaseG.equals(parameters.g.modPow(BigInteger.valueOf(l),
parameters.p))) {
+ success = true;
+ resultRestored = l;
+ break;
+ }
+ }
+
+ if (!success) {
+ throw new AssertionError();
+ }
+ return resultRestored;
+ }
+
+ /*
+ * Sigma is the the authority's commitment to its share
+ */
+ public void verifyTallyKeyShare(TallyKeyShare share) {
+ BigInteger p = parameters.p;
+ BigInteger g = parameters.g;
+
+ BigInteger c1 = share.c1;
+ BigInteger a = share.a;
+ BigInteger r = share.r;
+ BigInteger b = share.b;
+ BigInteger c = share.c;
+
+ // verifier
+ BigInteger expected1 = g.modPow(r, p);
+ BigInteger received1 = a.multiply(share.sigma.modPow(c, p)).mod(p);
+
+ BigInteger expected2 = c1.modPow(r, p);
+ BigInteger received2 = b.multiply(share.w.modPow(c, p)).mod(p);
+
+ if ((!expected1.equals(received1)) || (!expected2.equals(received2))) {
+ System.err.println(expected1);
+ System.err.println(received1);
+ throw new AssertionError("zero knowledge proof for decryption
failed");
+ }
+ }
+
+
+
+ public void verifyBallot(Ballot ballot) {
+ BigInteger g = parameters.g;
+ BigInteger p = parameters.p;
+ BigInteger h = groupPublicKey.getKey();
+ // verifier
+
+ BigInteger voterId = ballot.voterId;
+ BigInteger x = ballot.x;
+ BigInteger y = ballot.y;
+ BigInteger a_1 = ballot.a_1;
+ BigInteger a_2 = ballot.a_2;
+ BigInteger b_1 = ballot.b_1;
+ BigInteger b_2 = ballot.b_2;
+ BigInteger c = ballot.c;
+ BigInteger d_1 = ballot.d_1;
+ BigInteger d_2 = ballot.d_2;
+ BigInteger r_1 = ballot.r_1;
+ BigInteger r_2 = ballot.r_2;
+
+
+ // todo: we should blame someone here, not throw exceptions
+
+
+ if (!c.equals(CryptoUtil.hash(voterId, x, y, a_1, b_1, a_2,
b_2).mod(parameters.q))) {
+ throw new AssertionError();
+ }
+
+ if (!c.equals(d_1.add(d_2).mod(p))) {
+ throw new AssertionError();
+ }
+ if (!a_1.equals(g.modPow(r_1, p).multiply(x.modPow(d_1, p)).mod(p))) {
+ throw new AssertionError();
+ }
+ if (!b_1.equals(h.modPow(r_1, p).multiply(y.multiply(g).modPow(d_1,
p)).mod(p))) {
+ throw new AssertionError();
+ }
+
+ if (!a_2.equals(g.modPow(r_2, p).multiply(x.modPow(d_2, p)).mod(p))) {
+ throw new AssertionError();
+ }
+
+ if (!b_2.equals(h.modPow(r_2,
p).multiply(y.multiply(g.modInverse(p)).modPow(d_2, p)).mod(p))) {
+ throw new AssertionError();
+ }
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/voting/simulation/Ballot.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/simulation/Ballot.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/voting/simulation/Ballot.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,105 @@
+package org.gnunet.voting.simulation;
+
+import java.math.BigInteger;
+
+/**
+ * A ballot together with a ZKP for its validity
+ *
+ * @author Florian Dold
+ */
+public class Ballot {
+ public final BigInteger voterId;
+
+ // the ElGamal encryption of the vote
+ public final BigInteger x, y;
+ // values for the zero knowledge proof
+ public final BigInteger a_1, b_1, a_2, b_2, r_1, d_1, r_2, d_2, c;
+ private VotingParameters parameters;
+
+
+ public Ballot(boolean v, BigInteger voterId, GroupPublicKey
groupPublicKey, VotingParameters parameters) {
+ this.voterId = voterId;
+ this.parameters = parameters;
+
+ BigInteger g = parameters.g;
+ BigInteger p = parameters.p;
+ BigInteger h = groupPublicKey.getKey();
+
+
+ if (v) {
+ BigInteger alpha = parameters.generateZq();
+ BigInteger w = parameters.generateZq();
+ r_1 = parameters.generateZq();
+ d_1 = parameters.generateZq();
+
+ x = g.modPow(alpha, p);
+ y = h.modPow(alpha, p).multiply(g).mod(p);
+
+ a_1 = g.modPow(r_1, p).multiply(x.modPow(d_1, p)).mod(p);
+ b_1 = h.modPow(r_1, p).multiply(y.multiply(g).modPow(d_1,
p)).mod(p);
+ a_2 = g.modPow(w, p);
+ b_2 = h.modPow(w, p);
+
+
+ c = CryptoUtil.hash(voterId, x, y, a_1, b_1, a_2,
b_2).mod(parameters.q);
+
+ // prover
+ d_2 = c.subtract(d_1);
+ r_2 = w.subtract(alpha.multiply(d_2));
+ } else {
+ // prover
+ BigInteger alpha = parameters.generateZq();
+ BigInteger w = parameters.generateZq();
+ r_2 = parameters.generateZq();
+ d_2 = parameters.generateZq();
+
+ x = g.modPow(alpha, p);
+ y = h.modPow(alpha, p).multiply(g.modInverse(p)).mod(p);
+
+ a_1 = g.modPow(w, p);
+ b_1 = h.modPow(w, p);
+ a_2 = g.modPow(r_2, p).multiply(x.modPow(d_2, p)).mod(p);
+ b_2 = h.modPow(r_2,
p).multiply(y.multiply(g.modInverse(p)).modPow(d_2, p)).mod(p);
+
+
+ c = CryptoUtil.hash(voterId, x, y, a_1, b_1, a_2,
b_2).mod(parameters.q);
+
+ // prover
+ d_1 = c.subtract(d_2);
+ r_1 = w.subtract(alpha.multiply(d_1));
+ }
+ }
+
+ public void verify(GroupPublicKey groupPublicKey) {
+ BigInteger g = parameters.g;
+ BigInteger p = parameters.p;
+ BigInteger h = groupPublicKey.getKey();
+ // verifier
+
+
+ if (!c.equals(CryptoUtil.hash(voterId, x, y, a_1, b_1, a_2,
b_2).mod(parameters.q))) {
+ throw new AssertionError();
+ }
+
+ if (!c.equals(d_1.add(d_2).mod(p))) {
+ throw new AssertionError();
+ }
+ if (!a_1.equals(g.modPow(r_1, p).multiply(x.modPow(d_1, p)).mod(p))) {
+ throw new AssertionError();
+ }
+
+ if (!a_2.equals(g.modPow(r_2, p).multiply(x.modPow(d_2, p)).mod(p))) {
+ throw new AssertionError();
+ }
+
+ if (!b_2.equals(h.modPow(r_2,
p).multiply(y.multiply(g.modInverse(p)).modPow(d_2, p)).mod(p))) {
+ throw new AssertionError();
+ }
+
+ if (!b_1.equals(h.modPow(r_1, p).multiply(y.multiply(g).modPow(d_1,
p)).mod(p))) {
+ throw new AssertionError();
+ }
+
+
+ }
+}
Added:
gnunet-java/src/main/java/org/gnunet/voting/simulation/BogusAuthority.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/simulation/BogusAuthority.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/voting/simulation/BogusAuthority.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,9 @@
+package org.gnunet.voting.simulation;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class BogusAuthority extends Authority {
+}
Added: gnunet-java/src/main/java/org/gnunet/voting/simulation/CallForVoters.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/simulation/CallForVoters.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/voting/simulation/CallForVoters.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,14 @@
+package org.gnunet.voting.simulation;
+
+import java.util.List;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class CallForVoters {
+ public List<Authority> authorities;
+ public VotingParameters parameters;
+ public GroupPublicKey publicKey;
+}
Added: gnunet-java/src/main/java/org/gnunet/voting/simulation/CryptoUtil.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/simulation/CryptoUtil.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/voting/simulation/CryptoUtil.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,86 @@
+package org.gnunet.voting.simulation;
+
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Random;
+
+/**
+ * Miscellaneous helper functions.
+ *
+ * @author Florian Dold
+ */
+public class CryptoUtil {
+ public static final Random random = new Random();
+
+
+ /**
+ * Return a random BigInteger not less than 'min' and not greater than
'max' with uniform distribution.
+ *
+ * @param min the least value that may be generated
+ * @param max the greatest value that may be generated
+ * @return a random BigInteger value in the range [min,max]
+ */
+ public static BigInteger createRandomInRange(BigInteger min,
+ BigInteger max) {
+ int cmp = min.compareTo(max);
+ if (cmp >= 0) {
+ if (cmp > 0) {
+ throw new IllegalArgumentException("'min' may not be greater
than 'max'");
+ }
+
+ return min;
+ }
+
+ if (min.bitLength() > max.bitLength() / 2) {
+ return createRandomInRange(BigInteger.ZERO,
max.subtract(min)).add(min);
+ }
+
+ for (int i = 0; i < 1000; ++i) {
+ BigInteger x = new BigInteger(max.bitLength(), random);
+ if (x.compareTo(min) >= 0 && x.compareTo(max) <= 0) {
+ return x;
+ }
+ }
+
+ // fall back to a faster (restricted) method
+ // (using only this distribution would lead to a non-uniform
distribution, see the BigInteger constructor)
+ return new BigInteger(max.subtract(min).bitLength() - 1,
random).add(min);
+ }
+
+
+
+ /**
+ * Evaluate a polynomial over Zp*. Uses Horner's scheme.
+ *
+ * @param coeffs coefficients of the polynomial, where coeffs[i] is the
coefficient of x^i
+ * @param x the polynomial is evaluated at this value
+ * @param p what group are we operating in?
+ * @return the result of evaluating the polynomial at x
+ */
+ public static BigInteger evaluatePolynomial(BigInteger[] coeffs,
BigInteger x, BigInteger p) {
+ BigInteger z = BigInteger.ZERO;
+ for (int i = 0; i < coeffs.length; ++i) {
+ // z <- zx + c
+ z = z.multiply(x).add(coeffs[coeffs.length - i - 1]);
+ }
+ return z;
+ }
+
+ public static BigInteger hash(BigInteger... x) {
+ MessageDigest md;
+ try {
+ md = MessageDigest.getInstance("SHA-512");
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("no SHA-512 available");
+ }
+
+ for (BigInteger v : x) {
+ md.update(v.toByteArray());
+ }
+
+ return new BigInteger(md.digest());
+ }
+
+}
Added: gnunet-java/src/main/java/org/gnunet/voting/simulation/Cyphertext.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/simulation/Cyphertext.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/voting/simulation/Cyphertext.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,19 @@
+package org.gnunet.voting.simulation;
+
+import java.math.BigInteger;
+
+/**
+ * ElGamal encryption of a message.
+ *
+ * @author Florian Dold
+ */
+public class Cyphertext {
+ public final BigInteger c1;
+ public final BigInteger c2;
+
+
+ public Cyphertext(BigInteger c1, BigInteger c2) {
+ this.c1 = c1;
+ this.c2 = c2;
+ }
+}
Added:
gnunet-java/src/main/java/org/gnunet/voting/simulation/ElectionSupervisor.java
===================================================================
---
gnunet-java/src/main/java/org/gnunet/voting/simulation/ElectionSupervisor.java
(rev 0)
+++
gnunet-java/src/main/java/org/gnunet/voting/simulation/ElectionSupervisor.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,105 @@
+package org.gnunet.voting.simulation;
+
+import com.google.common.collect.Lists;
+
+import java.math.BigInteger;
+import java.util.List;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class ElectionSupervisor {
+ /**
+ * Accumulator for the group public key.
+ * todo: actually we should record the group publice key share of each
authority seperately
+ */
+ private BigInteger groupPublicKeyAccum = BigInteger.ONE;
+
+ private VotingParameters parameters;
+
+ /**
+ * Authorities that will be invited for participation
+ */
+ private List<Authority> availableAuthorities;
+
+ /**
+ * Authorities that have agreed to participate.
+ */
+ private List<Authority> participatingAuthorities = Lists.newArrayList();
+
+
+
+ private enum Phase { START, INVITED, KEYS_GENERATED, PUBKEY_PUBLISHED}
+
+ private Phase currentPhase = Phase.START;
+
+
+ public ElectionSupervisor(List<Authority> availableAuthorities,
VotingParameters parameters) {
+ this.parameters = parameters;
+ this.availableAuthorities = availableAuthorities;
+ }
+
+ /**
+ * Send an invitation to all available authorities
+ */
+ public void inviteAuthorities() {
+ if (currentPhase != Phase.START) {
+ throw new AssertionError();
+ }
+
+ int nextAuthorityNumber = 1;
+ for (Authority authority : availableAuthorities) {
+ BigInteger part = authority.inviteAuthority(nextAuthorityNumber,
parameters);
+ nextAuthorityNumber += 1;
+ if (part != null) {
+ participatingAuthorities.add(authority);
+ groupPublicKeyAccum =
groupPublicKeyAccum.multiply(part).mod(parameters.p);
+ }
+ }
+
+ currentPhase = Phase.INVITED;
+ }
+
+ public CallForVoters createCallForVote() {
+ if (currentPhase != Phase.PUBKEY_PUBLISHED) {
+ throw new AssertionError();
+ }
+
+ CallForVoters callForVoters = new CallForVoters();
+ callForVoters.authorities = participatingAuthorities;
+ callForVoters.parameters = parameters;
+ callForVoters.publicKey = new GroupPublicKey(groupPublicKeyAccum);
+ return callForVoters;
+
+ }
+
+
+ public void ascertainGroupPublicKey() {
+ if (currentPhase != Phase.KEYS_GENERATED) {
+ throw new AssertionError();
+ }
+
+ for (Authority authority : participatingAuthorities) {
+ authority.acceptGroupPublicKey(new
GroupPublicKey(groupPublicKeyAccum));
+ }
+
+ currentPhase = Phase.PUBKEY_PUBLISHED;
+
+ }
+
+
+ /**
+ * Publish participating authorities of the key generation, receiving
authorities will start the key generation.
+ */
+ public void startKeyGeneration() {
+ if (currentPhase != Phase.INVITED) {
+ throw new AssertionError();
+ }
+ for (Authority authority : participatingAuthorities) {
+ authority.generateKeyWithAuthorities(participatingAuthorities);
+ }
+ currentPhase = Phase.KEYS_GENERATED;
+ }
+}
Added:
gnunet-java/src/main/java/org/gnunet/voting/simulation/GroupPublicKey.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/simulation/GroupPublicKey.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/voting/simulation/GroupPublicKey.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,28 @@
+package org.gnunet.voting.simulation;
+
+import java.math.BigInteger;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class GroupPublicKey {
+ final BigInteger key;
+
+ public GroupPublicKey(Authority[] authorities, VotingParameters
parameters) {
+ BigInteger h = BigInteger.ONE;
+ for (Authority authority : authorities) {
+ h = h.multiply(authority.getPublicKeyShare()).mod(parameters.p);
+ }
+ key = h;
+ }
+
+ public GroupPublicKey(BigInteger groupPublicKey) {
+ this.key = groupPublicKey;
+ }
+
+ public BigInteger getKey() {
+ return key;
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/voting/simulation/TallyKeyShare.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/simulation/TallyKeyShare.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/voting/simulation/TallyKeyShare.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,41 @@
+package org.gnunet.voting.simulation;
+
+import java.math.BigInteger;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class TallyKeyShare {
+ final public BigInteger w;
+
+ final public BigInteger sigma;
+
+ final public BigInteger c1;
+ final public BigInteger a, b, c, r;
+
+ final VotingParameters parameters;
+
+ public TallyKeyShare(BigInteger c1, BigInteger share, VotingParameters
parameters) {
+ this.parameters = parameters;
+ this.c1 = c1;
+
+ sigma = parameters.g.modPow(share, parameters.p);
+
+ w = c1.modPow(share, parameters.p);
+
+ BigInteger p = parameters.p;
+ BigInteger g = parameters.g;
+
+ // prover
+ BigInteger beta = parameters.generateZq();
+ a = g.modPow(beta, p);
+ b = c1.modPow(beta, p);
+ // verifier
+ c = CryptoUtil.hash(a, b);
+ // prover
+ r = beta.add(share.multiply(c));
+ }
+}
+
Added:
gnunet-java/src/main/java/org/gnunet/voting/simulation/TransmitShareVerification.java
===================================================================
---
gnunet-java/src/main/java/org/gnunet/voting/simulation/TransmitShareVerification.java
(rev 0)
+++
gnunet-java/src/main/java/org/gnunet/voting/simulation/TransmitShareVerification.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,18 @@
+package org.gnunet.voting.simulation;
+
+import java.math.BigInteger;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class TransmitShareVerification {
+ public final BigInteger[] coeffs;
+ public TransmitShareVerification(BigInteger[] secretPolynomial,
VotingParameters parameters) {
+ coeffs = new BigInteger[secretPolynomial.length];
+ for (int i = 0; i < secretPolynomial.length; ++i) {
+ coeffs[i] = parameters.g.modPow(secretPolynomial[i], parameters.p);
+ }
+ }
+}
Added: gnunet-java/src/main/java/org/gnunet/voting/simulation/Voter.java
===================================================================
--- gnunet-java/src/main/java/org/gnunet/voting/simulation/Voter.java
(rev 0)
+++ gnunet-java/src/main/java/org/gnunet/voting/simulation/Voter.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,31 @@
+package org.gnunet.voting.simulation;
+
+import java.math.BigInteger;
+
+/**
+ *
+ *
+ * @author Florian Dold
+ */
+public class Voter {
+ boolean b;
+ BigInteger voterId;
+ private CallForVoters callForVoters;
+
+ public Voter(CallForVoters callForVoters) {
+ b = CryptoUtil.random.nextBoolean();
+ voterId = new BigInteger(64, CryptoUtil.random);
+ this.callForVoters = callForVoters;
+ }
+
+ public Ballot generateBallot() {
+ return new Ballot(b, voterId, callForVoters.publicKey,
callForVoters.parameters);
+ }
+
+ public void vote() {
+ Ballot ballot = generateBallot();
+ for (Authority authority : callForVoters.authorities) {
+ authority.acceptBallot(ballot);
+ }
+ }
+}
Added:
gnunet-java/src/main/java/org/gnunet/voting/simulation/VotingParameters.java
===================================================================
---
gnunet-java/src/main/java/org/gnunet/voting/simulation/VotingParameters.java
(rev 0)
+++
gnunet-java/src/main/java/org/gnunet/voting/simulation/VotingParameters.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,165 @@
+package org.gnunet.voting.simulation;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * Utilities for the modified ElGamal algorithm.
+ * <p/>
+ * p is a large prime, and g is a high-order element (or even a generator) of
Zp*
+ *
+ * @author Florian Dold
+ */
+public class VotingParameters {
+ // large prime, p = 2q + 1
+ public final BigInteger p;
+ // large prime, so that q divides (p-1)
+ public final BigInteger q;
+ // generator of Gq
+ public final BigInteger g;
+
+ public final int authorityCount;
+ public final int authorityThreshold;
+
+ public VotingParameters(BigInteger p, BigInteger q, BigInteger g, int
authorityCount, int authorityThreshold) {
+ this.p = p;
+ this.q = q;
+ this.g = g;
+ this.authorityCount = authorityCount;
+ this.authorityThreshold = authorityThreshold;
+ }
+
+ /**
+ * which generates the p and g values from the given parameters,
+ * returning the ElGamalScheme object.
+ * <p/>
+ * Note: can take a while...
+ */
+ public static VotingParameters generateRandomParameters(int size, int
certainty, int authorityCount, int authorityThreshold) {
+ BigInteger[] safePrimes = generateSafePrimes(size, certainty);
+ BigInteger p = safePrimes[0];
+ BigInteger q = safePrimes[1];
+ BigInteger alpha = selectGenerator(p, q);
+ BigInteger g = selectSubgroupHigherOrderElement(alpha, p, q);
+ if (!g.modPow(q, p).equals(BigInteger.ONE)) {
+ throw new AssertionError();
+ }
+ if (!(g.compareTo(p) < 0)) {
+ throw new AssertionError();
+ }
+ return new VotingParameters(p, q, g, authorityCount,
authorityThreshold);
+ }
+
+ /**
+ * Finds a pair of prime BigInteger's {p, q: p = 2q + 1}, called safe
primes.
+ * <p/>
+ * (see: Handbook of Applied Cryptography 4.86)
+ *
+ * @return A 2-element array {p,q} of safe primes.
+ */
+ private static BigInteger[] generateSafePrimes(int size, int certainty) {
+ BigInteger p, q;
+ int qLength = size - 1;
+
+ while (true) {
+ q = new BigInteger(qLength, 2, CryptoUtil.random);
+
+ // p <- 2q + 1
+ p = q.shiftLeft(1).add(BigInteger.ONE);
+
+ // XXX(dold): why do we test q for primality again?
+ if (p.isProbablePrime(certainty) && (certainty <= 2 ||
q.isProbablePrime(certainty))) {
+ break;
+ }
+ }
+
+ return new BigInteger[]{p, q};
+ }
+
+ /*
+ * Select a high order element of the multiplicative group Zn*
+ */
+ private static BigInteger selectHighOrderElement(BigInteger n,
SecureRandom random) {
+ BigInteger g;
+ final BigInteger nMinusTwo = n.subtract(BigInteger.valueOf(2));
+ do {
+ BigInteger h =
CryptoUtil.createRandomInRange(BigInteger.valueOf(2), nMinusTwo);
+
+ g = h.modPow(BigInteger.valueOf(2), n);
+ }
+ while (g.equals(BigInteger.valueOf(1)));
+
+ return g;
+ }
+
+ /**
+ * Returns a higher-order-element of Gq, the subgroup of Zp*, with order q
where alpha is a generator of Zp*
+ *
+ * (see Handbook of Applied Cryptography 4.81)
+ */
+ private static BigInteger selectSubgroupHigherOrderElement(BigInteger
alpha, BigInteger p, BigInteger q) {
+ return alpha.modPow(p.subtract(BigInteger.ONE).divide(q), p);
+ }
+
+ /**
+ * Get the size of the cyclic group Gp used for ElGamal
+ *
+ * @return the size of the cyclic group Gp used for ElGamal
+ */
+ public BigInteger getP() {
+ return p;
+ }
+
+ /**
+ * Get the generator of Gq
+ *
+ * @return the generator of Gq
+ */
+ public BigInteger getG() {
+ return g;
+ }
+
+ /**
+ * Get the generator of Zp*
+ *
+ * @return the generator of Zp*
+ */
+ public BigInteger getQ() {
+ return q;
+ }
+
+ public BigInteger generateGq() {
+ BigInteger r;
+ while (true) {
+ r = CryptoUtil.createRandomInRange(BigInteger.ZERO, this.p);
+ if (r.modPow(q, p).equals(BigInteger.ONE)) {
+ break;
+ }
+ }
+ return r;
+ }
+
+ public static BigInteger selectGenerator(BigInteger p, BigInteger q) {
+ BigInteger pMinusTwo = p.subtract(BigInteger.valueOf(2));
+ BigInteger g;
+ /*
+ * (see: Handbook of Applied Cryptography 4.80)
+ */
+ do {
+ g = CryptoUtil.createRandomInRange(BigInteger.valueOf(2),
pMinusTwo);
+ }
+ while (g.modPow(BigInteger.valueOf(2), p).equals(BigInteger.ONE) ||
g.modPow(q, p).equals(BigInteger.ONE));
+ return g;
+ }
+
+ public BigInteger generateZq() {
+ return CryptoUtil.createRandomInRange(BigInteger.ZERO,
this.q.subtract(BigInteger.ONE));
+ }
+
+ public Cyphertext encrypt(BigInteger message, BigInteger publicKey) {
+ BigInteger secret = generateZq();
+ return new Cyphertext(g.modPow(secret, p),
message.multiply(publicKey.modPow(secret, p).mod(p)));
+ }
+
+
+}
Added:
gnunet-java/src/main/java/org/gnunet/voting/simulation/VotingSimulation.java
===================================================================
---
gnunet-java/src/main/java/org/gnunet/voting/simulation/VotingSimulation.java
(rev 0)
+++
gnunet-java/src/main/java/org/gnunet/voting/simulation/VotingSimulation.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,122 @@
+package org.gnunet.voting.simulation;
+
+import com.google.common.collect.Lists;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Simulation of the voting protocol.
+ *
+ * @author Florian Dold
+ */
+public class VotingSimulation {
+ public static void main(String... args) {
+ final int authorityCount = 10;
+ final int authorityThreshold = 6;
+ final VotingParameters parameters =
VotingParameters.generateRandomParameters(64, 10, authorityCount,
authorityThreshold);
+
+ List<Authority> availableAuthorities =
spawnAuthorities(authorityCount, authorityCount);
+
+ final ElectionSupervisor supervisor = new
ElectionSupervisor(availableAuthorities, parameters);
+
+ supervisor.inviteAuthorities();
+
+ // todo: what if to little authorities accepted the invitation?
+
+ supervisor.startKeyGeneration();
+
+ // make sure that every authority and the supervisor has the same
public key
+ supervisor.ascertainGroupPublicKey();
+
+ CallForVoters callForVoters = supervisor.createCallForVote();
+
+ List<Voter> voters = spawnVoters(callForVoters, 100, 50);
+
+ int checkTally = countCheckTally(voters);
+
+ for (Voter voter : voters) {
+ voter.vote();
+ }
+
+ // todo: make sure every authority has the same votes
+
+ for (Authority authority : callForVoters.authorities) {
+ authority.distributeTallyKey();
+ }
+
+ // todo: blame authorities that failed the zero knowledge proof
+
+ for (Authority authority : callForVoters.authorities) {
+ int tally = authority.decryptTally();
+
+ if (tally != checkTally) {
+ throw new AssertionError();
+ }
+ }
+
+ }
+
+ private static int countCheckTally(List<Voter> voters) {
+ int tally = 0;
+ for (Voter voter : voters) {
+ tally += voter.b ? 1 : -1;
+ }
+ return tally;
+ }
+
+
+ /**
+ * Create all authorities involved in the election, where some authorities
are bogus authorities.
+ *
+ * @param authorityCount number of returned authorities
+ * @param authorityThreshold minimum number of honest authorities
+ * @return list of authorities
+ */
+ public static List<Authority> spawnAuthorities(int authorityCount, int
authorityThreshold) {
+ List<Authority> authorities = Lists.newArrayList();
+ Collection<Integer> honestAuthorityIndices =
VotingSimulation.randomIndices(authorityCount, authorityThreshold);
+ for (int i = 0; i < authorityCount; ++i) {
+ if (honestAuthorityIndices.contains(i)) {
+ authorities.add(new Authority());
+ }
+ }
+ return authorities;
+ }
+
+
+ /**
+ * Create voters, where some voters may be malicious.
+ *
+ * @param callForVote description of the election for the voter
+ * @param voterCount number of all voters
+ * @param honestVoterCount number of honest, non-malicious voters
+ */
+ private static List<Voter> spawnVoters(CallForVoters callForVote, int
voterCount, int honestVoterCount) {
+ List<Voter> voters = Lists.newArrayList();
+ for (int i = 0; i < voterCount; ++i) {
+ voters.add(new Voter(callForVote));
+ }
+ return voters;
+ }
+
+ /*
+ * Return between authorityThreshold and authorityCount indices
+ */
+ private static List<Integer> randomIndices(int authorityCount, int
authorityThreshold) {
+ ArrayList<Integer> x = Lists.newArrayListWithCapacity(authorityCount);
+ for (int i = 0; i < authorityCount; ++i) {
+ x.add(i);
+ }
+ Collections.shuffle(x);
+ int len;
+ if (authorityCount == authorityThreshold) {
+ len = authorityThreshold;
+ } else {
+ len = CryptoUtil.random.nextInt(authorityCount -
authorityThreshold) + authorityThreshold;
+ }
+ return Collections.unmodifiableList(x.subList(0, len));
+ }
+}
Added: gnunet-java/src/main/java/org/grothoff/Runabout.java
===================================================================
--- gnunet-java/src/main/java/org/grothoff/Runabout.java
(rev 0)
+++ gnunet-java/src/main/java/org/grothoff/Runabout.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,574 @@
+/*
+ * (C) 2002, 2003, 2004, 2005, 2006 Christian Grothoff
+ *
+ * The Runabout is free software; you can redistribute it and/or modify it
under
+ * the terms of the GNU General Public License as published by the Free
Software
+ * Foundation; either version 2, or (at your option) any later version. The
+ * Runabout is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License along with
+ * the Runabout; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * This software is also licensed under the Eclipse Public License v1.0
+ * available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+package org.grothoff;
+
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+
+/**
+ * Runabout is a fast implementation of the Walkabout which is a variant of the
+ * Visitor Pattern that does not require an accept method and uses reflection
+ * instead.
+ * <p/>
+ * An instance of Runabout is able to walk over an arbitrary object graph using
+ * visit methods which take arguments of the specific type of the object to
+ * visit. For each node in the object graph the Runabout invokes the most
+ * appropriate visit method.
+ * <p/>
+ * Using the Runabout typically involves subclassing Runabout and adding a
+ * couple of visit methods. The Runabout provides a 'visitAppropriate' method
+ * which will invoke the most appropriate visit method of the current Runabout
+ * instance. If no visit method is applicable, visitAppropriate calls
+ * visitDefault() which, if not overridden, throws an exception.
+ * <p/>
+ * The elements of the object graph typically extend the Element class, which
+ * provides a generic way to quickly invoke the Runabout on all the fields of
+ * the Element.
+ * <p/>
+ * Note that the Runabout uses dynamic code generation and dynamic loading in
+ * order to be quickly able to invoke the appropriate visit methods. To make
the
+ * dynamic code generation fast, the code inlines parts of Java class-files in
+ * binary form (ugly!).<br>
+ * A per-thread Cache is used to speed-up the creation of the Runabout by
+ * caching reflection, code creation and dynamic loading operations.
+ * <p/>
+ * <bf>Restrictions:</bf> Java semantics require:
+ * <ul>
+ * <li>all subclasses must be public, sadly this also means that <strong>you
+ * can not use an anonymous inner class</strong> (!)</li>
+ * <li>the types_length to all arguments of visit methods must be public</li>
+ * <li>all visit methods must be public (!)</li>
+ * </ul>
+ * Otherwise the visitor will die with an IllegalAccessError during execution.
+ * <p/>
+ *
+ * @author Christian Grothoff
+ * @version 5.0
+ */
+public class Runabout {
+
+ /**
+ * Singleton of the Runabout.Cache. We cache reflective information per VM;
+ * this avoids the need for repeated reflection, code generation and
+ * dispatching map updates.
+ */
+ private static final Runabout.Cache cache_ = new Runabout.Cache();
+
+ /**
+ * map_ contains a mapping from a class to the appropriate visit method.
+ * Note that at the beginning, map_ only contains the explicit mappings as
+ * given by the visit methods. Over time, map_ will be amended to also
+ * contain direct mappings for subclasses to the appropriate visit methods
+ * if they are used.
+ */
+ private final HashMap<Class, Runabout.Code> map_;
+
+ /**
+ * Code to invoke if no visitor is found (used to avoid scanning the
+ * hierarchy again and again).
+ */
+ private final Code noCode = new NoCode();
+
+ /**
+ * Set when the subclass of the runabout is not public.
+ */
+ private final boolean isPublic;
+
+ /**
+ * Create a Runabout.
+ */
+ public Runabout() {
+ this.isPublic = Modifier.isPublic(getClass().getModifiers());
+ map_ = cache_.get(this);
+ }
+
+ /**
+ * Call the appropriate visit method. Use this method if you are visiting a
+ * graph of objects (no primitives).
+ *
+ * @param o the object to visit
+ */
+ public void visitAppropriate(Object o) {
+ getAppropriateCodeInternal(o.getClass()).visit(this, o);
+ }
+
+ /**
+ * Obtain the appropriate code to call for class c. The method either
+ * obtains the code quickly from the code map (fast path) or by calling the
+ * lookup method getAppropriateCode.
+ *
+ * @return the code, never returns null
+ */
+ private Code getAppropriateCodeInternal(Class c) {
+ synchronized (cache_) {
+ Code co = map_.get(c);
+ if (co != null)
+ return co;
+ co = getAppropriateCode(c);
+ if (co == null)
+ co = noCode;
+ map_.put(c, co);
+ return co;
+ }
+ }
+
+ /**
+ * Find the appropriate Code to call in the map. If no code is found,
return
+ * null. This lookup strategy first attempts to find a visit method defined
+ * for the parent classes of c. If no such method exists, it attempts to
+ * find an unambiguous visit method matching any interface transitively
+ * implemented by c. If that does not exist either, null is returned. If
+ * only an ambiguous visit method exists, an exception is raised.
+ *
+ * @param c the class for which to find the code
+ * @return the code to run, or null if no code was found
+ * @throws RunaboutException if the lookup would be ambiguous
+ */
+ private Code getAppropriateCode(Class c) {
+ if (c.isArray()) {
+ // uh uh, array subtyping in action...
+ int dims = 1;
+ Class component = c.getComponentType();
+ while (component.isArray()) {
+ dims++;
+ component = component.getComponentType();
+ }
+ Class superComp = component.getSuperclass();
+ while (superComp != null) {
+ Code co = map_.get(Array.newInstance(superComp, new
int[dims]).getClass());
+ if (co != null)
+ return co;
+ superComp = superComp.getSuperclass();
+ }
+ // now try subtyping with multi-dimensional Object[]
+ // (see crazy runabout test).
+ Class objectClass = c.getSuperclass();
+ while (dims > 1) {
+ Code co = map_.get(Array.newInstance(objectClass, new
int[dims]).getClass());
+ if (co != null)
+ return co;
+ dims--;
+ }
+ }
+ Class cl = c.getSuperclass();
+ while (cl != null) {
+ Code co = map_.get(cl);
+ if (co != null)
+ return co;
+ cl = cl.getSuperclass();
+ }
+ return getAppropriateCode_ifc(c, c);
+ }
+
+ /**
+ * Find the appropriate Code to call in the map. If no code is found,
return
+ * null.
+ *
+ * @param c the class for which to find the code
+ * @param cl the class where to start looking from
+ * @return the code to run, or null if no code was found
+ */
+ private Code getAppropriateCode_ifc(Class c, Class cl) {
+ Code co = null;
+ while (cl != null) {
+ Class[] ifc = cl.getInterfaces();
+ for (Class anIfc : ifc) {
+ Code r = map_.get(anIfc);
+ if (r != null) {
+ if ((co != null) && (r != co))
+ throw new RunaboutException("Ambiguous resolution for
visit call to "
+ + c + " in " + this.getClass().getName());
+ co = r;
+ }
+ }
+ for (Class anIfc : ifc) {
+ Code r = getAppropriateCode_ifc(c, anIfc);
+ if (r != null) {
+ if ((co != null) && (r != co))
+ throw new RunaboutException("Ambiguous resolution for
visit call to "
+ + c + " in " + this.getClass().getName());
+ co = r;
+ }
+ }
+ cl = cl.getSuperclass();
+ }
+ return co;
+ }
+
+ /**
+ * Generate the initial version of the map that maps classes to Code to
call
+ * the appropriate visit method.
+ */
+ final HashMap<Class, Runabout.Code> makeMap() {
+ // get number of methods
+ int size = 0;
+ Class me = this.getClass();
+ while (me != null) {
+ size += me.getDeclaredMethods().length;
+ me = me.getSuperclass();
+ }
+ // create map with slight over-estimate
+ HashMap<Class, Runabout.Code> result = new HashMap<Class,
Runabout.Code>(size * 2);
+ // for all methods - create call code, put
+ me = this.getClass();
+ while (me != null) {
+ Method[] methods = me.getDeclaredMethods();
+ for (final Method m : methods) {
+ if ((m.getName().equals("visit"))
+ && (!Modifier.isStatic(m.getModifiers()))) {
+ Class[] args = m.getParameterTypes();
+ if (args.length != 1)
+ throw new RunaboutException("Invalid number of
arguments for Runabout in method "
+ + m);
+ final Class viC = args[0];
+ if (result.get(viC) != null)
+ continue;
+ Code co;
+ if (isPublic) {
+ // invoke the visitor with generated code
+ co = makeCode(viC);
+ if (co == null) {
+ throw new RunaboutException("Could not create/load
dynamic code!");
+ }
+ } else {
+ if (!m.isAccessible()) {
+ m.setAccessible(true);
+ }
+ // invoke the visitor with an anonymous inner class,
+ // allows for the runabout to be public as the method
made accessible
+ // by the Method instance.
+ // For Java 7+ the performance of this could be
improved by using a MethodHandle
+ co = new Code() {
+ @Override
+ public void visit(Runabout r, Object o) {
+ try {
+
+ m.invoke(r, o);
+ } catch (IllegalAccessException e) {
+ throw new RunaboutException(e.toString());
+ } catch (InvocationTargetException e) {
+ System.err.println("stacktrace:");
+ e.getCause().printStackTrace(System.err);
+ throw new
RunaboutException(e.getCause().toString());
+ }
+ }
+ };
+ }
+
+ result.put(viC, co);
+
+ }
+ }
+ me = me.getSuperclass();
+ }
+ return result;
+ }
+
+ /**
+ * Create the code to invoke a visit method.
+ *
+ * @param c the type of the argument to the visit method
+ */
+ private Code makeCode(Class c) {
+ byte[] myName // Lovm/util/RunaboutExample; substitute
+ = canonicalName(getClass(), false);
+ final int myNameLen = myName.length;
+ final int myNameLenM2 = myNameLen - 2;
+ byte[] cName // Ljava/lang/String; substitute
+ = canonicalName(c, false);
+ byte[] cNameCast = canonicalName(c, true);
+ final int cNameLen = cName.length;
+ final int cNameLenCast = cNameCast.length - 2;
+ byte[] code = new byte[genCodeTemplate.length - 62 + myNameLenM2
+ + cNameLenCast + cNameLen];
+
+ // Build code by substituting a few strings in genCodeTemplate.
+ // 117-145: org/grothoff/RunaboutExample => myName
+ // 148-164: java/lang/String => cName
+ // 192-200: XXXXXXXX => number
+ // 250-271: (Ljava/lang/String;)V => "("+cName+")V"
+
+ System.arraycopy(genCodeTemplate, 0, code, 0, 115);
+ code[115] = (byte) ((myNameLenM2) >> 8);
+ code[116] = (byte) ((myNameLenM2) & 255);
+ System.arraycopy(myName, 1, code, 117, myNameLenM2);
+ code[117 + myNameLenM2] = 1; // tag for string
+ code[118 + myNameLenM2] = (byte) ((cNameLenCast) >> 8);
+ code[119 + myNameLenM2] = (byte) ((cNameLenCast) & 255);
+ System.arraycopy(cNameCast, 1, code, 120 + myNameLenM2, cNameLenCast);
+ System.arraycopy(genCodeTemplate, 164, code, 120 + myNameLenM2
+ + cNameLenCast, 248 - 164);
+ code[120 + myNameLenM2 + cNameLenCast + 248 - 164] = (byte) ((cNameLen
+ 3) >> 8);
+ code[120 + myNameLenM2 + cNameLenCast + 249 - 164] = (byte) ((cNameLen
+ 3) & 255);
+ code[120 + myNameLenM2 + cNameLenCast + 250 - 164] = (byte) '(';
+ System.arraycopy(cName, 0, code, 120 + myNameLenM2 + cNameLenCast + 251
+ - 164, cNameLen);
+ code[120 + myNameLenM2 + cNameLenCast + 250 - 164 + cNameLen + 1] =
(byte) ')';
+ code[120 + myNameLenM2 + cNameLenCast + 250 - 164 + cNameLen + 2] =
(byte) 'V';
+ System.arraycopy(genCodeTemplate,
+ 271,
+ code,
+ 120 + myNameLenM2 + cNameLenCast + 250 - 164
+ + cNameLen + 3,
+ genCodeTemplate.length - 271);
+ return cache_.loadCode(code, 120 + myNameLenM2 + cNameLenCast + 192
+ - 164);
+ }
+
+ /**
+ * Get the class name in canonical form.
+ *
+ * @param cls the class, may not be primitive
+ * @return the ovm name, following the convention of
+ * address@hidden java.util.Class.forName} according to the JavaDoc
+ * specification (JDK 1.2.2/1.3/1.4) which differs from the actual
+ * implementation in both SUN and IBM VMs.
+ */
+ private static byte[] canonicalName(Class cls, boolean forCast) {
+ String cname = cls.getName();
+ try {
+ byte[] utf = cname.getBytes("UTF-8");
+ int len = utf.length; // may be > cname.length()!
+ if ((cname.charAt(0) != '[') || (forCast)) {
+ byte[] ret = new byte[len + 2];
+ ret[0] = (byte) 'L';
+ System.arraycopy(utf, 0, ret, 1, len);
+ ret[len + 1] = (byte) ';';
+ for (int i = len; i > 0; i--)
+ if (ret[i] == (byte) '.')
+ ret[i] = (byte) '/';
+ return ret;
+ }
+ for (int i = len - 1; i >= 0; i--)
+ if (utf[i] == (byte) '.')
+ utf[i] = (byte) '/';
+ return utf;
+ } catch (UnsupportedEncodingException uee) {
+ throw new RunaboutException("UTF8 encoding not supported!?: " +
uee);
+ }
+ }
+
+ /**
+ * The Runabout.Cache is essentially a per-class cache of the internal
+ * constant state of a Runabout instance. It contains the generated code to
+ * quicly invoke the appropriate visit methods.
+ *
+ * @author Christian Grothoff
+ */
+ static final class Cache {
+
+ /**
+ * ClassLoader to use to load the code.
+ */
+ private final ClassLoader loader_;
+
+ /**
+ * Last name used by the class loader.
+ */
+ private final byte[] lastName_;
+
+ /**
+ * Mapping of classes to Maps.
+ */
+ private final HashMap<Class, HashMap<Class, Runabout.Code>> cachemap_;
+
+ /**
+ * Code that the loader should use.
+ */
+ byte[] code;
+
+ /**
+ * Create the Cache.
+ */
+ Cache() {
+ loader_ = new ClassLoader() {
+ public Class<?> loadClass(String name)
+ throws ClassNotFoundException {
+ //noinspection StringEquality
+ if (name == "Code") // == works here, as both strings are
guaranteed to be interned
+ return defineClass(null, code, 0, code.length);
+ return
Thread.currentThread().getContextClassLoader().loadClass(name);
+ }
+ };
+ cachemap_ = new HashMap<Class, HashMap<Class, Runabout.Code>>();
+ lastName_ = new byte[8];
+ for (int i = 0; i < 8; i++)
+ lastName_[i] = (byte) '0';
+ }
+
+ /**
+ * Create a class from the given bytecode. Since classes loaded by the
+ * same Loader must have a unique name, this method patches the
bytecode
+ * at the given offset, changing the next 8 characters to a unique Java
+ * classname.
+ *
+ * @param byteCode the bytecode of the class which must describe a
class
+ * of type 'Code'. The class must contain a sequence
XXXXXXXX at
+ * offset xIdx where the classname is to be patched
+ * @param xIdx the index of the XXXXXXXX sequence
+ * @return an instance of the loaded class, null on error
+ * @throws ArrayIndexOutOfBoundsException if more than 62<sup>8</sup>
+ * classes are loaded :-)
+ * @throws RunaboutException if there are problems with
dynamic loading
+ * of the byteCode
+ */
+ Code loadCode(byte[] byteCode, int xIdx) {
+ boolean overflow = true;
+ int index = 7;
+ while (overflow) {
+ overflow = false;
+ lastName_[index]++;
+ if (lastName_[index] == (byte) ('9' + 1))
+ lastName_[index] = (byte) 'A';
+ if (lastName_[index] == (byte) ('Z' + 1))
+ lastName_[index] = (byte) 'a';
+ if (lastName_[index] == (byte) ('z' + 1)) {
+ lastName_[index] = (byte) '0';
+ overflow = true;
+ index--;
+ }
+ }
+ System.arraycopy(lastName_, 0, byteCode, xIdx, 8);
+ code = byteCode;
+
+ Code co;
+ try {
+ co = (Code) loader_.loadClass("Code").newInstance();
+ } catch (InstantiationException ie) {
+ throw new RunaboutException(ie.toString());
+ } catch (ClassNotFoundException cnfe) {
+ throw new RunaboutException(cnfe.toString());
+ } catch (IllegalArgumentException iae) {
+ throw new RunaboutException(iae.toString());
+ } catch (ClassFormatError cfe) {
+ throw new RunaboutException(cfe.toString());
+ } catch (IllegalAccessException iae) {
+ throw new RunaboutException(iae.toString());
+ }
+ code = null; // help GC
+ return co;
+ }
+
+ /**
+ * Obtain a map from the cache.
+ */
+ synchronized HashMap<Class, Runabout.Code> get(Runabout r) {
+ Class c = r.getClass();
+ HashMap<Class, Runabout.Code> map = cachemap_.get(c);
+ if (map == null) {
+ map = r.makeMap();
+ cachemap_.put(c, map);
+ }
+ return map;
+ }
+
+ } // end of Runabout.Cache
+
+ /**
+ * Code is the generic interface that all generated classes implement. It
is
+ * used to quickly map a given class to the appropriate visit method.
+ *
+ * @author Christian Grothoff
+ */
+ public static abstract class Code {
+ public Code() {
+ }
+
+ public abstract void visit(Runabout r, Object o);
+
+ } // end of Runabout.Code
+
+ /**
+ * Implementation of Code that is called if no visit method matches (calls
+ * visitDefault).
+ *
+ * @author Christian Grothoff
+ */
+ static final class NoCode extends Code {
+ public final void visit(Runabout r, Object o) {
+ r.visitDefault(o);
+ }
+ } // end of Runabout.NoCode
+
+ /**
+ * Override this method to provide a default behavior when no other visit
+ * matches. The Runabout semantics are to search for a visit(X) and if
there
+ * is no match, call visitDefault(). As usual with the Runabout, visit(X)
+ * looks at classes before interfaces. By default, visitDefault throws an
+ * exception.
+ */
+ protected void visitDefault(Object o) {
+ throw new RunaboutException("No visit method defined in "
+ + this.getClass() + " for " + o.getClass());
+ }
+
+ /**
+ * Generic Exception for problems in the Runabout.
+ *
+ * @author Christian Grothoff
+ */
+ public static final class RunaboutException extends RuntimeException {
+ RunaboutException(String s) {
+ super(s);
+ }
+ }
+
+ /**
+ * Compile 'GenCodeXXXXXXXX.java' with the option '-g:none' to tell javac
+ * not to include any debugging information. This is the generated class
+ * file.
+ */
+ private final static byte genCodeTemplate[] = {-54, -2, -70, -66, 0, 0, 0,
+ 49, 0, 22, 10, 0, 6, 0, 12, 7, 0, 13, 7, 0, 14, 10, 0, 2, 0, 15, 7,
+ 0, 16, 7, 0, 18, 1, 0, 6, 60, 105, 110, 105, 116, 62, 1, 0, 3, 40,
+ 41, 86, 1, 0, 4, 67, 111, 100, 101, 1, 0, 5, 118, 105, 115, 105,
+ 116, 1, 0, 44, 40, 76, 111, 114, 103, 47, 103, 114, 111, 116, 104,
+ 111, 102, 102, 47, 82, 117, 110, 97, 98, 111, 117, 116, 59, 76,
+ 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99,
+ 116, 59, 41, 86, 12, 0, 7, 0, 8, 1, 0, 28, 111, 114, 103, 47, 103,
+ 114, 111, 116, 104, 111, 102, 102, 47, 82, 117, 110, 97, 98, 111,
+ 117, 116, 69, 120, 97, 109, 112, 108, 101, 1, 0, 16, 106, 97, 118,
+ 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 12, 0,
+ 10, 0, 20, 1, 0, 28, 111, 114, 103, 47, 103, 114, 111, 116, 104,
+ 111, 102, 102, 47, 71, 101, 110, 67, 111, 100, 101, 88, 88, 88, 88,
+ 88, 88, 88, 88, 7, 0, 21, 1, 0, 26, 111, 114, 103, 47, 103, 114,
+ 111, 116, 104, 111, 102, 102, 47, 82, 117, 110, 97, 98, 111, 117,
+ 116, 36, 67, 111, 100, 101, 1, 0, 12, 73, 110, 110, 101, 114, 67,
+ 108, 97, 115, 115, 101, 115, 1, 0, 21, 40, 76, 106, 97, 118, 97,
+ 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 41, 86,
+ 1, 0, 21, 111, 114, 103, 47, 103, 114, 111, 116, 104, 111, 102,
+ 102, 47, 82, 117, 110, 97, 98, 111, 117, 116, 0, 33, 0, 5, 0, 6, 0,
+ 0, 0, 0, 0, 2, 0, 1, 0, 7, 0, 8, 0, 1, 0, 9, 0, 0, 0, 17, 0, 1, 0,
+ 1, 0, 0, 0, 5, 42, -73, 0, 1, -79, 0, 0, 0, 0, 0, 1, 0, 10, 0, 11,
+ 0, 1, 0, 9, 0, 0, 0, 24, 0, 2, 0, 3, 0, 0, 0, 12, 43, -64, 0, 2,
+ 44, -64, 0, 3, -74, 0, 4, -79, 0, 0, 0, 0, 0, 1, 0, 19, 0, 0, 0,
+ 10, 0, 1, 0, 6, 0, 17, 0, 9, 4, 9}; // GenCodeXXXXXXXX.class
+
+ public static void main(String[] args) {
+ Runabout r = new Runabout() {
+ public void visit(String s) {
+ System.out.println("hi!!");
+ }
+ };
+ r.visitAppropriate("foo");
+ }
+
+} // end of Runabout
Added: gnunet-java/src/main/java/org/grothoff/package-info.java
===================================================================
--- gnunet-java/src/main/java/org/grothoff/package-info.java
(rev 0)
+++ gnunet-java/src/main/java/org/grothoff/package-info.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,4 @@
+/**
+ * Pure java implementation of single argument multiple dispatch
+ */
+package org.grothoff;
Added: gnunet-java/src/main/resources/org/gnunet/construct/MsgMap.txt
===================================================================
--- gnunet-java/src/main/resources/org/gnunet/construct/MsgMap.txt
(rev 0)
+++ gnunet-java/src/main/resources/org/gnunet/construct/MsgMap.txt
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,46 @@
+org.gnunet.util.Resolver$Address|0=org.gnunet.util.Resolver$TextualAddress
+org.gnunet.util.Resolver$Address|1=org.gnunet.util.Resolver$NumericAddress
+org.gnunet.util.GnunetMessage$Body|68=org.gnunet.core.DisconnectNotifyMessage
+org.gnunet.util.GnunetMessage$Body|274=org.gnunet.mesh.TunnelDestroyMessage
+org.gnunet.util.GnunetMessage$Body|1=org.gnunet.util.TestMessage
+org.gnunet.util.GnunetMessage$Body|70=org.gnunet.core.NotifyInboundTrafficMessage
+org.gnunet.util.GnunetMessage$Body|273=org.gnunet.mesh.TunnelCreateMessage
+org.gnunet.util.GnunetMessage$Body|71=org.gnunet.core.NotifyOutboundTrafficMessage
+org.gnunet.util.GnunetMessage$Body|272=org.gnunet.mesh.ClientConnectMessage
+org.gnunet.util.GnunetMessage$Body|64=org.gnunet.core.InitMessage
+org.gnunet.util.GnunetMessage$Body|4=org.gnunet.util.Resolver$GetMessage
+org.gnunet.util.GnunetMessage$Body|65=org.gnunet.core.InitReplyMessage
+org.gnunet.util.GnunetMessage$Body|5=org.gnunet.util.Resolver$ResolverResponse
+org.gnunet.util.GnunetMessage$Body|143=org.gnunet.dht.ClientGetMessage
+org.gnunet.util.GnunetMessage$Body|67=org.gnunet.core.ConnectNotifyMessage
+org.gnunet.util.GnunetMessage$Body|142=org.gnunet.dht.ClientPutMessage
+org.gnunet.util.GnunetMessage$Body|76=org.gnunet.core.SendMessage
+org.gnunet.util.GnunetMessage$Body|286=org.gnunet.mesh.LocalAckMessage
+org.gnunet.util.GnunetMessage$Body|74=org.gnunet.core.SendMessageRequest
+org.gnunet.util.GnunetMessage$Body|75=org.gnunet.core.SendMessageReady
+org.gnunet.util.GnunetMessage$Body|153=org.gnunet.dht.MonitorStartStop
+org.gnunet.util.GnunetMessage$Body|155=org.gnunet.dht.ClientPutConfirmationMessage
+org.gnunet.util.GnunetMessage$Body|323=org.gnunet.nse.UpdateMessage
+org.gnunet.util.GnunetMessage$Body|260=org.gnunet.mesh.DataMessage
+org.gnunet.util.GnunetMessage$Body|321=org.gnunet.nse.StartMessage
+org.gnunet.util.GnunetMessage$Body|144=org.gnunet.dht.ClientGetStopMessage
+org.gnunet.util.GnunetMessage$Body|145=org.gnunet.dht.ClientResultMessage
+org.gnunet.util.GnunetMessage$Body|332=org.gnunet.peerinfo.InfoMessage
+org.gnunet.util.GnunetMessage$Body|333=org.gnunet.peerinfo.InfoEnd
+org.gnunet.util.GnunetMessage$Body|149=org.gnunet.dht.MonitorGetMessage
+org.gnunet.util.GnunetMessage$Body|331=org.gnunet.peerinfo.ListAllPeersMessage
+org.gnunet.util.GnunetMessage$Body|150=org.gnunet.dht.MonitorGetRespMessage
+org.gnunet.util.GnunetMessage$Body|151=org.gnunet.dht.MonitorPutMessage
+org.gnunet.util.GnunetMessage$Body|171=org.gnunet.statistics.GetResponseEndMessage
+org.gnunet.util.GnunetMessage$Body|170=org.gnunet.statistics.GetResponseMessage
+org.gnunet.util.GnunetMessage$Body|169=org.gnunet.statistics.GetMessage
+org.gnunet.util.GnunetMessage$Body|168=org.gnunet.statistics.SetMessage
+org.gnunet.util.GnunetMessage$Body|374=org.gnunet.transport.RequestConnectMessage
+org.gnunet.util.GnunetMessage$Body|173=org.gnunet.statistics.WatchResponseMessage
+org.gnunet.util.GnunetMessage$Body|172=org.gnunet.statistics.WatchMessage
+org.gnunet.util.GnunetMessage$Body|524=org.gnunet.consensus.ConcludeMessage
+org.gnunet.util.GnunetMessage$Body|521=org.gnunet.consensus.InsertElementMessage
+org.gnunet.util.GnunetMessage$Body|523=org.gnunet.consensus.NewElementMessage
+org.gnunet.util.GnunetMessage$Body|360=org.gnunet.transport.StartMessage
+org.gnunet.construct.MessageUnion|525=org.gnunet.consensus.ConcludeDoneMessage
+# generated 2013/08/22 21:29:40
Added: gnunet-java/src/test/java/org/gnunet/construct/ByteFillMessage.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/construct/ByteFillMessage.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/construct/ByteFillMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,32 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+
+public class ByteFillMessage implements Message {
+
+ @UInt32
+ public int someValue;
+
+ @FillWith @UInt8
+ public byte[] rest;
+
+}
Added: gnunet-java/src/test/java/org/gnunet/construct/ConstructTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/construct/ConstructTest.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/construct/ConstructTest.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,82 @@
+package org.gnunet.construct;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Random;
+
+/**
+ * @author Florian Dold
+ */
+public class ConstructTest {
+ public static class ByteFillTestMessage implements Message {
+ @FrameSize
+ @UInt32
+ public int frameSize;
+ @FillWith @UInt8
+ public byte[] bytes;
+ }
+
+ @Test
+ public void test_ByteFill() {
+ ByteFillTestMessage msg = new ByteFillTestMessage();
+ msg.bytes = new byte[]{0,1,2,3};
+ Construct.patch(msg);
+ byte[] bin = Construct.toBinary(msg);
+
+ ByteFillTestMessage msg_r = Construct.parseAs(bin,
ByteFillTestMessage.class);
+
+ Assert.assertArrayEquals(new byte[]{0,1,2,3}, msg_r.bytes);
+ }
+
+
+ @Test
+ public void test_IntMessage() {
+ IntMessage im = new IntMessage();
+ Random r = new Random();
+ im.i1 = r.nextLong();
+ im.i2 = r.nextLong();
+ im.i3 = r.nextLong();
+ im.i4 = r.nextLong();
+ im.i5 = r.nextLong();
+ im.i6 = r.nextLong();
+ im.i7 = r.nextLong();
+ im.i8 = r.nextLong();
+
+ byte[] data = Construct.toBinary(im);
+
+ Construct.parseAs(data, IntMessage.class);
+
+ Assert.assertEquals((1+2+4+8)*2, data.length);
+ Assert.assertEquals((1+2+4+8)*2, Construct.getStaticSize(im));
+ }
+
+ @Test(expected = AssertionError.class)
+ public void test_PrivateMemberMessage() {
+ PrivateMemberMessage m1 = new PrivateMemberMessage();
+ byte[] data = Construct.toBinary(m1);
+ Construct.parseAs(data, PrivateMemberMessage.class);
+ }
+
+
+ @Test
+ public void test_variable_size() {
+ VariableSizeMessage m1 = new VariableSizeMessage();
+ m1.n1 = 2;
+ m1.n2 = 3;
+ m1.a1 = new int[]{42,43};
+ m1.a2 = new int[]{1,2,1000};
+
+ byte[] data = Construct.toBinary(m1);
+
+ VariableSizeMessage m2 = Construct.parseAs(data,
VariableSizeMessage.class);
+
+ Assert.assertEquals(m1.n1, m2.n1);
+ Assert.assertEquals(m1.n2, m2.n2);
+ Assert.assertArrayEquals(m1.a1, m2.a1);
+ Assert.assertArrayEquals(m1.a2, m2.a2);
+ }
+
+
+}
+
Added: gnunet-java/src/test/java/org/gnunet/construct/DoubleTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/construct/DoubleTest.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/construct/DoubleTest.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,35 @@
+package org.gnunet.construct;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class DoubleTest {
+ public static class DoubleMessage implements Message {
+ @DoubleValue
+ public double d1;
+ @DoubleValue
+ public double d2;
+ }
+
+ @Test
+ public void test_double() {
+ DoubleMessage m = new DoubleMessage();
+ m.d1 = 1.123;
+ m.d2 = java.lang.Double.NaN;
+
+ byte[] data = Construct.toBinary(m);
+
+ DoubleMessage m2 = Construct.parseAs(data, DoubleMessage.class);
+
+ Assert.assertEquals(m.d1, m2.d1, 0);
+ Assert.assertEquals(m.d2, m2.d2, 0);
+
+ Assert.assertEquals(8+8, data.length);
+ }
+
+}
Added: gnunet-java/src/test/java/org/gnunet/construct/FillParserTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/construct/FillParserTest.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/construct/FillParserTest.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,37 @@
+package org.gnunet.construct;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class FillParserTest {
+
+ public static class FillTestMessage implements Message {
+ @FrameSize
+ @UInt32
+ public int size;
+ @FillWith
+ public StringTuple[] strings;
+ }
+
+ @Test
+ public void test_fillParser() {
+ FillTestMessage m = new FillTestMessage();
+ m.strings = new StringTuple[]{new StringTuple("foo", "bar"), new
StringTuple("quux", "spam")};
+ Construct.patch(m);
+ System.out.println(m.size);
+ byte[] data = Construct.toBinary(m);
+ Assert.assertEquals(m.size, data.length);
+
+ FillTestMessage m2 = Construct.parseAs(data, FillTestMessage.class);
+
+ Assert.assertEquals(m.strings.length, m2.strings.length);
+
+ Assert.assertEquals(m.strings[0], m2.strings[0]);
+ Assert.assertEquals(m.strings[1], m2.strings[1]);
+ }
+}
Added: gnunet-java/src/test/java/org/gnunet/construct/FixedSizeTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/construct/FixedSizeTest.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/construct/FixedSizeTest.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,52 @@
+package org.gnunet.construct;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class FixedSizeTest {
+
+ public static class Msg implements Message {
+ @UInt8
+ public int v;
+
+ public Msg() {
+ // default ctor required by Construct
+ }
+
+ public Msg(int v) {
+ this.v = v;
+ }
+ }
+
+ public static class FixedSizeTestMessage implements Message {
+ @FixedSizeArray(length = 4)
+ public Msg[] msgs;
+ }
+
+
+ @Test
+ public void test_fixedNested() {
+ FixedSizeTestMessage m = new FixedSizeTestMessage();
+ m.msgs = new Msg[]{new Msg(1), new Msg(2), new Msg(3), new Msg(4)};
+ byte[] bytes = Construct.toBinary(m);
+
+ FixedSizeTestMessage m2 = Construct.parseAs(bytes,
FixedSizeTestMessage.class);
+
+ Assert.assertEquals(m.msgs[0].v, m2.msgs[0].v);
+ Assert.assertEquals(m.msgs[1].v, m2.msgs[1].v);
+ Assert.assertEquals(m.msgs[2].v, m2.msgs[2].v);
+ Assert.assertEquals(m.msgs[3].v, m2.msgs[3].v);
+ }
+
+ @Test(expected = AssertionError.class)
+ public void test_sizeMismatch() {
+ FixedSizeTestMessage m = new FixedSizeTestMessage();
+ m.msgs = new Msg[]{new Msg(1), new Msg(2)};
+ Construct.toBinary(m);
+ }
+}
Added: gnunet-java/src/test/java/org/gnunet/construct/FrameSizeTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/construct/FrameSizeTest.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/construct/FrameSizeTest.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,50 @@
+package org.gnunet.construct;
+
+import org.junit.Assert;
+import org.gnunet.util.GnunetMessage;
+import org.junit.Test;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class FrameSizeTest {
+ public static class CoordMessage implements Message {
+ @FrameSize
+ @UInt32
+ public int size;
+ @UInt32
+ public int x;
+ @UInt8
+ public int y;
+ }
+
+ public static class RecursiveMessage implements Message {
+ @FrameSize
+ @UInt32
+ public int size;
+
+ @ZeroTerminatedString
+ public String data;
+
+ @NestedMessage(newFrame = true, optional = true)
+ public RecursiveMessage rec;
+
+ }
+
+ @Test
+ public void test_simple() {
+ CoordMessage m = new CoordMessage();
+ Construct.patch(m);
+ Assert.assertEquals(9, m.size);
+ }
+
+
+ //@Test
+ public void test_recursive_1() {
+ RecursiveMessage rm = new RecursiveMessage();
+ rm.data = "foo";
+ Construct.patch(rm);
+ }
+}
Added: gnunet-java/src/test/java/org/gnunet/construct/IntMessage.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/construct/IntMessage.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/construct/IntMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,25 @@
+package org.gnunet.construct;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class IntMessage implements Message {
+ @UInt64
+ public long i1;
+ @UInt32
+ public long i2;
+ @UInt16
+ public long i3;
+ @UInt8
+ public long i4;
+ @Int64
+ public long i5;
+ @Int32
+ public long i6;
+ @Int16
+ public long i7;
+ @Int8
+ public long i8;
+}
Added: gnunet-java/src/test/java/org/gnunet/construct/OptionalUnionTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/construct/OptionalUnionTest.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/construct/OptionalUnionTest.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,72 @@
+package org.gnunet.construct;
+
+import org.junit.Assert;
+import org.gnunet.util.GnunetMessage;
+import org.junit.Test;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class OptionalUnionTest {
+ public interface TestUnion extends MessageUnion {}
+ @UnionCase(1)
+ public static class UnionMember1 implements TestUnion {
+ @ZeroTerminatedString
+ public String str;
+ }
+ @UnionCase(2)
+ public static class UnionMember2 implements TestUnion {
+ @Int32
+ public int i;
+ }
+
+ public static class OptionalUnionMessage implements Message {
+ @FrameSize
+ @UInt32
+ public int size;
+ @UInt32
+ public int tag;
+ @Union(tag = "tag", optional = true)
+ public TestUnion x;
+ }
+
+ public void setupMessageMap() {
+ MessageLoader.registerUnionCase(TestUnion.class, UnionMember1.class,
1);
+ MessageLoader.registerUnionCase(TestUnion.class, UnionMember2.class,
2);
+ }
+
+ @Test
+ public void test_optional_union1() {
+ setupMessageMap();
+
+ OptionalUnionMessage m = new OptionalUnionMessage();
+ UnionMember1 u1 = new UnionMember1();
+ u1.str = "foo";
+ m.x = u1;
+
+ Construct.patch(m);
+ byte[] data = Construct.toBinary(m);
+
+ System.out.println(data.length);
+
+ OptionalUnionMessage m2 = Construct.parseAs(data,
OptionalUnionMessage.class);
+
+ Assert.assertNotNull(m2.x);
+ }
+
+ @Test
+ public void test_optional_union2() {
+ setupMessageMap();
+
+ OptionalUnionMessage m = new OptionalUnionMessage();
+
+ byte[] data = Construct.toBinary(m);
+
+ OptionalUnionMessage m2 = Construct.parseAs(data,
OptionalUnionMessage.class);
+
+ Assert.assertNull(m2.x);
+
+ }
+}
Added: gnunet-java/src/test/java/org/gnunet/construct/PrivateMemberMessage.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/construct/PrivateMemberMessage.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/construct/PrivateMemberMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,13 @@
+package org.gnunet.construct;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class PrivateMemberMessage implements Message {
+ @UInt32
+ public int foo;
+ @UInt32
+ private int bar;
+}
Added: gnunet-java/src/test/java/org/gnunet/construct/QueryMessage.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/construct/QueryMessage.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/construct/QueryMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,31 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+public class QueryMessage implements Message {
+
+
+ @UInt8
+ public int query;
+
+ @FillWith @UInt8
+ public byte[] varsize;
+}
Added: gnunet-java/src/test/java/org/gnunet/construct/SendMessageTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/construct/SendMessageTest.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/construct/SendMessageTest.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,34 @@
+package org.gnunet.construct;
+
+import org.gnunet.core.SendMessage;
+import org.gnunet.util.AbsoluteTime;
+import org.gnunet.util.GnunetMessage;
+import org.gnunet.util.PeerIdentity;
+import org.gnunet.util.TestMessage;
+import org.junit.Test;
+
+/**
+ * Regression test for a message class in org.gnunet.core
+ *
+ * todo: should this test be really here?
+ *
+ * @author Florian Dold
+ */
+public class SendMessageTest {
+
+ @Test
+ public void test_patch() {
+ SendMessage m = new SendMessage();
+ m.deadline = AbsoluteTime.FOREVER.asMessage();
+ m.peer = new PeerIdentity(); // null identity
+ m.payloadMessage = new GnunetMessage();
+ m.payloadMessage.body = new TestMessage();
+ m.payloadMessage.header = new GnunetMessage.Header();
+
+ GnunetMessage container = new GnunetMessage();
+ container.body = m;
+ container.header = new GnunetMessage.Header();
+
+ Construct.patch(container);
+ }
+}
Added: gnunet-java/src/test/java/org/gnunet/construct/StringMessage.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/construct/StringMessage.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/construct/StringMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,32 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.construct;
+
+public class StringMessage implements Message {
+ @UInt8
+ public int num;
+
+ @ZeroTerminatedString
+ public String str;
+
+ @UInt8
+ public int num2;
+}
Added: gnunet-java/src/test/java/org/gnunet/construct/StringTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/construct/StringTest.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/construct/StringTest.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,50 @@
+package org.gnunet.construct;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class StringTest {
+ public static class StrMsg implements Message {
+ @FrameSize
+ @UInt32
+ public int len;
+ @ZeroTerminatedString(optional = false)
+ public String str1;
+ @ZeroTerminatedString(optional = true)
+ public String str2;
+ }
+
+
+ @Test
+ public void test_empty() {
+ StrMsg m = new StrMsg();
+ m.str1 = "";
+ m.str2 = "";
+ Construct.patch(m);
+ byte[] data = Construct.toBinary(m);
+ Assert.assertEquals(4+1+1, data.length);
+ StrMsg m2 = Construct.parseAs(data, StrMsg.class);
+ Assert.assertEquals("", m2.str1);
+ Assert.assertEquals("", m2.str2);
+ }
+
+ @Test
+ public void test_null() {
+ StrMsg m = new StrMsg();
+ m.str1 = "";
+ m.str2 = null;
+ Construct.patch(m);
+ byte[] data = Construct.toBinary(m);
+ Assert.assertEquals(4+1, data.length);
+ Assert.assertEquals(4+1, m.len);
+ StrMsg m2 = Construct.parseAs(data, StrMsg.class);
+ Assert.assertEquals("", m2.str1);
+ Assert.assertEquals(null, m2.str2);
+ }
+}
+
Added: gnunet-java/src/test/java/org/gnunet/construct/StringTuple.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/construct/StringTuple.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/construct/StringTuple.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,37 @@
+package org.gnunet.construct;
+
+import com.google.common.base.Objects;
+import com.google.common.hash.HashCodes;
+
+/**
+* ...
+*
+* @author Florian Dold
+*/
+public class StringTuple implements Message {
+ @ZeroTerminatedString
+ public String str1;
+ @ZeroTerminatedString
+ public String str2;
+
+ public StringTuple() {
+ // empty default ctor needed by Construct
+ }
+ public StringTuple(String str1, String str2) {
+ this.str1 = str1;
+ this.str2 = str2;
+ }
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof StringTuple)) {
+ return false;
+ }
+ StringTuple otherT = (StringTuple) other;
+ return otherT.str1.equals(this.str1) && otherT.str2.equals(this.str2);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(str1, str2);
+ }
+}
Added: gnunet-java/src/test/java/org/gnunet/construct/VariableSizeArrayTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/construct/VariableSizeArrayTest.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/construct/VariableSizeArrayTest.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,33 @@
+package org.gnunet.construct;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class VariableSizeArrayTest {
+ public static class VariableTestMessage implements Message {
+ @UInt32
+ public int num;
+ @VariableSizeArray(lengthField = "num")
+ public StringTuple[] msgs;
+ }
+
+ @Test
+ public void test_variableSizeArray() {
+ VariableTestMessage m = new VariableTestMessage();
+ m.msgs = new StringTuple[]{new StringTuple("foo", "bar"), new
StringTuple("quux", "baz"), new StringTuple("spam", "eggs")};
+ Construct.patch(m);
+ Assert.assertEquals(3, m.num);
+ byte[] data = Construct.toBinary(m);
+ VariableTestMessage m2 = Construct.parseAs(data,
VariableTestMessage.class);
+ Assert.assertEquals(m2.num, 3);
+ Assert.assertEquals(m.msgs[0], m2.msgs[0]);
+ Assert.assertEquals(m.msgs[1], m2.msgs[1]);
+ Assert.assertEquals(m.msgs[2], m2.msgs[2]);
+
+ }
+}
Added: gnunet-java/src/test/java/org/gnunet/construct/VariableSizeMessage.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/construct/VariableSizeMessage.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/construct/VariableSizeMessage.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,17 @@
+package org.gnunet.construct;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class VariableSizeMessage implements Message {
+ @UInt16
+ public int n1;
+ @VariableSizeIntegerArray(lengthField = "n1", signed = false, bitSize = 16)
+ public int[] a1;
+ @UInt16
+ public int n2;
+ @VariableSizeIntegerArray(lengthField = "n2", signed = false, bitSize = 16)
+ public int[] a2;
+}
Added: gnunet-java/src/test/java/org/gnunet/core/CoreTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/core/CoreTest.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/core/CoreTest.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,111 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.core;
+
+
+import org.gnunet.testing.TestingFixture;
+import org.gnunet.testing.TestingSetup;
+import org.gnunet.testing.TestingSubsystem;
+import org.gnunet.util.*;
+import org.grothoff.Runabout;
+import org.junit.Assert;
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+
+public class CoreTest extends TestingFixture {
+ @Test(timeout = 10000)
+ public void test_core_init() {
+ Program.configureLogging("DEBUG");
+ TestingSubsystem ts = new TestingSubsystem("core");
+
+ final Wrapper<Boolean> res = new Wrapper<Boolean>(false);
+
+ final Core core = new Core(ts.getConfiguration());
+ core.observeConnect(new ConnectHandler() {
+ @Override
+ public void onConnect(PeerIdentity peerIdentity) {
+ }
+ });
+ core.init(new InitCallback() {
+ @Override
+ public void onInit(PeerIdentity myIdentity) {
+ res.value = true;
+ System.out.println("in core init");
+ assertTrue(myIdentity != null);
+ core.disconnect();
+ }
+ });
+
+ Scheduler.run();
+
+ ts.destroy();
+
+ assertTrue(res.value);
+ }
+
+
+ @Test(timeout = 10000)
+ public void test_core_echo() {
+ Program.configureLogging("DEBUG");
+ new TestingSubsystem("core");
+ new TestingSubsystem("core");
+ new TestingSubsystem("core");
+ new TestingSubsystem("core");
+ TestingSubsystem ts = new TestingSubsystem("core");
+
+ final Wrapper<Boolean> gotResponse = new Wrapper<Boolean>(false);
+
+ final Core core = new Core(ts.getConfiguration());
+ core.setMessageHandler(new Runabout() {
+ public void visit(TestMessage t) {
+ gotResponse.set(true);
+ core.disconnect();
+ }
+ });
+
+ core.init(new InitCallback() {
+ @Override
+ public void onInit(PeerIdentity myIdentity) {
+ System.out.println("in core init");
+ core.notifyTransmitReady(0, RelativeTime.FOREVER, myIdentity,
4, new MessageTransmitter() {
+ @Override
+ public void transmit(Connection.MessageSink sink) {
+ System.out.println("ntr called, calling send");
+ sink.send(new TestMessage());
+ }
+
+ @Override
+ public void handleError() {
+ Assert.fail();
+ }
+ });
+ }
+ });
+
+ Scheduler.run();
+
+ ts.destroy();
+
+ assertTrue(gotResponse.get());
+
+ }
+}
Added: gnunet-java/src/test/java/org/gnunet/dht/DHTTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/dht/DHTTest.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/dht/DHTTest.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,171 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.dht;
+
+import static org.junit.Assert.*;
+
+import org.gnunet.testing.TestingFixture;
+import org.gnunet.testing.TestingSubsystem;
+import org.gnunet.util.*;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.EnumSet;
+import java.util.List;
+
+public class DHTTest extends TestingFixture {
+ @Test(timeout = 1000)
+ public void test_dht_put() {
+ Program.configureLogging();
+
+ final Wrapper<Boolean> putFinished = new Wrapper<Boolean>(true);
+
+ TestingSubsystem ts = new TestingSubsystem("dht");
+
+ final DistributedHashTable dht = new
DistributedHashTable(ts.getConfiguration());
+ dht.put(new HashCode("gnj-test"), new byte[]{1, 2, 3}, 1,
EnumSet.noneOf(RouteOption.class),
+ BlockType.TEST.val, RelativeTime.HOUR.toAbsolute(),
RelativeTime.FOREVER, new Continuation() {
+ @Override
+ public void cont(boolean success) {
+ putFinished.set(true);
+ dht.destroy();
+ }
+ });
+
+ Scheduler.run();
+ Assert.assertTrue(putFinished.get());
+ }
+
+ @Test
+ public void test_dht_put_get() {
+ Program.configureLogging();
+
+ final Wrapper<Boolean> getFinished = new Wrapper<Boolean>(true);
+
+ TestingSubsystem ts = new TestingSubsystem("dht");
+
+ final HashCode hash1 = new HashCode("gnj-test");
+ final byte[] data = new byte[]{1, 2, 3};
+
+ final DistributedHashTable dht = new
DistributedHashTable(ts.getConfiguration());
+ dht.put(hash1, data, 1, EnumSet.noneOf(RouteOption.class),
+ BlockType.TEST.val, RelativeTime.HOUR.toAbsolute(),
RelativeTime.FOREVER, new Continuation() {
+ @Override
+ public void cont(boolean success) {
+ dht.startGet(RelativeTime.FOREVER, BlockType.TEST.val, hash1,
1, EnumSet.noneOf(RouteOption.class), null, new ResultCallback() {
+ @Override
+ public void handleResult(AbsoluteTime expiration, HashCode
key, List<PeerIdentity> getPath, List<PeerIdentity> putPath, BlockType type,
byte[] recData) {
+ assertArrayEquals(data, recData);
+ getFinished.set(true);
+ dht.destroy();
+ }
+ });
+ }
+ });
+
+ Scheduler.run();
+ Assert.assertTrue(getFinished.get());
+ }
+
+
+ @Test(timeout = 500)
+ public void test_dht_monitor_put() {
+ Program.configureLogging();
+
+ final Wrapper<Integer> putMonitorCount = new Wrapper<Integer>(0);
+
+ TestingSubsystem ts = new TestingSubsystem("dht");
+
+ final HashCode hash = new HashCode("gnj-test");
+ final byte[] data1 = new byte[]{1, 2, 3};
+
+ final byte[] data2 = new byte[]{5, 4, 1, 2, 6};
+
+ final DistributedHashTable dht = new
DistributedHashTable(ts.getConfiguration());
+
+ dht.startMonitor(BlockType.TEST.val, hash, null, null, new
MonitorPutHandler() {
+ @Override
+ public void onPut(int options, int type, int hop_count,
AbsoluteTimeMessage expirationTime, PeerIdentity[] putPath, HashCode key,
byte[] data) {
+ putMonitorCount.set(putMonitorCount.get() + 1);
+ if (putMonitorCount.get() == 2) {
+ dht.destroy();
+ }
+ }
+ });
+
+ Scheduler.addDelayed(new RelativeTime(50), new Scheduler.Task() {
+ @Override
+ public void run(Scheduler.RunContext ctx) {
+ dht.put(hash, data1, 1, EnumSet.noneOf(RouteOption.class),
BlockType.TEST.val, RelativeTime.HOUR.toAbsolute(), RelativeTime.FOREVER, null);
+ }
+ });
+
+
+ Scheduler.addDelayed(new RelativeTime(100), new Scheduler.Task() {
+ @Override
+ public void run(Scheduler.RunContext ctx) {
+ dht.put(hash, data2, 1, EnumSet.noneOf(RouteOption.class),
BlockType.TEST.val, RelativeTime.HOUR.toAbsolute(), RelativeTime.FOREVER, null);
+ }
+ });
+
+
+ Scheduler.run();
+ Assert.assertTrue(putMonitorCount.get() == 2);
+ }
+
+ @Test(timeout = 500)
+ public void test_dht_monitor_get() {
+ Program.configureLogging("debug");
+
+ final Wrapper<Boolean> ok = new Wrapper<Boolean>(false);
+
+ TestingSubsystem ts = new TestingSubsystem("dht");
+
+ final HashCode hash = new HashCode("gnj-test");
+
+ final DistributedHashTable dht1 = new
DistributedHashTable(ts.getConfiguration());
+ final DistributedHashTable dht2 = new
DistributedHashTable(ts.getConfiguration());
+
+ dht1.startMonitor(BlockType.TEST.val, hash, new MonitorGetHandler() {
+ @Override
+ public void onGet(int options, int type, int hop_count, int
desired_replication_level, PeerIdentity[] getPath, HashCode key) {
+ System.out.println("here!");
+ ok.set(true);
+ dht2.destroy();
+ dht1.destroy();
+ }
+ }, null, null);
+
+ Scheduler.addDelayed(RelativeTime.fromMilliseconds(50), new
Scheduler.Task() {
+ @Override
+ public void run(Scheduler.RunContext ctx) {
+ dht2.startGet(RelativeTime.FOREVER, BlockType.TEST.val, hash,
1, EnumSet.noneOf(RouteOption.class), null, null);
+ }
+ });
+
+
+ Scheduler.run();
+ Assert.assertTrue(ok.get());
+ }
+
+
+}
+
Added: gnunet-java/src/test/java/org/gnunet/mesh/MeshTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/mesh/MeshTest.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/mesh/MeshTest.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,47 @@
+package org.gnunet.mesh;
+
+import org.gnunet.testing.TestingFixture;
+import org.gnunet.testing.TestingSubsystem;
+import org.gnunet.util.*;
+import org.junit.Test;
+import java.lang.Void;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class MeshTest extends TestingFixture {
+ public static class MessageHandler1 extends MeshRunabout {
+ public Mesh m1;
+ public Mesh m2;
+ public void visit(TestMessage m) {
+ m1.destroy();
+ m2.destroy();
+ }
+ }
+ //@Test
+ public void test_mesh_send() {
+ Program.configureLogging("DEBUG");
+ final TestingSubsystem ts = new TestingSubsystem("mesh");
+ Configuration cfg = ts.getConfiguration();
+ MessageHandler1 mh = new MessageHandler1();
+ final Mesh mesh1 = new Mesh(cfg, null, null, null);
+ final Mesh mesh2 = new Mesh(cfg, new InboundTunnelHandler() {
+ @Override
+ public void onInboundTunnel(Mesh.Tunnel tunnel, PeerIdentity
initiator) {
+
+ }
+ }, new TunnelEndHandler() {
+ @Override
+ public void onTunnelEnd(Mesh.Tunnel tunnel) {
+
+ }
+ }, mh, 42);
+ mh.m1 = mesh1;
+ mh.m2 = mesh2;
+ Mesh.Tunnel<Void> tunnel = mesh2.createTunnel(null, 42, false, true,
null);
+ tunnel.send(new TestMessage());
+ Scheduler.run();
+ }
+}
Added: gnunet-java/src/test/java/org/gnunet/nse/NSETest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/nse/NSETest.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/nse/NSETest.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,56 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.nse;
+
+import org.gnunet.testing.TestingSetup;
+import org.gnunet.testing.TestingSubsystem;
+import org.gnunet.util.AbsoluteTime;
+import org.gnunet.util.Scheduler;
+import org.gnunet.util.Wrapper;
+import org.junit.Test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author Florian Dold
+ */
+public class NSETest {
+ @Test
+ public void test_nse() {
+ final Wrapper<Boolean> gotResult = new Wrapper<Boolean>(false);
+ TestingSubsystem ts = new TestingSubsystem("nse");
+
+ final NetworkSizeEstimation nse = new
NetworkSizeEstimation(ts.getConfiguration());
+ nse.subscribe(new NetworkSizeEstimation.Subscriber() {
+ @Override
+ public void update(AbsoluteTime timestamp, double estimate, double
deviation) {
+ assertNotNull(timestamp);
+ gotResult.set(true);
+ nse.disconnect();
+ }
+ });
+
+ Scheduler.run();
+
+ assertTrue(gotResult.get());
+ }
+}
Added: gnunet-java/src/test/java/org/gnunet/peerinfo/PeerInfoTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/peerinfo/PeerInfoTest.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/peerinfo/PeerInfoTest.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,41 @@
+package org.gnunet.peerinfo;
+
+import org.gnunet.hello.HelloMessage;
+import org.gnunet.testing.TestingSubsystem;
+import org.gnunet.util.*;
+import org.junit.Test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class PeerInfoTest {
+
+ @Test
+ public void test_peerinfo() {
+ Program.configureLogging("debug");
+ final Wrapper<Boolean> ended = new Wrapper<Boolean>(false);
+ TestingSubsystem ts = new TestingSubsystem("peerinfo");
+ final PeerInfo peerInfo = new PeerInfo(ts.getConfiguration());
+
+ peerInfo.iterate(RelativeTime.FOREVER, false, new PeerProcessor() {
+ @Override
+ public void onPeer(PeerIdentity peerIdentity, HelloMessage hello) {
+ // we can't expect to get anything here, peerinfo is the only
running service in this setup
+ }
+
+ @Override
+ public void onEnd() {
+ peerInfo.disconnect();
+ ended.set(true);
+ }
+ });
+
+ Scheduler.run();
+ assertTrue(ended.get());
+ }
+}
Added: gnunet-java/src/test/java/org/gnunet/statistics/StatisticsTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/statistics/StatisticsTest.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/statistics/StatisticsTest.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,180 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.statistics;
+
+import org.junit.Assert;
+import org.gnunet.testing.TestingFixture;
+import org.gnunet.testing.TestingSetup;
+import org.gnunet.testing.TestingSubsystem;
+import org.gnunet.util.*;
+import org.junit.Test;
+
+
+public class StatisticsTest extends TestingFixture {
+ public interface Next {
+ void next();
+ }
+
+ public void assertStatisticsGet(AssertionList assertions, Statistics stat,
final String subsystem,
+ final String name,
+ final long expectedValue, final Next next)
{
+ Program.configureLogging();
+ final Assertion getAssertion = assertions.create("get %s:%s -> %s",
subsystem, name, expectedValue);
+ stat.get(RelativeTime.FOREVER, subsystem, name, new
StatisticsReceiver() {
+ @Override
+ public void onReceive(String rsubsystem, String rname,
long rvalue) {
+ if (rsubsystem.equals(subsystem) && rname.equals(name)
&& rvalue == expectedValue) {
+ getAssertion.assertTrue(true);
+ } else {
+ getAssertion.assertTrue(false);
+ }
+ }
+
+ @Override
+ public void onTimeout() {
+ Assert.fail();
+ }
+
+ @Override
+ public void onDone() {
+ if (next != null) {
+ next.next();
+ }
+ }
+ });
+ }
+
+
+ @Test(timeout = 1000)
+ public void test_simple() {
+ Program.configureLogging("DEBUG");
+ final TestingSubsystem ts = new TestingSubsystem("statistics");
+
+ final Statistics stat = new Statistics(ts.getConfiguration());
+
+ final Wrapper<Boolean> contReached = new Wrapper<Boolean>(false);
+
+ stat.set("gnj-test", "test", 42, false);
+
+ stat.get(RelativeTime.FOREVER, "gnj-test", "test",
+ new StatisticsReceiver() {
+ @Override
+ public void onReceive(String subsystem, String name, long
value) {
+ Assert.assertEquals("gnj-test", subsystem);
+ Assert.assertEquals("test", name);
+ Assert.assertEquals(42, value);
+ }
+
+ @Override
+ public void onTimeout() {
+
+ }
+
+ public void onDone() {
+ contReached.set(true);
+ stat.destroy();
+
+ }
+ });
+
+ Scheduler.run();
+
+ Assert.assertTrue(contReached.get());
+ }
+
+ /**
+ * Test setting, updating and getting values with two statistics handles.
+ * This test is somewhat fragile, as we have a fixed time we wait for
+ * the values to be set in the service.
+ */
+ @Test(timeout = 1000)
+ public void test_statistics_get_set() {
+ Program.configureLogging();
+ final TestingSubsystem ts = new TestingSubsystem("statistics");
+
+ final AssertionList assertions = new AssertionList();
+
+ final Statistics stat1 = new Statistics(ts.getConfiguration());
+
+ stat1.set("gnj-test", "test1", 5, false);
+ stat1.set("gnj-test", "test2", 7, false);
+ stat1.set("gnj-test", "test3", 0, false);
+ stat1.update("gnj-test", "test3", 5, false);
+ stat1.update("gnj-test", "test3", -1, false);
+
+ Scheduler.addDelayed(RelativeTime.fromMilliseconds(200), new
Scheduler.Task() {
+ @Override
+ public void run(Scheduler.RunContext ctx) {
+ stat1.destroy();
+ final Statistics stat2 = new Statistics(ts.getConfiguration());
+ assertStatisticsGet(assertions, stat2, "gnj-test", "test1", 5,
new Next() {
+ @Override
+ public void next() {
+ assertStatisticsGet(assertions, stat2, "gnj-test",
"test2", 7, new Next() {
+ @Override
+ public void next() {
+ assertStatisticsGet(assertions, stat2,
"gnj-test", "test3", 4, new Next() {
+ @Override
+ public void next() {
+ stat2.destroy();
+ }
+ });
+ }
+ });
+
+ }
+ });
+ }
+ });
+
+
+ Scheduler.run();
+ assertions.assertAll();
+ }
+
+
+ @Test(timeout = 1000)
+ public void test_watch() {
+ Program.configureLogging("DEBUG");
+ final TestingSubsystem ts = new TestingSubsystem("statistics");
+
+ final Statistics stat = new Statistics(ts.getConfiguration());
+
+ stat.watch("gnj-test", "test", new StatisticsWatcher() {
+ @Override
+ public void onReceive(String subsystem, String name, long value) {
+ System.out.println("received update!");
+ stat.destroy();
+ }
+
+ @Override
+ public void onTimeout() {
+ Assert.fail();
+ }
+ });
+
+ // the set is sent after the watch, thus it is guaranteed we
+ // well get the update
+ stat.set("gnj-test", "test", 42, false);
+
+ Scheduler.run();
+ }
+}
Added: gnunet-java/src/test/java/org/gnunet/testing/TestingSetupTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/testing/TestingSetupTest.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/testing/TestingSetupTest.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,54 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.testing;
+
+import org.gnunet.util.Program;
+import org.junit.Test;
+
+/**
+ * @author Florian Dold
+ */
+public class TestingSetupTest {
+ static final String service = "nse";
+
+ @Test(timeout = 1000)
+ public void test_testing() {
+ Program.configureLogging();
+ // could be any service, just use statistics
+ TestingSubsystem ts = new TestingSubsystem(service);
+ String port = ts.getConfiguration().getValueString(service,
"PORT").get();
+ org.junit.Assert.assertTrue(port != null);
+
+ ts.destroy();
+ }
+
+ @Test(expected = TestingSetup.SetupException.class)
+ public void test_no_service() {
+ new TestingSubsystem("foobar _ !!!");
+ }
+
+ @Test(timeout = 1000)
+ public void test_restart() {
+ TestingSubsystem ts = new TestingSubsystem(service);
+ ts.restart();
+ ts.destroy();
+ }
+}
Added: gnunet-java/src/test/java/org/gnunet/util/Assertion.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/util/Assertion.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/util/Assertion.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,37 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+
+public class Assertion {
+ public boolean success;
+ public int asserted;
+ public String message;
+
+ public Assertion(String message) {
+ this.message = message;
+ }
+
+ public void assertTrue(boolean b) {
+ success = b;
+ asserted += 1;
+ }
+}
Added: gnunet-java/src/test/java/org/gnunet/util/AssertionList.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/util/AssertionList.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/util/AssertionList.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,30 @@
+package org.gnunet.util;
+
+import java.util.LinkedList;
+import java.util.List;
+
+public class AssertionList {
+
+ List<Assertion> asyncAssertions = new LinkedList<Assertion>();
+
+
+ public Assertion create(String message, Object... args) {
+ Assertion assertion = new Assertion(String.format(message, args));
+ asyncAssertions.add(assertion);
+ return assertion;
+ }
+
+ public void assertAll() {
+ for (Assertion assertion : asyncAssertions) {
+ if (assertion.asserted != 1) {
+ throw new AssertionError(
+ String.format("Assertion '%s' asserted %s times",
assertion.message, assertion.asserted));
+ }
+ if (!assertion.success) {
+ throw new AssertionError(
+ String.format("Assertion '%s' failed",
assertion.message));
+ }
+ }
+ }
+
+}
Added: gnunet-java/src/test/java/org/gnunet/util/ClientServerTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/util/ClientServerTest.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/util/ClientServerTest.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,251 @@
+package org.gnunet.util;
+
+import com.google.common.collect.Lists;
+import org.gnunet.construct.UInt32;
+import org.gnunet.construct.UnionCase;
+import org.gnunet.testing.TestingServer;
+import org.gnunet.testing.TestingSetup;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.net.*;
+import java.nio.ByteBuffer;
+import java.nio.channels.Pipe;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.ArrayList;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class ClientServerTest {
+
+ @Test
+ public void test_start_stop() {
+ Program.configureLogging("DEBUG", null);
+ final TestingServer srv = new TestingServer();
+ srv.server.stopListening();
+ }
+
+ /**
+ * Test if the server receives a message sent by a client.
+ */
+ @Test
+ public void test_testing_server() {
+ Program.configureLogging("DEBUG", null);
+
+ final TestingServer srv = new TestingServer();
+
+ final Wrapper<Boolean> gotMessage = new Wrapper<Boolean>(false);
+
+ srv.server.setHandler(new Server.MessageRunabout() {
+ public void visit(TestMessage tm) {
+ gotMessage.set(true);
+ srv.server.destroy();
+ }
+ });
+
+ Scheduler.run(new Scheduler.Task() {
+ @Override
+ public void run(Scheduler.RunContext ctx) {
+ final Client cli = srv.createClient();
+ cli.notifyTransmitReady(RelativeTime.FOREVER,true, 0, new
MessageTransmitter() {
+ @Override
+ public void transmit(Connection.MessageSink sink) {
+ System.out.println("ntr!");
+ sink.send(new TestMessage());
+ }
+
+ @Override
+ public void handleError() {
+ Assert.fail();
+ }
+ });
+ System.out.println("done");
+ }
+ });
+
+ Assert.assertTrue(gotMessage.get());
+ }
+
+
+ /**
+ * Test what happens when a client calls notifyTransmitReady, but does not
send
+ * a message in the callback and disconnects.
+ */
+ @Test(timeout = 1000)
+ public void test_premature_disconnect() {
+ Program.configureLogging("DEBUG", null);
+ final TestingServer srv = new TestingServer();
+
+ srv.server.notifyDisconnect(new Server.DisconnectHandler() {
+ @Override
+ public void onDisconnect(Server.ClientHandle clientHandle) {
+ srv.server.destroy();
+ }
+ });
+
+ Scheduler.run(new Scheduler.Task() {
+ @Override
+ public void run(Scheduler.RunContext ctx) {
+ final Client cli = srv.createClient();
+ cli.notifyTransmitReady(RelativeTime.FOREVER,true, 0, new
MessageTransmitter() {
+ @Override
+ public void transmit(Connection.MessageSink sink) {
+ sink.send(new TestMessage());
+ cli.disconnect();
+ }
+
+ @Override
+ public void handleError() {
+ Assert.fail();
+ }
+ });
+ }
+ });
+ }
+
+
+ @Test
+ public void test_receiveDone() {
+ Program.configureLogging("DEBUG", null);
+ final TestingServer srv = new TestingServer();
+
+ final Wrapper<Integer> msgCount = new Wrapper<Integer>(0);
+
+ srv.server.setHandler(new Server.MessageRunabout() {
+ public void visit(TestMessage tm) {
+ msgCount.set(msgCount.get() + 1);
+ if (msgCount.get() == 3) {
+ getSender().receiveDone(false);
+ srv.server.stopListening();
+ } else {
+ getSender().receiveDone(true);
+ }
+ }
+ });
+
+ Scheduler.run(new Scheduler.Task() {
+ @Override
+ public void run(Scheduler.RunContext ctx) {
+ final Client cli = srv.createClient();
+
+ cli.transmitWhenReady(RelativeTime.FOREVER, new TestMessage(),
new Continuation() {
+ @Override
+ public void cont(boolean success) {
+ cli.transmitWhenReady(RelativeTime.FOREVER, new
TestMessage(), new Continuation() {
+ @Override
+ public void cont(boolean success) {
+ cli.transmitWhenReady(RelativeTime.FOREVER,
new TestMessage(), null);
+ }
+ });
+ }
+ });
+ }
+ });
+ }
+
+ @Test
+ public void test_acceptFromAddresses() {
+ Program.configureLogging("DEBUG", null);
+
+ InetAddress localhost = null;
+ try {
+ localhost = Inet4Address.getLocalHost();
+ } catch (UnknownHostException e) {
+ Assert.fail();
+ }
+
+ // does this work on all operating systems?
+ SocketAddress addr = new InetSocketAddress(localhost, 0);
+
+ Server server = new Server(Lists.newArrayList(addr),
RelativeTime.FOREVER, false);
+
+ server.destroy();
+
+ }
+
+
+ @Test
+ public void test_keep_drop() {
+ Program.configureLogging("DEBUG", null);
+ final TestingServer srv = new TestingServer();
+
+ final Wrapper<Integer> msgCount = new Wrapper<Integer>(0);
+
+
+
+ srv.server.setHandler(new Server.MessageRunabout() {
+ public void visit(TestMessage tm) {
+ srv.server.stopListening();
+ if (msgCount.get() == 0) {
+ getSender().keep();
+ getSender().drop();
+ getSender().receiveDone(true);
+ } else if (msgCount.get() == 1) {
+ getSender().receiveDone(false);
+
+ } else {
+ Assert.fail();
+ }
+
+ msgCount.set(msgCount.get() + 1);
+ }
+ });
+
+ Scheduler.run(new Scheduler.Task() {
+ @Override
+ public void run(Scheduler.RunContext ctx) {
+ final Client cli = srv.createClient();
+ cli.transmitWhenReady(new TestMessage(), new Continuation() {
+ @Override
+ public void cont(boolean success) {
+ cli.transmitWhenReady(new TestMessage(), null);
+ }
+ });
+ }
+ });
+ }
+
+
+
+ /**
+ * test if markMonitor / soft shutdown works.
+ */
+ @Test
+ public void test_monitor_clients() {
+ Program.configureLogging("DEBUG", null);
+ final TestingServer srv = new TestingServer();
+
+ final Wrapper<Integer> msgCount = new Wrapper<Integer>(0);
+
+ srv.server.setHandler(new Server.MessageRunabout() {
+ public void visit(TestMessage tm) {
+ if (msgCount.get() == 0) {
+ getSender().markMonitor();
+ getSender().receiveDone(true);
+ } else if (msgCount.get() == 1) {
+ srv.server.stopListening();
+ getSender().receiveDone(false);
+ } else {
+ Assert.fail();
+ }
+
+ msgCount.set(msgCount.get() + 1);
+ }
+ });
+
+ Scheduler.run(new Scheduler.Task() {
+ @Override
+ public void run(Scheduler.RunContext ctx) {
+ final Client cli1 = srv.createClient();
+ final Client cli2 = srv.createClient();
+
+ cli1.transmitWhenReady(new TestMessage(), null);
+ cli2.transmitWhenReady(new TestMessage(), null);
+ }
+ });
+ }
+}
Added: gnunet-java/src/test/java/org/gnunet/util/FilePipeExample.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/util/FilePipeExample.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/util/FilePipeExample.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,41 @@
+package org.gnunet.util;
+
+import java.io.File;
+import java.io.IOError;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class FilePipeExample {
+ public static void main(String... args) {
+
+ Program.configureLogging("DEBUG", null);
+
+ final Scheduler.FilePipe fp = Scheduler.openFilePipe(new
File("test.pipe"));
+
+
+ Scheduler.addRead(RelativeTime.FOREVER, fp.getSource(), new
Scheduler.Task() {
+ @Override
+ public void run(Scheduler.RunContext ctx) {
+ ByteBuffer b = ByteBuffer.allocate(1);
+ b.clear();
+ try {
+ fp.getSource().read(b);
+ } catch (IOException e) {
+ throw new IOError(e);
+ }
+ b.flip();
+ System.out.println("got: " + b.get());
+
+ Scheduler.addRead(RelativeTime.FOREVER, fp.getSource(), this);
+
+ }
+ });
+
+ Scheduler.run();
+ }
+}
Added: gnunet-java/src/test/java/org/gnunet/util/ResolverTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/util/ResolverTest.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/util/ResolverTest.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,92 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+import org.gnunet.testing.TestingSetup;
+import org.gnunet.testing.TestingSubsystem;
+import org.junit.Assert;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.InetAddress;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * @author Florian Dold
+ */
+public class ResolverTest {
+ private static final Logger logger = LoggerFactory
+ .getLogger(ResolverTest.class);
+ @Test
+ public void test_resolver() {
+ final Wrapper<Boolean> finished1 = new Wrapper<Boolean>(true);
+ final Wrapper<Boolean> finished2 = new Wrapper<Boolean>(true);
+
+ TestingSubsystem ts = new TestingSubsystem("resolver");
+
+
+ Resolver r = Resolver.getInstance();
+ r.setConfiguration(ts.getConfiguration());
+
+ r.resolveHostname("gnunet.org", RelativeTime.FOREVER, new
Resolver.AddressCallback() {
+ @Override
+ public void onAddress(InetAddress addr) {
+ logger.info("Hostname resolved to " + addr.getHostAddress());
+ }
+
+ @Override
+ public void onFinished() {
+ finished1.set(true);
+ }
+
+ @Override
+ public void onTimeout() {
+ fail();
+ }
+ });
+ r.resolveHostname("gnu.org", RelativeTime.FOREVER, new
Resolver.AddressCallback() {
+ @Override
+ public void onAddress(InetAddress addr) {
+ logger.info("Hostname resolved to " + addr.getHostAddress());
+ }
+
+ @Override
+ public void onFinished() {
+ finished2.set(true);
+ }
+
+ @Override
+ public void onTimeout() {
+ fail();
+ }
+ });
+
+ Scheduler.run();
+
+ assertTrue(finished1.get());
+
+ assertTrue(finished2.get());
+ }
+}
+
Added: gnunet-java/src/test/java/org/gnunet/util/ServerExample.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/util/ServerExample.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/util/ServerExample.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,79 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.Arrays;
+
+import static org.gnunet.util.Server.*;
+
+/**
+ * Example server implementation.
+ *
+ * @author Florian Dold
+ */
+public class ServerExample {
+
+ public static void main(String[] args) {
+ // usually servers should run inside a service, this is just for
testing
+ new Program(args) {
+ @Override
+ public void run() {
+ Server s = new Server(Arrays.asList(new SocketAddress[]{new
InetSocketAddress("127.0.0.1", 3456)}),
+ RelativeTime.MINUTE,
+ false);
+ s.setHandler(new Server.MessageRunabout() {
+ public void visit(TestMessage tm) {
+ System.out.println("got TEST message");
+ final Server.ClientHandle sender = getSender();
+ sender.notifyTransmitReady(4, RelativeTime.FOREVER,
new MessageTransmitter() {
+ @Override
+ public void transmit(Connection.MessageSink sink) {
+ sink.send(new TestMessage());
+ System.out.println("TEST message sent");
+ sender.receiveDone(true);
+ }
+
+ @Override
+ public void handleError() {
+ System.out.println("error talking to client!");
+ }
+ });
+ }
+
+ public void visit(UnknownMessageBody b) {
+ System.out.println("got message of unknown type " +
b.id);
+ }
+ });
+
+ s.notifyDisconnect(new DisconnectHandler() {
+ @Override
+ public void onDisconnect(Server.ClientHandle clientHandle)
{
+ System.out.println("client disconnected");
+
+ }
+ });
+
+ }
+ }.start();
+ }
+}
Added: gnunet-java/src/test/java/org/gnunet/util/StringsTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/util/StringsTest.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/util/StringsTest.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,20 @@
+package org.gnunet.util;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class StringsTest {
+ @Test
+ public void test_inverse() {
+ byte[] data = "asdfgASDD$!123".getBytes();
+ String str = Strings.dataToString(data);
+ byte[] data2 = Strings.stringToData(str, data.length);
+ Assert.assertArrayEquals(data, data2);
+ }
+}
+
Added: gnunet-java/src/test/java/org/gnunet/util/TimeTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/util/TimeTest.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/util/TimeTest.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,29 @@
+package org.gnunet.util;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * ...
+ *
+ * @author Florian Dold
+ */
+public class TimeTest {
+
+ @Test
+ public void test_absolute_add_subtract() {
+ AbsoluteTime t1 = AbsoluteTime.now().add(RelativeTime.FOREVER);
+ Assert.assertEquals(t1, AbsoluteTime.FOREVER);
+ Assert.assertTrue(t1.isForever());
+
+ t1 = AbsoluteTime.FOREVER.add(RelativeTime.SECOND);
+ Assert.assertEquals(t1, AbsoluteTime.FOREVER);
+ Assert.assertTrue(t1.isForever());
+
+ AbsoluteTime t2 = (new
AbsoluteTime(123000000)).add(RelativeTime.SECOND);
+ Assert.assertEquals(124000000, t2.getMicroseconds());
+
+ AbsoluteTime t3 = (new
AbsoluteTime(123000000)).subtract(RelativeTime.SECOND);
+ Assert.assertEquals(122000000, t3.getMicroseconds());
+ }
+}
Added: gnunet-java/src/test/java/org/gnunet/util/Wrapper.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/util/Wrapper.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/util/Wrapper.java 2013-08-27
17:16:18 UTC (rev 28880)
@@ -0,0 +1,43 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util;
+
+
+/**
+ * Wrapper, used when it is necessary to store a value in a final-variable.
+ *
+ * @param <E> type of the stored value
+ */
+public class Wrapper<E> {
+ public E value;
+ public Wrapper(E initialValue) {
+ value = initialValue;
+ }
+ public Wrapper() {
+ // default constructor
+ }
+ public void set(E newValue) {
+ value = newValue;
+ }
+ public E get() {
+ return value;
+ }
+}
Added: gnunet-java/src/test/java/org/gnunet/util/getopt/GetoptTest.java
===================================================================
--- gnunet-java/src/test/java/org/gnunet/util/getopt/GetoptTest.java
(rev 0)
+++ gnunet-java/src/test/java/org/gnunet/util/getopt/GetoptTest.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,286 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.gnunet.util.getopt;
+
+
+import org.junit.Assert;
+import org.junit.Test;
+
+class Target {
+ @Argument(
+ action = ArgumentAction.STORE_STRING,
+ shortname = "s",
+ longname = "string",
+ argumentName = "SOME_STRING",
+ description = "just some string"
+ )
+ String someString;
+
+ @Argument(
+ action = ArgumentAction.SET,
+ shortname = "y",
+ longname = "set",
+ description = "enable, default disabled"
+ )
+ boolean set = false;
+
+ @Argument(
+ action = ArgumentAction.RESET,
+ shortname = "n",
+ longname = "reset",
+ description = "disable, default enabled"
+ )
+ boolean reset = true;
+
+
+ @Argument(
+ action = ArgumentAction.STORE_NUMBER,
+ shortname = "w",
+ longname = "value",
+ description = "some value"
+ )
+ int intVal = 0;
+
+ static int someConstant = 42;
+}
+
+class InvalidTarget {
+ @Argument(action = ArgumentAction.SET, shortname = "foo", longname =
"bar", description = "bla bla")
+ boolean foo;
+}
+
+public class GetoptTest {
+ @Test
+ public void test_str() {
+ Target t = new Target();
+ Parser p = new Parser(t);
+
+
+ t.someString = null;
+
+ // argument directly with shortopt
+ p.parse(new String[]{"-sfoo"});
+ Assert.assertEquals("foo", t.someString);
+
+ t.someString = null;
+
+ // argument after shortopt
+ p.parse(new String[]{"-s", "foo"});
+ Assert.assertEquals("foo", t.someString);
+
+ t.someString = null;
+
+ p.parse(new String[]{"--string=foo"});
+ Assert.assertEquals("foo", t.someString);
+
+ t.someString = null;
+
+ p.parse(new String[]{"--string", "foo"});
+ Assert.assertEquals("foo", t.someString);
+
+
+ t.someString = null;
+
+ // last argument counts
+ p.parse(new String[]{"--string", "bar", "--string", "foo"});
+ Assert.assertEquals("foo", t.someString);
+
+ t.someString = null;
+
+ boolean thrown;
+
+ thrown = false;
+
+ // absence of argument throws ArgumentError (longopt)
+ try {
+ p.parse(new String[]{"--string"});
+ } catch (Parser.ArgumentError e) {
+ thrown = true;
+ }
+
+ Assert.assertTrue(thrown);
+
+ thrown = false;
+ // absence of argument throws ArgumentError (shortopt)
+ try {
+ p.parse(new String[]{"-s"});
+ } catch (Parser.ArgumentError e) {
+ thrown = true;
+ }
+
+ Assert.assertTrue(thrown);
+
+ t.someString = null;
+
+ // a way to specify an empty string
+ p.parse(new String[]{"--string="});
+ Assert.assertEquals("", t.someString);
+ }
+
+ @Test
+ public void test_help() {
+ Target t = new Target();
+ Parser p = new Parser(t);
+
+ String help = p.getHelp();
+
+ Assert.assertTrue(help.contains("--string"));
+ Assert.assertTrue(help.contains("-s"));
+
+ Assert.assertTrue(help.contains("-y"));
+ Assert.assertTrue(help.contains("--set"));
+ }
+
+
+ @Test
+ public void test_bool() {
+ Target t = new Target();
+ Parser p = new Parser(t);
+
+ p.parse(new String[]{"--set", "--reset"});
+ Assert.assertTrue(t.set);
+ Assert.assertTrue(!t.reset);
+
+ t.set = false;
+ t.reset = true;
+
+ p.parse(new String[]{"-y", "-n"});
+
+ Assert.assertTrue(t.set);
+ Assert.assertTrue(!t.reset);
+
+ t.set = false;
+ t.reset = true;
+
+ p.parse(new String[]{"-yn"});
+
+ Assert.assertTrue(t.set);
+ Assert.assertTrue(!t.reset);
+ }
+
+ @Test
+ public void test_positional() {
+ Target t = new Target();
+ Parser p = new Parser(t);
+
+ String[] rest = p.parse(new String[]{"--string=bla", "foo", "bar",
"--set", "--", "--reset", "baz"});
+
+ Assert.assertArrayEquals(new String[]{"foo", "bar", "--reset", "baz"},
rest);
+ }
+
+
+ @Test(expected = Parser.ArgumentError.class)
+ public void test_missingLongopt() {
+ Target t = new Target();
+ Parser p = new Parser(t);
+ p.parse(new String[]{"--foobar"});
+ }
+
+ @Test(expected = Parser.ArgumentError.class)
+ public void test_missingShortopt_1() {
+ Target t = new Target();
+ Parser p = new Parser(t);
+ p.parse(new String[]{"-x"});
+ }
+
+ @Test
+ public void test_long() {
+ Target t = new Target();
+ Parser p = new Parser(t);
+
+ String[] rest;
+
+ rest = p.parse(new String[]{"-w5"});
+ Assert.assertEquals(5, t.intVal);
+
+ rest = p.parse(new String[]{"-w", "5"});
+ Assert.assertEquals(5, t.intVal);
+
+ rest = p.parse(new String[]{"--value=6"});
+ Assert.assertEquals(6, t.intVal);
+
+ rest = p.parse(new String[]{"--value", "7"});
+ Assert.assertEquals(7, t.intVal);
+
+ rest = p.parse(new String[]{"--value", "-7"});
+ Assert.assertEquals(-7, t.intVal);
+
+ boolean thrown = false;
+ try {
+ rest = p.parse(new String[]{"--value", "x"});
+ } catch (Parser.ArgumentError e) {
+ thrown = true;
+ }
+ Assert.assertTrue(thrown);
+ }
+
+
+ @Test(expected = Parser.ArgumentError.class)
+ public void test_missingNumberArgument_short() {
+ Target t = new Target();
+ Parser p = new Parser(t);
+
+ p.parse(new String[]{"-w"});
+ Assert.assertEquals(5, t.intVal);
+ }
+
+ @Test(expected = Parser.ArgumentError.class)
+ public void test_missingNumberArgument_long() {
+ Target t = new Target();
+ Parser p = new Parser(t);
+
+
+ p.parse(new String[]{"--w"});
+ Assert.assertEquals(5, t.intVal);
+ }
+
+
+ @Test(expected = Parser.ArgumentError.class)
+ public void test_invalidNumberFormat() {
+ Target t = new Target();
+ Parser p = new Parser(t);
+
+
+ p.parse(new String[]{"-w", "abc"});
+ Assert.assertEquals(5, t.intVal);
+ }
+
+
+ @Test
+ public void test_dashRest() {
+ Target t = new Target();
+ Parser p = new Parser(t);
+
+ String[] rest;
+
+ rest = p.parse(new String[]{"-w", "123", "-"});
+ Assert.assertArrayEquals(new String[]{"-"}, rest);
+ }
+
+
+ @Test(expected = AssertionError.class)
+ public void test_invalid() {
+ InvalidTarget it = new InvalidTarget();
+ Parser p = new Parser(it);
+
+ p.parse(new String[]{"-foo"});
+ }
+}
Added: gnunet-java/src/test/java/org/grothoff/RunaboutBenchmark.java
===================================================================
--- gnunet-java/src/test/java/org/grothoff/RunaboutBenchmark.java
(rev 0)
+++ gnunet-java/src/test/java/org/grothoff/RunaboutBenchmark.java
2013-08-27 17:16:18 UTC (rev 28880)
@@ -0,0 +1,82 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+package org.grothoff;
+
+
+public class RunaboutBenchmark {
+
+ public static class MyRunabout extends Runabout {
+ public void visit(String s) {
+
+ }
+ public void visit(Integer i) {
+
+ }
+ }
+
+
+ public static void main(String[] args) {
+ final int runs = 5000000;
+
+ Runabout r = new MyRunabout();
+
+ long start = System.currentTimeMillis();
+
+ Integer integer = 42;
+ for (int i = 0; i < runs; ++i) {
+ r.visitAppropriate("foo");
+ r.visitAppropriate(integer);
+ }
+
+ long end = System.currentTimeMillis();
+
+ long duration1 = end - start;
+
+
+ Runabout r2 = new Runabout() {
+ public void visit(String s) {
+
+ }
+ public void visit(Integer i) {
+
+ }
+ };
+
+
+ start = System.currentTimeMillis();
+
+ for (int i = 0; i < runs; ++i) {
+ r2.visitAppropriate("foo");
+ r2.visitAppropriate(integer);
+ }
+
+ end = System.currentTimeMillis();
+
+ long duration2 = end - start;
+
+
+ System.out.println("Runs: " + runs);
+ System.out.println("public: " + duration1);
+ System.out.println("Anon Inner Class: " + duration2);
+ System.out.println("Overhead: " + duration2 / (double) duration1);
+
+ }
+}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r28880 - in gnunet-java: . gradle gradle/wrapper src src/main src/main/java src/main/java/org src/main/java/org/gnunet src/main/java/org/gnunet/consensus src/main/java/org/gnunet/construct src/main/java/org/gnunet/construct/parsers src/main/java/org/gnunet/core src/main/java/org/gnunet/dht src/main/java/org/gnunet/hello src/main/java/org/gnunet/mesh src/main/java/org/gnunet/mq src/main/java/org/gnunet/nse src/main/java/org/gnunet/peerinfo src/main/java/org/gnunet/requests src/main/java/org/gnunet/statistics src/main/java/org/gnunet/testbed src/main/java/org/gnunet/testing src/main/java/org/gnunet/transport src/main/java/org/gnunet/util src/main/java/org/gnunet/util/getopt src/main/java/org/gnunet/voting src/main/java/org/gnunet/voting/simulation src/main/java/org/grothoff src/main/resources src/main/resources/org src/main/resources/org/gnunet src/main/resources/org/gnunet/construct src/test src/test/java src/test/java/org src/test/java/org/gnunet src/test/java/org/gn unet/con struct src/test/java/org/gnunet/core src/test/java/org/gnunet/dht src/test/java/org/gnunet/mesh src/test/java/org/gnunet/nse src/test/java/org/gnunet/peerinfo src/test/java/org/gnunet/statistics src/test/java/org/gnunet/testing src/test/java/org/gnunet/util src/test/java/org/gnunet/util/getopt src/test/java/org/grothoff,
gnunet <=