From a942ffadee0fe9fd385decdf818ad6baae8c99b3 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Tue, 27 Aug 2013 17:16:18 +0000 Subject: - 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 --- .../org/gnunet/consensus/ConcludeCallback.java | 5 + .../org/gnunet/consensus/ConcludeDoneMessage.java | 13 + .../java/org/gnunet/consensus/ConcludeMessage.java | 19 + src/main/java/org/gnunet/consensus/Consensus.java | 128 ++++ .../org/gnunet/consensus/ConsensusElement.java | 16 + .../org/gnunet/consensus/InsertDoneCallback.java | 5 + .../org/gnunet/consensus/InsertElementMessage.java | 23 + .../org/gnunet/consensus/NewElementCallback.java | 5 + .../org/gnunet/consensus/NewElementMessage.java | 20 + src/main/java/org/gnunet/construct/Construct.java | 482 ++++++++++++++ .../java/org/gnunet/construct/DoubleValue.java | 34 + src/main/java/org/gnunet/construct/FillWith.java | 37 ++ .../java/org/gnunet/construct/FixedSizeArray.java | 37 ++ .../gnunet/construct/FixedSizeIntegerArray.java | 21 + src/main/java/org/gnunet/construct/FrameSize.java | 34 + src/main/java/org/gnunet/construct/Int16.java | 38 ++ src/main/java/org/gnunet/construct/Int32.java | 38 ++ src/main/java/org/gnunet/construct/Int64.java | 37 ++ src/main/java/org/gnunet/construct/Int8.java | 40 ++ .../java/org/gnunet/construct/IntegerFill.java | 37 ++ src/main/java/org/gnunet/construct/Message.java | 29 + .../construct/MessageIdAnnotationProcessor.java | 137 ++++ .../java/org/gnunet/construct/MessageLoader.java | 215 +++++++ .../java/org/gnunet/construct/MessageUnion.java | 27 + src/main/java/org/gnunet/construct/MsgMap.txt | 46 ++ .../java/org/gnunet/construct/NestedMessage.java | 39 ++ .../construct/ProtocolViolationException.java | 40 ++ .../java/org/gnunet/construct/ReflectUtil.java | 297 +++++++++ src/main/java/org/gnunet/construct/UInt16.java | 40 ++ src/main/java/org/gnunet/construct/UInt32.java | 39 ++ src/main/java/org/gnunet/construct/UInt64.java | 39 ++ src/main/java/org/gnunet/construct/UInt8.java | 41 ++ src/main/java/org/gnunet/construct/Union.java | 37 ++ src/main/java/org/gnunet/construct/UnionCase.java | 39 ++ .../org/gnunet/construct/VariableSizeArray.java | 39 ++ .../gnunet/construct/VariableSizeIntegerArray.java | 41 ++ .../org/gnunet/construct/ZeroTerminatedString.java | 37 ++ .../java/org/gnunet/construct/package-info.java | 24 + .../org/gnunet/construct/parsers/DoubleParser.java | 75 +++ .../org/gnunet/construct/parsers/FillParser.java | 126 ++++ .../construct/parsers/FixedSizeArrayParser.java | 106 ++++ .../parsers/FixedSizeIntegerArrayParser.java | 106 ++++ .../construct/parsers/IntegerFillParser.java | 113 ++++ .../gnunet/construct/parsers/IntegerParser.java | 95 +++ .../org/gnunet/construct/parsers/IntegerUtil.java | 92 +++ .../org/gnunet/construct/parsers/NestedParser.java | 119 ++++ .../java/org/gnunet/construct/parsers/Parser.java | 78 +++ .../gnunet/construct/parsers/SequenceParser.java | 106 ++++ .../org/gnunet/construct/parsers/StringParser.java | 145 +++++ .../org/gnunet/construct/parsers/UnionParser.java | 143 +++++ .../construct/parsers/VariableSizeArrayParser.java | 106 ++++ .../parsers/VariableSizeIntegerArrayParser.java | 103 +++ .../org/gnunet/construct/parsers/package-info.java | 25 + src/main/java/org/gnunet/core/ConnectHandler.java | 30 + .../java/org/gnunet/core/ConnectNotifyMessage.java | 54 ++ src/main/java/org/gnunet/core/Core.java | 347 ++++++++++ .../java/org/gnunet/core/DisconnectHandler.java | 30 + .../org/gnunet/core/DisconnectNotifyMessage.java | 46 ++ src/main/java/org/gnunet/core/HeaderNotify.java | 30 + src/main/java/org/gnunet/core/InitCallback.java | 30 + src/main/java/org/gnunet/core/InitMessage.java | 45 ++ .../java/org/gnunet/core/InitReplyMessage.java | 39 ++ src/main/java/org/gnunet/core/MessageNotify.java | 28 + .../gnunet/core/NotifyInboundTrafficMessage.java | 47 ++ .../gnunet/core/NotifyOutboundTrafficMessage.java | 58 ++ .../org/gnunet/core/RequestIdentification.java | 35 ++ src/main/java/org/gnunet/core/SendMessage.java | 71 +++ .../java/org/gnunet/core/SendMessageReady.java | 56 ++ .../java/org/gnunet/core/SendMessageRequest.java | 73 +++ src/main/java/org/gnunet/core/package-info.java | 24 + src/main/java/org/gnunet/dht/BlockType.java | 81 +++ src/main/java/org/gnunet/dht/ClientGetMessage.java | 51 ++ .../java/org/gnunet/dht/ClientGetStopMessage.java | 45 ++ .../gnunet/dht/ClientPutConfirmationMessage.java | 38 ++ src/main/java/org/gnunet/dht/ClientPutMessage.java | 54 ++ .../java/org/gnunet/dht/ClientResultMessage.java | 56 ++ .../java/org/gnunet/dht/DistributedHashTable.java | 449 +++++++++++++ .../java/org/gnunet/dht/MonitorGetHandler.java | 30 + .../java/org/gnunet/dht/MonitorGetMessage.java | 75 +++ .../java/org/gnunet/dht/MonitorGetRespMessage.java | 72 +++ .../org/gnunet/dht/MonitorGetResponseHandler.java | 31 + .../java/org/gnunet/dht/MonitorPutHandler.java | 31 + .../java/org/gnunet/dht/MonitorPutMessage.java | 82 +++ src/main/java/org/gnunet/dht/MonitorStartStop.java | 70 +++ src/main/java/org/gnunet/dht/ResultCallback.java | 46 ++ src/main/java/org/gnunet/dht/RouteOption.java | 55 ++ src/main/java/org/gnunet/dht/package-info.java | 24 + src/main/java/org/gnunet/hello/HelloMessage.java | 50 ++ src/main/java/org/gnunet/hello/package-info.java | 25 + .../java/org/gnunet/mesh/ClientConnectMessage.java | 17 + src/main/java/org/gnunet/mesh/ConnectHandler.java | 13 + src/main/java/org/gnunet/mesh/DataMessage.java | 19 + .../java/org/gnunet/mesh/DisconnectHandler.java | 12 + .../java/org/gnunet/mesh/InboundTunnelHandler.java | 12 + src/main/java/org/gnunet/mesh/LocalAckMessage.java | 18 + src/main/java/org/gnunet/mesh/Mesh.java | 309 +++++++++ src/main/java/org/gnunet/mesh/MeshRunabout.java | 19 + .../java/org/gnunet/mesh/TunnelCreateMessage.java | 27 + .../java/org/gnunet/mesh/TunnelDestroyMessage.java | 16 + .../java/org/gnunet/mesh/TunnelEndHandler.java | 10 + .../org/gnunet/mesh/TunnelNotificationMessage.java | 22 + src/main/java/org/gnunet/mesh/package-info.java | 25 + src/main/java/org/gnunet/mq/Envelope.java | 36 ++ src/main/java/org/gnunet/mq/MessageQueue.java | 84 +++ src/main/java/org/gnunet/mq/NotifySentHandler.java | 6 + .../java/org/gnunet/nse/NetworkSizeEstimation.java | 167 +++++ src/main/java/org/gnunet/nse/StartMessage.java | 12 + src/main/java/org/gnunet/nse/UpdateMessage.java | 26 + src/main/java/org/gnunet/nse/package-info.java | 24 + src/main/java/org/gnunet/peerinfo/InfoEnd.java | 14 + src/main/java/org/gnunet/peerinfo/InfoMessage.java | 50 ++ .../org/gnunet/peerinfo/ListAllPeersMessage.java | 39 ++ .../java/org/gnunet/peerinfo/ListPeerMessage.java | 39 ++ src/main/java/org/gnunet/peerinfo/PeerInfo.java | 159 +++++ .../java/org/gnunet/peerinfo/PeerProcessor.java | 12 + .../gnunet/peerinfo/RsaPublicKeyBinaryEncoded.java | 56 ++ .../java/org/gnunet/peerinfo/package-info.java | 25 + .../gnunet/requests/MatchingRequestContainer.java | 51 ++ .../java/org/gnunet/requests/RequestContainer.java | 59 ++ .../requests/SequentialRequestContainer.java | 86 +++ .../java/org/gnunet/requests/package-info.java | 25 + .../java/org/gnunet/statistics/GetMessage.java | 43 ++ .../java/org/gnunet/statistics/GetRequest.java | 31 + .../gnunet/statistics/GetResponseEndMessage.java | 32 + .../org/gnunet/statistics/GetResponseMessage.java | 49 ++ .../java/org/gnunet/statistics/SetMessage.java | 43 ++ .../java/org/gnunet/statistics/SetRequest.java | 48 ++ .../java/org/gnunet/statistics/Statistics.java | 310 +++++++++ .../org/gnunet/statistics/StatisticsReceiver.java | 29 + .../org/gnunet/statistics/StatisticsWatcher.java | 13 + .../java/org/gnunet/statistics/WatchMessage.java | 40 ++ .../java/org/gnunet/statistics/WatchRequest.java | 31 + .../gnunet/statistics/WatchResponseMessage.java | 39 ++ .../java/org/gnunet/statistics/package-info.java | 24 + src/main/java/org/gnunet/testbed/Controller.java | 84 +++ .../gnunet/testbed/ControllerEventCallback.java | 21 + .../org/gnunet/testbed/ControllerInitMessage.java | 30 + .../java/org/gnunet/testbed/ControllerProc.java | 89 +++ .../gnunet/testbed/ControllerStatusCallback.java | 9 + .../java/org/gnunet/testbed/HelperInitMessage.java | 37 ++ .../org/gnunet/testbed/HelperReplyMessage.java | 17 + src/main/java/org/gnunet/testbed/Host.java | 51 ++ src/main/java/org/gnunet/testbed/Operation.java | 11 + .../testbed/OperationCompletionCallback.java | 11 + src/main/java/org/gnunet/testbed/Peer.java | 57 ++ .../java/org/gnunet/testbed/PeerChurnCallback.java | 7 + .../org/gnunet/testbed/PeerCreateCallback.java | 7 + .../java/org/gnunet/testing/TestingFixture.java | 21 + .../java/org/gnunet/testing/TestingServer.java | 65 ++ src/main/java/org/gnunet/testing/TestingSetup.java | 56 ++ .../java/org/gnunet/testing/TestingSubsystem.java | 133 ++++ src/main/java/org/gnunet/testing/package-info.java | 27 + .../gnunet/transport/AddressIterateMessage.java | 34 + .../org/gnunet/transport/BlacklistCallback.java | 12 + .../org/gnunet/transport/BlacklistInitMessage.java | 9 + .../org/gnunet/transport/HelloUpdateCallback.java | 9 + .../org/gnunet/transport/PeerIterateCallback.java | 12 + .../gnunet/transport/RequestConnectMessage.java | 24 + .../java/org/gnunet/transport/StartMessage.java | 32 + src/main/java/org/gnunet/transport/Transport.java | 156 +++++ .../org/gnunet/transport/TryConnectCallback.java | 10 + src/main/java/org/gnunet/util/ATSInformation.java | 37 ++ src/main/java/org/gnunet/util/AbsoluteTime.java | 269 ++++++++ .../java/org/gnunet/util/AbsoluteTimeMessage.java | 47 ++ src/main/java/org/gnunet/util/Cancelable.java | 28 + src/main/java/org/gnunet/util/Client.java | 329 ++++++++++ src/main/java/org/gnunet/util/Configuration.java | 389 ++++++++++++ src/main/java/org/gnunet/util/Connection.java | 696 +++++++++++++++++++++ src/main/java/org/gnunet/util/Continuation.java | 25 + src/main/java/org/gnunet/util/GnunetMessage.java | 81 +++ src/main/java/org/gnunet/util/HashCode.java | 94 +++ src/main/java/org/gnunet/util/Helper.java | 208 ++++++ src/main/java/org/gnunet/util/MessageReceiver.java | 41 ++ .../java/org/gnunet/util/MessageTransmitter.java | 43 ++ src/main/java/org/gnunet/util/PeerIdentity.java | 69 ++ src/main/java/org/gnunet/util/Program.java | 229 +++++++ src/main/java/org/gnunet/util/RelativeTime.java | 231 +++++++ .../java/org/gnunet/util/RelativeTimeMessage.java | 55 ++ src/main/java/org/gnunet/util/Resolver.java | 421 +++++++++++++ .../org/gnunet/util/RunaboutMessageReceiver.java | 33 + src/main/java/org/gnunet/util/RunaboutUtil.java | 55 ++ src/main/java/org/gnunet/util/Scheduler.java | 678 ++++++++++++++++++++ src/main/java/org/gnunet/util/Server.java | 509 +++++++++++++++ src/main/java/org/gnunet/util/Service.java | 154 +++++ src/main/java/org/gnunet/util/Strings.java | 138 ++++ src/main/java/org/gnunet/util/TestMessage.java | 31 + .../java/org/gnunet/util/UnknownMessageBody.java | 35 ++ src/main/java/org/gnunet/util/getopt/Argument.java | 47 ++ .../org/gnunet/util/getopt/ArgumentAction.java | 29 + src/main/java/org/gnunet/util/getopt/Parser.java | 294 +++++++++ .../java/org/gnunet/util/getopt/package-info.java | 24 + src/main/java/org/gnunet/util/package-info.java | 24 + .../gnunet/voting/CertificateAuthorityService.java | 7 + .../java/org/gnunet/voting/ElectionCallTool.java | 50 ++ .../org/gnunet/voting/ElectionSpecification.java | 5 + .../org/gnunet/voting/TallyAuthorityService.java | 5 + src/main/java/org/gnunet/voting/VotingTool.java | 49 ++ .../org/gnunet/voting/simulation/Authority.java | 266 ++++++++ .../java/org/gnunet/voting/simulation/Ballot.java | 105 ++++ .../gnunet/voting/simulation/BogusAuthority.java | 9 + .../gnunet/voting/simulation/CallForVoters.java | 14 + .../org/gnunet/voting/simulation/CryptoUtil.java | 86 +++ .../org/gnunet/voting/simulation/Cyphertext.java | 19 + .../voting/simulation/ElectionSupervisor.java | 105 ++++ .../gnunet/voting/simulation/GroupPublicKey.java | 28 + .../gnunet/voting/simulation/TallyKeyShare.java | 41 ++ .../simulation/TransmitShareVerification.java | 18 + .../java/org/gnunet/voting/simulation/Voter.java | 31 + .../gnunet/voting/simulation/VotingParameters.java | 165 +++++ .../gnunet/voting/simulation/VotingSimulation.java | 122 ++++ src/main/java/org/grothoff/Runabout.java | 574 +++++++++++++++++ src/main/java/org/grothoff/package-info.java | 4 + src/main/resources/org/gnunet/construct/MsgMap.txt | 46 ++ src/org/gnunet/consensus/ConcludeCallback.java | 5 - src/org/gnunet/consensus/ConcludeDoneMessage.java | 13 - src/org/gnunet/consensus/ConcludeMessage.java | 19 - src/org/gnunet/consensus/Consensus.java | 136 ---- src/org/gnunet/consensus/ConsensusElement.java | 16 - src/org/gnunet/consensus/InsertDoneCallback.java | 5 - src/org/gnunet/consensus/InsertElementMessage.java | 23 - src/org/gnunet/consensus/NewElementCallback.java | 5 - src/org/gnunet/consensus/NewElementMessage.java | 20 - src/org/gnunet/construct/Construct.java | 482 -------------- src/org/gnunet/construct/DoubleValue.java | 34 - src/org/gnunet/construct/FillWith.java | 37 -- src/org/gnunet/construct/FixedSizeArray.java | 37 -- .../gnunet/construct/FixedSizeIntegerArray.java | 21 - src/org/gnunet/construct/FrameSize.java | 34 - src/org/gnunet/construct/Int16.java | 38 -- src/org/gnunet/construct/Int32.java | 38 -- src/org/gnunet/construct/Int64.java | 37 -- src/org/gnunet/construct/Int8.java | 40 -- src/org/gnunet/construct/IntegerFill.java | 37 -- src/org/gnunet/construct/Message.java | 29 - .../construct/MessageIdAnnotationProcessor.java | 139 ---- src/org/gnunet/construct/MessageLoader.java | 215 ------- src/org/gnunet/construct/MessageUnion.java | 27 - src/org/gnunet/construct/MsgMap.txt | 46 -- src/org/gnunet/construct/NestedMessage.java | 39 -- .../construct/ProtocolViolationException.java | 40 -- src/org/gnunet/construct/ReflectUtil.java | 297 --------- src/org/gnunet/construct/UInt16.java | 40 -- src/org/gnunet/construct/UInt32.java | 39 -- src/org/gnunet/construct/UInt64.java | 39 -- src/org/gnunet/construct/UInt8.java | 41 -- src/org/gnunet/construct/Union.java | 37 -- src/org/gnunet/construct/UnionCase.java | 39 -- src/org/gnunet/construct/VariableSizeArray.java | 39 -- .../gnunet/construct/VariableSizeIntegerArray.java | 41 -- src/org/gnunet/construct/ZeroTerminatedString.java | 37 -- src/org/gnunet/construct/package-info.java | 24 - src/org/gnunet/construct/parsers/DoubleParser.java | 75 --- src/org/gnunet/construct/parsers/FillParser.java | 126 ---- .../construct/parsers/FixedSizeArrayParser.java | 106 ---- .../parsers/FixedSizeIntegerArrayParser.java | 106 ---- .../construct/parsers/IntegerFillParser.java | 113 ---- .../gnunet/construct/parsers/IntegerParser.java | 95 --- src/org/gnunet/construct/parsers/IntegerUtil.java | 92 --- src/org/gnunet/construct/parsers/NestedParser.java | 119 ---- src/org/gnunet/construct/parsers/Parser.java | 78 --- .../gnunet/construct/parsers/SequenceParser.java | 106 ---- src/org/gnunet/construct/parsers/StringParser.java | 146 ----- src/org/gnunet/construct/parsers/UnionParser.java | 143 ----- .../construct/parsers/VariableSizeArrayParser.java | 106 ---- .../parsers/VariableSizeIntegerArrayParser.java | 103 --- src/org/gnunet/construct/parsers/package-info.java | 25 - src/org/gnunet/core/ConnectHandler.java | 30 - src/org/gnunet/core/ConnectNotifyMessage.java | 54 -- src/org/gnunet/core/Core.java | 379 ----------- src/org/gnunet/core/DisconnectHandler.java | 30 - src/org/gnunet/core/DisconnectNotifyMessage.java | 46 -- src/org/gnunet/core/HeaderNotify.java | 30 - src/org/gnunet/core/InitCallback.java | 30 - src/org/gnunet/core/InitMessage.java | 45 -- src/org/gnunet/core/InitReplyMessage.java | 39 -- src/org/gnunet/core/MessageNotify.java | 28 - .../gnunet/core/NotifyInboundTrafficMessage.java | 47 -- .../gnunet/core/NotifyOutboundTrafficMessage.java | 58 -- src/org/gnunet/core/SendMessage.java | 71 --- src/org/gnunet/core/SendMessageReady.java | 56 -- src/org/gnunet/core/SendMessageRequest.java | 73 --- src/org/gnunet/core/package-info.java | 24 - src/org/gnunet/dht/BlockType.java | 81 --- src/org/gnunet/dht/ClientGetMessage.java | 51 -- src/org/gnunet/dht/ClientGetStopMessage.java | 45 -- .../gnunet/dht/ClientPutConfirmationMessage.java | 38 -- src/org/gnunet/dht/ClientPutMessage.java | 54 -- src/org/gnunet/dht/ClientResultMessage.java | 56 -- src/org/gnunet/dht/DistributedHashTable.java | 469 -------------- src/org/gnunet/dht/MonitorGetHandler.java | 30 - src/org/gnunet/dht/MonitorGetMessage.java | 75 --- src/org/gnunet/dht/MonitorGetRespMessage.java | 72 --- src/org/gnunet/dht/MonitorGetResponseHandler.java | 31 - src/org/gnunet/dht/MonitorPutHandler.java | 31 - src/org/gnunet/dht/MonitorPutMessage.java | 82 --- src/org/gnunet/dht/MonitorStartStop.java | 70 --- src/org/gnunet/dht/ResultCallback.java | 46 -- src/org/gnunet/dht/RouteOption.java | 55 -- src/org/gnunet/dht/package-info.java | 24 - src/org/gnunet/hello/HelloMessage.java | 50 -- src/org/gnunet/hello/package-info.java | 25 - src/org/gnunet/mesh/ClientConnectMessage.java | 17 - src/org/gnunet/mesh/ConnectHandler.java | 13 - src/org/gnunet/mesh/DataMessage.java | 19 - src/org/gnunet/mesh/DisconnectHandler.java | 12 - src/org/gnunet/mesh/InboundTunnelHandler.java | 12 - src/org/gnunet/mesh/LocalAckMessage.java | 18 - src/org/gnunet/mesh/Mesh.java | 293 --------- src/org/gnunet/mesh/MeshRunabout.java | 19 - src/org/gnunet/mesh/TunnelCreateMessage.java | 27 - src/org/gnunet/mesh/TunnelDestroyMessage.java | 16 - src/org/gnunet/mesh/TunnelEndHandler.java | 10 - src/org/gnunet/mesh/TunnelNotificationMessage.java | 22 - src/org/gnunet/mesh/package-info.java | 25 - src/org/gnunet/mq/ClientMessageQueue.java | 44 -- src/org/gnunet/mq/Envelope.java | 34 - src/org/gnunet/mq/MessageQueue.java | 41 -- src/org/gnunet/mq/NotifySentHandler.java | 6 - src/org/gnunet/nse/NetworkSizeEstimation.java | 169 ----- src/org/gnunet/nse/StartMessage.java | 12 - src/org/gnunet/nse/UpdateMessage.java | 26 - src/org/gnunet/nse/package-info.java | 24 - src/org/gnunet/peerinfo/InfoEnd.java | 14 - src/org/gnunet/peerinfo/InfoMessage.java | 50 -- src/org/gnunet/peerinfo/ListAllPeersMessage.java | 39 -- src/org/gnunet/peerinfo/ListPeerMessage.java | 39 -- src/org/gnunet/peerinfo/PeerInfo.java | 123 ---- src/org/gnunet/peerinfo/PeerProcessor.java | 12 - .../gnunet/peerinfo/RsaPublicKeyBinaryEncoded.java | 56 -- src/org/gnunet/peerinfo/package-info.java | 25 - src/org/gnunet/requests/FixedMessageRequest.java | 23 - src/org/gnunet/requests/Request.java | 82 --- src/org/gnunet/requests/RequestQueue.java | 294 --------- src/org/gnunet/requests/package-info.java | 25 - src/org/gnunet/statistics/GetMessage.java | 43 -- .../gnunet/statistics/GetResponseEndMessage.java | 32 - src/org/gnunet/statistics/GetResponseMessage.java | 49 -- src/org/gnunet/statistics/SetMessage.java | 43 -- src/org/gnunet/statistics/Statistics.java | 408 ------------ src/org/gnunet/statistics/StatisticsReceiver.java | 27 - src/org/gnunet/statistics/WatchMessage.java | 40 -- .../gnunet/statistics/WatchResponseMessage.java | 39 -- src/org/gnunet/statistics/package-info.java | 24 - src/org/gnunet/testing/TestingServer.java | 65 -- src/org/gnunet/testing/TestingSetup.java | 56 -- src/org/gnunet/testing/TestingSubsystem.java | 143 ----- src/org/gnunet/testing/package-info.java | 27 - src/org/gnunet/transport/BlacklistCallback.java | 9 - src/org/gnunet/transport/HelloUpdateCallback.java | 9 - src/org/gnunet/transport/PeerIterateCallback.java | 9 - .../gnunet/transport/RequestConnectMessage.java | 24 - src/org/gnunet/transport/StartMessage.java | 32 - src/org/gnunet/transport/Transport.java | 116 ---- src/org/gnunet/transport/TryConnectCallback.java | 9 - src/org/gnunet/util/ATSInformation.java | 37 -- src/org/gnunet/util/AbsoluteTime.java | 269 -------- src/org/gnunet/util/AbsoluteTimeMessage.java | 47 -- src/org/gnunet/util/Cancelable.java | 28 - src/org/gnunet/util/Client.java | 262 -------- src/org/gnunet/util/Configuration.java | 378 ----------- src/org/gnunet/util/Connection.java | 695 -------------------- src/org/gnunet/util/Continuation.java | 25 - src/org/gnunet/util/GnunetMessage.java | 81 --- src/org/gnunet/util/HashCode.java | 94 --- src/org/gnunet/util/HelperProcess.java | 21 - src/org/gnunet/util/MessageReceiver.java | 41 -- src/org/gnunet/util/MessageTransmitter.java | 43 -- src/org/gnunet/util/PeerIdentity.java | 69 -- src/org/gnunet/util/Program.java | 221 ------- src/org/gnunet/util/RelativeTime.java | 223 ------- src/org/gnunet/util/RelativeTimeMessage.java | 55 -- src/org/gnunet/util/Resolver.java | 421 ------------- src/org/gnunet/util/RunaboutMessageReceiver.java | 33 - src/org/gnunet/util/RunaboutUtil.java | 55 -- src/org/gnunet/util/Scheduler.java | 674 -------------------- src/org/gnunet/util/Server.java | 509 --------------- src/org/gnunet/util/Service.java | 154 ----- src/org/gnunet/util/Strings.java | 138 ---- src/org/gnunet/util/TestMessage.java | 31 - src/org/gnunet/util/UnknownMessageBody.java | 35 -- src/org/gnunet/util/getopt/Argument.java | 47 -- src/org/gnunet/util/getopt/ArgumentAction.java | 29 - src/org/gnunet/util/getopt/Parser.java | 294 --------- src/org/gnunet/util/getopt/package-info.java | 24 - src/org/gnunet/util/package-info.java | 24 - src/org/gnunet/voting/Authority.java | 266 -------- src/org/gnunet/voting/Ballot.java | 105 ---- src/org/gnunet/voting/BogusAuthority.java | 9 - src/org/gnunet/voting/CallForVoters.java | 14 - src/org/gnunet/voting/CryptoUtil.java | 86 --- src/org/gnunet/voting/Cyphertext.java | 19 - src/org/gnunet/voting/ElectionSupervisor.java | 105 ---- src/org/gnunet/voting/GroupPublicKey.java | 28 - src/org/gnunet/voting/TallyKeyShare.java | 41 -- .../gnunet/voting/TransmitShareVerification.java | 18 - src/org/gnunet/voting/Voter.java | 31 - src/org/gnunet/voting/VotingParameters.java | 166 ----- src/org/gnunet/voting/VotingSimulation.java | 122 ---- src/org/grothoff/Runabout.java | 574 ----------------- src/org/grothoff/package-info.java | 4 - .../java/org/gnunet/construct/ByteFillMessage.java | 32 + .../java/org/gnunet/construct/ConstructTest.java | 82 +++ src/test/java/org/gnunet/construct/DoubleTest.java | 35 ++ .../java/org/gnunet/construct/FillParserTest.java | 37 ++ .../java/org/gnunet/construct/FixedSizeTest.java | 52 ++ .../java/org/gnunet/construct/FrameSizeTest.java | 50 ++ src/test/java/org/gnunet/construct/IntMessage.java | 25 + .../org/gnunet/construct/OptionalUnionTest.java | 72 +++ .../org/gnunet/construct/PrivateMemberMessage.java | 13 + .../java/org/gnunet/construct/QueryMessage.java | 31 + .../java/org/gnunet/construct/SendMessageTest.java | 34 + .../java/org/gnunet/construct/StringMessage.java | 32 + src/test/java/org/gnunet/construct/StringTest.java | 50 ++ .../java/org/gnunet/construct/StringTuple.java | 37 ++ .../gnunet/construct/VariableSizeArrayTest.java | 33 + .../org/gnunet/construct/VariableSizeMessage.java | 17 + src/test/java/org/gnunet/core/CoreTest.java | 111 ++++ src/test/java/org/gnunet/dht/DHTTest.java | 171 +++++ src/test/java/org/gnunet/mesh/MeshTest.java | 47 ++ src/test/java/org/gnunet/nse/NSETest.java | 56 ++ .../java/org/gnunet/peerinfo/PeerInfoTest.java | 41 ++ .../java/org/gnunet/statistics/StatisticsTest.java | 180 ++++++ .../java/org/gnunet/testing/TestingSetupTest.java | 54 ++ src/test/java/org/gnunet/util/Assertion.java | 37 ++ src/test/java/org/gnunet/util/AssertionList.java | 30 + .../java/org/gnunet/util/ClientServerTest.java | 251 ++++++++ src/test/java/org/gnunet/util/FilePipeExample.java | 41 ++ src/test/java/org/gnunet/util/ResolverTest.java | 92 +++ src/test/java/org/gnunet/util/ServerExample.java | 79 +++ src/test/java/org/gnunet/util/StringsTest.java | 20 + src/test/java/org/gnunet/util/TimeTest.java | 29 + src/test/java/org/gnunet/util/Wrapper.java | 43 ++ .../java/org/gnunet/util/getopt/GetoptTest.java | 286 +++++++++ src/test/java/org/grothoff/RunaboutBenchmark.java | 82 +++ 434 files changed, 18847 insertions(+), 15739 deletions(-) create mode 100644 src/main/java/org/gnunet/consensus/ConcludeCallback.java create mode 100644 src/main/java/org/gnunet/consensus/ConcludeDoneMessage.java create mode 100644 src/main/java/org/gnunet/consensus/ConcludeMessage.java create mode 100644 src/main/java/org/gnunet/consensus/Consensus.java create mode 100644 src/main/java/org/gnunet/consensus/ConsensusElement.java create mode 100644 src/main/java/org/gnunet/consensus/InsertDoneCallback.java create mode 100644 src/main/java/org/gnunet/consensus/InsertElementMessage.java create mode 100644 src/main/java/org/gnunet/consensus/NewElementCallback.java create mode 100644 src/main/java/org/gnunet/consensus/NewElementMessage.java create mode 100644 src/main/java/org/gnunet/construct/Construct.java create mode 100644 src/main/java/org/gnunet/construct/DoubleValue.java create mode 100644 src/main/java/org/gnunet/construct/FillWith.java create mode 100644 src/main/java/org/gnunet/construct/FixedSizeArray.java create mode 100644 src/main/java/org/gnunet/construct/FixedSizeIntegerArray.java create mode 100644 src/main/java/org/gnunet/construct/FrameSize.java create mode 100644 src/main/java/org/gnunet/construct/Int16.java create mode 100644 src/main/java/org/gnunet/construct/Int32.java create mode 100644 src/main/java/org/gnunet/construct/Int64.java create mode 100644 src/main/java/org/gnunet/construct/Int8.java create mode 100644 src/main/java/org/gnunet/construct/IntegerFill.java create mode 100644 src/main/java/org/gnunet/construct/Message.java create mode 100644 src/main/java/org/gnunet/construct/MessageIdAnnotationProcessor.java create mode 100644 src/main/java/org/gnunet/construct/MessageLoader.java create mode 100644 src/main/java/org/gnunet/construct/MessageUnion.java create mode 100644 src/main/java/org/gnunet/construct/MsgMap.txt create mode 100644 src/main/java/org/gnunet/construct/NestedMessage.java create mode 100644 src/main/java/org/gnunet/construct/ProtocolViolationException.java create mode 100644 src/main/java/org/gnunet/construct/ReflectUtil.java create mode 100644 src/main/java/org/gnunet/construct/UInt16.java create mode 100644 src/main/java/org/gnunet/construct/UInt32.java create mode 100644 src/main/java/org/gnunet/construct/UInt64.java create mode 100644 src/main/java/org/gnunet/construct/UInt8.java create mode 100644 src/main/java/org/gnunet/construct/Union.java create mode 100644 src/main/java/org/gnunet/construct/UnionCase.java create mode 100644 src/main/java/org/gnunet/construct/VariableSizeArray.java create mode 100644 src/main/java/org/gnunet/construct/VariableSizeIntegerArray.java create mode 100644 src/main/java/org/gnunet/construct/ZeroTerminatedString.java create mode 100644 src/main/java/org/gnunet/construct/package-info.java create mode 100644 src/main/java/org/gnunet/construct/parsers/DoubleParser.java create mode 100644 src/main/java/org/gnunet/construct/parsers/FillParser.java create mode 100644 src/main/java/org/gnunet/construct/parsers/FixedSizeArrayParser.java create mode 100644 src/main/java/org/gnunet/construct/parsers/FixedSizeIntegerArrayParser.java create mode 100644 src/main/java/org/gnunet/construct/parsers/IntegerFillParser.java create mode 100644 src/main/java/org/gnunet/construct/parsers/IntegerParser.java create mode 100644 src/main/java/org/gnunet/construct/parsers/IntegerUtil.java create mode 100644 src/main/java/org/gnunet/construct/parsers/NestedParser.java create mode 100644 src/main/java/org/gnunet/construct/parsers/Parser.java create mode 100644 src/main/java/org/gnunet/construct/parsers/SequenceParser.java create mode 100644 src/main/java/org/gnunet/construct/parsers/StringParser.java create mode 100644 src/main/java/org/gnunet/construct/parsers/UnionParser.java create mode 100644 src/main/java/org/gnunet/construct/parsers/VariableSizeArrayParser.java create mode 100644 src/main/java/org/gnunet/construct/parsers/VariableSizeIntegerArrayParser.java create mode 100644 src/main/java/org/gnunet/construct/parsers/package-info.java create mode 100644 src/main/java/org/gnunet/core/ConnectHandler.java create mode 100644 src/main/java/org/gnunet/core/ConnectNotifyMessage.java create mode 100644 src/main/java/org/gnunet/core/Core.java create mode 100644 src/main/java/org/gnunet/core/DisconnectHandler.java create mode 100644 src/main/java/org/gnunet/core/DisconnectNotifyMessage.java create mode 100644 src/main/java/org/gnunet/core/HeaderNotify.java create mode 100644 src/main/java/org/gnunet/core/InitCallback.java create mode 100644 src/main/java/org/gnunet/core/InitMessage.java create mode 100644 src/main/java/org/gnunet/core/InitReplyMessage.java create mode 100644 src/main/java/org/gnunet/core/MessageNotify.java create mode 100644 src/main/java/org/gnunet/core/NotifyInboundTrafficMessage.java create mode 100644 src/main/java/org/gnunet/core/NotifyOutboundTrafficMessage.java create mode 100644 src/main/java/org/gnunet/core/RequestIdentification.java create mode 100644 src/main/java/org/gnunet/core/SendMessage.java create mode 100644 src/main/java/org/gnunet/core/SendMessageReady.java create mode 100644 src/main/java/org/gnunet/core/SendMessageRequest.java create mode 100644 src/main/java/org/gnunet/core/package-info.java create mode 100644 src/main/java/org/gnunet/dht/BlockType.java create mode 100644 src/main/java/org/gnunet/dht/ClientGetMessage.java create mode 100644 src/main/java/org/gnunet/dht/ClientGetStopMessage.java create mode 100644 src/main/java/org/gnunet/dht/ClientPutConfirmationMessage.java create mode 100644 src/main/java/org/gnunet/dht/ClientPutMessage.java create mode 100644 src/main/java/org/gnunet/dht/ClientResultMessage.java create mode 100644 src/main/java/org/gnunet/dht/DistributedHashTable.java create mode 100644 src/main/java/org/gnunet/dht/MonitorGetHandler.java create mode 100644 src/main/java/org/gnunet/dht/MonitorGetMessage.java create mode 100644 src/main/java/org/gnunet/dht/MonitorGetRespMessage.java create mode 100644 src/main/java/org/gnunet/dht/MonitorGetResponseHandler.java create mode 100644 src/main/java/org/gnunet/dht/MonitorPutHandler.java create mode 100644 src/main/java/org/gnunet/dht/MonitorPutMessage.java create mode 100644 src/main/java/org/gnunet/dht/MonitorStartStop.java create mode 100644 src/main/java/org/gnunet/dht/ResultCallback.java create mode 100644 src/main/java/org/gnunet/dht/RouteOption.java create mode 100644 src/main/java/org/gnunet/dht/package-info.java create mode 100644 src/main/java/org/gnunet/hello/HelloMessage.java create mode 100644 src/main/java/org/gnunet/hello/package-info.java create mode 100644 src/main/java/org/gnunet/mesh/ClientConnectMessage.java create mode 100644 src/main/java/org/gnunet/mesh/ConnectHandler.java create mode 100644 src/main/java/org/gnunet/mesh/DataMessage.java create mode 100644 src/main/java/org/gnunet/mesh/DisconnectHandler.java create mode 100644 src/main/java/org/gnunet/mesh/InboundTunnelHandler.java create mode 100644 src/main/java/org/gnunet/mesh/LocalAckMessage.java create mode 100644 src/main/java/org/gnunet/mesh/Mesh.java create mode 100644 src/main/java/org/gnunet/mesh/MeshRunabout.java create mode 100644 src/main/java/org/gnunet/mesh/TunnelCreateMessage.java create mode 100644 src/main/java/org/gnunet/mesh/TunnelDestroyMessage.java create mode 100644 src/main/java/org/gnunet/mesh/TunnelEndHandler.java create mode 100644 src/main/java/org/gnunet/mesh/TunnelNotificationMessage.java create mode 100644 src/main/java/org/gnunet/mesh/package-info.java create mode 100644 src/main/java/org/gnunet/mq/Envelope.java create mode 100644 src/main/java/org/gnunet/mq/MessageQueue.java create mode 100644 src/main/java/org/gnunet/mq/NotifySentHandler.java create mode 100644 src/main/java/org/gnunet/nse/NetworkSizeEstimation.java create mode 100644 src/main/java/org/gnunet/nse/StartMessage.java create mode 100644 src/main/java/org/gnunet/nse/UpdateMessage.java create mode 100644 src/main/java/org/gnunet/nse/package-info.java create mode 100644 src/main/java/org/gnunet/peerinfo/InfoEnd.java create mode 100644 src/main/java/org/gnunet/peerinfo/InfoMessage.java create mode 100644 src/main/java/org/gnunet/peerinfo/ListAllPeersMessage.java create mode 100644 src/main/java/org/gnunet/peerinfo/ListPeerMessage.java create mode 100644 src/main/java/org/gnunet/peerinfo/PeerInfo.java create mode 100644 src/main/java/org/gnunet/peerinfo/PeerProcessor.java create mode 100644 src/main/java/org/gnunet/peerinfo/RsaPublicKeyBinaryEncoded.java create mode 100644 src/main/java/org/gnunet/peerinfo/package-info.java create mode 100644 src/main/java/org/gnunet/requests/MatchingRequestContainer.java create mode 100644 src/main/java/org/gnunet/requests/RequestContainer.java create mode 100644 src/main/java/org/gnunet/requests/SequentialRequestContainer.java create mode 100644 src/main/java/org/gnunet/requests/package-info.java create mode 100644 src/main/java/org/gnunet/statistics/GetMessage.java create mode 100644 src/main/java/org/gnunet/statistics/GetRequest.java create mode 100644 src/main/java/org/gnunet/statistics/GetResponseEndMessage.java create mode 100644 src/main/java/org/gnunet/statistics/GetResponseMessage.java create mode 100644 src/main/java/org/gnunet/statistics/SetMessage.java create mode 100644 src/main/java/org/gnunet/statistics/SetRequest.java create mode 100644 src/main/java/org/gnunet/statistics/Statistics.java create mode 100644 src/main/java/org/gnunet/statistics/StatisticsReceiver.java create mode 100644 src/main/java/org/gnunet/statistics/StatisticsWatcher.java create mode 100644 src/main/java/org/gnunet/statistics/WatchMessage.java create mode 100644 src/main/java/org/gnunet/statistics/WatchRequest.java create mode 100644 src/main/java/org/gnunet/statistics/WatchResponseMessage.java create mode 100644 src/main/java/org/gnunet/statistics/package-info.java create mode 100644 src/main/java/org/gnunet/testbed/Controller.java create mode 100644 src/main/java/org/gnunet/testbed/ControllerEventCallback.java create mode 100644 src/main/java/org/gnunet/testbed/ControllerInitMessage.java create mode 100644 src/main/java/org/gnunet/testbed/ControllerProc.java create mode 100644 src/main/java/org/gnunet/testbed/ControllerStatusCallback.java create mode 100644 src/main/java/org/gnunet/testbed/HelperInitMessage.java create mode 100644 src/main/java/org/gnunet/testbed/HelperReplyMessage.java create mode 100644 src/main/java/org/gnunet/testbed/Host.java create mode 100644 src/main/java/org/gnunet/testbed/Operation.java create mode 100644 src/main/java/org/gnunet/testbed/OperationCompletionCallback.java create mode 100644 src/main/java/org/gnunet/testbed/Peer.java create mode 100644 src/main/java/org/gnunet/testbed/PeerChurnCallback.java create mode 100644 src/main/java/org/gnunet/testbed/PeerCreateCallback.java create mode 100644 src/main/java/org/gnunet/testing/TestingFixture.java create mode 100644 src/main/java/org/gnunet/testing/TestingServer.java create mode 100644 src/main/java/org/gnunet/testing/TestingSetup.java create mode 100644 src/main/java/org/gnunet/testing/TestingSubsystem.java create mode 100644 src/main/java/org/gnunet/testing/package-info.java create mode 100644 src/main/java/org/gnunet/transport/AddressIterateMessage.java create mode 100644 src/main/java/org/gnunet/transport/BlacklistCallback.java create mode 100644 src/main/java/org/gnunet/transport/BlacklistInitMessage.java create mode 100644 src/main/java/org/gnunet/transport/HelloUpdateCallback.java create mode 100644 src/main/java/org/gnunet/transport/PeerIterateCallback.java create mode 100644 src/main/java/org/gnunet/transport/RequestConnectMessage.java create mode 100644 src/main/java/org/gnunet/transport/StartMessage.java create mode 100644 src/main/java/org/gnunet/transport/Transport.java create mode 100644 src/main/java/org/gnunet/transport/TryConnectCallback.java create mode 100644 src/main/java/org/gnunet/util/ATSInformation.java create mode 100644 src/main/java/org/gnunet/util/AbsoluteTime.java create mode 100644 src/main/java/org/gnunet/util/AbsoluteTimeMessage.java create mode 100644 src/main/java/org/gnunet/util/Cancelable.java create mode 100644 src/main/java/org/gnunet/util/Client.java create mode 100644 src/main/java/org/gnunet/util/Configuration.java create mode 100644 src/main/java/org/gnunet/util/Connection.java create mode 100644 src/main/java/org/gnunet/util/Continuation.java create mode 100644 src/main/java/org/gnunet/util/GnunetMessage.java create mode 100644 src/main/java/org/gnunet/util/HashCode.java create mode 100644 src/main/java/org/gnunet/util/Helper.java create mode 100644 src/main/java/org/gnunet/util/MessageReceiver.java create mode 100644 src/main/java/org/gnunet/util/MessageTransmitter.java create mode 100644 src/main/java/org/gnunet/util/PeerIdentity.java create mode 100644 src/main/java/org/gnunet/util/Program.java create mode 100644 src/main/java/org/gnunet/util/RelativeTime.java create mode 100644 src/main/java/org/gnunet/util/RelativeTimeMessage.java create mode 100644 src/main/java/org/gnunet/util/Resolver.java create mode 100644 src/main/java/org/gnunet/util/RunaboutMessageReceiver.java create mode 100644 src/main/java/org/gnunet/util/RunaboutUtil.java create mode 100644 src/main/java/org/gnunet/util/Scheduler.java create mode 100644 src/main/java/org/gnunet/util/Server.java create mode 100644 src/main/java/org/gnunet/util/Service.java create mode 100644 src/main/java/org/gnunet/util/Strings.java create mode 100644 src/main/java/org/gnunet/util/TestMessage.java create mode 100644 src/main/java/org/gnunet/util/UnknownMessageBody.java create mode 100644 src/main/java/org/gnunet/util/getopt/Argument.java create mode 100644 src/main/java/org/gnunet/util/getopt/ArgumentAction.java create mode 100644 src/main/java/org/gnunet/util/getopt/Parser.java create mode 100644 src/main/java/org/gnunet/util/getopt/package-info.java create mode 100644 src/main/java/org/gnunet/util/package-info.java create mode 100644 src/main/java/org/gnunet/voting/CertificateAuthorityService.java create mode 100644 src/main/java/org/gnunet/voting/ElectionCallTool.java create mode 100644 src/main/java/org/gnunet/voting/ElectionSpecification.java create mode 100644 src/main/java/org/gnunet/voting/TallyAuthorityService.java create mode 100644 src/main/java/org/gnunet/voting/VotingTool.java create mode 100644 src/main/java/org/gnunet/voting/simulation/Authority.java create mode 100644 src/main/java/org/gnunet/voting/simulation/Ballot.java create mode 100644 src/main/java/org/gnunet/voting/simulation/BogusAuthority.java create mode 100644 src/main/java/org/gnunet/voting/simulation/CallForVoters.java create mode 100644 src/main/java/org/gnunet/voting/simulation/CryptoUtil.java create mode 100644 src/main/java/org/gnunet/voting/simulation/Cyphertext.java create mode 100644 src/main/java/org/gnunet/voting/simulation/ElectionSupervisor.java create mode 100644 src/main/java/org/gnunet/voting/simulation/GroupPublicKey.java create mode 100644 src/main/java/org/gnunet/voting/simulation/TallyKeyShare.java create mode 100644 src/main/java/org/gnunet/voting/simulation/TransmitShareVerification.java create mode 100644 src/main/java/org/gnunet/voting/simulation/Voter.java create mode 100644 src/main/java/org/gnunet/voting/simulation/VotingParameters.java create mode 100644 src/main/java/org/gnunet/voting/simulation/VotingSimulation.java create mode 100644 src/main/java/org/grothoff/Runabout.java create mode 100644 src/main/java/org/grothoff/package-info.java create mode 100644 src/main/resources/org/gnunet/construct/MsgMap.txt delete mode 100644 src/org/gnunet/consensus/ConcludeCallback.java delete mode 100644 src/org/gnunet/consensus/ConcludeDoneMessage.java delete mode 100644 src/org/gnunet/consensus/ConcludeMessage.java delete mode 100644 src/org/gnunet/consensus/Consensus.java delete mode 100644 src/org/gnunet/consensus/ConsensusElement.java delete mode 100644 src/org/gnunet/consensus/InsertDoneCallback.java delete mode 100644 src/org/gnunet/consensus/InsertElementMessage.java delete mode 100644 src/org/gnunet/consensus/NewElementCallback.java delete mode 100644 src/org/gnunet/consensus/NewElementMessage.java delete mode 100644 src/org/gnunet/construct/Construct.java delete mode 100644 src/org/gnunet/construct/DoubleValue.java delete mode 100644 src/org/gnunet/construct/FillWith.java delete mode 100644 src/org/gnunet/construct/FixedSizeArray.java delete mode 100644 src/org/gnunet/construct/FixedSizeIntegerArray.java delete mode 100644 src/org/gnunet/construct/FrameSize.java delete mode 100644 src/org/gnunet/construct/Int16.java delete mode 100644 src/org/gnunet/construct/Int32.java delete mode 100644 src/org/gnunet/construct/Int64.java delete mode 100644 src/org/gnunet/construct/Int8.java delete mode 100644 src/org/gnunet/construct/IntegerFill.java delete mode 100644 src/org/gnunet/construct/Message.java delete mode 100644 src/org/gnunet/construct/MessageIdAnnotationProcessor.java delete mode 100644 src/org/gnunet/construct/MessageLoader.java delete mode 100644 src/org/gnunet/construct/MessageUnion.java delete mode 100644 src/org/gnunet/construct/MsgMap.txt delete mode 100644 src/org/gnunet/construct/NestedMessage.java delete mode 100644 src/org/gnunet/construct/ProtocolViolationException.java delete mode 100644 src/org/gnunet/construct/ReflectUtil.java delete mode 100644 src/org/gnunet/construct/UInt16.java delete mode 100644 src/org/gnunet/construct/UInt32.java delete mode 100644 src/org/gnunet/construct/UInt64.java delete mode 100644 src/org/gnunet/construct/UInt8.java delete mode 100644 src/org/gnunet/construct/Union.java delete mode 100644 src/org/gnunet/construct/UnionCase.java delete mode 100644 src/org/gnunet/construct/VariableSizeArray.java delete mode 100644 src/org/gnunet/construct/VariableSizeIntegerArray.java delete mode 100644 src/org/gnunet/construct/ZeroTerminatedString.java delete mode 100644 src/org/gnunet/construct/package-info.java delete mode 100644 src/org/gnunet/construct/parsers/DoubleParser.java delete mode 100644 src/org/gnunet/construct/parsers/FillParser.java delete mode 100644 src/org/gnunet/construct/parsers/FixedSizeArrayParser.java delete mode 100644 src/org/gnunet/construct/parsers/FixedSizeIntegerArrayParser.java delete mode 100644 src/org/gnunet/construct/parsers/IntegerFillParser.java delete mode 100644 src/org/gnunet/construct/parsers/IntegerParser.java delete mode 100644 src/org/gnunet/construct/parsers/IntegerUtil.java delete mode 100644 src/org/gnunet/construct/parsers/NestedParser.java delete mode 100644 src/org/gnunet/construct/parsers/Parser.java delete mode 100644 src/org/gnunet/construct/parsers/SequenceParser.java delete mode 100644 src/org/gnunet/construct/parsers/StringParser.java delete mode 100644 src/org/gnunet/construct/parsers/UnionParser.java delete mode 100644 src/org/gnunet/construct/parsers/VariableSizeArrayParser.java delete mode 100644 src/org/gnunet/construct/parsers/VariableSizeIntegerArrayParser.java delete mode 100644 src/org/gnunet/construct/parsers/package-info.java delete mode 100644 src/org/gnunet/core/ConnectHandler.java delete mode 100644 src/org/gnunet/core/ConnectNotifyMessage.java delete mode 100644 src/org/gnunet/core/Core.java delete mode 100644 src/org/gnunet/core/DisconnectHandler.java delete mode 100644 src/org/gnunet/core/DisconnectNotifyMessage.java delete mode 100644 src/org/gnunet/core/HeaderNotify.java delete mode 100644 src/org/gnunet/core/InitCallback.java delete mode 100644 src/org/gnunet/core/InitMessage.java delete mode 100644 src/org/gnunet/core/InitReplyMessage.java delete mode 100644 src/org/gnunet/core/MessageNotify.java delete mode 100644 src/org/gnunet/core/NotifyInboundTrafficMessage.java delete mode 100644 src/org/gnunet/core/NotifyOutboundTrafficMessage.java delete mode 100644 src/org/gnunet/core/SendMessage.java delete mode 100644 src/org/gnunet/core/SendMessageReady.java delete mode 100644 src/org/gnunet/core/SendMessageRequest.java delete mode 100644 src/org/gnunet/core/package-info.java delete mode 100644 src/org/gnunet/dht/BlockType.java delete mode 100644 src/org/gnunet/dht/ClientGetMessage.java delete mode 100644 src/org/gnunet/dht/ClientGetStopMessage.java delete mode 100644 src/org/gnunet/dht/ClientPutConfirmationMessage.java delete mode 100644 src/org/gnunet/dht/ClientPutMessage.java delete mode 100644 src/org/gnunet/dht/ClientResultMessage.java delete mode 100644 src/org/gnunet/dht/DistributedHashTable.java delete mode 100644 src/org/gnunet/dht/MonitorGetHandler.java delete mode 100644 src/org/gnunet/dht/MonitorGetMessage.java delete mode 100644 src/org/gnunet/dht/MonitorGetRespMessage.java delete mode 100644 src/org/gnunet/dht/MonitorGetResponseHandler.java delete mode 100644 src/org/gnunet/dht/MonitorPutHandler.java delete mode 100644 src/org/gnunet/dht/MonitorPutMessage.java delete mode 100644 src/org/gnunet/dht/MonitorStartStop.java delete mode 100644 src/org/gnunet/dht/ResultCallback.java delete mode 100644 src/org/gnunet/dht/RouteOption.java delete mode 100644 src/org/gnunet/dht/package-info.java delete mode 100644 src/org/gnunet/hello/HelloMessage.java delete mode 100644 src/org/gnunet/hello/package-info.java delete mode 100644 src/org/gnunet/mesh/ClientConnectMessage.java delete mode 100644 src/org/gnunet/mesh/ConnectHandler.java delete mode 100644 src/org/gnunet/mesh/DataMessage.java delete mode 100644 src/org/gnunet/mesh/DisconnectHandler.java delete mode 100644 src/org/gnunet/mesh/InboundTunnelHandler.java delete mode 100644 src/org/gnunet/mesh/LocalAckMessage.java delete mode 100644 src/org/gnunet/mesh/Mesh.java delete mode 100644 src/org/gnunet/mesh/MeshRunabout.java delete mode 100644 src/org/gnunet/mesh/TunnelCreateMessage.java delete mode 100644 src/org/gnunet/mesh/TunnelDestroyMessage.java delete mode 100644 src/org/gnunet/mesh/TunnelEndHandler.java delete mode 100644 src/org/gnunet/mesh/TunnelNotificationMessage.java delete mode 100644 src/org/gnunet/mesh/package-info.java delete mode 100644 src/org/gnunet/mq/ClientMessageQueue.java delete mode 100644 src/org/gnunet/mq/Envelope.java delete mode 100644 src/org/gnunet/mq/MessageQueue.java delete mode 100644 src/org/gnunet/mq/NotifySentHandler.java delete mode 100644 src/org/gnunet/nse/NetworkSizeEstimation.java delete mode 100644 src/org/gnunet/nse/StartMessage.java delete mode 100644 src/org/gnunet/nse/UpdateMessage.java delete mode 100644 src/org/gnunet/nse/package-info.java delete mode 100644 src/org/gnunet/peerinfo/InfoEnd.java delete mode 100644 src/org/gnunet/peerinfo/InfoMessage.java delete mode 100644 src/org/gnunet/peerinfo/ListAllPeersMessage.java delete mode 100644 src/org/gnunet/peerinfo/ListPeerMessage.java delete mode 100644 src/org/gnunet/peerinfo/PeerInfo.java delete mode 100644 src/org/gnunet/peerinfo/PeerProcessor.java delete mode 100644 src/org/gnunet/peerinfo/RsaPublicKeyBinaryEncoded.java delete mode 100644 src/org/gnunet/peerinfo/package-info.java delete mode 100644 src/org/gnunet/requests/FixedMessageRequest.java delete mode 100644 src/org/gnunet/requests/Request.java delete mode 100644 src/org/gnunet/requests/RequestQueue.java delete mode 100644 src/org/gnunet/requests/package-info.java delete mode 100644 src/org/gnunet/statistics/GetMessage.java delete mode 100644 src/org/gnunet/statistics/GetResponseEndMessage.java delete mode 100644 src/org/gnunet/statistics/GetResponseMessage.java delete mode 100644 src/org/gnunet/statistics/SetMessage.java delete mode 100644 src/org/gnunet/statistics/Statistics.java delete mode 100644 src/org/gnunet/statistics/StatisticsReceiver.java delete mode 100644 src/org/gnunet/statistics/WatchMessage.java delete mode 100644 src/org/gnunet/statistics/WatchResponseMessage.java delete mode 100644 src/org/gnunet/statistics/package-info.java delete mode 100644 src/org/gnunet/testing/TestingServer.java delete mode 100644 src/org/gnunet/testing/TestingSetup.java delete mode 100644 src/org/gnunet/testing/TestingSubsystem.java delete mode 100644 src/org/gnunet/testing/package-info.java delete mode 100644 src/org/gnunet/transport/BlacklistCallback.java delete mode 100644 src/org/gnunet/transport/HelloUpdateCallback.java delete mode 100644 src/org/gnunet/transport/PeerIterateCallback.java delete mode 100644 src/org/gnunet/transport/RequestConnectMessage.java delete mode 100644 src/org/gnunet/transport/StartMessage.java delete mode 100644 src/org/gnunet/transport/Transport.java delete mode 100644 src/org/gnunet/transport/TryConnectCallback.java delete mode 100644 src/org/gnunet/util/ATSInformation.java delete mode 100644 src/org/gnunet/util/AbsoluteTime.java delete mode 100644 src/org/gnunet/util/AbsoluteTimeMessage.java delete mode 100644 src/org/gnunet/util/Cancelable.java delete mode 100644 src/org/gnunet/util/Client.java delete mode 100644 src/org/gnunet/util/Configuration.java delete mode 100644 src/org/gnunet/util/Connection.java delete mode 100644 src/org/gnunet/util/Continuation.java delete mode 100644 src/org/gnunet/util/GnunetMessage.java delete mode 100644 src/org/gnunet/util/HashCode.java delete mode 100644 src/org/gnunet/util/HelperProcess.java delete mode 100644 src/org/gnunet/util/MessageReceiver.java delete mode 100644 src/org/gnunet/util/MessageTransmitter.java delete mode 100644 src/org/gnunet/util/PeerIdentity.java delete mode 100644 src/org/gnunet/util/Program.java delete mode 100644 src/org/gnunet/util/RelativeTime.java delete mode 100644 src/org/gnunet/util/RelativeTimeMessage.java delete mode 100644 src/org/gnunet/util/Resolver.java delete mode 100644 src/org/gnunet/util/RunaboutMessageReceiver.java delete mode 100644 src/org/gnunet/util/RunaboutUtil.java delete mode 100644 src/org/gnunet/util/Scheduler.java delete mode 100644 src/org/gnunet/util/Server.java delete mode 100644 src/org/gnunet/util/Service.java delete mode 100644 src/org/gnunet/util/Strings.java delete mode 100644 src/org/gnunet/util/TestMessage.java delete mode 100644 src/org/gnunet/util/UnknownMessageBody.java delete mode 100644 src/org/gnunet/util/getopt/Argument.java delete mode 100644 src/org/gnunet/util/getopt/ArgumentAction.java delete mode 100644 src/org/gnunet/util/getopt/Parser.java delete mode 100644 src/org/gnunet/util/getopt/package-info.java delete mode 100644 src/org/gnunet/util/package-info.java delete mode 100644 src/org/gnunet/voting/Authority.java delete mode 100644 src/org/gnunet/voting/Ballot.java delete mode 100644 src/org/gnunet/voting/BogusAuthority.java delete mode 100644 src/org/gnunet/voting/CallForVoters.java delete mode 100644 src/org/gnunet/voting/CryptoUtil.java delete mode 100644 src/org/gnunet/voting/Cyphertext.java delete mode 100644 src/org/gnunet/voting/ElectionSupervisor.java delete mode 100644 src/org/gnunet/voting/GroupPublicKey.java delete mode 100644 src/org/gnunet/voting/TallyKeyShare.java delete mode 100644 src/org/gnunet/voting/TransmitShareVerification.java delete mode 100644 src/org/gnunet/voting/Voter.java delete mode 100644 src/org/gnunet/voting/VotingParameters.java delete mode 100644 src/org/gnunet/voting/VotingSimulation.java delete mode 100644 src/org/grothoff/Runabout.java delete mode 100644 src/org/grothoff/package-info.java create mode 100644 src/test/java/org/gnunet/construct/ByteFillMessage.java create mode 100644 src/test/java/org/gnunet/construct/ConstructTest.java create mode 100644 src/test/java/org/gnunet/construct/DoubleTest.java create mode 100644 src/test/java/org/gnunet/construct/FillParserTest.java create mode 100644 src/test/java/org/gnunet/construct/FixedSizeTest.java create mode 100644 src/test/java/org/gnunet/construct/FrameSizeTest.java create mode 100644 src/test/java/org/gnunet/construct/IntMessage.java create mode 100644 src/test/java/org/gnunet/construct/OptionalUnionTest.java create mode 100644 src/test/java/org/gnunet/construct/PrivateMemberMessage.java create mode 100644 src/test/java/org/gnunet/construct/QueryMessage.java create mode 100644 src/test/java/org/gnunet/construct/SendMessageTest.java create mode 100644 src/test/java/org/gnunet/construct/StringMessage.java create mode 100644 src/test/java/org/gnunet/construct/StringTest.java create mode 100644 src/test/java/org/gnunet/construct/StringTuple.java create mode 100644 src/test/java/org/gnunet/construct/VariableSizeArrayTest.java create mode 100644 src/test/java/org/gnunet/construct/VariableSizeMessage.java create mode 100644 src/test/java/org/gnunet/core/CoreTest.java create mode 100644 src/test/java/org/gnunet/dht/DHTTest.java create mode 100644 src/test/java/org/gnunet/mesh/MeshTest.java create mode 100644 src/test/java/org/gnunet/nse/NSETest.java create mode 100644 src/test/java/org/gnunet/peerinfo/PeerInfoTest.java create mode 100644 src/test/java/org/gnunet/statistics/StatisticsTest.java create mode 100644 src/test/java/org/gnunet/testing/TestingSetupTest.java create mode 100644 src/test/java/org/gnunet/util/Assertion.java create mode 100644 src/test/java/org/gnunet/util/AssertionList.java create mode 100644 src/test/java/org/gnunet/util/ClientServerTest.java create mode 100644 src/test/java/org/gnunet/util/FilePipeExample.java create mode 100644 src/test/java/org/gnunet/util/ResolverTest.java create mode 100644 src/test/java/org/gnunet/util/ServerExample.java create mode 100644 src/test/java/org/gnunet/util/StringsTest.java create mode 100644 src/test/java/org/gnunet/util/TimeTest.java create mode 100644 src/test/java/org/gnunet/util/Wrapper.java create mode 100644 src/test/java/org/gnunet/util/getopt/GetoptTest.java create mode 100644 src/test/java/org/grothoff/RunaboutBenchmark.java (limited to 'src') diff --git a/src/main/java/org/gnunet/consensus/ConcludeCallback.java b/src/main/java/org/gnunet/consensus/ConcludeCallback.java new file mode 100644 index 0000000..7660c49 --- /dev/null +++ b/src/main/java/org/gnunet/consensus/ConcludeCallback.java @@ -0,0 +1,5 @@ +package org.gnunet.consensus; + +public interface ConcludeCallback { + void onConcludeDone(); +} diff --git a/src/main/java/org/gnunet/consensus/ConcludeDoneMessage.java b/src/main/java/org/gnunet/consensus/ConcludeDoneMessage.java new file mode 100644 index 0000000..51757aa --- /dev/null +++ b/src/main/java/org/gnunet/consensus/ConcludeDoneMessage.java @@ -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 + */ +@UnionCase(525) +public class ConcludeDoneMessage implements MessageUnion { +} diff --git a/src/main/java/org/gnunet/consensus/ConcludeMessage.java b/src/main/java/org/gnunet/consensus/ConcludeMessage.java new file mode 100644 index 0000000..7b43928 --- /dev/null +++ b/src/main/java/org/gnunet/consensus/ConcludeMessage.java @@ -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 + */ +@UnionCase(524) +public class ConcludeMessage implements GnunetMessage.Body { + /* empty body */ +} \ No newline at end of file diff --git a/src/main/java/org/gnunet/consensus/Consensus.java b/src/main/java/org/gnunet/consensus/Consensus.java new file mode 100644 index 0000000..322599c --- /dev/null +++ b/src/main/java/org/gnunet/consensus/Consensus.java @@ -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; + } +} diff --git a/src/main/java/org/gnunet/consensus/ConsensusElement.java b/src/main/java/org/gnunet/consensus/ConsensusElement.java new file mode 100644 index 0000000..846e72a --- /dev/null +++ b/src/main/java/org/gnunet/consensus/ConsensusElement.java @@ -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; +} diff --git a/src/main/java/org/gnunet/consensus/InsertDoneCallback.java b/src/main/java/org/gnunet/consensus/InsertDoneCallback.java new file mode 100644 index 0000000..f0e86ca --- /dev/null +++ b/src/main/java/org/gnunet/consensus/InsertDoneCallback.java @@ -0,0 +1,5 @@ +package org.gnunet.consensus; + +public interface InsertDoneCallback { + void onInsertDone(); +} diff --git a/src/main/java/org/gnunet/consensus/InsertElementMessage.java b/src/main/java/org/gnunet/consensus/InsertElementMessage.java new file mode 100644 index 0000000..fd0ff67 --- /dev/null +++ b/src/main/java/org/gnunet/consensus/InsertElementMessage.java @@ -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 + */ +@UnionCase(521) +public class InsertElementMessage implements GnunetMessage.Body { + @UInt16 + public int element_type; + @FillWith + @UInt8 + public byte[] element_data; +} \ No newline at end of file diff --git a/src/main/java/org/gnunet/consensus/NewElementCallback.java b/src/main/java/org/gnunet/consensus/NewElementCallback.java new file mode 100644 index 0000000..4b07a71 --- /dev/null +++ b/src/main/java/org/gnunet/consensus/NewElementCallback.java @@ -0,0 +1,5 @@ +package org.gnunet.consensus; + +public interface NewElementCallback { + void onNewElement(ConsensusElement element); +} diff --git a/src/main/java/org/gnunet/consensus/NewElementMessage.java b/src/main/java/org/gnunet/consensus/NewElementMessage.java new file mode 100644 index 0000000..deb3634 --- /dev/null +++ b/src/main/java/org/gnunet/consensus/NewElementMessage.java @@ -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 + */ +@UnionCase(523) +public class NewElementMessage implements GnunetMessage.Body { + @UInt16 + public int element_type; + @FillWith + @UInt8 + public byte[] element_data; +} \ No newline at end of file diff --git a/src/main/java/org/gnunet/construct/Construct.java b/src/main/java/org/gnunet/construct/Construct.java new file mode 100644 index 0000000..a74a5c2 --- /dev/null +++ b/src/main/java/org/gnunet/construct/Construct.java @@ -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 => signed or unsigned fixnum, represented by n bits +- @NestedMessage => nested message +- @FillWith @(U)Int => 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 = "") => 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 + */ +@SuppressWarnings("unchecked") +public class Construct { + private static final Logger logger = LoggerFactory + .getLogger(Construct.class); + + + private static Map, Parser> parserCache = new HashMap, + 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 parseAs(ByteBuffer srcBuf, Class 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 parseAs(byte[] srcBuf, Class 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 c) { + + if (parserCache.containsKey(c)) { + return parserCache.get(c); + } + + Parser p = getParser(c, new ParserGenerator()); + + parserCache.put(c, p); + + return p; + } + + private static List getMessageFields(Class c) { + LinkedList fields = new LinkedList(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 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 path = new LinkedList(); + + // path of the object that has a frame size field + List frameSizePath; + + private ParserGenerator() { + } + + public void visit(Union u) { + parser = new UnionParser(u.optional(), (Class) field.getType(), + ReflectUtil.getFieldPathFromString(u.tag(), c), field); + } + + public void visit(FrameSize ts) { + + frameSizePath = new LinkedList(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) nestedField.getType()); + + parser = new NestedParser(p, n.optional(), nestedField, true); + + } else { + Field old_f = field; + List old_path = new ArrayList(path); + Class old_c = c; + + path.add(field); + + Parser p = getParser((Class) 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) 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) 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) 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) 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(); + } + +} diff --git a/src/main/java/org/gnunet/construct/DoubleValue.java b/src/main/java/org/gnunet/construct/DoubleValue.java new file mode 100644 index 0000000..0856fe8 --- /dev/null +++ b/src/main/java/org/gnunet/construct/DoubleValue.java @@ -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. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface DoubleValue { +} diff --git a/src/main/java/org/gnunet/construct/FillWith.java b/src/main/java/org/gnunet/construct/FillWith.java new file mode 100644 index 0000000..f95aa3d --- /dev/null +++ b/src/main/java/org/gnunet/construct/FillWith.java @@ -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 + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface FillWith { +} diff --git a/src/main/java/org/gnunet/construct/FixedSizeArray.java b/src/main/java/org/gnunet/construct/FixedSizeArray.java new file mode 100644 index 0000000..699ae68 --- /dev/null +++ b/src/main/java/org/gnunet/construct/FixedSizeArray.java @@ -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 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface FixedSizeArray { + int length(); +} diff --git a/src/main/java/org/gnunet/construct/FixedSizeIntegerArray.java b/src/main/java/org/gnunet/construct/FixedSizeIntegerArray.java new file mode 100644 index 0000000..b2418b8 --- /dev/null +++ b/src/main/java/org/gnunet/construct/FixedSizeIntegerArray.java @@ -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 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface FixedSizeIntegerArray { + int length(); + int bitSize(); + boolean signed(); +} diff --git a/src/main/java/org/gnunet/construct/FrameSize.java b/src/main/java/org/gnunet/construct/FrameSize.java new file mode 100644 index 0000000..0533d0b --- /dev/null +++ b/src/main/java/org/gnunet/construct/FrameSize.java @@ -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 + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface FrameSize { +} diff --git a/src/main/java/org/gnunet/construct/Int16.java b/src/main/java/org/gnunet/construct/Int16.java new file mode 100644 index 0000000..677324b --- /dev/null +++ b/src/main/java/org/gnunet/construct/Int16.java @@ -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 + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Int16 { + +} diff --git a/src/main/java/org/gnunet/construct/Int32.java b/src/main/java/org/gnunet/construct/Int32.java new file mode 100644 index 0000000..da993ca --- /dev/null +++ b/src/main/java/org/gnunet/construct/Int32.java @@ -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 + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Int32 { + +} diff --git a/src/main/java/org/gnunet/construct/Int64.java b/src/main/java/org/gnunet/construct/Int64.java new file mode 100644 index 0000000..be5d940 --- /dev/null +++ b/src/main/java/org/gnunet/construct/Int64.java @@ -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. + * + */ + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Int64 { + +} diff --git a/src/main/java/org/gnunet/construct/Int8.java b/src/main/java/org/gnunet/construct/Int8.java new file mode 100644 index 0000000..a0aaa14 --- /dev/null +++ b/src/main/java/org/gnunet/construct/Int8.java @@ -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 + * + */ + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Int8 { + +} diff --git a/src/main/java/org/gnunet/construct/IntegerFill.java b/src/main/java/org/gnunet/construct/IntegerFill.java new file mode 100644 index 0000000..4564c83 --- /dev/null +++ b/src/main/java/org/gnunet/construct/IntegerFill.java @@ -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. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface IntegerFill { + boolean signed(); + int bitSize(); +} diff --git a/src/main/java/org/gnunet/construct/Message.java b/src/main/java/org/gnunet/construct/Message.java new file mode 100644 index 0000000..d0068b5 --- /dev/null +++ b/src/main/java/org/gnunet/construct/Message.java @@ -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 { +} diff --git a/src/main/java/org/gnunet/construct/MessageIdAnnotationProcessor.java b/src/main/java/org/gnunet/construct/MessageIdAnnotationProcessor.java new file mode 100644 index 0000000..ab80be3 --- /dev/null +++ b/src/main/java/org/gnunet/construct/MessageIdAnnotationProcessor.java @@ -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. + */ +@SupportedAnnotationTypes("org.gnunet.construct.UnionCase") +@SupportedSourceVersion(SourceVersion.RELEASE_6) +public class MessageIdAnnotationProcessor extends AbstractProcessor { + private final Table idToMember = HashBasedTable.create(); + + @Override + public boolean process(Set 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 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 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; + } +} diff --git a/src/main/java/org/gnunet/construct/MessageLoader.java b/src/main/java/org/gnunet/construct/MessageLoader.java new file mode 100644 index 0000000..71e2719 --- /dev/null +++ b/src/main/java/org/gnunet/construct/MessageLoader.java @@ -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. + *

+ * XXX: how much of generics is too much? + */ + private static Map, Map>> unionmap + = new HashMap, Map>>(100); + + /* + * Maps a union interface and union case to the corresponding tag. + */ + private static Map, Map, Integer>> tagmap + = new HashMap, Map, Integer>>(100); + + + static { + ClassLoader classLoader = MessageLoader.class.getClassLoader(); + Enumeration 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 unionInterface = loadClass(unionInterfaceName); + Class unionCase = loadClass(unionCaseName); + + if (!unionmap.containsKey(unionInterface)) { + unionmap.put(unionInterface, new HashMap>(5)); + } + unionmap.get(unionInterface).put(id, unionCase); + + + if (!tagmap.containsKey(unionInterface)) { + tagmap.put(unionInterface, new HashMap, 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 loadClass(String className) { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + Class msgClass; + try { + msgClass = (Class) 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 getUnionClass(Class unionInterface, int tag) { + Map> map = unionmap.get(unionInterface); + if (map == null) { + throw new UnknownUnionException("don't know how to handle unions of type '" + unionInterface + "'"); + } + + Class 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 unionInterface, Class unionCase) { + Map, 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 unionInterface, + Class unionCase, int tag) { + if (!unionmap.containsKey(unionInterface)) { + unionmap.put(unionInterface, new HashMap>(5)); + } + unionmap.get(unionInterface).put(tag, unionCase); + + + if (!tagmap.containsKey(unionInterface)) { + tagmap.put(unionInterface, new HashMap, Integer>(5)); + } + tagmap.get(unionInterface).put(unionCase, tag); + + + } +} diff --git a/src/main/java/org/gnunet/construct/MessageUnion.java b/src/main/java/org/gnunet/construct/MessageUnion.java new file mode 100644 index 0000000..0481df2 --- /dev/null +++ b/src/main/java/org/gnunet/construct/MessageUnion.java @@ -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 { +} diff --git a/src/main/java/org/gnunet/construct/MsgMap.txt b/src/main/java/org/gnunet/construct/MsgMap.txt new file mode 100644 index 0000000..30a4656 --- /dev/null +++ b/src/main/java/org/gnunet/construct/MsgMap.txt @@ -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 diff --git a/src/main/java/org/gnunet/construct/NestedMessage.java b/src/main/java/org/gnunet/construct/NestedMessage.java new file mode 100644 index 0000000..fe65323 --- /dev/null +++ b/src/main/java/org/gnunet/construct/NestedMessage.java @@ -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 + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface NestedMessage { + boolean newFrame() default false; + boolean optional() default false; +} \ No newline at end of file diff --git a/src/main/java/org/gnunet/construct/ProtocolViolationException.java b/src/main/java/org/gnunet/construct/ProtocolViolationException.java new file mode 100644 index 0000000..9de46d4 --- /dev/null +++ b/src/main/java/org/gnunet/construct/ProtocolViolationException.java @@ -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); + } +} diff --git a/src/main/java/org/gnunet/construct/ReflectUtil.java b/src/main/java/org/gnunet/construct/ReflectUtil.java new file mode 100644 index 0000000..1115641 --- /dev/null +++ b/src/main/java/org/gnunet/construct/ReflectUtil.java @@ -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 justInstantiate(Class 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 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 fl, Object obj) { + return followFieldPath(fl, obj, fl.size()); + } + + public static Object followFieldPathToParent(List 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 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 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 getFieldPathFromString(final String p, final Class root) { + Class current = root; + + String[] components = p.split("[.]"); + + List fp = new ArrayList(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; + } +} diff --git a/src/main/java/org/gnunet/construct/UInt16.java b/src/main/java/org/gnunet/construct/UInt16.java new file mode 100644 index 0000000..18c24b2 --- /dev/null +++ b/src/main/java/org/gnunet/construct/UInt16.java @@ -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 + * + */ + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface UInt16 { + +} diff --git a/src/main/java/org/gnunet/construct/UInt32.java b/src/main/java/org/gnunet/construct/UInt32.java new file mode 100644 index 0000000..ab4a278 --- /dev/null +++ b/src/main/java/org/gnunet/construct/UInt32.java @@ -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 + * + */ + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface UInt32 { + +} diff --git a/src/main/java/org/gnunet/construct/UInt64.java b/src/main/java/org/gnunet/construct/UInt64.java new file mode 100644 index 0000000..d45cf69 --- /dev/null +++ b/src/main/java/org/gnunet/construct/UInt64.java @@ -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 + * + */ + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface UInt64 { + +} diff --git a/src/main/java/org/gnunet/construct/UInt8.java b/src/main/java/org/gnunet/construct/UInt8.java new file mode 100644 index 0000000..58b8335 --- /dev/null +++ b/src/main/java/org/gnunet/construct/UInt8.java @@ -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 + * + */ + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface UInt8 { + +} diff --git a/src/main/java/org/gnunet/construct/Union.java b/src/main/java/org/gnunet/construct/Union.java new file mode 100644 index 0000000..d35512e --- /dev/null +++ b/src/main/java/org/gnunet/construct/Union.java @@ -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 {@literal tag}. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Union { + String tag(); + boolean optional() default false; +} \ No newline at end of file diff --git a/src/main/java/org/gnunet/construct/UnionCase.java b/src/main/java/org/gnunet/construct/UnionCase.java new file mode 100644 index 0000000..7622dd4 --- /dev/null +++ b/src/main/java/org/gnunet/construct/UnionCase.java @@ -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 {@literal UnionCase} should implement + * the marker interface for their respective union type. + */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE) +public @interface UnionCase { + int value(); +} \ No newline at end of file diff --git a/src/main/java/org/gnunet/construct/VariableSizeArray.java b/src/main/java/org/gnunet/construct/VariableSizeArray.java new file mode 100644 index 0000000..64daece --- /dev/null +++ b/src/main/java/org/gnunet/construct/VariableSizeArray.java @@ -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 + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface VariableSizeArray { + String lengthField(); +} diff --git a/src/main/java/org/gnunet/construct/VariableSizeIntegerArray.java b/src/main/java/org/gnunet/construct/VariableSizeIntegerArray.java new file mode 100644 index 0000000..a3a9f28 --- /dev/null +++ b/src/main/java/org/gnunet/construct/VariableSizeIntegerArray.java @@ -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 + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface VariableSizeIntegerArray { + String lengthField(); + boolean signed(); + int bitSize(); +} diff --git a/src/main/java/org/gnunet/construct/ZeroTerminatedString.java b/src/main/java/org/gnunet/construct/ZeroTerminatedString.java new file mode 100644 index 0000000..2d70d71 --- /dev/null +++ b/src/main/java/org/gnunet/construct/ZeroTerminatedString.java @@ -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 + * + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface ZeroTerminatedString { + String charset() default "UTF-8"; + boolean optional() default false; +} diff --git a/src/main/java/org/gnunet/construct/package-info.java b/src/main/java/org/gnunet/construct/package-info.java new file mode 100644 index 0000000..add5d40 --- /dev/null +++ b/src/main/java/org/gnunet/construct/package-info.java @@ -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; diff --git a/src/main/java/org/gnunet/construct/parsers/DoubleParser.java b/src/main/java/org/gnunet/construct/parsers/DoubleParser.java new file mode 100644 index 0000000..c6cc835 --- /dev/null +++ b/src/main/java/org/gnunet/construct/parsers/DoubleParser.java @@ -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 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 frameSizePath, Message frameObj) { + // nothing to do here + } + + @Override + public int getStaticSize() { + return Double.SIZE / 8; + } +} diff --git a/src/main/java/org/gnunet/construct/parsers/FillParser.java b/src/main/java/org/gnunet/construct/parsers/FillParser.java new file mode 100644 index 0000000..156e120 --- /dev/null +++ b/src/main/java/org/gnunet/construct/parsers/FillParser.java @@ -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 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 list = new ArrayList(10); + + while (remaining > 0) { + @SuppressWarnings("unchecked") + Message next = ReflectUtil.justInstantiate((Class) 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 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; + } + +} diff --git a/src/main/java/org/gnunet/construct/parsers/FixedSizeArrayParser.java b/src/main/java/org/gnunet/construct/parsers/FixedSizeArrayParser.java new file mode 100644 index 0000000..3dbc720 --- /dev/null +++ b/src/main/java/org/gnunet/construct/parsers/FixedSizeArrayParser.java @@ -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 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)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 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(); + } +} diff --git a/src/main/java/org/gnunet/construct/parsers/FixedSizeIntegerArrayParser.java b/src/main/java/org/gnunet/construct/parsers/FixedSizeIntegerArrayParser.java new file mode 100644 index 0000000..ae633b0 --- /dev/null +++ b/src/main/java/org/gnunet/construct/parsers/FixedSizeIntegerArrayParser.java @@ -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 frameSizePath) { + int size = 0; + + @SuppressWarnings("unchecked") + final Class arrayElementType = (Class) 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 frameSizePath, Message frameObj) { + // nothing to patch! + } + + @Override + public int getStaticSize() { + return elemNumber * byteSize; + } +} diff --git a/src/main/java/org/gnunet/construct/parsers/IntegerFillParser.java b/src/main/java/org/gnunet/construct/parsers/IntegerFillParser.java new file mode 100644 index 0000000..7027afc --- /dev/null +++ b/src/main/java/org/gnunet/construct/parsers/IntegerFillParser.java @@ -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 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 arrayElementType = (Class) 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 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; + } +} diff --git a/src/main/java/org/gnunet/construct/parsers/IntegerParser.java b/src/main/java/org/gnunet/construct/parsers/IntegerParser.java new file mode 100644 index 0000000..4f71aa5 --- /dev/null +++ b/src/main/java/org/gnunet/construct/parsers/IntegerParser.java @@ -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 + 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 frameSizePath, Message frameObj) { + // todo: optimize this! + /* + if (frameSizePath != null) { + ReflectUtil.justSetInt(frameObj, frameSizePath, frameSize); + } + */ + } + + @Override + public int getStaticSize() { + return byteSize; + } +} diff --git a/src/main/java/org/gnunet/construct/parsers/IntegerUtil.java b/src/main/java/org/gnunet/construct/parsers/IntegerUtil.java new file mode 100644 index 0000000..83391de --- /dev/null +++ b/src/main/java/org/gnunet/construct/parsers/IntegerUtil.java @@ -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"); + } +} diff --git a/src/main/java/org/gnunet/construct/parsers/NestedParser.java b/src/main/java/org/gnunet/construct/parsers/NestedParser.java new file mode 100644 index 0000000..76aa397 --- /dev/null +++ b/src/main/java/org/gnunet/construct/parsers/NestedParser.java @@ -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 + 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 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(); + } + +} diff --git a/src/main/java/org/gnunet/construct/parsers/Parser.java b/src/main/java/org/gnunet/construct/parsers/Parser.java new file mode 100644 index 0000000..3eb02a6 --- /dev/null +++ b/src/main/java/org/gnunet/construct/parsers/Parser.java @@ -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 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 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(); +} diff --git a/src/main/java/org/gnunet/construct/parsers/SequenceParser.java b/src/main/java/org/gnunet/construct/parsers/SequenceParser.java new file mode 100644 index 0000000..4128e1b --- /dev/null +++ b/src/main/java/org/gnunet/construct/parsers/SequenceParser.java @@ -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 childParsers = new LinkedList(); + private List 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 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 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 frameSizePath) { + this.myFrameSizePath = frameSizePath; + } +} diff --git a/src/main/java/org/gnunet/construct/parsers/StringParser.java b/src/main/java/org/gnunet/construct/parsers/StringParser.java new file mode 100644 index 0000000..46d98ae --- /dev/null +++ b/src/main/java/org/gnunet/construct/parsers/StringParser.java @@ -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 + 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 frameSizePath, Message frameObj) { + if (frameSizePath != null) { + ReflectUtil.justSetInt(frameObj, frameSizePath, frameSize); + } + } + + @Override + public int getStaticSize() { + return optional ? 0 : 1; + } + +} diff --git a/src/main/java/org/gnunet/construct/parsers/UnionParser.java b/src/main/java/org/gnunet/construct/parsers/UnionParser.java new file mode 100644 index 0000000..e9fcc92 --- /dev/null +++ b/src/main/java/org/gnunet/construct/parsers/UnionParser.java @@ -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 +@SuppressWarnings("unchecked") +public class UnionParser implements Parser { + + private final Field targetField; + + private final List unionTagPath; + private final ReflectUtil.NumField unionTagField; + private final Class unionType; + + boolean optional; + + public UnionParser(boolean optional, Class unionType, + List 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 + 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) ReflectUtil.justGet(m, targetField).getClass()); + } + + @Override + public void patch(Message m, int frameSize, List 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; + } +} diff --git a/src/main/java/org/gnunet/construct/parsers/VariableSizeArrayParser.java b/src/main/java/org/gnunet/construct/parsers/VariableSizeArrayParser.java new file mode 100644 index 0000000..fd55925 --- /dev/null +++ b/src/main/java/org/gnunet/construct/parsers/VariableSizeArrayParser.java @@ -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 + frameSizePath) { + final int elemNumber = (int) sizeField.get(dstObj); + + @SuppressWarnings("unchecked") + final Class arrayElementType = (Class) 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 frameSizePath, Message frameObj) { + int size = Array.getLength(ReflectUtil.justGet(m, targetField)); + sizeField.set(m, size); + } + + @Override + public int getStaticSize() { + return 0; + } + +} diff --git a/src/main/java/org/gnunet/construct/parsers/VariableSizeIntegerArrayParser.java b/src/main/java/org/gnunet/construct/parsers/VariableSizeIntegerArrayParser.java new file mode 100644 index 0000000..b3f134d --- /dev/null +++ b/src/main/java/org/gnunet/construct/parsers/VariableSizeIntegerArrayParser.java @@ -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 + frameSizePath) { + final int elemNumber = (int) sizeField.get(dstObj); + + + @SuppressWarnings("unchecked") + final Class arrayElementType = (Class) 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 frameSizePath, Message frameObj) { + int size = Array.getLength(ReflectUtil.justGet(m, targetField)); + sizeField.set(m, size); + } + + @Override + public int getStaticSize() { + return 0; + } + +} diff --git a/src/main/java/org/gnunet/construct/parsers/package-info.java b/src/main/java/org/gnunet/construct/parsers/package-info.java new file mode 100644 index 0000000..5da3a94 --- /dev/null +++ b/src/main/java/org/gnunet/construct/parsers/package-info.java @@ -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; diff --git a/src/main/java/org/gnunet/core/ConnectHandler.java b/src/main/java/org/gnunet/core/ConnectHandler.java new file mode 100644 index 0000000..a36d798 --- /dev/null +++ b/src/main/java/org/gnunet/core/ConnectHandler.java @@ -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); +} diff --git a/src/main/java/org/gnunet/core/ConnectNotifyMessage.java b/src/main/java/org/gnunet/core/ConnectNotifyMessage.java new file mode 100644 index 0000000..4eafe02 --- /dev/null +++ b/src/main/java/org/gnunet/core/ConnectNotifyMessage.java @@ -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. + */ +@UnionCase(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; + +} diff --git a/src/main/java/org/gnunet/core/Core.java b/src/main/java/org/gnunet/core/Core.java new file mode 100644 index 0000000..2895e41 --- /dev/null +++ b/src/main/java/org/gnunet/core/Core.java @@ -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. + *

+ * 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 connectedPeers = Maps.newHashMap(); + + /** + * Request container for notify transmit requests. + */ + private MatchingRequestContainer 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(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(); + } +} diff --git a/src/main/java/org/gnunet/core/DisconnectHandler.java b/src/main/java/org/gnunet/core/DisconnectHandler.java new file mode 100644 index 0000000..c7ca407 --- /dev/null +++ b/src/main/java/org/gnunet/core/DisconnectHandler.java @@ -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); +} diff --git a/src/main/java/org/gnunet/core/DisconnectNotifyMessage.java b/src/main/java/org/gnunet/core/DisconnectNotifyMessage.java new file mode 100644 index 0000000..e4c3209 --- /dev/null +++ b/src/main/java/org/gnunet/core/DisconnectNotifyMessage.java @@ -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. + */ +@UnionCase(68) +public class DisconnectNotifyMessage implements GnunetMessage.Body { + /** + * Always zero. + */ + @UInt32 + public int reserved; + + /** + * Identity of the connecting peer. + */ + @NestedMessage + public PeerIdentity peer; +} diff --git a/src/main/java/org/gnunet/core/HeaderNotify.java b/src/main/java/org/gnunet/core/HeaderNotify.java new file mode 100644 index 0000000..4f536e3 --- /dev/null +++ b/src/main/java/org/gnunet/core/HeaderNotify.java @@ -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); +} diff --git a/src/main/java/org/gnunet/core/InitCallback.java b/src/main/java/org/gnunet/core/InitCallback.java new file mode 100644 index 0000000..889f8cf --- /dev/null +++ b/src/main/java/org/gnunet/core/InitCallback.java @@ -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); +} diff --git a/src/main/java/org/gnunet/core/InitMessage.java b/src/main/java/org/gnunet/core/InitMessage.java new file mode 100644 index 0000000..5546088 --- /dev/null +++ b/src/main/java/org/gnunet/core/InitMessage.java @@ -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; + + +@UnionCase(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; +} diff --git a/src/main/java/org/gnunet/core/InitReplyMessage.java b/src/main/java/org/gnunet/core/InitReplyMessage.java new file mode 100644 index 0000000..02e8eef --- /dev/null +++ b/src/main/java/org/gnunet/core/InitReplyMessage.java @@ -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; + + +@UnionCase(65) +public class InitReplyMessage implements GnunetMessage.Body { + @UInt32 + public int reserved = 0; + /** + * pubkey of the local peer + */ + @NestedMessage + public PeerIdentity myIdentity; +} diff --git a/src/main/java/org/gnunet/core/MessageNotify.java b/src/main/java/org/gnunet/core/MessageNotify.java new file mode 100644 index 0000000..b14ce29 --- /dev/null +++ b/src/main/java/org/gnunet/core/MessageNotify.java @@ -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); +} diff --git a/src/main/java/org/gnunet/core/NotifyInboundTrafficMessage.java b/src/main/java/org/gnunet/core/NotifyInboundTrafficMessage.java new file mode 100644 index 0000000..2bdd428 --- /dev/null +++ b/src/main/java/org/gnunet/core/NotifyInboundTrafficMessage.java @@ -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; + + +@UnionCase(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; +} diff --git a/src/main/java/org/gnunet/core/NotifyOutboundTrafficMessage.java b/src/main/java/org/gnunet/core/NotifyOutboundTrafficMessage.java new file mode 100644 index 0000000..900f8be --- /dev/null +++ b/src/main/java/org/gnunet/core/NotifyOutboundTrafficMessage.java @@ -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; + + +@UnionCase(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; + +} diff --git a/src/main/java/org/gnunet/core/RequestIdentification.java b/src/main/java/org/gnunet/core/RequestIdentification.java new file mode 100644 index 0000000..4f6a734 --- /dev/null +++ b/src/main/java/org/gnunet/core/RequestIdentification.java @@ -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; + } +} diff --git a/src/main/java/org/gnunet/core/SendMessage.java b/src/main/java/org/gnunet/core/SendMessage.java new file mode 100644 index 0000000..e4c6215 --- /dev/null +++ b/src/main/java/org/gnunet/core/SendMessage.java @@ -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). + */ +@UnionCase(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; + +} diff --git a/src/main/java/org/gnunet/core/SendMessageReady.java b/src/main/java/org/gnunet/core/SendMessageReady.java new file mode 100644 index 0000000..aa5bf44 --- /dev/null +++ b/src/main/java/org/gnunet/core/SendMessageReady.java @@ -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). + */ +@UnionCase(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; +} diff --git a/src/main/java/org/gnunet/core/SendMessageRequest.java b/src/main/java/org/gnunet/core/SendMessageRequest.java new file mode 100644 index 0000000..7a95127 --- /dev/null +++ b/src/main/java/org/gnunet/core/SendMessageRequest.java @@ -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. + */ +@UnionCase(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; +} diff --git a/src/main/java/org/gnunet/core/package-info.java b/src/main/java/org/gnunet/core/package-info.java new file mode 100644 index 0000000..64e5d59 --- /dev/null +++ b/src/main/java/org/gnunet/core/package-info.java @@ -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; diff --git a/src/main/java/org/gnunet/dht/BlockType.java b/src/main/java/org/gnunet/dht/BlockType.java new file mode 100644 index 0000000..cf00d38 --- /dev/null +++ b/src/main/java/org/gnunet/dht/BlockType.java @@ -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; + } +} diff --git a/src/main/java/org/gnunet/dht/ClientGetMessage.java b/src/main/java/org/gnunet/dht/ClientGetMessage.java new file mode 100644 index 0000000..cd317fb --- /dev/null +++ b/src/main/java/org/gnunet/dht/ClientGetMessage.java @@ -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. +*/ +@UnionCase(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; +} diff --git a/src/main/java/org/gnunet/dht/ClientGetStopMessage.java b/src/main/java/org/gnunet/dht/ClientGetStopMessage.java new file mode 100644 index 0000000..4cdee12 --- /dev/null +++ b/src/main/java/org/gnunet/dht/ClientGetStopMessage.java @@ -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. +*/ +@UnionCase(144) +public class ClientGetStopMessage implements GnunetMessage.Body { + @UInt32 + public int reserved = 0; + @UInt64 + public long unique_id; + @NestedMessage + public HashCode key; +} diff --git a/src/main/java/org/gnunet/dht/ClientPutConfirmationMessage.java b/src/main/java/org/gnunet/dht/ClientPutConfirmationMessage.java new file mode 100644 index 0000000..45bbe60 --- /dev/null +++ b/src/main/java/org/gnunet/dht/ClientPutConfirmationMessage.java @@ -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; + + +@UnionCase(155) +public class ClientPutConfirmationMessage implements GnunetMessage.Body { + @UInt32 + public int reserved; + /** + * UID used to identify request with the response + */ + @UInt64 + public long uid; +} diff --git a/src/main/java/org/gnunet/dht/ClientPutMessage.java b/src/main/java/org/gnunet/dht/ClientPutMessage.java new file mode 100644 index 0000000..4b63e92 --- /dev/null +++ b/src/main/java/org/gnunet/dht/ClientPutMessage.java @@ -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; + + +@UnionCase(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; +} diff --git a/src/main/java/org/gnunet/dht/ClientResultMessage.java b/src/main/java/org/gnunet/dht/ClientResultMessage.java new file mode 100644 index 0000000..fab614f --- /dev/null +++ b/src/main/java/org/gnunet/dht/ClientResultMessage.java @@ -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. +*/ +@UnionCase(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; +} diff --git a/src/main/java/org/gnunet/dht/DistributedHashTable.java b/src/main/java/org/gnunet/dht/DistributedHashTable.java new file mode 100644 index 0000000..0a561bf --- /dev/null +++ b/src/main/java/org/gnunet/dht/DistributedHashTable.java @@ -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. + *

+ * Stores data under a key, distributed across the network. + *

+ */ +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 putRequests; + private MatchingRequestContainer getRequests; + private SequentialRequestContainer 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(client); + getRequests = new MatchingRequestContainer(client); + monitorRequests = new SequentialRequestContainer(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 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 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 + getPath, List putPath, BlockType type, byte[] data) { + System.out.println("got result:"); + System.out.println(new String(data, Charsets.UTF_8)); + } + }); + } + } + }.start(); + } +} diff --git a/src/main/java/org/gnunet/dht/MonitorGetHandler.java b/src/main/java/org/gnunet/dht/MonitorGetHandler.java new file mode 100644 index 0000000..c7dad7c --- /dev/null +++ b/src/main/java/org/gnunet/dht/MonitorGetHandler.java @@ -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); +} diff --git a/src/main/java/org/gnunet/dht/MonitorGetMessage.java b/src/main/java/org/gnunet/dht/MonitorGetMessage.java new file mode 100644 index 0000000..e96ec96 --- /dev/null +++ b/src/main/java/org/gnunet/dht/MonitorGetMessage.java @@ -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. + */ +@UnionCase(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; +} diff --git a/src/main/java/org/gnunet/dht/MonitorGetRespMessage.java b/src/main/java/org/gnunet/dht/MonitorGetRespMessage.java new file mode 100644 index 0000000..3bf145b --- /dev/null +++ b/src/main/java/org/gnunet/dht/MonitorGetRespMessage.java @@ -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. + */ +@UnionCase(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; +} diff --git a/src/main/java/org/gnunet/dht/MonitorGetResponseHandler.java b/src/main/java/org/gnunet/dht/MonitorGetResponseHandler.java new file mode 100644 index 0000000..ff03cce --- /dev/null +++ b/src/main/java/org/gnunet/dht/MonitorGetResponseHandler.java @@ -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); +} diff --git a/src/main/java/org/gnunet/dht/MonitorPutHandler.java b/src/main/java/org/gnunet/dht/MonitorPutHandler.java new file mode 100644 index 0000000..0abb79b --- /dev/null +++ b/src/main/java/org/gnunet/dht/MonitorPutHandler.java @@ -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); +} diff --git a/src/main/java/org/gnunet/dht/MonitorPutMessage.java b/src/main/java/org/gnunet/dht/MonitorPutMessage.java new file mode 100644 index 0000000..103c05b --- /dev/null +++ b/src/main/java/org/gnunet/dht/MonitorPutMessage.java @@ -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. + */ +@UnionCase(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; +} diff --git a/src/main/java/org/gnunet/dht/MonitorStartStop.java b/src/main/java/org/gnunet/dht/MonitorStartStop.java new file mode 100644 index 0000000..b3f3268 --- /dev/null +++ b/src/main/java/org/gnunet/dht/MonitorStartStop.java @@ -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. + */ +@UnionCase(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; +} diff --git a/src/main/java/org/gnunet/dht/ResultCallback.java b/src/main/java/org/gnunet/dht/ResultCallback.java new file mode 100644 index 0000000..fa5c7ef --- /dev/null +++ b/src/main/java/org/gnunet/dht/ResultCallback.java @@ -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 getPath, List putPath, + BlockType type, byte[] data); +} diff --git a/src/main/java/org/gnunet/dht/RouteOption.java b/src/main/java/org/gnunet/dht/RouteOption.java new file mode 100644 index 0000000..b74b528 --- /dev/null +++ b/src/main/java/org/gnunet/dht/RouteOption.java @@ -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; + } +} diff --git a/src/main/java/org/gnunet/dht/package-info.java b/src/main/java/org/gnunet/dht/package-info.java new file mode 100644 index 0000000..3d8c6ed --- /dev/null +++ b/src/main/java/org/gnunet/dht/package-info.java @@ -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; diff --git a/src/main/java/org/gnunet/hello/HelloMessage.java b/src/main/java/org/gnunet/hello/HelloMessage.java new file mode 100644 index 0000000..0d90912 --- /dev/null +++ b/src/main/java/org/gnunet/hello/HelloMessage.java @@ -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; +} diff --git a/src/main/java/org/gnunet/hello/package-info.java b/src/main/java/org/gnunet/hello/package-info.java new file mode 100644 index 0000000..78a5193 --- /dev/null +++ b/src/main/java/org/gnunet/hello/package-info.java @@ -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; diff --git a/src/main/java/org/gnunet/mesh/ClientConnectMessage.java b/src/main/java/org/gnunet/mesh/ClientConnectMessage.java new file mode 100644 index 0000000..1a56ebb --- /dev/null +++ b/src/main/java/org/gnunet/mesh/ClientConnectMessage.java @@ -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 + */ +@UnionCase(272) +public class ClientConnectMessage implements GnunetMessage.Body { + @IntegerFill(signed = false, bitSize = 32) + public int[] apps_list; +} diff --git a/src/main/java/org/gnunet/mesh/ConnectHandler.java b/src/main/java/org/gnunet/mesh/ConnectHandler.java new file mode 100644 index 0000000..021e8f0 --- /dev/null +++ b/src/main/java/org/gnunet/mesh/ConnectHandler.java @@ -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); +} diff --git a/src/main/java/org/gnunet/mesh/DataMessage.java b/src/main/java/org/gnunet/mesh/DataMessage.java new file mode 100644 index 0000000..92546c8 --- /dev/null +++ b/src/main/java/org/gnunet/mesh/DataMessage.java @@ -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 + */ +@UnionCase(260) +public class DataMessage implements GnunetMessage.Body { + @UInt32 + public int tid; + @FillWith + @UInt8 + public byte[] payload; +} diff --git a/src/main/java/org/gnunet/mesh/DisconnectHandler.java b/src/main/java/org/gnunet/mesh/DisconnectHandler.java new file mode 100644 index 0000000..8fd6428 --- /dev/null +++ b/src/main/java/org/gnunet/mesh/DisconnectHandler.java @@ -0,0 +1,12 @@ +package org.gnunet.mesh; + +import org.gnunet.util.PeerIdentity; + +/** + * ... + * + * @author Florian Dold + */ +public interface DisconnectHandler { + void onDisconnect(PeerIdentity peer); +} diff --git a/src/main/java/org/gnunet/mesh/InboundTunnelHandler.java b/src/main/java/org/gnunet/mesh/InboundTunnelHandler.java new file mode 100644 index 0000000..ebcf225 --- /dev/null +++ b/src/main/java/org/gnunet/mesh/InboundTunnelHandler.java @@ -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); +} diff --git a/src/main/java/org/gnunet/mesh/LocalAckMessage.java b/src/main/java/org/gnunet/mesh/LocalAckMessage.java new file mode 100644 index 0000000..6a09411 --- /dev/null +++ b/src/main/java/org/gnunet/mesh/LocalAckMessage.java @@ -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 + */ +@UnionCase(286) +public class LocalAckMessage implements GnunetMessage.Body { + @UInt32 + public int tid; + @UInt32 + public int maxPid; +} diff --git a/src/main/java/org/gnunet/mesh/Mesh.java b/src/main/java/org/gnunet/mesh/Mesh.java new file mode 100644 index 0000000..a6bf602 --- /dev/null +++ b/src/main/java/org/gnunet/mesh/Mesh.java @@ -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 tunnelMap = new HashMap(); + + /** + * Counter for generating fresh tunnel ID's + * when creating new tunnels. + */ + private int next_tid = 1; + + /** + * A tunnel to a remote peer. + * @param type of context data for the tunnel + */ + public class Tunnel 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 Tunnel createTunnel(PeerIdentity peer, int port, boolean nobuffer, boolean reliable, T initialContext) { + return new Tunnel(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(); + } +} diff --git a/src/main/java/org/gnunet/mesh/MeshRunabout.java b/src/main/java/org/gnunet/mesh/MeshRunabout.java new file mode 100644 index 0000000..ea4248c --- /dev/null +++ b/src/main/java/org/gnunet/mesh/MeshRunabout.java @@ -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; + } +} diff --git a/src/main/java/org/gnunet/mesh/TunnelCreateMessage.java b/src/main/java/org/gnunet/mesh/TunnelCreateMessage.java new file mode 100644 index 0000000..eaa4d6c --- /dev/null +++ b/src/main/java/org/gnunet/mesh/TunnelCreateMessage.java @@ -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 + */ +@UnionCase(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; +} diff --git a/src/main/java/org/gnunet/mesh/TunnelDestroyMessage.java b/src/main/java/org/gnunet/mesh/TunnelDestroyMessage.java new file mode 100644 index 0000000..bce60bb --- /dev/null +++ b/src/main/java/org/gnunet/mesh/TunnelDestroyMessage.java @@ -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 + */ +@UnionCase(274) +public class TunnelDestroyMessage implements GnunetMessage.Body { + @UInt32 + public int tunnel_id; +} diff --git a/src/main/java/org/gnunet/mesh/TunnelEndHandler.java b/src/main/java/org/gnunet/mesh/TunnelEndHandler.java new file mode 100644 index 0000000..e56fdd4 --- /dev/null +++ b/src/main/java/org/gnunet/mesh/TunnelEndHandler.java @@ -0,0 +1,10 @@ +package org.gnunet.mesh; + +/** + * ... + * + * @author Florian Dold + */ +public interface TunnelEndHandler { + void onTunnelEnd(Mesh.Tunnel tunnel); +} diff --git a/src/main/java/org/gnunet/mesh/TunnelNotificationMessage.java b/src/main/java/org/gnunet/mesh/TunnelNotificationMessage.java new file mode 100644 index 0000000..8846088 --- /dev/null +++ b/src/main/java/org/gnunet/mesh/TunnelNotificationMessage.java @@ -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; +} diff --git a/src/main/java/org/gnunet/mesh/package-info.java b/src/main/java/org/gnunet/mesh/package-info.java new file mode 100644 index 0000000..fb5a8a4 --- /dev/null +++ b/src/main/java/org/gnunet/mesh/package-info.java @@ -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; diff --git a/src/main/java/org/gnunet/mq/Envelope.java b/src/main/java/org/gnunet/mq/Envelope.java new file mode 100644 index 0000000..fa19225 --- /dev/null +++ b/src/main/java/org/gnunet/mq/Envelope.java @@ -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(); + } +} diff --git a/src/main/java/org/gnunet/mq/MessageQueue.java b/src/main/java/org/gnunet/mq/MessageQueue.java new file mode 100644 index 0000000..4df3ae4 --- /dev/null +++ b/src/main/java/org/gnunet/mq/MessageQueue.java @@ -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 queued_envelopes = new LinkedList(); + private LinkedList prefered_queued_envelopes = new LinkedList(); + 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); + } + } +} diff --git a/src/main/java/org/gnunet/mq/NotifySentHandler.java b/src/main/java/org/gnunet/mq/NotifySentHandler.java new file mode 100644 index 0000000..7ec13b2 --- /dev/null +++ b/src/main/java/org/gnunet/mq/NotifySentHandler.java @@ -0,0 +1,6 @@ +package org.gnunet.mq; + + +public interface NotifySentHandler { + void onSent(); +} diff --git a/src/main/java/org/gnunet/nse/NetworkSizeEstimation.java b/src/main/java/org/gnunet/nse/NetworkSizeEstimation.java new file mode 100644 index 0000000..5fc7453 --- /dev/null +++ b/src/main/java/org/gnunet/nse/NetworkSizeEstimation.java @@ -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 subscribers = new HashSet(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(); + } +} diff --git a/src/main/java/org/gnunet/nse/StartMessage.java b/src/main/java/org/gnunet/nse/StartMessage.java new file mode 100644 index 0000000..9f5b79e --- /dev/null +++ b/src/main/java/org/gnunet/nse/StartMessage.java @@ -0,0 +1,12 @@ +package org.gnunet.nse; + +import org.gnunet.construct.UnionCase; +import org.gnunet.util.GnunetMessage; + +/** +* ... +* +* @author Florian Dold +*/ +@UnionCase(321) +public class StartMessage implements GnunetMessage.Body {} diff --git a/src/main/java/org/gnunet/nse/UpdateMessage.java b/src/main/java/org/gnunet/nse/UpdateMessage.java new file mode 100644 index 0000000..5c64a54 --- /dev/null +++ b/src/main/java/org/gnunet/nse/UpdateMessage.java @@ -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 +*/ +@UnionCase(323) +public class UpdateMessage implements GnunetMessage.Body { + @UInt32 + public int reserved; + + @NestedMessage + public AbsoluteTimeMessage timestamp; + + @DoubleValue + public double sizeEstimate; + + @DoubleValue + public double stdDeviation; +} diff --git a/src/main/java/org/gnunet/nse/package-info.java b/src/main/java/org/gnunet/nse/package-info.java new file mode 100644 index 0000000..3bbc064 --- /dev/null +++ b/src/main/java/org/gnunet/nse/package-info.java @@ -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; diff --git a/src/main/java/org/gnunet/peerinfo/InfoEnd.java b/src/main/java/org/gnunet/peerinfo/InfoEnd.java new file mode 100644 index 0000000..b59e194 --- /dev/null +++ b/src/main/java/org/gnunet/peerinfo/InfoEnd.java @@ -0,0 +1,14 @@ +package org.gnunet.peerinfo; + +import org.gnunet.construct.UnionCase; +import org.gnunet.util.GnunetMessage; + +/** + * ... + * + * @author Florian Dold + */ +@UnionCase(333) +public class InfoEnd implements GnunetMessage.Body { + +} diff --git a/src/main/java/org/gnunet/peerinfo/InfoMessage.java b/src/main/java/org/gnunet/peerinfo/InfoMessage.java new file mode 100644 index 0000000..d8d7daa --- /dev/null +++ b/src/main/java/org/gnunet/peerinfo/InfoMessage.java @@ -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 + */ +@UnionCase(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; +} diff --git a/src/main/java/org/gnunet/peerinfo/ListAllPeersMessage.java b/src/main/java/org/gnunet/peerinfo/ListAllPeersMessage.java new file mode 100644 index 0000000..e384c93 --- /dev/null +++ b/src/main/java/org/gnunet/peerinfo/ListAllPeersMessage.java @@ -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 + */ +@UnionCase(331) +public class ListAllPeersMessage implements GnunetMessage.Body { + @UInt32 + public int include_friend_only; +} diff --git a/src/main/java/org/gnunet/peerinfo/ListPeerMessage.java b/src/main/java/org/gnunet/peerinfo/ListPeerMessage.java new file mode 100644 index 0000000..56e6b5d --- /dev/null +++ b/src/main/java/org/gnunet/peerinfo/ListPeerMessage.java @@ -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; +} diff --git a/src/main/java/org/gnunet/peerinfo/PeerInfo.java b/src/main/java/org/gnunet/peerinfo/PeerInfo.java new file mode 100644 index 0000000..46d35bf --- /dev/null +++ b/src/main/java/org/gnunet/peerinfo/PeerInfo.java @@ -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 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(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(); + } +} diff --git a/src/main/java/org/gnunet/peerinfo/PeerProcessor.java b/src/main/java/org/gnunet/peerinfo/PeerProcessor.java new file mode 100644 index 0000000..b096c37 --- /dev/null +++ b/src/main/java/org/gnunet/peerinfo/PeerProcessor.java @@ -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(); +} diff --git a/src/main/java/org/gnunet/peerinfo/RsaPublicKeyBinaryEncoded.java b/src/main/java/org/gnunet/peerinfo/RsaPublicKeyBinaryEncoded.java new file mode 100644 index 0000000..86985f3 --- /dev/null +++ b/src/main/java/org/gnunet/peerinfo/RsaPublicKeyBinaryEncoded.java @@ -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; +} diff --git a/src/main/java/org/gnunet/peerinfo/package-info.java b/src/main/java/org/gnunet/peerinfo/package-info.java new file mode 100644 index 0000000..19cebdb --- /dev/null +++ b/src/main/java/org/gnunet/peerinfo/package-info.java @@ -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; diff --git a/src/main/java/org/gnunet/requests/MatchingRequestContainer.java b/src/main/java/org/gnunet/requests/MatchingRequestContainer.java new file mode 100644 index 0000000..656d162 --- /dev/null +++ b/src/main/java/org/gnunet/requests/MatchingRequestContainer.java @@ -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 extends RequestContainer { + private Map 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 requestsOld = requests; + requests = Maps.newHashMap(); + for (Map.Entry 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); + } +} diff --git a/src/main/java/org/gnunet/requests/RequestContainer.java b/src/main/java/org/gnunet/requests/RequestContainer.java new file mode 100644 index 0000000..c7627f0 --- /dev/null +++ b/src/main/java/org/gnunet/requests/RequestContainer.java @@ -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; + } + +} diff --git a/src/main/java/org/gnunet/requests/SequentialRequestContainer.java b/src/main/java/org/gnunet/requests/SequentialRequestContainer.java new file mode 100644 index 0000000..037055f --- /dev/null +++ b/src/main/java/org/gnunet/requests/SequentialRequestContainer.java @@ -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 extends RequestContainer { + private LinkedList requests = new LinkedList(); + 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 requestsOld = requests; + requests = new LinkedList(); + for (T r : requestsOld) { + if (!isRequestCancelled(r)) { + setRequestTransmitting(r, false); + addRequest(r); + } + } + } + + + public Iterable iter() { + return requests; + } +} diff --git a/src/main/java/org/gnunet/requests/package-info.java b/src/main/java/org/gnunet/requests/package-info.java new file mode 100644 index 0000000..892a606 --- /dev/null +++ b/src/main/java/org/gnunet/requests/package-info.java @@ -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; diff --git a/src/main/java/org/gnunet/statistics/GetMessage.java b/src/main/java/org/gnunet/statistics/GetMessage.java new file mode 100644 index 0000000..eb44fbd --- /dev/null +++ b/src/main/java/org/gnunet/statistics/GetMessage.java @@ -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 + * + */ +@UnionCase(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; +} diff --git a/src/main/java/org/gnunet/statistics/GetRequest.java b/src/main/java/org/gnunet/statistics/GetRequest.java new file mode 100644 index 0000000..8f421b1 --- /dev/null +++ b/src/main/java/org/gnunet/statistics/GetRequest.java @@ -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() { + } +} diff --git a/src/main/java/org/gnunet/statistics/GetResponseEndMessage.java b/src/main/java/org/gnunet/statistics/GetResponseEndMessage.java new file mode 100644 index 0000000..eebe16e --- /dev/null +++ b/src/main/java/org/gnunet/statistics/GetResponseEndMessage.java @@ -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; + +/** + * ... +*/ +@UnionCase(171) +public class GetResponseEndMessage implements GnunetMessage.Body { + // empty +} diff --git a/src/main/java/org/gnunet/statistics/GetResponseMessage.java b/src/main/java/org/gnunet/statistics/GetResponseMessage.java new file mode 100644 index 0000000..2a722e6 --- /dev/null +++ b/src/main/java/org/gnunet/statistics/GetResponseMessage.java @@ -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 + * + * + */ +@UnionCase(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; +} diff --git a/src/main/java/org/gnunet/statistics/SetMessage.java b/src/main/java/org/gnunet/statistics/SetMessage.java new file mode 100644 index 0000000..d75e3bf --- /dev/null +++ b/src/main/java/org/gnunet/statistics/SetMessage.java @@ -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. + */ +@UnionCase(168) +public class SetMessage implements GnunetMessage.Body { + @UInt32 + public int flags; + @UInt64 + public long value; + @ZeroTerminatedString + public String subsystemName; + @ZeroTerminatedString + public String statisticName; +} diff --git a/src/main/java/org/gnunet/statistics/SetRequest.java b/src/main/java/org/gnunet/statistics/SetRequest.java new file mode 100644 index 0000000..4aa4a82 --- /dev/null +++ b/src/main/java/org/gnunet/statistics/SetRequest.java @@ -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. + } +} diff --git a/src/main/java/org/gnunet/statistics/Statistics.java b/src/main/java/org/gnunet/statistics/Statistics.java new file mode 100644 index 0000000..416db0c --- /dev/null +++ b/src/main/java/org/gnunet/statistics/Statistics.java @@ -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. + *

+ * Set, get and monitor statistics values, represented as unsigned 64bit integer. + * Note that {@literal 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 set_requests; + SequentialRequestContainer get_requests; + MatchingRequestContainer 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(client); + set_requests = new SequentialRequestContainer(client); + watch_requests = new MatchingRequestContainer(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(); + } +} diff --git a/src/main/java/org/gnunet/statistics/StatisticsReceiver.java b/src/main/java/org/gnunet/statistics/StatisticsReceiver.java new file mode 100644 index 0000000..0c25acc --- /dev/null +++ b/src/main/java/org/gnunet/statistics/StatisticsReceiver.java @@ -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(); +} diff --git a/src/main/java/org/gnunet/statistics/StatisticsWatcher.java b/src/main/java/org/gnunet/statistics/StatisticsWatcher.java new file mode 100644 index 0000000..d3fb645 --- /dev/null +++ b/src/main/java/org/gnunet/statistics/StatisticsWatcher.java @@ -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(); +} diff --git a/src/main/java/org/gnunet/statistics/WatchMessage.java b/src/main/java/org/gnunet/statistics/WatchMessage.java new file mode 100644 index 0000000..814f263 --- /dev/null +++ b/src/main/java/org/gnunet/statistics/WatchMessage.java @@ -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; + +@UnionCase(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; +} diff --git a/src/main/java/org/gnunet/statistics/WatchRequest.java b/src/main/java/org/gnunet/statistics/WatchRequest.java new file mode 100644 index 0000000..49e1615 --- /dev/null +++ b/src/main/java/org/gnunet/statistics/WatchRequest.java @@ -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() { + + } +} diff --git a/src/main/java/org/gnunet/statistics/WatchResponseMessage.java b/src/main/java/org/gnunet/statistics/WatchResponseMessage.java new file mode 100644 index 0000000..19c56b5 --- /dev/null +++ b/src/main/java/org/gnunet/statistics/WatchResponseMessage.java @@ -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; + +@UnionCase(173) +public class WatchResponseMessage implements GnunetMessage.Body { + @UInt32 + public int flags; + @UInt32 + public int wid; + @UInt32 + public int reserved ; + @UInt64 + public long value; +} diff --git a/src/main/java/org/gnunet/statistics/package-info.java b/src/main/java/org/gnunet/statistics/package-info.java new file mode 100644 index 0000000..fce59e7 --- /dev/null +++ b/src/main/java/org/gnunet/statistics/package-info.java @@ -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; diff --git a/src/main/java/org/gnunet/testbed/Controller.java b/src/main/java/org/gnunet/testbed/Controller.java new file mode 100644 index 0000000..7372986 --- /dev/null +++ b/src/main/java/org/gnunet/testbed/Controller.java @@ -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 () { + + } + + +} diff --git a/src/main/java/org/gnunet/testbed/ControllerEventCallback.java b/src/main/java/org/gnunet/testbed/ControllerEventCallback.java new file mode 100644 index 0000000..099977f --- /dev/null +++ b/src/main/java/org/gnunet/testbed/ControllerEventCallback.java @@ -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"); + } +} diff --git a/src/main/java/org/gnunet/testbed/ControllerInitMessage.java b/src/main/java/org/gnunet/testbed/ControllerInitMessage.java new file mode 100644 index 0000000..95114d7 --- /dev/null +++ b/src/main/java/org/gnunet/testbed/ControllerInitMessage.java @@ -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; + +@UnionCase(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; + +} diff --git a/src/main/java/org/gnunet/testbed/ControllerProc.java b/src/main/java/org/gnunet/testbed/ControllerProc.java new file mode 100644 index 0000000..9eaca2c --- /dev/null +++ b/src/main/java/org/gnunet/testbed/ControllerProc.java @@ -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; + } +} diff --git a/src/main/java/org/gnunet/testbed/ControllerStatusCallback.java b/src/main/java/org/gnunet/testbed/ControllerStatusCallback.java new file mode 100644 index 0000000..ba9e56f --- /dev/null +++ b/src/main/java/org/gnunet/testbed/ControllerStatusCallback.java @@ -0,0 +1,9 @@ +package org.gnunet.testbed; + + +import org.gnunet.util.Configuration; + +public interface ControllerStatusCallback { + void onStartupSuccess(Configuration cfg); + void onStartupFailure(); +} diff --git a/src/main/java/org/gnunet/testbed/HelperInitMessage.java b/src/main/java/org/gnunet/testbed/HelperInitMessage.java new file mode 100644 index 0000000..29d8bb6 --- /dev/null +++ b/src/main/java/org/gnunet/testbed/HelperInitMessage.java @@ -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 + */ +@UnionCase(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; +} diff --git a/src/main/java/org/gnunet/testbed/HelperReplyMessage.java b/src/main/java/org/gnunet/testbed/HelperReplyMessage.java new file mode 100644 index 0000000..bb50860 --- /dev/null +++ b/src/main/java/org/gnunet/testbed/HelperReplyMessage.java @@ -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; + +@UnionCase(496) +public class HelperReplyMessage implements GnunetMessage.Body { + @UInt16 + int uncompressed_config_size; + + @FillWith @UInt8 + byte[] compressed_config; +} diff --git a/src/main/java/org/gnunet/testbed/Host.java b/src/main/java/org/gnunet/testbed/Host.java new file mode 100644 index 0000000..fb89028 --- /dev/null +++ b/src/main/java/org/gnunet/testbed/Host.java @@ -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; + } +} diff --git a/src/main/java/org/gnunet/testbed/Operation.java b/src/main/java/org/gnunet/testbed/Operation.java new file mode 100644 index 0000000..4403540 --- /dev/null +++ b/src/main/java/org/gnunet/testbed/Operation.java @@ -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 { +} diff --git a/src/main/java/org/gnunet/testbed/OperationCompletionCallback.java b/src/main/java/org/gnunet/testbed/OperationCompletionCallback.java new file mode 100644 index 0000000..413be06 --- /dev/null +++ b/src/main/java/org/gnunet/testbed/OperationCompletionCallback.java @@ -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 { +} diff --git a/src/main/java/org/gnunet/testbed/Peer.java b/src/main/java/org/gnunet/testbed/Peer.java new file mode 100644 index 0000000..f9cfc3e --- /dev/null +++ b/src/main/java/org/gnunet/testbed/Peer.java @@ -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; + } + +} diff --git a/src/main/java/org/gnunet/testbed/PeerChurnCallback.java b/src/main/java/org/gnunet/testbed/PeerChurnCallback.java new file mode 100644 index 0000000..a5dacbd --- /dev/null +++ b/src/main/java/org/gnunet/testbed/PeerChurnCallback.java @@ -0,0 +1,7 @@ +package org.gnunet.testbed; + + +public interface PeerChurnCallback { + void onChurnSuccess(); + void onChurnError(String emsg); +} diff --git a/src/main/java/org/gnunet/testbed/PeerCreateCallback.java b/src/main/java/org/gnunet/testbed/PeerCreateCallback.java new file mode 100644 index 0000000..b6100f6 --- /dev/null +++ b/src/main/java/org/gnunet/testbed/PeerCreateCallback.java @@ -0,0 +1,7 @@ +package org.gnunet.testbed; + + +public interface PeerCreateCallback { + void onPeerCreated(Peer peer); + void onError(String errorMessage); +} diff --git a/src/main/java/org/gnunet/testing/TestingFixture.java b/src/main/java/org/gnunet/testing/TestingFixture.java new file mode 100644 index 0000000..4303512 --- /dev/null +++ b/src/main/java/org/gnunet/testing/TestingFixture.java @@ -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(); + } +} diff --git a/src/main/java/org/gnunet/testing/TestingServer.java b/src/main/java/org/gnunet/testing/TestingServer.java new file mode 100644 index 0000000..97b6bc0 --- /dev/null +++ b/src/main/java/org/gnunet/testing/TestingServer.java @@ -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()); + } + +} diff --git a/src/main/java/org/gnunet/testing/TestingSetup.java b/src/main/java/org/gnunet/testing/TestingSetup.java new file mode 100644 index 0000000..6f8d578 --- /dev/null +++ b/src/main/java/org/gnunet/testing/TestingSetup.java @@ -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); + } + } +} diff --git a/src/main/java/org/gnunet/testing/TestingSubsystem.java b/src/main/java/org/gnunet/testing/TestingSubsystem.java new file mode 100644 index 0000000..da7f2e4 --- /dev/null +++ b/src/main/java/org/gnunet/testing/TestingSubsystem.java @@ -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"); + } +} diff --git a/src/main/java/org/gnunet/testing/package-info.java b/src/main/java/org/gnunet/testing/package-info.java new file mode 100644 index 0000000..1a91586 --- /dev/null +++ b/src/main/java/org/gnunet/testing/package-info.java @@ -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; diff --git a/src/main/java/org/gnunet/transport/AddressIterateMessage.java b/src/main/java/org/gnunet/transport/AddressIterateMessage.java new file mode 100644 index 0000000..59ea6a8 --- /dev/null +++ b/src/main/java/org/gnunet/transport/AddressIterateMessage.java @@ -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. + */ +@UnionCase(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; +} diff --git a/src/main/java/org/gnunet/transport/BlacklistCallback.java b/src/main/java/org/gnunet/transport/BlacklistCallback.java new file mode 100644 index 0000000..b763dec --- /dev/null +++ b/src/main/java/org/gnunet/transport/BlacklistCallback.java @@ -0,0 +1,12 @@ +package org.gnunet.transport; + +import org.gnunet.util.PeerIdentity; + +/** + * ... + * + * @author Florian Dold + */ +public interface BlacklistCallback { + boolean isAllowed(PeerIdentity peerIdentity); +} diff --git a/src/main/java/org/gnunet/transport/BlacklistInitMessage.java b/src/main/java/org/gnunet/transport/BlacklistInitMessage.java new file mode 100644 index 0000000..be3209e --- /dev/null +++ b/src/main/java/org/gnunet/transport/BlacklistInitMessage.java @@ -0,0 +1,9 @@ +package org.gnunet.transport; + +import org.gnunet.construct.UnionCase; +import org.gnunet.util.GnunetMessage; + +@UnionCase(369) +public class BlacklistInitMessage implements GnunetMessage.Body { + // message body is empty +} diff --git a/src/main/java/org/gnunet/transport/HelloUpdateCallback.java b/src/main/java/org/gnunet/transport/HelloUpdateCallback.java new file mode 100644 index 0000000..d5253b7 --- /dev/null +++ b/src/main/java/org/gnunet/transport/HelloUpdateCallback.java @@ -0,0 +1,9 @@ +package org.gnunet.transport; + +/** + * ... + * + * @author Florian Dold + */ +public class HelloUpdateCallback { +} diff --git a/src/main/java/org/gnunet/transport/PeerIterateCallback.java b/src/main/java/org/gnunet/transport/PeerIterateCallback.java new file mode 100644 index 0000000..25bea5a --- /dev/null +++ b/src/main/java/org/gnunet/transport/PeerIterateCallback.java @@ -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); +} diff --git a/src/main/java/org/gnunet/transport/RequestConnectMessage.java b/src/main/java/org/gnunet/transport/RequestConnectMessage.java new file mode 100644 index 0000000..63bbc39 --- /dev/null +++ b/src/main/java/org/gnunet/transport/RequestConnectMessage.java @@ -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 + */ +@UnionCase(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; +} diff --git a/src/main/java/org/gnunet/transport/StartMessage.java b/src/main/java/org/gnunet/transport/StartMessage.java new file mode 100644 index 0000000..2169565 --- /dev/null +++ b/src/main/java/org/gnunet/transport/StartMessage.java @@ -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 + */ +@UnionCase(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; + + +} diff --git a/src/main/java/org/gnunet/transport/Transport.java b/src/main/java/org/gnunet/transport/Transport.java new file mode 100644 index 0000000..b9881b6 --- /dev/null +++ b/src/main/java/org/gnunet/transport/Transport.java @@ -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 + *

+ * 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(); + } +} + diff --git a/src/main/java/org/gnunet/transport/TryConnectCallback.java b/src/main/java/org/gnunet/transport/TryConnectCallback.java new file mode 100644 index 0000000..41e743b --- /dev/null +++ b/src/main/java/org/gnunet/transport/TryConnectCallback.java @@ -0,0 +1,10 @@ +package org.gnunet.transport; + +/** + * ... + * + * @author Florian Dold + */ +public interface TryConnectCallback { + void onDone(); +} diff --git a/src/main/java/org/gnunet/util/ATSInformation.java b/src/main/java/org/gnunet/util/ATSInformation.java new file mode 100644 index 0000000..b93931b --- /dev/null +++ b/src/main/java/org/gnunet/util/ATSInformation.java @@ -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; +} diff --git a/src/main/java/org/gnunet/util/AbsoluteTime.java b/src/main/java/org/gnunet/util/AbsoluteTime.java new file mode 100644 index 0000000..9d22d36 --- /dev/null +++ b/src/main/java/org/gnunet/util/AbsoluteTime.java @@ -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 { + 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 {@literal this} + * @return {@literal 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); + } + + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object other) { + return other instanceof AbsoluteTime && compareTo((AbsoluteTime) other) == 0; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return (int) this.abs_value_us; + } + + /** + * {@inheritDoc} + */ + @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; + } + + /** + * {@inheritDoc} + */ + @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 {@literal 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); + } +} diff --git a/src/main/java/org/gnunet/util/AbsoluteTimeMessage.java b/src/main/java/org/gnunet/util/AbsoluteTimeMessage.java new file mode 100644 index 0000000..f46d577 --- /dev/null +++ b/src/main/java/org/gnunet/util/AbsoluteTimeMessage.java @@ -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(); + } + } +} diff --git a/src/main/java/org/gnunet/util/Cancelable.java b/src/main/java/org/gnunet/util/Cancelable.java new file mode 100644 index 0000000..173f4c0 --- /dev/null +++ b/src/main/java/org/gnunet/util/Cancelable.java @@ -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(); +} diff --git a/src/main/java/org/gnunet/util/Client.java b/src/main/java/org/gnunet/util/Client.java new file mode 100644 index 0000000..18c206b --- /dev/null +++ b/src/main/java/org/gnunet/util/Client.java @@ -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 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(); + } +} diff --git a/src/main/java/org/gnunet/util/Configuration.java b/src/main/java/org/gnunet/util/Configuration.java new file mode 100644 index 0000000..ea67e1b --- /dev/null +++ b/src/main/java/org/gnunet/util/Configuration.java @@ -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 sections = HashBasedTable.create(); + + private final Map> sectionSources = new HashMap>(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 env = System.getenv(); + for (final Map.Entry e : env.entrySet()) { + orig = orig.replace("$" + e.getKey(), e.getValue()); + } + + for (final Map.Entry 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 getSection(String s) { + Map 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 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 getValueChoice(String section, String option, + Iterable choices) { + Optional 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 getValueNumber(String section, String option) { + Optional 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 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 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 getValueYesNo(String section, String option) { + final Optional v = getValueChoice(section, option, + Arrays.asList("YES", "NO")); + if (!v.isPresent()) { + Set 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 it; + + try { + List 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(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 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> section : sections.rowMap().entrySet()) { + buf.append("[" + section.getKey() + "]\n"); + for (Map.Entry option : section.getValue().entrySet()) { + buf.append(option.getKey() + " = " + option.getValue() + "\n"); + } + } + return buf.toString(); + } + + + public void loadDefaults() { + Collection dirs = new ArrayList(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); + } + } +} diff --git a/src/main/java/org/gnunet/util/Connection.java b/src/main/java/org/gnunet/util/Connection.java new file mode 100644 index 0000000..1fd1458 --- /dev/null +++ b/src/main/java/org/gnunet/util/Connection.java @@ -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 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(); + 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; + } + } +} diff --git a/src/main/java/org/gnunet/util/Continuation.java b/src/main/java/org/gnunet/util/Continuation.java new file mode 100644 index 0000000..e1027c0 --- /dev/null +++ b/src/main/java/org/gnunet/util/Continuation.java @@ -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); +} diff --git a/src/main/java/org/gnunet/util/GnunetMessage.java b/src/main/java/org/gnunet/util/GnunetMessage.java new file mode 100644 index 0000000..89c7a80 --- /dev/null +++ b/src/main/java/org/gnunet/util/GnunetMessage.java @@ -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; +} diff --git a/src/main/java/org/gnunet/util/HashCode.java b/src/main/java/org/gnunet/util/HashCode.java new file mode 100644 index 0000000..0c2790f --- /dev/null +++ b/src/main/java/org/gnunet/util/HashCode.java @@ -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 diff --git a/src/main/java/org/gnunet/util/Helper.java b/src/main/java/org/gnunet/util/Helper.java new file mode 100644 index 0000000..e8c1723 --- /dev/null +++ b/src/main/java/org/gnunet/util/Helper.java @@ -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 argv, + RunaboutMessageReceiver receiver) { + this.receiver = receiver; + List command = new LinkedList(); + 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; + } + } +} diff --git a/src/main/java/org/gnunet/util/MessageReceiver.java b/src/main/java/org/gnunet/util/MessageReceiver.java new file mode 100644 index 0000000..548695f --- /dev/null +++ b/src/main/java/org/gnunet/util/MessageReceiver.java @@ -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(); +} diff --git a/src/main/java/org/gnunet/util/MessageTransmitter.java b/src/main/java/org/gnunet/util/MessageTransmitter.java new file mode 100644 index 0000000..54a6555 --- /dev/null +++ b/src/main/java/org/gnunet/util/MessageTransmitter.java @@ -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(); +} diff --git a/src/main/java/org/gnunet/util/PeerIdentity.java b/src/main/java/org/gnunet/util/PeerIdentity.java new file mode 100644 index 0000000..46a67cd --- /dev/null +++ b/src/main/java/org/gnunet/util/PeerIdentity.java @@ -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); + } +} diff --git a/src/main/java/org/gnunet/util/Program.java b/src/main/java/org/gnunet/util/Program.java new file mode 100644 index 0000000..bd413b9 --- /dev/null +++ b/src/main/java/org/gnunet/util/Program.java @@ -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; + } +} diff --git a/src/main/java/org/gnunet/util/RelativeTime.java b/src/main/java/org/gnunet/util/RelativeTime.java new file mode 100644 index 0000000..512ed01 --- /dev/null +++ b/src/main/java/org/gnunet/util/RelativeTime.java @@ -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 { + 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__); + } + } + +} diff --git a/src/main/java/org/gnunet/util/RelativeTimeMessage.java b/src/main/java/org/gnunet/util/RelativeTimeMessage.java new file mode 100644 index 0000000..ac4e66c --- /dev/null +++ b/src/main/java/org/gnunet/util/RelativeTimeMessage.java @@ -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(); + } + } + +} diff --git a/src/main/java/org/gnunet/util/Resolver.java b/src/main/java/org/gnunet/util/Resolver.java new file mode 100644 index 0000000..22047aa --- /dev/null +++ b/src/main/java/org/gnunet/util/Resolver.java @@ -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. + *

+ * 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. + *

+ * 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 queuedRequests = new LinkedList(); + + 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(); + } +} diff --git a/src/main/java/org/gnunet/util/RunaboutMessageReceiver.java b/src/main/java/org/gnunet/util/RunaboutMessageReceiver.java new file mode 100644 index 0000000..2a0f067 --- /dev/null +++ b/src/main/java/org/gnunet/util/RunaboutMessageReceiver.java @@ -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); + } +} diff --git a/src/main/java/org/gnunet/util/RunaboutUtil.java b/src/main/java/org/gnunet/util/RunaboutUtil.java new file mode 100644 index 0000000..a82dc0a --- /dev/null +++ b/src/main/java/org/gnunet/util/RunaboutUtil.java @@ -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 getRunaboutVisitees(Runabout r) { + Class rc = r.getClass(); + ArrayList ret = new ArrayList(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 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; + } +} diff --git a/src/main/java/org/gnunet/util/Scheduler.java b/src/main/java/org/gnunet/util/Scheduler.java new file mode 100644 index 0000000..78ea288 --- /dev/null +++ b/src/main/java/org/gnunet/util/Scheduler.java @@ -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[] readyLists = new LinkedList[Priority.numberOfPriorities]; + + static { + for (int i = 0; i < Priority.numberOfPriorities; ++i) { + readyLists[i] = new LinkedList(); + } + } + + 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 pending = new PriorityQueue(5, new Comparator + () { + @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(); + } + 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 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 eventChannels = null; + private ArrayList 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(); + eventTypes = new ArrayList(); + } + 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 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 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 executableTasks = new HashSet(); + 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 + *

    + *
  • there are no ready tasks
  • + *
  • there is a pending task (which may be of higher priority)
  • + *
+ */ + 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 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(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); + } +} + diff --git a/src/main/java/org/gnunet/util/Server.java b/src/main/java/org/gnunet/util/Server.java new file mode 100644 index 0000000..8a86b45 --- /dev/null +++ b/src/main/java/org/gnunet/util/Server.java @@ -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 listenSockets = new ArrayList(); + + /** + * The list of all clients connected to this server. + */ + private List clientHandles = new LinkedList(); + + /** + * 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 disconnectHandlers = new LinkedList(); + + /** + * 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 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. + *

+ * 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). + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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 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. + *

+ * 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(); + } +} diff --git a/src/main/java/org/gnunet/util/Service.java b/src/main/java/org/gnunet/util/Service.java new file mode 100644 index 0000000..d93e296 --- /dev/null +++ b/src/main/java/org/gnunet/util/Service.java @@ -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 addrs = new LinkedList(); + + 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 diff --git a/src/main/java/org/gnunet/util/Strings.java b/src/main/java/org/gnunet/util/Strings.java new file mode 100644 index 0000000..a35568a --- /dev/null +++ b/src/main/java/org/gnunet/util/Strings.java @@ -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; + } + +} diff --git a/src/main/java/org/gnunet/util/TestMessage.java b/src/main/java/org/gnunet/util/TestMessage.java new file mode 100644 index 0000000..b08a706 --- /dev/null +++ b/src/main/java/org/gnunet/util/TestMessage.java @@ -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. + */ +@UnionCase(1) +public class TestMessage implements GnunetMessage.Body { + // empty +} diff --git a/src/main/java/org/gnunet/util/UnknownMessageBody.java b/src/main/java/org/gnunet/util/UnknownMessageBody.java new file mode 100644 index 0000000..b978ec6 --- /dev/null +++ b/src/main/java/org/gnunet/util/UnknownMessageBody.java @@ -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; +} diff --git a/src/main/java/org/gnunet/util/getopt/Argument.java b/src/main/java/org/gnunet/util/getopt/Argument.java new file mode 100644 index 0000000..34159d0 --- /dev/null +++ b/src/main/java/org/gnunet/util/getopt/Argument.java @@ -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. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(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(); +} diff --git a/src/main/java/org/gnunet/util/getopt/ArgumentAction.java b/src/main/java/org/gnunet/util/getopt/ArgumentAction.java new file mode 100644 index 0000000..077e71c --- /dev/null +++ b/src/main/java/org/gnunet/util/getopt/ArgumentAction.java @@ -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 +} diff --git a/src/main/java/org/gnunet/util/getopt/Parser.java b/src/main/java/org/gnunet/util/getopt/Parser.java new file mode 100644 index 0000000..6ecc220 --- /dev/null +++ b/src/main/java/org/gnunet/util/getopt/Parser.java @@ -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 getFields(Class c) { + LinkedList fields = new LinkedList(Arrays.asList(c.getDeclaredFields())); + while ((c = c.getSuperclass()) != null) { + fields.addAll(0, Arrays.asList(c.getDeclaredFields())); + } + return fields; + } + + private Map longOpt = new HashMap(); + private Map shortOpt = new HashMap(); + + private Collection arguments = new LinkedList(); + + 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 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 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 positionalArgs = new LinkedList(); + + LinkedList argsList = new LinkedList(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()]); + } + +} diff --git a/src/main/java/org/gnunet/util/getopt/package-info.java b/src/main/java/org/gnunet/util/getopt/package-info.java new file mode 100644 index 0000000..0e3bdf5 --- /dev/null +++ b/src/main/java/org/gnunet/util/getopt/package-info.java @@ -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; diff --git a/src/main/java/org/gnunet/util/package-info.java b/src/main/java/org/gnunet/util/package-info.java new file mode 100644 index 0000000..df61afd --- /dev/null +++ b/src/main/java/org/gnunet/util/package-info.java @@ -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; diff --git a/src/main/java/org/gnunet/voting/CertificateAuthorityService.java b/src/main/java/org/gnunet/voting/CertificateAuthorityService.java new file mode 100644 index 0000000..559bd97 --- /dev/null +++ b/src/main/java/org/gnunet/voting/CertificateAuthorityService.java @@ -0,0 +1,7 @@ +package org.gnunet.voting; + +/** + * Permits or denies a voter to participate in an election. + */ +public class CertificateAuthorityService { +} diff --git a/src/main/java/org/gnunet/voting/ElectionCallTool.java b/src/main/java/org/gnunet/voting/ElectionCallTool.java new file mode 100644 index 0000000..52ad5fb --- /dev/null +++ b/src/main/java/org/gnunet/voting/ElectionCallTool.java @@ -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(); + } +} diff --git a/src/main/java/org/gnunet/voting/ElectionSpecification.java b/src/main/java/org/gnunet/voting/ElectionSpecification.java new file mode 100644 index 0000000..8671ad5 --- /dev/null +++ b/src/main/java/org/gnunet/voting/ElectionSpecification.java @@ -0,0 +1,5 @@ +package org.gnunet.voting; + +public class ElectionSpecification { + +} diff --git a/src/main/java/org/gnunet/voting/TallyAuthorityService.java b/src/main/java/org/gnunet/voting/TallyAuthorityService.java new file mode 100644 index 0000000..435c318 --- /dev/null +++ b/src/main/java/org/gnunet/voting/TallyAuthorityService.java @@ -0,0 +1,5 @@ +package org.gnunet.voting; + + +public class TallyAuthorityService { +} diff --git a/src/main/java/org/gnunet/voting/VotingTool.java b/src/main/java/org/gnunet/voting/VotingTool.java new file mode 100644 index 0000000..02874b6 --- /dev/null +++ b/src/main/java/org/gnunet/voting/VotingTool.java @@ -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(); + + } + +} diff --git a/src/main/java/org/gnunet/voting/simulation/Authority.java b/src/main/java/org/gnunet/voting/simulation/Authority.java new file mode 100644 index 0000000..792dbbd --- /dev/null +++ b/src/main/java/org/gnunet/voting/simulation/Authority.java @@ -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 participatingAuthorities; + + private List ballots = Lists.newLinkedList(); + + private Map specializedKeyShares = Maps.newTreeMap(); + + private Cyphertext encryptedTally; + private BigInteger tallyBaseG; + + + /** + * The commitments of each authority to it's share of the group secret. + */ + Map 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 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 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(); + } + } +} diff --git a/src/main/java/org/gnunet/voting/simulation/Ballot.java b/src/main/java/org/gnunet/voting/simulation/Ballot.java new file mode 100644 index 0000000..1c2bfbe --- /dev/null +++ b/src/main/java/org/gnunet/voting/simulation/Ballot.java @@ -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(); + } + + + } +} diff --git a/src/main/java/org/gnunet/voting/simulation/BogusAuthority.java b/src/main/java/org/gnunet/voting/simulation/BogusAuthority.java new file mode 100644 index 0000000..d59f0cf --- /dev/null +++ b/src/main/java/org/gnunet/voting/simulation/BogusAuthority.java @@ -0,0 +1,9 @@ +package org.gnunet.voting.simulation; + +/** + * ... + * + * @author Florian Dold + */ +public class BogusAuthority extends Authority { +} diff --git a/src/main/java/org/gnunet/voting/simulation/CallForVoters.java b/src/main/java/org/gnunet/voting/simulation/CallForVoters.java new file mode 100644 index 0000000..a84484d --- /dev/null +++ b/src/main/java/org/gnunet/voting/simulation/CallForVoters.java @@ -0,0 +1,14 @@ +package org.gnunet.voting.simulation; + +import java.util.List; + +/** + * ... + * + * @author Florian Dold + */ +public class CallForVoters { + public List authorities; + public VotingParameters parameters; + public GroupPublicKey publicKey; +} diff --git a/src/main/java/org/gnunet/voting/simulation/CryptoUtil.java b/src/main/java/org/gnunet/voting/simulation/CryptoUtil.java new file mode 100644 index 0000000..87ecd9f --- /dev/null +++ b/src/main/java/org/gnunet/voting/simulation/CryptoUtil.java @@ -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()); + } + +} diff --git a/src/main/java/org/gnunet/voting/simulation/Cyphertext.java b/src/main/java/org/gnunet/voting/simulation/Cyphertext.java new file mode 100644 index 0000000..6e7d72f --- /dev/null +++ b/src/main/java/org/gnunet/voting/simulation/Cyphertext.java @@ -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; + } +} diff --git a/src/main/java/org/gnunet/voting/simulation/ElectionSupervisor.java b/src/main/java/org/gnunet/voting/simulation/ElectionSupervisor.java new file mode 100644 index 0000000..ee0b181 --- /dev/null +++ b/src/main/java/org/gnunet/voting/simulation/ElectionSupervisor.java @@ -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 availableAuthorities; + + /** + * Authorities that have agreed to participate. + */ + private List participatingAuthorities = Lists.newArrayList(); + + + + private enum Phase { START, INVITED, KEYS_GENERATED, PUBKEY_PUBLISHED} + + private Phase currentPhase = Phase.START; + + + public ElectionSupervisor(List 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; + } +} diff --git a/src/main/java/org/gnunet/voting/simulation/GroupPublicKey.java b/src/main/java/org/gnunet/voting/simulation/GroupPublicKey.java new file mode 100644 index 0000000..a6f2c74 --- /dev/null +++ b/src/main/java/org/gnunet/voting/simulation/GroupPublicKey.java @@ -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; + } +} diff --git a/src/main/java/org/gnunet/voting/simulation/TallyKeyShare.java b/src/main/java/org/gnunet/voting/simulation/TallyKeyShare.java new file mode 100644 index 0000000..1982358 --- /dev/null +++ b/src/main/java/org/gnunet/voting/simulation/TallyKeyShare.java @@ -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)); + } +} + diff --git a/src/main/java/org/gnunet/voting/simulation/TransmitShareVerification.java b/src/main/java/org/gnunet/voting/simulation/TransmitShareVerification.java new file mode 100644 index 0000000..13da325 --- /dev/null +++ b/src/main/java/org/gnunet/voting/simulation/TransmitShareVerification.java @@ -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); + } + } +} diff --git a/src/main/java/org/gnunet/voting/simulation/Voter.java b/src/main/java/org/gnunet/voting/simulation/Voter.java new file mode 100644 index 0000000..53a5640 --- /dev/null +++ b/src/main/java/org/gnunet/voting/simulation/Voter.java @@ -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); + } + } +} diff --git a/src/main/java/org/gnunet/voting/simulation/VotingParameters.java b/src/main/java/org/gnunet/voting/simulation/VotingParameters.java new file mode 100644 index 0000000..bc6b987 --- /dev/null +++ b/src/main/java/org/gnunet/voting/simulation/VotingParameters.java @@ -0,0 +1,165 @@ +package org.gnunet.voting.simulation; + +import java.math.BigInteger; +import java.security.SecureRandom; + +/** + * Utilities for the modified ElGamal algorithm. + *

+ * 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. + *

+ * 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. + *

+ * (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))); + } + + +} diff --git a/src/main/java/org/gnunet/voting/simulation/VotingSimulation.java b/src/main/java/org/gnunet/voting/simulation/VotingSimulation.java new file mode 100644 index 0000000..607c653 --- /dev/null +++ b/src/main/java/org/gnunet/voting/simulation/VotingSimulation.java @@ -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 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 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 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 spawnAuthorities(int authorityCount, int authorityThreshold) { + List authorities = Lists.newArrayList(); + Collection 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 spawnVoters(CallForVoters callForVote, int voterCount, int honestVoterCount) { + List 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 randomIndices(int authorityCount, int authorityThreshold) { + ArrayList 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)); + } +} diff --git a/src/main/java/org/grothoff/Runabout.java b/src/main/java/org/grothoff/Runabout.java new file mode 100644 index 0000000..2a1dbb0 --- /dev/null +++ b/src/main/java/org/grothoff/Runabout.java @@ -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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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!).
+ * A per-thread Cache is used to speed-up the creation of the Runabout by + * caching reflection, code creation and dynamic loading operations. + *

+ * Restrictions: Java semantics require: + *

    + *
  • all subclasses must be public, sadly this also means that you + * can not use an anonymous inner class (!)
  • + *
  • the types_length to all arguments of visit methods must be public
  • + *
  • all visit methods must be public (!)
  • + *
+ * Otherwise the visitor will die with an IllegalAccessError during execution. + *

+ * + * @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 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 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 result = new HashMap(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 + * {@code 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> 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>(); + 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 628 + * 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 get(Runabout r) { + Class c = r.getClass(); + HashMap 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 diff --git a/src/main/java/org/grothoff/package-info.java b/src/main/java/org/grothoff/package-info.java new file mode 100644 index 0000000..2a8b8f0 --- /dev/null +++ b/src/main/java/org/grothoff/package-info.java @@ -0,0 +1,4 @@ +/** + * Pure java implementation of single argument multiple dispatch + */ +package org.grothoff; diff --git a/src/main/resources/org/gnunet/construct/MsgMap.txt b/src/main/resources/org/gnunet/construct/MsgMap.txt new file mode 100644 index 0000000..2ca1246 --- /dev/null +++ b/src/main/resources/org/gnunet/construct/MsgMap.txt @@ -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 diff --git a/src/org/gnunet/consensus/ConcludeCallback.java b/src/org/gnunet/consensus/ConcludeCallback.java deleted file mode 100644 index 7660c49..0000000 --- a/src/org/gnunet/consensus/ConcludeCallback.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.gnunet.consensus; - -public interface ConcludeCallback { - void onConcludeDone(); -} diff --git a/src/org/gnunet/consensus/ConcludeDoneMessage.java b/src/org/gnunet/consensus/ConcludeDoneMessage.java deleted file mode 100644 index 51757aa..0000000 --- a/src/org/gnunet/consensus/ConcludeDoneMessage.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.gnunet.consensus; - - -import org.gnunet.construct.MessageUnion; -import org.gnunet.construct.UnionCase; - -/** - * Notify the client that conclude has finished. - * Direction: service -> client - */ -@UnionCase(525) -public class ConcludeDoneMessage implements MessageUnion { -} diff --git a/src/org/gnunet/consensus/ConcludeMessage.java b/src/org/gnunet/consensus/ConcludeMessage.java deleted file mode 100644 index 7b43928..0000000 --- a/src/org/gnunet/consensus/ConcludeMessage.java +++ /dev/null @@ -1,19 +0,0 @@ -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 - */ -@UnionCase(524) -public class ConcludeMessage implements GnunetMessage.Body { - /* empty body */ -} \ No newline at end of file diff --git a/src/org/gnunet/consensus/Consensus.java b/src/org/gnunet/consensus/Consensus.java deleted file mode 100644 index 2047454..0000000 --- a/src/org/gnunet/consensus/Consensus.java +++ /dev/null @@ -1,136 +0,0 @@ -package org.gnunet.consensus; - -import org.gnunet.mq.ClientMessageQueue; -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; - - /** - * Message queue for 'client'. - */ - private MessageQueue client_mq; - - /** - * 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_mq = new ClientMessageQueue(client, 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_mq.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_mq.send(m); - } - - /** - * Destroy a consensus handle. - * Free all state associated with - * it, no longer call any of the callbacks. - */ - public void destroy() { - client_mq.destroy(); - client_mq = null; - client.disconnect(); - client = null; - } -} diff --git a/src/org/gnunet/consensus/ConsensusElement.java b/src/org/gnunet/consensus/ConsensusElement.java deleted file mode 100644 index 846e72a..0000000 --- a/src/org/gnunet/consensus/ConsensusElement.java +++ /dev/null @@ -1,16 +0,0 @@ -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; -} diff --git a/src/org/gnunet/consensus/InsertDoneCallback.java b/src/org/gnunet/consensus/InsertDoneCallback.java deleted file mode 100644 index f0e86ca..0000000 --- a/src/org/gnunet/consensus/InsertDoneCallback.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.gnunet.consensus; - -public interface InsertDoneCallback { - void onInsertDone(); -} diff --git a/src/org/gnunet/consensus/InsertElementMessage.java b/src/org/gnunet/consensus/InsertElementMessage.java deleted file mode 100644 index fd0ff67..0000000 --- a/src/org/gnunet/consensus/InsertElementMessage.java +++ /dev/null @@ -1,23 +0,0 @@ -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 - */ -@UnionCase(521) -public class InsertElementMessage implements GnunetMessage.Body { - @UInt16 - public int element_type; - @FillWith - @UInt8 - public byte[] element_data; -} \ No newline at end of file diff --git a/src/org/gnunet/consensus/NewElementCallback.java b/src/org/gnunet/consensus/NewElementCallback.java deleted file mode 100644 index 4b07a71..0000000 --- a/src/org/gnunet/consensus/NewElementCallback.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.gnunet.consensus; - -public interface NewElementCallback { - void onNewElement(ConsensusElement element); -} diff --git a/src/org/gnunet/consensus/NewElementMessage.java b/src/org/gnunet/consensus/NewElementMessage.java deleted file mode 100644 index deb3634..0000000 --- a/src/org/gnunet/consensus/NewElementMessage.java +++ /dev/null @@ -1,20 +0,0 @@ -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 - */ -@UnionCase(523) -public class NewElementMessage implements GnunetMessage.Body { - @UInt16 - public int element_type; - @FillWith - @UInt8 - public byte[] element_data; -} \ No newline at end of file diff --git a/src/org/gnunet/construct/Construct.java b/src/org/gnunet/construct/Construct.java deleted file mode 100644 index a74a5c2..0000000 --- a/src/org/gnunet/construct/Construct.java +++ /dev/null @@ -1,482 +0,0 @@ -/* - 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 => signed or unsigned fixnum, represented by n bits -- @NestedMessage => nested message -- @FillWith @(U)Int => 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 = "") => 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 - */ -@SuppressWarnings("unchecked") -public class Construct { - private static final Logger logger = LoggerFactory - .getLogger(Construct.class); - - - private static Map, Parser> parserCache = new HashMap, - 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 parseAs(ByteBuffer srcBuf, Class 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 parseAs(byte[] srcBuf, Class 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 c) { - - if (parserCache.containsKey(c)) { - return parserCache.get(c); - } - - Parser p = getParser(c, new ParserGenerator()); - - parserCache.put(c, p); - - return p; - } - - private static List getMessageFields(Class c) { - LinkedList fields = new LinkedList(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 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 path = new LinkedList(); - - // path of the object that has a frame size field - List frameSizePath; - - private ParserGenerator() { - } - - public void visit(Union u) { - parser = new UnionParser(u.optional(), (Class) field.getType(), - ReflectUtil.getFieldPathFromString(u.tag(), c), field); - } - - public void visit(FrameSize ts) { - - frameSizePath = new LinkedList(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) nestedField.getType()); - - parser = new NestedParser(p, n.optional(), nestedField, true); - - } else { - Field old_f = field; - List old_path = new ArrayList(path); - Class old_c = c; - - path.add(field); - - Parser p = getParser((Class) 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) 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) 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) 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) 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(); - } - -} diff --git a/src/org/gnunet/construct/DoubleValue.java b/src/org/gnunet/construct/DoubleValue.java deleted file mode 100644 index 0856fe8..0000000 --- a/src/org/gnunet/construct/DoubleValue.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - 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. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface DoubleValue { -} diff --git a/src/org/gnunet/construct/FillWith.java b/src/org/gnunet/construct/FillWith.java deleted file mode 100644 index f95aa3d..0000000 --- a/src/org/gnunet/construct/FillWith.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - 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 - * - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface FillWith { -} diff --git a/src/org/gnunet/construct/FixedSizeArray.java b/src/org/gnunet/construct/FixedSizeArray.java deleted file mode 100644 index 699ae68..0000000 --- a/src/org/gnunet/construct/FixedSizeArray.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - 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 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface FixedSizeArray { - int length(); -} diff --git a/src/org/gnunet/construct/FixedSizeIntegerArray.java b/src/org/gnunet/construct/FixedSizeIntegerArray.java deleted file mode 100644 index b2418b8..0000000 --- a/src/org/gnunet/construct/FixedSizeIntegerArray.java +++ /dev/null @@ -1,21 +0,0 @@ -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 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface FixedSizeIntegerArray { - int length(); - int bitSize(); - boolean signed(); -} diff --git a/src/org/gnunet/construct/FrameSize.java b/src/org/gnunet/construct/FrameSize.java deleted file mode 100644 index 0533d0b..0000000 --- a/src/org/gnunet/construct/FrameSize.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - 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 - * - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface FrameSize { -} diff --git a/src/org/gnunet/construct/Int16.java b/src/org/gnunet/construct/Int16.java deleted file mode 100644 index 677324b..0000000 --- a/src/org/gnunet/construct/Int16.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - 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 - * - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface Int16 { - -} diff --git a/src/org/gnunet/construct/Int32.java b/src/org/gnunet/construct/Int32.java deleted file mode 100644 index da993ca..0000000 --- a/src/org/gnunet/construct/Int32.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - 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 - * - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface Int32 { - -} diff --git a/src/org/gnunet/construct/Int64.java b/src/org/gnunet/construct/Int64.java deleted file mode 100644 index be5d940..0000000 --- a/src/org/gnunet/construct/Int64.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - 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. - * - */ - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface Int64 { - -} diff --git a/src/org/gnunet/construct/Int8.java b/src/org/gnunet/construct/Int8.java deleted file mode 100644 index a0aaa14..0000000 --- a/src/org/gnunet/construct/Int8.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - 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 - * - */ - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface Int8 { - -} diff --git a/src/org/gnunet/construct/IntegerFill.java b/src/org/gnunet/construct/IntegerFill.java deleted file mode 100644 index 4564c83..0000000 --- a/src/org/gnunet/construct/IntegerFill.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - 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. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface IntegerFill { - boolean signed(); - int bitSize(); -} diff --git a/src/org/gnunet/construct/Message.java b/src/org/gnunet/construct/Message.java deleted file mode 100644 index d0068b5..0000000 --- a/src/org/gnunet/construct/Message.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - 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 { -} diff --git a/src/org/gnunet/construct/MessageIdAnnotationProcessor.java b/src/org/gnunet/construct/MessageIdAnnotationProcessor.java deleted file mode 100644 index 8a17ba9..0000000 --- a/src/org/gnunet/construct/MessageIdAnnotationProcessor.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - 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. - */ -@SupportedAnnotationTypes("org.gnunet.construct.UnionCase") -@SupportedSourceVersion(SourceVersion.RELEASE_6) -public class MessageIdAnnotationProcessor extends AbstractProcessor { - // a mapping from (union, id) to member - //private final Map> unionmap = new HashMap>(100); - private final Table idToMember = HashBasedTable.create(); - - @Override - public boolean process(Set 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 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 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; - } -} diff --git a/src/org/gnunet/construct/MessageLoader.java b/src/org/gnunet/construct/MessageLoader.java deleted file mode 100644 index 71e2719..0000000 --- a/src/org/gnunet/construct/MessageLoader.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * - * 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. - *

- * XXX: how much of generics is too much? - */ - private static Map, Map>> unionmap - = new HashMap, Map>>(100); - - /* - * Maps a union interface and union case to the corresponding tag. - */ - private static Map, Map, Integer>> tagmap - = new HashMap, Map, Integer>>(100); - - - static { - ClassLoader classLoader = MessageLoader.class.getClassLoader(); - Enumeration 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 unionInterface = loadClass(unionInterfaceName); - Class unionCase = loadClass(unionCaseName); - - if (!unionmap.containsKey(unionInterface)) { - unionmap.put(unionInterface, new HashMap>(5)); - } - unionmap.get(unionInterface).put(id, unionCase); - - - if (!tagmap.containsKey(unionInterface)) { - tagmap.put(unionInterface, new HashMap, 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 loadClass(String className) { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - Class msgClass; - try { - msgClass = (Class) 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 getUnionClass(Class unionInterface, int tag) { - Map> map = unionmap.get(unionInterface); - if (map == null) { - throw new UnknownUnionException("don't know how to handle unions of type '" + unionInterface + "'"); - } - - Class 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 unionInterface, Class unionCase) { - Map, 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 unionInterface, - Class unionCase, int tag) { - if (!unionmap.containsKey(unionInterface)) { - unionmap.put(unionInterface, new HashMap>(5)); - } - unionmap.get(unionInterface).put(tag, unionCase); - - - if (!tagmap.containsKey(unionInterface)) { - tagmap.put(unionInterface, new HashMap, Integer>(5)); - } - tagmap.get(unionInterface).put(unionCase, tag); - - - } -} diff --git a/src/org/gnunet/construct/MessageUnion.java b/src/org/gnunet/construct/MessageUnion.java deleted file mode 100644 index 0481df2..0000000 --- a/src/org/gnunet/construct/MessageUnion.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - 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 { -} diff --git a/src/org/gnunet/construct/MsgMap.txt b/src/org/gnunet/construct/MsgMap.txt deleted file mode 100644 index 7f3d2f4..0000000 --- a/src/org/gnunet/construct/MsgMap.txt +++ /dev/null @@ -1,46 +0,0 @@ -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/13 20:15:12 diff --git a/src/org/gnunet/construct/NestedMessage.java b/src/org/gnunet/construct/NestedMessage.java deleted file mode 100644 index fe65323..0000000 --- a/src/org/gnunet/construct/NestedMessage.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - 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 - * - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface NestedMessage { - boolean newFrame() default false; - boolean optional() default false; -} \ No newline at end of file diff --git a/src/org/gnunet/construct/ProtocolViolationException.java b/src/org/gnunet/construct/ProtocolViolationException.java deleted file mode 100644 index 9de46d4..0000000 --- a/src/org/gnunet/construct/ProtocolViolationException.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - 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); - } -} diff --git a/src/org/gnunet/construct/ReflectUtil.java b/src/org/gnunet/construct/ReflectUtil.java deleted file mode 100644 index 1115641..0000000 --- a/src/org/gnunet/construct/ReflectUtil.java +++ /dev/null @@ -1,297 +0,0 @@ -/* - 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 justInstantiate(Class 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 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 fl, Object obj) { - return followFieldPath(fl, obj, fl.size()); - } - - public static Object followFieldPathToParent(List 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 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 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 getFieldPathFromString(final String p, final Class root) { - Class current = root; - - String[] components = p.split("[.]"); - - List fp = new ArrayList(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; - } -} diff --git a/src/org/gnunet/construct/UInt16.java b/src/org/gnunet/construct/UInt16.java deleted file mode 100644 index 18c24b2..0000000 --- a/src/org/gnunet/construct/UInt16.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - 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 - * - */ - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface UInt16 { - -} diff --git a/src/org/gnunet/construct/UInt32.java b/src/org/gnunet/construct/UInt32.java deleted file mode 100644 index ab4a278..0000000 --- a/src/org/gnunet/construct/UInt32.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - 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 - * - */ - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface UInt32 { - -} diff --git a/src/org/gnunet/construct/UInt64.java b/src/org/gnunet/construct/UInt64.java deleted file mode 100644 index d45cf69..0000000 --- a/src/org/gnunet/construct/UInt64.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - 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 - * - */ - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface UInt64 { - -} diff --git a/src/org/gnunet/construct/UInt8.java b/src/org/gnunet/construct/UInt8.java deleted file mode 100644 index 58b8335..0000000 --- a/src/org/gnunet/construct/UInt8.java +++ /dev/null @@ -1,41 +0,0 @@ - -/* - 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 - * - */ - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface UInt8 { - -} diff --git a/src/org/gnunet/construct/Union.java b/src/org/gnunet/construct/Union.java deleted file mode 100644 index d35512e..0000000 --- a/src/org/gnunet/construct/Union.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - 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 {@literal tag}. - */ -@Target(ElementType.FIELD) -@Retention(RetentionPolicy.RUNTIME) -public @interface Union { - String tag(); - boolean optional() default false; -} \ No newline at end of file diff --git a/src/org/gnunet/construct/UnionCase.java b/src/org/gnunet/construct/UnionCase.java deleted file mode 100644 index 7622dd4..0000000 --- a/src/org/gnunet/construct/UnionCase.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - 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 {@literal UnionCase} should implement - * the marker interface for their respective union type. - */ -@Retention(RetentionPolicy.SOURCE) -@Target(ElementType.TYPE) -public @interface UnionCase { - int value(); -} \ No newline at end of file diff --git a/src/org/gnunet/construct/VariableSizeArray.java b/src/org/gnunet/construct/VariableSizeArray.java deleted file mode 100644 index 64daece..0000000 --- a/src/org/gnunet/construct/VariableSizeArray.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - 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 - * - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface VariableSizeArray { - String lengthField(); -} diff --git a/src/org/gnunet/construct/VariableSizeIntegerArray.java b/src/org/gnunet/construct/VariableSizeIntegerArray.java deleted file mode 100644 index a3a9f28..0000000 --- a/src/org/gnunet/construct/VariableSizeIntegerArray.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - 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 - * - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface VariableSizeIntegerArray { - String lengthField(); - boolean signed(); - int bitSize(); -} diff --git a/src/org/gnunet/construct/ZeroTerminatedString.java b/src/org/gnunet/construct/ZeroTerminatedString.java deleted file mode 100644 index 2d70d71..0000000 --- a/src/org/gnunet/construct/ZeroTerminatedString.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - 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 - * - */ -@Retention(RetentionPolicy.RUNTIME) -public @interface ZeroTerminatedString { - String charset() default "UTF-8"; - boolean optional() default false; -} diff --git a/src/org/gnunet/construct/package-info.java b/src/org/gnunet/construct/package-info.java deleted file mode 100644 index add5d40..0000000 --- a/src/org/gnunet/construct/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - 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; diff --git a/src/org/gnunet/construct/parsers/DoubleParser.java b/src/org/gnunet/construct/parsers/DoubleParser.java deleted file mode 100644 index c6cc835..0000000 --- a/src/org/gnunet/construct/parsers/DoubleParser.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - 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 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 frameSizePath, Message frameObj) { - // nothing to do here - } - - @Override - public int getStaticSize() { - return Double.SIZE / 8; - } -} diff --git a/src/org/gnunet/construct/parsers/FillParser.java b/src/org/gnunet/construct/parsers/FillParser.java deleted file mode 100644 index 156e120..0000000 --- a/src/org/gnunet/construct/parsers/FillParser.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - 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 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 list = new ArrayList(10); - - while (remaining > 0) { - @SuppressWarnings("unchecked") - Message next = ReflectUtil.justInstantiate((Class) 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 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; - } - -} diff --git a/src/org/gnunet/construct/parsers/FixedSizeArrayParser.java b/src/org/gnunet/construct/parsers/FixedSizeArrayParser.java deleted file mode 100644 index 3dbc720..0000000 --- a/src/org/gnunet/construct/parsers/FixedSizeArrayParser.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - 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 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)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 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(); - } -} diff --git a/src/org/gnunet/construct/parsers/FixedSizeIntegerArrayParser.java b/src/org/gnunet/construct/parsers/FixedSizeIntegerArrayParser.java deleted file mode 100644 index ae633b0..0000000 --- a/src/org/gnunet/construct/parsers/FixedSizeIntegerArrayParser.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - 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 frameSizePath) { - int size = 0; - - @SuppressWarnings("unchecked") - final Class arrayElementType = (Class) 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 frameSizePath, Message frameObj) { - // nothing to patch! - } - - @Override - public int getStaticSize() { - return elemNumber * byteSize; - } -} diff --git a/src/org/gnunet/construct/parsers/IntegerFillParser.java b/src/org/gnunet/construct/parsers/IntegerFillParser.java deleted file mode 100644 index 7027afc..0000000 --- a/src/org/gnunet/construct/parsers/IntegerFillParser.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - 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 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 arrayElementType = (Class) 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 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; - } -} diff --git a/src/org/gnunet/construct/parsers/IntegerParser.java b/src/org/gnunet/construct/parsers/IntegerParser.java deleted file mode 100644 index 4f71aa5..0000000 --- a/src/org/gnunet/construct/parsers/IntegerParser.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - 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 - 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 frameSizePath, Message frameObj) { - // todo: optimize this! - /* - if (frameSizePath != null) { - ReflectUtil.justSetInt(frameObj, frameSizePath, frameSize); - } - */ - } - - @Override - public int getStaticSize() { - return byteSize; - } -} diff --git a/src/org/gnunet/construct/parsers/IntegerUtil.java b/src/org/gnunet/construct/parsers/IntegerUtil.java deleted file mode 100644 index 83391de..0000000 --- a/src/org/gnunet/construct/parsers/IntegerUtil.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - 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"); - } -} diff --git a/src/org/gnunet/construct/parsers/NestedParser.java b/src/org/gnunet/construct/parsers/NestedParser.java deleted file mode 100644 index 733bf9e..0000000 --- a/src/org/gnunet/construct/parsers/NestedParser.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - 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(); - } - return nestedParser.getSize(inner); - } - - @Override - public int parse(final ByteBuffer srcBuf, int frameOffset, Message frameObj, final Message dstObj, List - 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 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(); - } - -} diff --git a/src/org/gnunet/construct/parsers/Parser.java b/src/org/gnunet/construct/parsers/Parser.java deleted file mode 100644 index 3eb02a6..0000000 --- a/src/org/gnunet/construct/parsers/Parser.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - 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 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 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(); -} diff --git a/src/org/gnunet/construct/parsers/SequenceParser.java b/src/org/gnunet/construct/parsers/SequenceParser.java deleted file mode 100644 index 4128e1b..0000000 --- a/src/org/gnunet/construct/parsers/SequenceParser.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - 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 childParsers = new LinkedList(); - private List 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 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 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 frameSizePath) { - this.myFrameSizePath = frameSizePath; - } -} diff --git a/src/org/gnunet/construct/parsers/StringParser.java b/src/org/gnunet/construct/parsers/StringParser.java deleted file mode 100644 index 8df171e..0000000 --- a/src/org/gnunet/construct/parsers/StringParser.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - 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 - 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 frameSizePath, Message frameObj) { - if (frameSizePath != null) { - ReflectUtil.justSetInt(frameObj, frameSizePath, frameSize); - } - } - - @Override - public int getStaticSize() { - return optional ? 0 : 1; - } - -} diff --git a/src/org/gnunet/construct/parsers/UnionParser.java b/src/org/gnunet/construct/parsers/UnionParser.java deleted file mode 100644 index e9fcc92..0000000 --- a/src/org/gnunet/construct/parsers/UnionParser.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - 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 -@SuppressWarnings("unchecked") -public class UnionParser implements Parser { - - private final Field targetField; - - private final List unionTagPath; - private final ReflectUtil.NumField unionTagField; - private final Class unionType; - - boolean optional; - - public UnionParser(boolean optional, Class unionType, - List 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 - 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) ReflectUtil.justGet(m, targetField).getClass()); - } - - @Override - public void patch(Message m, int frameSize, List 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; - } -} diff --git a/src/org/gnunet/construct/parsers/VariableSizeArrayParser.java b/src/org/gnunet/construct/parsers/VariableSizeArrayParser.java deleted file mode 100644 index fd55925..0000000 --- a/src/org/gnunet/construct/parsers/VariableSizeArrayParser.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - 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 - frameSizePath) { - final int elemNumber = (int) sizeField.get(dstObj); - - @SuppressWarnings("unchecked") - final Class arrayElementType = (Class) 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 frameSizePath, Message frameObj) { - int size = Array.getLength(ReflectUtil.justGet(m, targetField)); - sizeField.set(m, size); - } - - @Override - public int getStaticSize() { - return 0; - } - -} diff --git a/src/org/gnunet/construct/parsers/VariableSizeIntegerArrayParser.java b/src/org/gnunet/construct/parsers/VariableSizeIntegerArrayParser.java deleted file mode 100644 index b3f134d..0000000 --- a/src/org/gnunet/construct/parsers/VariableSizeIntegerArrayParser.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - 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 - frameSizePath) { - final int elemNumber = (int) sizeField.get(dstObj); - - - @SuppressWarnings("unchecked") - final Class arrayElementType = (Class) 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 frameSizePath, Message frameObj) { - int size = Array.getLength(ReflectUtil.justGet(m, targetField)); - sizeField.set(m, size); - } - - @Override - public int getStaticSize() { - return 0; - } - -} diff --git a/src/org/gnunet/construct/parsers/package-info.java b/src/org/gnunet/construct/parsers/package-info.java deleted file mode 100644 index 5da3a94..0000000 --- a/src/org/gnunet/construct/parsers/package-info.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - 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; diff --git a/src/org/gnunet/core/ConnectHandler.java b/src/org/gnunet/core/ConnectHandler.java deleted file mode 100644 index a36d798..0000000 --- a/src/org/gnunet/core/ConnectHandler.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - 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); -} diff --git a/src/org/gnunet/core/ConnectNotifyMessage.java b/src/org/gnunet/core/ConnectNotifyMessage.java deleted file mode 100644 index 4eafe02..0000000 --- a/src/org/gnunet/core/ConnectNotifyMessage.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - 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. - */ -@UnionCase(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; - -} diff --git a/src/org/gnunet/core/Core.java b/src/org/gnunet/core/Core.java deleted file mode 100644 index 8fffe08..0000000 --- a/src/org/gnunet/core/Core.java +++ /dev/null @@ -1,379 +0,0 @@ -/* - 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.Construct; -import org.gnunet.construct.MessageLoader; -import org.gnunet.requests.Request; -import org.gnunet.requests.RequestQueue; -import org.gnunet.util.*; -import org.grothoff.Runabout; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.HashMap; -import java.util.Map; - - -/** - * API for the gnunet core service. - *

- * Sends messages to connected peers. - */ -public class Core { - private static final Logger logger = LoggerFactory - .getLogger(Core.class); - - private final Client client; - - private final RequestQueue requestQueue; - - /* - * set to null once connected for the first time - */ - private InitCallback initCallback; - - /* - * Callbacks for traffic notifications. null if not used. - */ - private HeaderNotify notifyOutboundHeaders; - private HeaderNotify notifyInboundHeaders; - private MessageNotify notifyOutboundMessages; - private MessageNotify notifyInboundMessages; - - - /* - * Callbacks for connect/disconnect events - */ - private ConnectHandler connectHandler; - private DisconnectHandler disconnectHandler; - - - // 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; - - - /** - * All currently connected peers with information about them attached - */ - HashMap connectedPeers = new HashMap(10); - - - /** - * Information about the requests on connected peers. - */ - private static class ConnectedPeerInfo { - public Map requestsToPeer = new HashMap(1); - public int nextSmrId; - } - - - /** - * Request to transmit a message, sent after the corresponding NotifyTransmitRequest has been - * approved by core. - */ - private static class TransmitRequest extends Request { - public NotifyTransmitReadyRequest origin; - public GnunetMessage message; - - @Override - public AbsoluteTime getDeadline() { - return origin.getDeadline(); - } - - @Override - public void transmit(Connection.MessageSink sink) { - SendMessage sm = new SendMessage(); - sm.cork = 0; - sm.deadline = origin.getDeadline().asMessage(); - sm.peer = origin.target; - sm.priority = origin.priority; - sm.payloadMessage = message; - - sink.send(sm); - } - - @Override - public void onCancel(boolean alreadyTransmitted) { - throw new AssertionError("TransmitRequest cannot be canceled"); - } - } - - /** - * Sent after we get a SendMessageReady - */ - private static class NotifyTransmitReadyRequest extends Request { - public int size; - public int priority; - public PeerIdentity target; - public MessageTransmitter transmitter; - public int smrId; - public Cancelable transmitRequestCancel; - - - @Override - public void transmit(Connection.MessageSink sink) { - SendMessageRequest smr = new SendMessageRequest(); - smr.queueSize = 0; - smr.priority = priority; - smr.deadline = deadline.asMessage(); - smr.smrId = smrId; - smr.peer = target; - - sink.send(smr); - } - - @Override - public void onCancel(boolean alreadyTransmitted) { - // only thing we have to do is cancel the following transmitRequest, if any! - if (transmitRequestCancel != null) { - transmitRequestCancel.cancel(); - } - } - } - - private class InitRequest extends Request { - @Override - public AbsoluteTime getDeadline() { - return AbsoluteTime.FOREVER; - } - - @Override - public void transmit(Connection.MessageSink sink) { - InitMessage initMessage = new InitMessage(); - - initMessage.interested = interested; - initMessage.options = 0; - - for (int i : interested) { - logger.info("we are interested in " + i); - } - - sink.send(initMessage); - } - - @Override - public void onCancel(boolean alreadyTransmitted) { - throw new AssertionError("init request can't be canceled"); - } - - @Override - public boolean onReconnect() { - // keep the init message on reconnect. - return true; - } - } - - public class CoreReceiver extends RunaboutMessageReceiver { - public void visit(InitReplyMessage m) { - PeerIdentity myIdentity = m.myIdentity; - connectedPeers.put(myIdentity, new ConnectedPeerInfo()); - - 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) { - ConnectedPeerInfo cpi = connectedPeers.get(m.peer); - NotifyTransmitReadyRequest req = cpi.requestsToPeer.get(m.smrId); - - final TransmitRequest transmitRequest = new TransmitRequest(); - transmitRequest.origin = req; - - - 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"); - } - transmitRequest.message = GnunetMessage.fromBody(m); - sent = true; - } - }); - - req.transmitRequestCancel = requestQueue.add(transmitRequest); - } - - @Override - public void visitDefault(Object o) { - logger.warn("received unexpected message from core: {}", o.getClass()); - } - - @Override - public void handleError() { - if (disconnectHandler != null) { - for (Map.Entry e : connectedPeers.entrySet()) { - disconnectHandler.onDisconnect(e.getKey()); - } - } - connectedPeers.clear(); - } - } - - public Core(Configuration cfg) { - client = new Client("core", cfg); - requestQueue = new RequestQueue(client, new CoreReceiver()); - } - - public void init(InitCallback initCallback) { - this.initCallback = initCallback; - requestQueue.sendNext(new InitRequest()); - } - - /** - * 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) { - NotifyTransmitReadyRequest notifyRequest = new NotifyTransmitReadyRequest(); - notifyRequest.priority = priority; - notifyRequest.size = size; - notifyRequest.target = target; - notifyRequest.transmitter = transmitter; - notifyRequest.setDeadline(maxdelay.toAbsolute()); - - ConnectedPeerInfo cpi = connectedPeers.get(target); - if (cpi == null) { - throw new AssertionError("notifyTransmitReady called for unconnected peer"); - } - - notifyRequest.smrId = cpi.nextSmrId; - cpi.nextSmrId++; - - cpi.requestsToPeer.put(notifyRequest.smrId, notifyRequest); - - return requestQueue.add(notifyRequest); - } - - - 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. - */ - 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() { - requestQueue.destroy(); - client.disconnect(); - } -} diff --git a/src/org/gnunet/core/DisconnectHandler.java b/src/org/gnunet/core/DisconnectHandler.java deleted file mode 100644 index c7ca407..0000000 --- a/src/org/gnunet/core/DisconnectHandler.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - 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); -} diff --git a/src/org/gnunet/core/DisconnectNotifyMessage.java b/src/org/gnunet/core/DisconnectNotifyMessage.java deleted file mode 100644 index e4c3209..0000000 --- a/src/org/gnunet/core/DisconnectNotifyMessage.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - 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. - */ -@UnionCase(68) -public class DisconnectNotifyMessage implements GnunetMessage.Body { - /** - * Always zero. - */ - @UInt32 - public int reserved; - - /** - * Identity of the connecting peer. - */ - @NestedMessage - public PeerIdentity peer; -} diff --git a/src/org/gnunet/core/HeaderNotify.java b/src/org/gnunet/core/HeaderNotify.java deleted file mode 100644 index 4f536e3..0000000 --- a/src/org/gnunet/core/HeaderNotify.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - 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); -} diff --git a/src/org/gnunet/core/InitCallback.java b/src/org/gnunet/core/InitCallback.java deleted file mode 100644 index 889f8cf..0000000 --- a/src/org/gnunet/core/InitCallback.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - 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); -} diff --git a/src/org/gnunet/core/InitMessage.java b/src/org/gnunet/core/InitMessage.java deleted file mode 100644 index 5546088..0000000 --- a/src/org/gnunet/core/InitMessage.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - 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; - - -@UnionCase(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; -} diff --git a/src/org/gnunet/core/InitReplyMessage.java b/src/org/gnunet/core/InitReplyMessage.java deleted file mode 100644 index 02e8eef..0000000 --- a/src/org/gnunet/core/InitReplyMessage.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - 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; - - -@UnionCase(65) -public class InitReplyMessage implements GnunetMessage.Body { - @UInt32 - public int reserved = 0; - /** - * pubkey of the local peer - */ - @NestedMessage - public PeerIdentity myIdentity; -} diff --git a/src/org/gnunet/core/MessageNotify.java b/src/org/gnunet/core/MessageNotify.java deleted file mode 100644 index b14ce29..0000000 --- a/src/org/gnunet/core/MessageNotify.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - 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); -} diff --git a/src/org/gnunet/core/NotifyInboundTrafficMessage.java b/src/org/gnunet/core/NotifyInboundTrafficMessage.java deleted file mode 100644 index 2bdd428..0000000 --- a/src/org/gnunet/core/NotifyInboundTrafficMessage.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - 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; - - -@UnionCase(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; -} diff --git a/src/org/gnunet/core/NotifyOutboundTrafficMessage.java b/src/org/gnunet/core/NotifyOutboundTrafficMessage.java deleted file mode 100644 index 900f8be..0000000 --- a/src/org/gnunet/core/NotifyOutboundTrafficMessage.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - 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; - - -@UnionCase(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; - -} diff --git a/src/org/gnunet/core/SendMessage.java b/src/org/gnunet/core/SendMessage.java deleted file mode 100644 index e4c6215..0000000 --- a/src/org/gnunet/core/SendMessage.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - 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). - */ -@UnionCase(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; - -} diff --git a/src/org/gnunet/core/SendMessageReady.java b/src/org/gnunet/core/SendMessageReady.java deleted file mode 100644 index aa5bf44..0000000 --- a/src/org/gnunet/core/SendMessageReady.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - 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). - */ -@UnionCase(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; -} diff --git a/src/org/gnunet/core/SendMessageRequest.java b/src/org/gnunet/core/SendMessageRequest.java deleted file mode 100644 index 17087d3..0000000 --- a/src/org/gnunet/core/SendMessageRequest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - 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. - */ -@UnionCase(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 long queueSize; - - /** - * How large is the message? - */ - @UInt16 - public int size; - - /** - * Counter for this peer to match SMRs to replies. - */ - @UInt16 - public int smrId; -} diff --git a/src/org/gnunet/core/package-info.java b/src/org/gnunet/core/package-info.java deleted file mode 100644 index 64e5d59..0000000 --- a/src/org/gnunet/core/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - 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; diff --git a/src/org/gnunet/dht/BlockType.java b/src/org/gnunet/dht/BlockType.java deleted file mode 100644 index cf00d38..0000000 --- a/src/org/gnunet/dht/BlockType.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - 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; - } -} diff --git a/src/org/gnunet/dht/ClientGetMessage.java b/src/org/gnunet/dht/ClientGetMessage.java deleted file mode 100644 index cd317fb..0000000 --- a/src/org/gnunet/dht/ClientGetMessage.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - 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. -*/ -@UnionCase(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; -} diff --git a/src/org/gnunet/dht/ClientGetStopMessage.java b/src/org/gnunet/dht/ClientGetStopMessage.java deleted file mode 100644 index 4cdee12..0000000 --- a/src/org/gnunet/dht/ClientGetStopMessage.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - 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. -*/ -@UnionCase(144) -public class ClientGetStopMessage implements GnunetMessage.Body { - @UInt32 - public int reserved = 0; - @UInt64 - public long unique_id; - @NestedMessage - public HashCode key; -} diff --git a/src/org/gnunet/dht/ClientPutConfirmationMessage.java b/src/org/gnunet/dht/ClientPutConfirmationMessage.java deleted file mode 100644 index 45bbe60..0000000 --- a/src/org/gnunet/dht/ClientPutConfirmationMessage.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - 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; - - -@UnionCase(155) -public class ClientPutConfirmationMessage implements GnunetMessage.Body { - @UInt32 - public int reserved; - /** - * UID used to identify request with the response - */ - @UInt64 - public long uid; -} diff --git a/src/org/gnunet/dht/ClientPutMessage.java b/src/org/gnunet/dht/ClientPutMessage.java deleted file mode 100644 index 4b63e92..0000000 --- a/src/org/gnunet/dht/ClientPutMessage.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - 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; - - -@UnionCase(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; -} diff --git a/src/org/gnunet/dht/ClientResultMessage.java b/src/org/gnunet/dht/ClientResultMessage.java deleted file mode 100644 index fab614f..0000000 --- a/src/org/gnunet/dht/ClientResultMessage.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - 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. -*/ -@UnionCase(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; -} diff --git a/src/org/gnunet/dht/DistributedHashTable.java b/src/org/gnunet/dht/DistributedHashTable.java deleted file mode 100644 index 3f42492..0000000 --- a/src/org/gnunet/dht/DistributedHashTable.java +++ /dev/null @@ -1,469 +0,0 @@ -/* - 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 com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import org.gnunet.requests.Request; -import org.gnunet.requests.RequestQueue; -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. - *

- * Stores data under a key, distributed across the network. - *

- */ -public class DistributedHashTable { - private static final Logger logger = LoggerFactory - .getLogger(DistributedHashTable.class); - - - private Client client; - - private RequestQueue requestQueue; - - /** - * next UID used on get/monitor requests, incremented after each use. - */ - private long nextUID = 1; - - private Map putRequests = Maps.newTreeMap(); - private Map getRequests = Maps.newTreeMap(); - - /** - * monitor requests are kind of special, responses from the dht don't include the UID! - */ - private List monitorRequests = Lists.newLinkedList(); - - - /** - * Create a connection with the DHT service. - * - * @param cfg the configuration to use - */ - public DistributedHashTable(Configuration cfg) { - client = new Client("dht", cfg); - requestQueue = new RequestQueue(client, new DHTMessageReceiver()); - } - - private class PutRequest extends 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++; - putRequests.put(uid, this); - } - - @Override - public void transmit(Connection.MessageSink sink) { - final ClientPutMessage cpm = new ClientPutMessage(); - cpm.data = data; - cpm.hash = key; - cpm.desiredReplicationLevel = replicationLevel; - cpm.expiration = expiration.asMessage(); - cpm.type = type; - cpm.uid = uid; - sink.send(cpm); - } - - public boolean onDestroy() { - return true; // keep! - } - } - - - private class GetRequest extends 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++; - getRequests.put(uid, this); - } - - @Override - public void transmit(Connection.MessageSink sink) { - ClientGetMessage gm = new ClientGetMessage(); - gm.desiredReplicationLevel = replication; - gm.type = type; - gm.xquery = xquery == null ? new byte[0] : xquery; - gm.key = key; - gm.uniqueId = uid; - - sink.send(gm); - } - } - - private class MonitorRequest extends Request { - public int blockType; - public HashCode key; - public MonitorGetHandler getHandler; - public MonitorGetResponseHandler getResponseHandler; - public MonitorPutHandler putHandler; - - @Override - public AbsoluteTime getDeadline() { - return AbsoluteTime.FOREVER; - } - - public MonitorRequest() { - monitorRequests.add(this); - } - - @Override - public void transmit(Connection.MessageSink sink) { - 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; - - sink.send(mss); - } - - @Override - public void onCancel(boolean alreadyTransmitted) { - if (alreadyTransmitted) { - MonitorRequest cancelRequest = new MonitorRequest(); - cancelRequest.getHandler = null; - cancelRequest.getResponseHandler = null; - cancelRequest.putHandler = null; - requestQueue.add(new MonitorRequest()); - } - } - } - - public class DHTMessageReceiver extends RunaboutMessageReceiver { - public void visit(ClientPutConfirmationMessage pcm) { - PutRequest thePutRequest = putRequests.get(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.get(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) { - 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) { - 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) { - 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() { - requestQueue.reconnect(); - } - } - - /** - * 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 routeOptions, - int type, AbsoluteTime expiration, - RelativeTime timeout, final Continuation cont) { - PutRequest pr = new PutRequest(); - pr.key = key; - pr.data = data; - pr.replicationLevel = replicationLevel; - pr.setDeadline(timeout.toAbsolute()); - pr.expiration = expiration; - pr.type = type; - pr.cont = cont; - - requestQueue.add(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 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; - getRequest.setDeadline(timeout.toAbsolute()); - - return requestQueue.add(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 requestQueue.add(monitorRequest); - - } - - - /** - * Destroy the connection to the service. - */ - public void destroy() { - // there's nothing to sync, just destroy! - requestQueue.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 - getPath, List putPath, BlockType type, byte[] data) { - System.out.println("got result:"); - System.out.println(new String(data, Charsets.UTF_8)); - } - }); - } - } - }.start(); - } -} diff --git a/src/org/gnunet/dht/MonitorGetHandler.java b/src/org/gnunet/dht/MonitorGetHandler.java deleted file mode 100644 index c7dad7c..0000000 --- a/src/org/gnunet/dht/MonitorGetHandler.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - 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); -} diff --git a/src/org/gnunet/dht/MonitorGetMessage.java b/src/org/gnunet/dht/MonitorGetMessage.java deleted file mode 100644 index e96ec96..0000000 --- a/src/org/gnunet/dht/MonitorGetMessage.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - 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. - */ -@UnionCase(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; -} diff --git a/src/org/gnunet/dht/MonitorGetRespMessage.java b/src/org/gnunet/dht/MonitorGetRespMessage.java deleted file mode 100644 index 3bf145b..0000000 --- a/src/org/gnunet/dht/MonitorGetRespMessage.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - 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. - */ -@UnionCase(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; -} diff --git a/src/org/gnunet/dht/MonitorGetResponseHandler.java b/src/org/gnunet/dht/MonitorGetResponseHandler.java deleted file mode 100644 index ff03cce..0000000 --- a/src/org/gnunet/dht/MonitorGetResponseHandler.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - 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); -} diff --git a/src/org/gnunet/dht/MonitorPutHandler.java b/src/org/gnunet/dht/MonitorPutHandler.java deleted file mode 100644 index 0abb79b..0000000 --- a/src/org/gnunet/dht/MonitorPutHandler.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - 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); -} diff --git a/src/org/gnunet/dht/MonitorPutMessage.java b/src/org/gnunet/dht/MonitorPutMessage.java deleted file mode 100644 index 103c05b..0000000 --- a/src/org/gnunet/dht/MonitorPutMessage.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - 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. - */ -@UnionCase(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; -} diff --git a/src/org/gnunet/dht/MonitorStartStop.java b/src/org/gnunet/dht/MonitorStartStop.java deleted file mode 100644 index b3f3268..0000000 --- a/src/org/gnunet/dht/MonitorStartStop.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - 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. - */ -@UnionCase(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; -} diff --git a/src/org/gnunet/dht/ResultCallback.java b/src/org/gnunet/dht/ResultCallback.java deleted file mode 100644 index fa5c7ef..0000000 --- a/src/org/gnunet/dht/ResultCallback.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - 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 getPath, List putPath, - BlockType type, byte[] data); -} diff --git a/src/org/gnunet/dht/RouteOption.java b/src/org/gnunet/dht/RouteOption.java deleted file mode 100644 index b74b528..0000000 --- a/src/org/gnunet/dht/RouteOption.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - 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; - } -} diff --git a/src/org/gnunet/dht/package-info.java b/src/org/gnunet/dht/package-info.java deleted file mode 100644 index 3d8c6ed..0000000 --- a/src/org/gnunet/dht/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - 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; diff --git a/src/org/gnunet/hello/HelloMessage.java b/src/org/gnunet/hello/HelloMessage.java deleted file mode 100644 index 0d90912..0000000 --- a/src/org/gnunet/hello/HelloMessage.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - 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; -} diff --git a/src/org/gnunet/hello/package-info.java b/src/org/gnunet/hello/package-info.java deleted file mode 100644 index 78a5193..0000000 --- a/src/org/gnunet/hello/package-info.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - 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; diff --git a/src/org/gnunet/mesh/ClientConnectMessage.java b/src/org/gnunet/mesh/ClientConnectMessage.java deleted file mode 100644 index 1a56ebb..0000000 --- a/src/org/gnunet/mesh/ClientConnectMessage.java +++ /dev/null @@ -1,17 +0,0 @@ -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 - */ -@UnionCase(272) -public class ClientConnectMessage implements GnunetMessage.Body { - @IntegerFill(signed = false, bitSize = 32) - public int[] apps_list; -} diff --git a/src/org/gnunet/mesh/ConnectHandler.java b/src/org/gnunet/mesh/ConnectHandler.java deleted file mode 100644 index 021e8f0..0000000 --- a/src/org/gnunet/mesh/ConnectHandler.java +++ /dev/null @@ -1,13 +0,0 @@ -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); -} diff --git a/src/org/gnunet/mesh/DataMessage.java b/src/org/gnunet/mesh/DataMessage.java deleted file mode 100644 index 92546c8..0000000 --- a/src/org/gnunet/mesh/DataMessage.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.gnunet.mesh; - -import org.gnunet.construct.*; -import org.gnunet.util.GnunetMessage; -import org.gnunet.util.PeerIdentity; - -/** - * ... - * - * @author Florian Dold - */ -@UnionCase(260) -public class DataMessage implements GnunetMessage.Body { - @UInt32 - public int tid; - @FillWith - @UInt8 - public byte[] payload; -} diff --git a/src/org/gnunet/mesh/DisconnectHandler.java b/src/org/gnunet/mesh/DisconnectHandler.java deleted file mode 100644 index 8fd6428..0000000 --- a/src/org/gnunet/mesh/DisconnectHandler.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.gnunet.mesh; - -import org.gnunet.util.PeerIdentity; - -/** - * ... - * - * @author Florian Dold - */ -public interface DisconnectHandler { - void onDisconnect(PeerIdentity peer); -} diff --git a/src/org/gnunet/mesh/InboundTunnelHandler.java b/src/org/gnunet/mesh/InboundTunnelHandler.java deleted file mode 100644 index ebcf225..0000000 --- a/src/org/gnunet/mesh/InboundTunnelHandler.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.gnunet.mesh; - -import org.gnunet.util.PeerIdentity; - -/** - * ... - * - * @author Florian Dold - */ -public interface InboundTunnelHandler { - void onInboundTunnel(Mesh.Tunnel tunnel, PeerIdentity initiator); -} diff --git a/src/org/gnunet/mesh/LocalAckMessage.java b/src/org/gnunet/mesh/LocalAckMessage.java deleted file mode 100644 index 6a09411..0000000 --- a/src/org/gnunet/mesh/LocalAckMessage.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.gnunet.mesh; - -import org.gnunet.construct.UInt32; -import org.gnunet.construct.UnionCase; -import org.gnunet.util.GnunetMessage; - -/** - * ... - * - * @author Florian Dold - */ -@UnionCase(286) -public class LocalAckMessage implements GnunetMessage.Body { - @UInt32 - public int tid; - @UInt32 - public int maxPid; -} diff --git a/src/org/gnunet/mesh/Mesh.java b/src/org/gnunet/mesh/Mesh.java deleted file mode 100644 index b272b0b..0000000 --- a/src/org/gnunet/mesh/Mesh.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - 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.ClientMessageQueue; -import org.gnunet.mq.Envelope; -import org.gnunet.mq.MessageQueue; -import org.gnunet.requests.Request; -import org.gnunet.requests.RequestQueue; -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; - - /** - * Message queue for the client. - */ - private final ClientMessageQueue client_mq; - - /** - * 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 tunnelMap = new HashMap<>(); - - /** - * Counter for generating fresh tunnel ID's - * when creating new tunnels. - */ - int next_tid = 1; - - /** - * A tunnel to a remote peer. - * @param type of context data for the tunnel - */ - public class Tunnel 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 = 0; - - /** - * 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_mq.send(tcm); - } - - /** - * Private tunnel constructor, for creating tunnel objects for - * incoming tunnels. - * - * @param peer - * @param tunnelId - * @param port - * @param nobuffer - * @param reliable - */ - private 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_mq.send(am); - receive_done_expected = false; - } - - public void destroy() { - TunnelDestroyMessage m = new TunnelDestroyMessage(); - m.tunnel_id = tunnelId; - client_mq.send(m); - } - - @Override - protected void sendImmediate(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); - client_mq.send(mesh_ev); - ack_count -= 1; - } - - 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_mq.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_mq = new ClientMessageQueue(client, new MeshMessageReceiver()); - ClientConnectMessage ccm = new ClientConnectMessage(); - ccm.apps_list = ports; - client_mq.send(ccm); - } - - /** - * 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 disconnect() { - client_mq.destroy(); - client.disconnect(); - } -} diff --git a/src/org/gnunet/mesh/MeshRunabout.java b/src/org/gnunet/mesh/MeshRunabout.java deleted file mode 100644 index ea4248c..0000000 --- a/src/org/gnunet/mesh/MeshRunabout.java +++ /dev/null @@ -1,19 +0,0 @@ -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; - } -} diff --git a/src/org/gnunet/mesh/TunnelCreateMessage.java b/src/org/gnunet/mesh/TunnelCreateMessage.java deleted file mode 100644 index eaa4d6c..0000000 --- a/src/org/gnunet/mesh/TunnelCreateMessage.java +++ /dev/null @@ -1,27 +0,0 @@ -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 - */ -@UnionCase(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; -} diff --git a/src/org/gnunet/mesh/TunnelDestroyMessage.java b/src/org/gnunet/mesh/TunnelDestroyMessage.java deleted file mode 100644 index bce60bb..0000000 --- a/src/org/gnunet/mesh/TunnelDestroyMessage.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.gnunet.mesh; - -import org.gnunet.construct.UInt32; -import org.gnunet.construct.UnionCase; -import org.gnunet.util.GnunetMessage; - -/** - * ... - * - * @author Florian Dold - */ -@UnionCase(274) -public class TunnelDestroyMessage implements GnunetMessage.Body { - @UInt32 - public int tunnel_id; -} diff --git a/src/org/gnunet/mesh/TunnelEndHandler.java b/src/org/gnunet/mesh/TunnelEndHandler.java deleted file mode 100644 index e56fdd4..0000000 --- a/src/org/gnunet/mesh/TunnelEndHandler.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.gnunet.mesh; - -/** - * ... - * - * @author Florian Dold - */ -public interface TunnelEndHandler { - void onTunnelEnd(Mesh.Tunnel tunnel); -} diff --git a/src/org/gnunet/mesh/TunnelNotificationMessage.java b/src/org/gnunet/mesh/TunnelNotificationMessage.java deleted file mode 100644 index 8846088..0000000 --- a/src/org/gnunet/mesh/TunnelNotificationMessage.java +++ /dev/null @@ -1,22 +0,0 @@ -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; -} diff --git a/src/org/gnunet/mesh/package-info.java b/src/org/gnunet/mesh/package-info.java deleted file mode 100644 index fb5a8a4..0000000 --- a/src/org/gnunet/mesh/package-info.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - 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; diff --git a/src/org/gnunet/mq/ClientMessageQueue.java b/src/org/gnunet/mq/ClientMessageQueue.java deleted file mode 100644 index b3fccc7..0000000 --- a/src/org/gnunet/mq/ClientMessageQueue.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.gnunet.mq; - - -import org.gnunet.construct.Construct; -import org.gnunet.util.*; - -/** - * Message queue for org.util.Connection - */ -public class ClientMessageQueue extends MessageQueue { - private final Client client; - private final RunaboutMessageReceiver receiver; - - public ClientMessageQueue(Client client, RunaboutMessageReceiver receiver) { - this.client = client; - this.receiver = receiver; - } - - public ClientMessageQueue(Client client) { - this(client, null); - } - - @Override - protected void sendImmediate(final Envelope ev) { - int size = Construct.getSize(ev.message); - client.notifyTransmitReady(RelativeTime.FOREVER, false, size, new MessageTransmitter() { - @Override - public void transmit(Connection.MessageSink sink) { - sink.send(ev.message); - reportMessageSent(); - } - - @Override - public void handleError() { - // FIXME - } - }); - } - - @Override - public void destroy() { - - } -} diff --git a/src/org/gnunet/mq/Envelope.java b/src/org/gnunet/mq/Envelope.java deleted file mode 100644 index 09c0c2c..0000000 --- a/src/org/gnunet/mq/Envelope.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.gnunet.mq; - -import org.gnunet.util.GnunetMessage; - -/** - * Container for a message to be sent by a message queue. - */ -public class Envelope { - 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() { - // TODO - } - - /* pkg-private */ void invokeSentNotification() { - if (null != notify_sent_handler) - notify_sent_handler.onSent(); - } -} diff --git a/src/org/gnunet/mq/MessageQueue.java b/src/org/gnunet/mq/MessageQueue.java deleted file mode 100644 index de08edf..0000000 --- a/src/org/gnunet/mq/MessageQueue.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.gnunet.mq; - - -import org.gnunet.util.GnunetMessage; - -import java.util.LinkedList; - -/** - * General-purpose message queue - */ -public abstract class MessageQueue { - private LinkedList queued_envelopes = new LinkedList<>(); - protected Envelope current_envelope; - - protected abstract void sendImmediate(Envelope ev); - - public void send(GnunetMessage.Body body) { - send(new Envelope(body)); - } - - public void send(Envelope ev) { - if (null == current_envelope) { - current_envelope = ev; - sendImmediate(current_envelope); - } else { - queued_envelopes.addLast(ev); - } - } - - protected void reportMessageSent() { - if (null == current_envelope) - throw new AssertionError(); - current_envelope.invokeSentNotification(); - if (queued_envelopes.isEmpty()) - return; - current_envelope = queued_envelopes.pop(); - sendImmediate(current_envelope); - } - - public abstract void destroy(); -} diff --git a/src/org/gnunet/mq/NotifySentHandler.java b/src/org/gnunet/mq/NotifySentHandler.java deleted file mode 100644 index 7ec13b2..0000000 --- a/src/org/gnunet/mq/NotifySentHandler.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.gnunet.mq; - - -public interface NotifySentHandler { - void onSent(); -} diff --git a/src/org/gnunet/nse/NetworkSizeEstimation.java b/src/org/gnunet/nse/NetworkSizeEstimation.java deleted file mode 100644 index 366ab80..0000000 --- a/src/org/gnunet/nse/NetworkSizeEstimation.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - 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.construct.ProtocolViolationException; -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 subscribers = new HashSet(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.receive(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.receive(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(); - } -} diff --git a/src/org/gnunet/nse/StartMessage.java b/src/org/gnunet/nse/StartMessage.java deleted file mode 100644 index 9f5b79e..0000000 --- a/src/org/gnunet/nse/StartMessage.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.gnunet.nse; - -import org.gnunet.construct.UnionCase; -import org.gnunet.util.GnunetMessage; - -/** -* ... -* -* @author Florian Dold -*/ -@UnionCase(321) -public class StartMessage implements GnunetMessage.Body {} diff --git a/src/org/gnunet/nse/UpdateMessage.java b/src/org/gnunet/nse/UpdateMessage.java deleted file mode 100644 index 5c64a54..0000000 --- a/src/org/gnunet/nse/UpdateMessage.java +++ /dev/null @@ -1,26 +0,0 @@ -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 -*/ -@UnionCase(323) -public class UpdateMessage implements GnunetMessage.Body { - @UInt32 - public int reserved; - - @NestedMessage - public AbsoluteTimeMessage timestamp; - - @DoubleValue - public double sizeEstimate; - - @DoubleValue - public double stdDeviation; -} diff --git a/src/org/gnunet/nse/package-info.java b/src/org/gnunet/nse/package-info.java deleted file mode 100644 index 3bbc064..0000000 --- a/src/org/gnunet/nse/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - 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; diff --git a/src/org/gnunet/peerinfo/InfoEnd.java b/src/org/gnunet/peerinfo/InfoEnd.java deleted file mode 100644 index b59e194..0000000 --- a/src/org/gnunet/peerinfo/InfoEnd.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.gnunet.peerinfo; - -import org.gnunet.construct.UnionCase; -import org.gnunet.util.GnunetMessage; - -/** - * ... - * - * @author Florian Dold - */ -@UnionCase(333) -public class InfoEnd implements GnunetMessage.Body { - -} diff --git a/src/org/gnunet/peerinfo/InfoMessage.java b/src/org/gnunet/peerinfo/InfoMessage.java deleted file mode 100644 index d8d7daa..0000000 --- a/src/org/gnunet/peerinfo/InfoMessage.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - 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 - */ -@UnionCase(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; -} diff --git a/src/org/gnunet/peerinfo/ListAllPeersMessage.java b/src/org/gnunet/peerinfo/ListAllPeersMessage.java deleted file mode 100644 index e384c93..0000000 --- a/src/org/gnunet/peerinfo/ListAllPeersMessage.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - 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 - */ -@UnionCase(331) -public class ListAllPeersMessage implements GnunetMessage.Body { - @UInt32 - public int include_friend_only; -} diff --git a/src/org/gnunet/peerinfo/ListPeerMessage.java b/src/org/gnunet/peerinfo/ListPeerMessage.java deleted file mode 100644 index 56e6b5d..0000000 --- a/src/org/gnunet/peerinfo/ListPeerMessage.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - 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; -} diff --git a/src/org/gnunet/peerinfo/PeerInfo.java b/src/org/gnunet/peerinfo/PeerInfo.java deleted file mode 100644 index 9d92763..0000000 --- a/src/org/gnunet/peerinfo/PeerInfo.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - 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.requests.Request; -import org.gnunet.requests.RequestQueue; -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); - - private final RequestQueue requests; - private PeerIterateRequest activeRequest; - - private class PeerIterateRequest extends Request { - public PeerIdentity peer; - public PeerProcessor peerProcessor; - @Override - public void transmit(Connection.MessageSink sink) { - if (peer == null) { - ListAllPeersMessage lapm = new ListAllPeersMessage(); - sink.send(lapm); - } else { - ListPeerMessage lpm = new ListPeerMessage(); - lpm.peer = peer; - sink.send(lpm); - } - activeRequest = this; - requests.clog(); - } - } - - private class PeerInfoMessageReceiver extends RunaboutMessageReceiver { - public void visit(InfoEnd infoEnd) { - activeRequest.peerProcessor.onEnd(); - activeRequest = null; - requests.unclog(); - } - public void visit(InfoMessage infoMessage) { - if (activeRequest == null) { - logger.warn("PEERINFO sent info message, but no request is active"); - } - activeRequest.peerProcessor.onPeer(infoMessage.peerIdentity, infoMessage.hello); - } - - @Override - public void handleError() { - } - } - - - public PeerInfo(Configuration cfg) { - Client client = new Client("peerinfo", cfg); - requests = new RequestQueue(client, new PeerInfoMessageReceiver()); - } - - public Cancelable iterate(RelativeTime timeout, PeerProcessor processor) { - return iterate(timeout, null, processor); - } - - public Cancelable iterate(RelativeTime timeout, PeerIdentity peer, PeerProcessor processor) { - PeerIterateRequest peerIterateRequest = new PeerIterateRequest(); - peerIterateRequest.peer = peer; - peerIterateRequest.peerProcessor = processor; - peerIterateRequest.setDeadline(timeout.toAbsolute()); - return requests.add(peerIterateRequest); - } - - public void disconnect() { - requests.destroy(); - } - - public static void main(String... args) { - new Program(args) { - - @Override - public void run() { - final PeerInfo peerInfo = new PeerInfo(getConfiguration()); - peerInfo.iterate(RelativeTime.FOREVER, 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(); - - } -} diff --git a/src/org/gnunet/peerinfo/PeerProcessor.java b/src/org/gnunet/peerinfo/PeerProcessor.java deleted file mode 100644 index b096c37..0000000 --- a/src/org/gnunet/peerinfo/PeerProcessor.java +++ /dev/null @@ -1,12 +0,0 @@ -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(); -} diff --git a/src/org/gnunet/peerinfo/RsaPublicKeyBinaryEncoded.java b/src/org/gnunet/peerinfo/RsaPublicKeyBinaryEncoded.java deleted file mode 100644 index 86985f3..0000000 --- a/src/org/gnunet/peerinfo/RsaPublicKeyBinaryEncoded.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - 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; -} diff --git a/src/org/gnunet/peerinfo/package-info.java b/src/org/gnunet/peerinfo/package-info.java deleted file mode 100644 index 19cebdb..0000000 --- a/src/org/gnunet/peerinfo/package-info.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - 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; diff --git a/src/org/gnunet/requests/FixedMessageRequest.java b/src/org/gnunet/requests/FixedMessageRequest.java deleted file mode 100644 index 1420e28..0000000 --- a/src/org/gnunet/requests/FixedMessageRequest.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.gnunet.requests; - -import org.gnunet.util.Connection; -import org.gnunet.util.GnunetMessage; - -/** - * A request that sends a message, pre-determined at construction of the FixedMessageRequest. - * - * @author Florian Dold - */ -public class FixedMessageRequest extends Request { - private final GnunetMessage.Body msg; - - public FixedMessageRequest(GnunetMessage.Body msg) { - this.msg = msg; - } - - final - @Override - public void transmit(Connection.MessageSink sink) { - sink.send(msg); - } -} diff --git a/src/org/gnunet/requests/Request.java b/src/org/gnunet/requests/Request.java deleted file mode 100644 index 953b5e1..0000000 --- a/src/org/gnunet/requests/Request.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.gnunet.requests; - -import org.gnunet.util.AbsoluteTime; -import org.gnunet.util.Connection; -import org.gnunet.util.RelativeTime; - -/** - * Abstract base class for a Request. - * - * Every request defines what happens when one of the following happens: - *

    - *
  • - * The request is canceled. There may be some cleanup necessary, depending on whether the request has already been - * sent to the service or not. - *
  • - *
  • - * On timeout. - *
  • - *
  • - * On reconnect. In particular, every Request has to decide whether it will be kept after a reconnect to the service. - *
  • - *
  • - * On destruction of the request queue. Some request may be important enough to delay the destruction until they have been sent. - *
  • - *
- * - * @author Florian Dold -*/ -public abstract class Request { - protected AbsoluteTime deadline = AbsoluteTime.FOREVER; - - /** - * Called whenever the request could not be transmitted due to timeout. - * - * @return true if the request should be queued again - */ - public boolean onTransmitTimeout() { - // per default, just drop the message on timeout! - return false; - } - - /** - * - * - * @return true if the request should be kept after the destroy request - */ - public boolean onDestroy() { - // per default, do not keep on destroy - return false; - } - - /** - * @return true if the request should be kept after the reconnect - */ - public boolean onReconnect() { - // per default, do not keep on reconnect - return false; - } - - /** - * @param alreadyTransmitted true if message has already been sent over the network - */ - public void onCancel(boolean alreadyTransmitted) { - // do nothing - } - - public void setDeadline(AbsoluteTime deadline) { - this.deadline = deadline; - } - - /** - * Called to determine after how long the request should time out. - * Per default, the deadline is FOREVER. - * - * @return the deadline for this request - */ - public AbsoluteTime getDeadline() { - return deadline; - } - - public abstract void transmit(Connection.MessageSink sink); -} diff --git a/src/org/gnunet/requests/RequestQueue.java b/src/org/gnunet/requests/RequestQueue.java deleted file mode 100644 index 6f7102d..0000000 --- a/src/org/gnunet/requests/RequestQueue.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - 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.requests; - -import org.gnunet.util.*; - -import java.util.LinkedList; - -/** - * Generic queues for Requests to be sent to the service. - */ -public class RequestQueue { - - /** - * Requests to be transmitted to the service. - */ - private final LinkedList requestsAwaitingTransmit = new LinkedList(); - - /** - * Persistent requests. Will be informed about reconnect / destroy events even - * if already transmitted. Have to be canceled manually. - */ - private final LinkedList persistentRequests = new LinkedList(); - - /** - * List of all requests from requestAwaitingTransmit and persistentRequest, containing no duplicates. - */ - private final LinkedList allRequests = new LinkedList(); - - /** - * The designated receiver for all messages. - */ - private MessageReceiver receiver; - - /** - * The active transmit request handle, if any. - */ - private Cancelable currentTransmit; - - /** - * Current receive handler. - */ - private Cancelable currentReceive; - - /** - * True if we should not send further requests until queue is unclogged. - */ - private boolean clogged = false; - - private boolean destroyed = false; - private final Client client; - - public RequestQueue(Client client, MessageReceiver receiver) { - this.client = client; - this.receiver = receiver; - } - - /** - * Handle next request. - */ - private void handleNextTransmit() { - - if (clogged) { - return; - } - - // return if we are already transmitting something - if (currentTransmit != null) { - return; - } - - final Request request = requestsAwaitingTransmit.poll(); - if (request == null) { - handleReceive(); - return; - } - - AbsoluteTime deadline = request.getDeadline(); - if (deadline == null) { - throw new AssertionError("getDeadline() must return a non-null AbsoluteTime"); - } - - currentTransmit = client.notifyTransmitReady(deadline.getRemaining(), true, 0, new MessageTransmitter() { - @Override - public void transmit(Connection.MessageSink sink) { - currentTransmit = null; - - try { - request.transmit(sink); - } finally { - handleReceive(); - handleNextTransmit(); - } - } - - @Override - public void handleError() { - throw new AssertionError("not implemented"); - } - }); - } - - /** - * Continue receiving if necessary. - */ - private void handleReceive() { - if (currentReceive != null || destroyed || !client.isConnected()) { - return; - } - currentReceive = client.receive(RelativeTime.FOREVER, new MessageReceiver() { - @Override - public void process(GnunetMessage.Body msg) { - currentReceive = null; - - try { - receiver.process(msg); - } finally { - handleNextTransmit(); - handleReceive(); - } - } - - @Override - public void handleError() { - receiver.handleError(); - } - }); - } - - /** - * Add a request to the end of the queue. - * - * @param request request to be added - * @return a handle to cancel the request - */ - public Cancelable add(final Request request) { - allRequests.add(request); - requestsAwaitingTransmit.add(request); - handleNextTransmit(); - - return new Cancelable() { - @Override - public void cancel() { - RequestQueue.this.requestsAwaitingTransmit.remove(request); - RequestQueue.this.persistentRequests.remove(request); - RequestQueue.this.allRequests.remove(request); - request.onCancel(!requestsAwaitingTransmit.contains(request)); - } - }; - } - - - /** - * Add a request so that it will get notified about reconnect/destroy events, - * even if it already has been transmitted. - */ - public Cancelable addPersistent(final Request request) { - persistentRequests.add(request); - return add(request); - } - - - /** - * Add a request to the front of the queue, this request will be sent as - * the next message (if not preempted by another sendNext). - * - * @param request request to be sent next - * @return a handle to cancel the request - */ - public Cancelable sendNext(final Request request) { - requestsAwaitingTransmit.addFirst(request); - handleNextTransmit(); - // todo: should this really return Cancelable? When do we want to cancel a request added by sendNext? - return new Cancelable() { - @Override - public void cancel() { - RequestQueue.this.requestsAwaitingTransmit.remove(request); - RequestQueue.this.persistentRequests.remove(request); - RequestQueue.this.allRequests.remove(request); - request.onCancel(!requestsAwaitingTransmit.contains(request)); - } - }; - } - - /** - * Reconnect the client and notify all pending request of the reconnect. - */ - public void reconnect() { - client.reconnect(); - currentReceive = null; - currentTransmit = null; - - final LinkedList remove = new LinkedList(); - - - for (Request r : allRequests) { - boolean keep = r.onReconnect(); - if (!keep) { - remove.add(r); - } else { - // retransmit an apparently persistent request. - if (!requestsAwaitingTransmit.contains(r)) { - requestsAwaitingTransmit.add(r); - } - } - } - requestsAwaitingTransmit.removeAll(remove); - persistentRequests.removeAll(remove); - allRequests.removeAll(remove); - - // only transmit, receive should only be called after the first transmit - handleNextTransmit(); - } - - /** - * Notify all request of the shutdown. Does not actually destroy the connection. - */ - public void shutdown() { - final LinkedList remove = new LinkedList(); - - for (Request r : allRequests) { - boolean keep = r.onDestroy(); - if (!keep) { - remove.add(r); - } else { - // retransmit an apparently persistent request. - if (!requestsAwaitingTransmit.contains(r)) { - requestsAwaitingTransmit.add(r); - } - } - } - requestsAwaitingTransmit.removeAll(remove); - persistentRequests.removeAll(remove); - allRequests.removeAll(remove); - - handleNextTransmit(); - handleReceive(); - } - - /** - * Cancel all requests and destroy the connection. - */ - public void destroy() { - destroyed = true; - allRequests.clear(); - persistentRequests.clear(); - requestsAwaitingTransmit.clear(); - if (currentTransmit != null) { - currentTransmit.cancel(); - } - if (currentReceive != null) { - currentReceive.cancel(); - } - } - - /** - * Allow no further requests to be transmitted until the queue is unclogged. - */ - public void clog() { - if (clogged) { - throw new AssertionError("double clog"); - } - clogged = true; - } - - /** - * Unclog the queue, must have been previously clogged. - */ - public void unclog() { - if (!clogged) { - throw new AssertionError("unclogg before clog"); - } - clogged = false; - handleNextTransmit(); - } -} diff --git a/src/org/gnunet/requests/package-info.java b/src/org/gnunet/requests/package-info.java deleted file mode 100644 index 892a606..0000000 --- a/src/org/gnunet/requests/package-info.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - 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; diff --git a/src/org/gnunet/statistics/GetMessage.java b/src/org/gnunet/statistics/GetMessage.java deleted file mode 100644 index eb44fbd..0000000 --- a/src/org/gnunet/statistics/GetMessage.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - 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 - * - */ -@UnionCase(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; -} diff --git a/src/org/gnunet/statistics/GetResponseEndMessage.java b/src/org/gnunet/statistics/GetResponseEndMessage.java deleted file mode 100644 index eebe16e..0000000 --- a/src/org/gnunet/statistics/GetResponseEndMessage.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - 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; - -/** - * ... -*/ -@UnionCase(171) -public class GetResponseEndMessage implements GnunetMessage.Body { - // empty -} diff --git a/src/org/gnunet/statistics/GetResponseMessage.java b/src/org/gnunet/statistics/GetResponseMessage.java deleted file mode 100644 index 2a722e6..0000000 --- a/src/org/gnunet/statistics/GetResponseMessage.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - 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 - * - * - */ -@UnionCase(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; -} diff --git a/src/org/gnunet/statistics/SetMessage.java b/src/org/gnunet/statistics/SetMessage.java deleted file mode 100644 index d75e3bf..0000000 --- a/src/org/gnunet/statistics/SetMessage.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - 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. - */ -@UnionCase(168) -public class SetMessage implements GnunetMessage.Body { - @UInt32 - public int flags; - @UInt64 - public long value; - @ZeroTerminatedString - public String subsystemName; - @ZeroTerminatedString - public String statisticName; -} diff --git a/src/org/gnunet/statistics/Statistics.java b/src/org/gnunet/statistics/Statistics.java deleted file mode 100644 index d755dd7..0000000 --- a/src/org/gnunet/statistics/Statistics.java +++ /dev/null @@ -1,408 +0,0 @@ -/* - 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.Request; -import org.gnunet.requests.RequestQueue; -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.ArrayList; - -/** - * API for the gnunet statistics service. - *

- * Set, get and monitor statistics values, represented as unsigned 64bit integer. - * Note that {@literal 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); - - /** - * 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 Client client; - - private final RequestQueue requestQueue; - - /** - * Callback for the current get request. Only one get request ist allowed at a time. - */ - private StatisticsReceiver currentGetReceiver; - /** - * Success/Error continuation for the current get request. - */ - private Continuation currentGetContinuation; - - /** - * List of all watch requests, canceled watch requests are null (but stay due to protocol limitations) - */ - private ArrayList watchRequests = new ArrayList(); - - /** - * A request to the statistics service. - */ - private abstract class StatisticsRequest extends Request { - public String name; - public String subsystem; - } - - private class StatisticsGetRequest extends StatisticsRequest { - public StatisticsReceiver receiver; - - public void onCancel(boolean alreadyTransmitted) { - currentGetReceiver = null; - } - - public void transmit(Connection.MessageSink sink) { - GetMessage rm = new GetMessage(); - rm.statisticsName = name; - rm.subsystemName = subsystem; - - sink.send(rm); - } - - public boolean onReconnect() { - return true; - } - } - - private class StatisticsSetRequest extends StatisticsRequest { - public long value; - public int flags; - - public AbsoluteTime getDeadline() { - return SET_TIMEOUT.toAbsolute(); - } - - public void transmit(Connection.MessageSink sink) { - SetMessage sm = new SetMessage(); - sm.statisticName = name; - sm.subsystemName = subsystem; - sm.value = value; - sm.flags = flags; - sink.send(sm); - } - - public boolean onDestroy() { - // keep the request - return true; - } - - public boolean onReconnect() { - // just keep the request on reconnect - return true; - } - } - - - private class StatisticsWatchRequest extends StatisticsRequest { - public StatisticsReceiver receiver; - - public AbsoluteTime getDeadline() { - return AbsoluteTime.FOREVER; - } - - public void onCancel(boolean alreadyTransmitted) { - System.out.println("already transmitted: " + alreadyTransmitted); - if (alreadyTransmitted) { - watchRequests.set(watchRequests.indexOf(this), null); - } - - } - - public boolean onReconnect() { - // do this because we'll probably get new WatchIDs for every watch request on reconnect - if (watchRequests.contains(this)) { - watchRequests.clear(); - } - - watchRequests.add(this); - - return true; - } - - public void transmit(Connection.MessageSink sink) { - WatchMessage wm = new WatchMessage(); - wm.statisticsName = name; - wm.subsystemName = subsystem; - sink.send(wm); - - - watchRequests.add(this); - } - } - - private static class TESTRequest extends Request { - private AbsoluteTime deadline; - - public TESTRequest(AbsoluteTime deadline) { - this.deadline = deadline; - } - - public boolean onDestroy() { - // keep on destroy - return true; - } - - public AbsoluteTime getDeadline() { - return deadline; - } - - public void transmit(Connection.MessageSink sink) { - sink.send(new TestMessage()); - // todo: disconnect when not receiving the TEST message back after timeout - } - } - - - public class StatisticsMessageReceiver extends RunaboutMessageReceiver { - public void visit(GetResponseMessage m) { - currentGetReceiver.onReceive(m.subsystemName, m.statisticName, m.value); - } - - public void visit(GetResponseEndMessage m) { - currentGetReceiver = null; - if (currentGetContinuation != null) { - currentGetContinuation.cont(true); - } - } - - public void visit(TestMessage m) { - client.disconnect(); - } - - public void visit(WatchResponseMessage wrm) { - if (watchRequests.size() <= wrm.wid) { - logger.warn("statistics service got confused with watch request"); - return; - } - StatisticsWatchRequest wr = watchRequests.get(wrm.wid); - // request may have been canceled by the api (but not by the server) - if (wr != null) { - wr.receiver.onReceive(wr.subsystem, wr.name, wrm.value); - } - } - - @Override - public void handleError() { - requestQueue.reconnect(); - } - } - - public Statistics(Configuration cfg) { - client = new Client("statistics", cfg); - requestQueue = new RequestQueue(this.client, new StatisticsMessageReceiver()); - } - - /** - * Retrieve values from statistics. - * - * @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 - * @param continuation - * @return handle to cancel the request - */ - public Cancelable get(RelativeTime timeout, final String subsystem, final String name, - final StatisticsReceiver receiver, Continuation continuation) { - - if (currentGetReceiver != null) { - throw new AssertionError("only one Statistics get request can be active at a time"); - } - currentGetReceiver = receiver; - currentGetContinuation = continuation; - - final StatisticsGetRequest getRequest = new StatisticsGetRequest(); - getRequest.setDeadline(timeout.toAbsolute()); - getRequest.name = (name == null) ? "" : name; - getRequest.subsystem = (subsystem == null) ? "" : subsystem; - getRequest.receiver = receiver; - - return requestQueue.add(getRequest); - } - - - /** - * 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) { - StatisticsSetRequest setRequest = new StatisticsSetRequest(); - setRequest.setDeadline(SET_TIMEOUT.toAbsolute()); - setRequest.subsystem = subsystem; - setRequest.name = name; - setRequest.value = value; - setRequest.flags = persist ? SETFLAG_PERSIST : 0; - - return requestQueue.add(setRequest); - } - - /** - * 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) { - StatisticsSetRequest setRequest = new StatisticsSetRequest(); - setRequest.setDeadline(SET_TIMEOUT.toAbsolute()); - setRequest.subsystem = subsystem; - setRequest.name = name; - setRequest.value = delta; - setRequest.flags = (persist ? SETFLAG_PERSIST : 0) | SETFLAG_RELATIVE; - - return requestQueue.add(setRequest); - } - - public Cancelable watch(final String subsystem, final String name, StatisticsReceiver receiver) { - StatisticsWatchRequest watchRequest = new StatisticsWatchRequest(); - watchRequest.setDeadline(AbsoluteTime.FOREVER); - watchRequest.name = name; - watchRequest.subsystem = subsystem; - watchRequest.receiver = receiver; - - // even after the request has been sent, we want to keep it - // (e.g. for retransmission on reconnect) - return requestQueue.addPersistent(watchRequest); - } - - /** - * Destroy handle to the statistics service. Always finishes writing pending values. - */ - public void destroy() { - // the request queue handles the destruction, maybe we still have important messages pending etc. - requestQueue.add(new TESTRequest(SET_TIMEOUT.toAbsolute())); - requestQueue.shutdown(); - } - - - /** - * 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 = "set a value") - boolean test; - @Argument( - shortname = "w", - longname = "watch", - action = ArgumentAction.SET, - description = "set a value") - boolean watch; - @Argument( - shortname = "n", - longname = "name", - action = ArgumentAction.STORE_STRING, - description = "statistics name") - String statisticsName = ""; - @Argument( - shortname = "s", - longname = "subsystem", - action = ArgumentAction.STORE_STRING, - description = "subsystem name") - String subsystemName = ""; - - public void run() { - final Statistics statistics = new Statistics(cfg); - if (test) { - if (subsystemName.isEmpty() || statisticsName.isEmpty()) { - System.err.println("must specify non-empty subsystem and name"); - 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; - } - statistics.set(subsystemName, statisticsName, value, false); - statistics.destroy(); - } else { - if (unprocessedArgs.length == 0) { - if (watch) { - statistics.watch(subsystemName, statisticsName, - new StatisticsReceiver() { - @Override - public void onReceive(String subsystem, String name, long value) { - System.out.println(subsystem + "(" + name + ") = " + value); - } - } - ); - } 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); - } - }, - new Continuation() { - @Override - public void cont(boolean success) { - statistics.destroy(); - } - } - ); - } - } else { - System.err.println("dumping statistics does not take any positional parameters"); - } - } - } - }.start(); - } - -} diff --git a/src/org/gnunet/statistics/StatisticsReceiver.java b/src/org/gnunet/statistics/StatisticsReceiver.java deleted file mode 100644 index 87fbdd6..0000000 --- a/src/org/gnunet/statistics/StatisticsReceiver.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - 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); -} diff --git a/src/org/gnunet/statistics/WatchMessage.java b/src/org/gnunet/statistics/WatchMessage.java deleted file mode 100644 index 814f263..0000000 --- a/src/org/gnunet/statistics/WatchMessage.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - 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; - -@UnionCase(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; -} diff --git a/src/org/gnunet/statistics/WatchResponseMessage.java b/src/org/gnunet/statistics/WatchResponseMessage.java deleted file mode 100644 index 19c56b5..0000000 --- a/src/org/gnunet/statistics/WatchResponseMessage.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - 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; - -@UnionCase(173) -public class WatchResponseMessage implements GnunetMessage.Body { - @UInt32 - public int flags; - @UInt32 - public int wid; - @UInt32 - public int reserved ; - @UInt64 - public long value; -} diff --git a/src/org/gnunet/statistics/package-info.java b/src/org/gnunet/statistics/package-info.java deleted file mode 100644 index fce59e7..0000000 --- a/src/org/gnunet/statistics/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - 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; diff --git a/src/org/gnunet/testing/TestingServer.java b/src/org/gnunet/testing/TestingServer.java deleted file mode 100644 index 97b6bc0..0000000 --- a/src/org/gnunet/testing/TestingServer.java +++ /dev/null @@ -1,65 +0,0 @@ -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()); - } - -} diff --git a/src/org/gnunet/testing/TestingSetup.java b/src/org/gnunet/testing/TestingSetup.java deleted file mode 100644 index 6f8d578..0000000 --- a/src/org/gnunet/testing/TestingSetup.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - 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); - } - } -} diff --git a/src/org/gnunet/testing/TestingSubsystem.java b/src/org/gnunet/testing/TestingSubsystem.java deleted file mode 100644 index 29de0bc..0000000 --- a/src/org/gnunet/testing/TestingSubsystem.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - 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-run-service", "-s", 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); - } - String line; - try { - line = reader.readLine(); - } catch (IOException e) { - throw new TestingSetup.SetupException(e); - } - if (line == null || !line.equals("bye")) { - throw new TestingSetup.SetupException("service not destroyed correctly"); - } - System.out.println("read bye"); - try { - p.waitFor(); - } catch (InterruptedException e) { - throw new TestingSetup.SetupException(e); - } - if (p.exitValue() != 0) { - throw new TestingSetup.SetupException("gnunet-testing-run-service 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-run-service 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"); - } -} diff --git a/src/org/gnunet/testing/package-info.java b/src/org/gnunet/testing/package-info.java deleted file mode 100644 index 1a91586..0000000 --- a/src/org/gnunet/testing/package-info.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - 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; diff --git a/src/org/gnunet/transport/BlacklistCallback.java b/src/org/gnunet/transport/BlacklistCallback.java deleted file mode 100644 index a9da35f..0000000 --- a/src/org/gnunet/transport/BlacklistCallback.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.gnunet.transport; - -/** - * ... - * - * @author Florian Dold - */ -public class BlacklistCallback { -} diff --git a/src/org/gnunet/transport/HelloUpdateCallback.java b/src/org/gnunet/transport/HelloUpdateCallback.java deleted file mode 100644 index d5253b7..0000000 --- a/src/org/gnunet/transport/HelloUpdateCallback.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.gnunet.transport; - -/** - * ... - * - * @author Florian Dold - */ -public class HelloUpdateCallback { -} diff --git a/src/org/gnunet/transport/PeerIterateCallback.java b/src/org/gnunet/transport/PeerIterateCallback.java deleted file mode 100644 index da9a3ae..0000000 --- a/src/org/gnunet/transport/PeerIterateCallback.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.gnunet.transport; - -/** - * ... - * - * @author Florian Dold - */ -public class PeerIterateCallback { -} diff --git a/src/org/gnunet/transport/RequestConnectMessage.java b/src/org/gnunet/transport/RequestConnectMessage.java deleted file mode 100644 index 63bbc39..0000000 --- a/src/org/gnunet/transport/RequestConnectMessage.java +++ /dev/null @@ -1,24 +0,0 @@ -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 - */ -@UnionCase(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; -} diff --git a/src/org/gnunet/transport/StartMessage.java b/src/org/gnunet/transport/StartMessage.java deleted file mode 100644 index 2169565..0000000 --- a/src/org/gnunet/transport/StartMessage.java +++ /dev/null @@ -1,32 +0,0 @@ -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 - */ -@UnionCase(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; - - -} diff --git a/src/org/gnunet/transport/Transport.java b/src/org/gnunet/transport/Transport.java deleted file mode 100644 index 5ccbc77..0000000 --- a/src/org/gnunet/transport/Transport.java +++ /dev/null @@ -1,116 +0,0 @@ -package org.gnunet.transport; - -import org.gnunet.hello.HelloMessage; -import org.gnunet.mq.Envelope; -import org.gnunet.util.*; - -/** - * ... - * - * @author Florian Dold - */ -public class Transport { - - public Transport(Configuration cfg) { - - } - - /** - * 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 GNUNET_TRANSPORT_TryConnectHandle handle or - * NULL on failure (cb will not be called) - */ - Cancelable tryConnect(PeerIdentity target, TryConnectCallback cb) { - RequestConnectMessage m = new RequestConnectMessage(); - m.peer = target; - m.reserved = 0; - final Envelope ev = new Envelope(m); - ev.notifySent(null /* FIXME */); - //client_mq.send(ev); - - return new Cancelable() { - @Override - public void cancel() { - ev.cancel(); - } - }; - } - - - /** - * 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. If the blacklisting callback is unregistered, - * all hosts that were denied in the past will automatically be - * whitelisted again. Cancelling the blacklist handle is also the - * only way to re-enable connections from peers that were previously - * blacklisted. - * - * @param cfg configuration to use - * @param cb callback to invoke to check if connections are allowed - * @return NULL on error, otherwise handle for cancellation - */ - static Cancelable blacklist(Configuration cfg, - BlacklistCallback cb) { - throw new UnsupportedOperationException(); - } - - /** - * Return all the known addresses for a specific peer or all peers. - * Returns continuously all address if one_shot is set to GNUNET_NO - *

- * CHANGE: 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 cfg configuration to use - * @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 - peer_get_active_addresses(Configuration cfg, PeerIdentity peer, int one_shot, - RelativeTime timeout, PeerIterateCallback peer_address_callback) { - throw new UnsupportedOperationException(); - } -} - diff --git a/src/org/gnunet/transport/TryConnectCallback.java b/src/org/gnunet/transport/TryConnectCallback.java deleted file mode 100644 index 93c0f76..0000000 --- a/src/org/gnunet/transport/TryConnectCallback.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.gnunet.transport; - -/** - * ... - * - * @author Florian Dold - */ -public class TryConnectCallback { -} diff --git a/src/org/gnunet/util/ATSInformation.java b/src/org/gnunet/util/ATSInformation.java deleted file mode 100644 index b93931b..0000000 --- a/src/org/gnunet/util/ATSInformation.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - 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; -} diff --git a/src/org/gnunet/util/AbsoluteTime.java b/src/org/gnunet/util/AbsoluteTime.java deleted file mode 100644 index 06f41ac..0000000 --- a/src/org/gnunet/util/AbsoluteTime.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - 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 { - 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()); - } - - 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 {@literal this} - * @return {@literal 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); - } - - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(Object other) { - return other instanceof AbsoluteTime && compareTo((AbsoluteTime) other) == 0; - } - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - return (int) this.abs_value_us; - } - - /** - * {@inheritDoc} - */ - @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; - } - - /** - * {@inheritDoc} - */ - @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 {@literal 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); - } -} diff --git a/src/org/gnunet/util/AbsoluteTimeMessage.java b/src/org/gnunet/util/AbsoluteTimeMessage.java deleted file mode 100644 index f46d577..0000000 --- a/src/org/gnunet/util/AbsoluteTimeMessage.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - 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(); - } - } -} diff --git a/src/org/gnunet/util/Cancelable.java b/src/org/gnunet/util/Cancelable.java deleted file mode 100644 index 173f4c0..0000000 --- a/src/org/gnunet/util/Cancelable.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - 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(); -} diff --git a/src/org/gnunet/util/Client.java b/src/org/gnunet/util/Client.java deleted file mode 100644 index 182c797..0000000 --- a/src/org/gnunet/util/Client.java +++ /dev/null @@ -1,262 +0,0 @@ -/* - 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.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 { - private static final Logger logger = LoggerFactory - .getLogger(Client.class); - - /** - * Underlying connection to the service. - */ - private Connection connection; - - /** - * Host this client should be connected to. - */ - private final int port; - private final String hostname; - - /** - * 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; - - /** - * 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 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 receive(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) { - 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 { - 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(); - } -} diff --git a/src/org/gnunet/util/Configuration.java b/src/org/gnunet/util/Configuration.java deleted file mode 100644 index 5cf950c..0000000 --- a/src/org/gnunet/util/Configuration.java +++ /dev/null @@ -1,378 +0,0 @@ -/* - 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 sections = HashBasedTable.create(); - - private final Map> sectionSources = new HashMap>(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 env = System.getenv(); - for (final Map.Entry e : env.entrySet()) { - orig = orig.replace("$" + e.getKey(), e.getValue()); - } - - for (final Map.Entry 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 getSection(String s) { - Map 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 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 getValueChoice(String section, String option, - Iterable choices) { - Optional 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 getValueNumber(String section, String option) { - Optional 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 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 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 getValueYesNo(String section, String option) { - final Optional v = getValueChoice(section, option, - Arrays.asList("YES", "NO")); - if (!v.isPresent()) { - Set 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 it; - - try { - List 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(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 e : sections.row(section).entrySet()) { - w.write(e.getKey() + " = " + e.getValue()); - w.newLine(); - } - } - } finally { - w.close(); - } - } - - - public void loadDefaults() { - Collection dirs = new ArrayList(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); - } - } -} diff --git a/src/org/gnunet/util/Connection.java b/src/org/gnunet/util/Connection.java deleted file mode 100644 index f969cbe..0000000 --- a/src/org/gnunet/util/Connection.java +++ /dev/null @@ -1,695 +0,0 @@ -/* - 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; - - private List 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(); - 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 { - public void cancel(); - } - - /** - * 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; - } - } - -} diff --git a/src/org/gnunet/util/Continuation.java b/src/org/gnunet/util/Continuation.java deleted file mode 100644 index e1027c0..0000000 --- a/src/org/gnunet/util/Continuation.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - 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); -} diff --git a/src/org/gnunet/util/GnunetMessage.java b/src/org/gnunet/util/GnunetMessage.java deleted file mode 100644 index 89c7a80..0000000 --- a/src/org/gnunet/util/GnunetMessage.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - 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; -} diff --git a/src/org/gnunet/util/HashCode.java b/src/org/gnunet/util/HashCode.java deleted file mode 100644 index 0c2790f..0000000 --- a/src/org/gnunet/util/HashCode.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - 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 diff --git a/src/org/gnunet/util/HelperProcess.java b/src/org/gnunet/util/HelperProcess.java deleted file mode 100644 index 5b0458f..0000000 --- a/src/org/gnunet/util/HelperProcess.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.gnunet.util; - -/** - * A helper process is a process that can be started, shut down and communicated with asynchronously. - * - * @author Florian Dold - */ -public class HelperProcess { - - public void HelperProcess(String name, String... args) { - - } - - public void readLine() { - - } - - public void write(String s) { - - } -} diff --git a/src/org/gnunet/util/MessageReceiver.java b/src/org/gnunet/util/MessageReceiver.java deleted file mode 100644 index 548695f..0000000 --- a/src/org/gnunet/util/MessageReceiver.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - 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(); -} diff --git a/src/org/gnunet/util/MessageTransmitter.java b/src/org/gnunet/util/MessageTransmitter.java deleted file mode 100644 index 54a6555..0000000 --- a/src/org/gnunet/util/MessageTransmitter.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - 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(); -} diff --git a/src/org/gnunet/util/PeerIdentity.java b/src/org/gnunet/util/PeerIdentity.java deleted file mode 100644 index 46a67cd..0000000 --- a/src/org/gnunet/util/PeerIdentity.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - 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); - } -} diff --git a/src/org/gnunet/util/Program.java b/src/org/gnunet/util/Program.java deleted file mode 100644 index c54322b..0000000 --- a/src/org/gnunet/util/Program.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - 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; - - - /** - * 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"; - } - - /** - * 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(); - } - }); - } - } - - /** - * 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; - } -} diff --git a/src/org/gnunet/util/RelativeTime.java b/src/org/gnunet/util/RelativeTime.java deleted file mode 100644 index 0faedfc..0000000 --- a/src/org/gnunet/util/RelativeTime.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - 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 { - 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; - } - - /** - * 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__); - } - } - -} diff --git a/src/org/gnunet/util/RelativeTimeMessage.java b/src/org/gnunet/util/RelativeTimeMessage.java deleted file mode 100644 index ac4e66c..0000000 --- a/src/org/gnunet/util/RelativeTimeMessage.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - 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(); - } - } - -} diff --git a/src/org/gnunet/util/Resolver.java b/src/org/gnunet/util/Resolver.java deleted file mode 100644 index 1d8ec87..0000000 --- a/src/org/gnunet/util/Resolver.java +++ /dev/null @@ -1,421 +0,0 @@ -/* - 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. - *

- * 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. - *

- * 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 queuedRequests = new LinkedList(); - - 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.receive(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.receive(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(); - } -} diff --git a/src/org/gnunet/util/RunaboutMessageReceiver.java b/src/org/gnunet/util/RunaboutMessageReceiver.java deleted file mode 100644 index 2a0f067..0000000 --- a/src/org/gnunet/util/RunaboutMessageReceiver.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - 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); - } -} diff --git a/src/org/gnunet/util/RunaboutUtil.java b/src/org/gnunet/util/RunaboutUtil.java deleted file mode 100644 index a82dc0a..0000000 --- a/src/org/gnunet/util/RunaboutUtil.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - 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 getRunaboutVisitees(Runabout r) { - Class rc = r.getClass(); - ArrayList ret = new ArrayList(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 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; - } -} diff --git a/src/org/gnunet/util/Scheduler.java b/src/org/gnunet/util/Scheduler.java deleted file mode 100644 index 6998633..0000000 --- a/src/org/gnunet/util/Scheduler.java +++ /dev/null @@ -1,674 +0,0 @@ -/* - 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; - - // number of tasks in the ready queue - private static int readyCount = 0; - - // for every priority, there is a list of tasks that is definitely ready to run - @SuppressWarnings("unchecked") - final private static LinkedList[] readyLists = new LinkedList[Priority.numberOfPriorities]; - - static { - for (int i = 0; i < Priority.numberOfPriorities; ++i) { - readyLists[i] = new LinkedList(); - } - } - - 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 pending = new PriorityQueue(5, new Comparator - () { - @Override - public int compare(TaskConfiguration a, TaskConfiguration b) { - return a.deadline.compareTo(b.deadline); - } - }); - - - /** - * 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 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 eventChannels = null; - private ArrayList eventTypes = null; - - private boolean hasRun = false; - private boolean isCanceled = false; - - /** - * Create a TaskIdentifier. - * - * @param task task to run with this TaskIdentifier - */ - TaskConfiguration(RelativeTime delay, Task task) { - this.task = task; - this.deadline = delay.toAbsolute(); - } - - /** - * Create a light-weight task identifier that is not registered as pending in the Scheduler, - * used for continuations. - * - * @param t task - * @param ctx the RunContext - */ - TaskConfiguration(Task t, RunContext ctx) { - this.task = t; - this.ctx = ctx; - this.deadline = AbsoluteTime.ZERO; - this.priority = (activeTask == null) ? Priority.DEFAULT : activeTask.priority; - this.lifeness = true; - } - - private void addChannelEvent(SelectableChannel channel, int eventType) { - if (channel == null) { - throw new AssertionError("channel must be non-null"); - } - if (eventChannels == null) { - eventChannels = new ArrayList(); - eventTypes = new ArrayList(); - } - 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 (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 void addContinuation(Task task, - EnumSet reasons) { - RunContext ctx = new RunContext(); - ctx.reasons = reasons; - queueReady(new TaskConfiguration(task, ctx)); - } - - /** - * 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 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 executableTasks, - TaskConfiguration[] subscribers, int eventType) { - if (subscribers[eventType] == null) { - return; - } - executableTasks.add(subscribers[eventType]); - subscribers[eventType].ctx.reasons.add(eventToReason[eventType]); - } - - private static void handleSelect(RelativeTime timeout) { - try { - // selector.select(0) would block indefinitely (counter-intuitive, java's fault) - if (timeout.getMicroseconds() == 0) { - selector.selectNow(); - } else if (timeout.isForever()) { - selector.select(0); - } else { - selector.select(timeout.getMicroseconds()); - } - } catch (IOException e) { - throw new IOError(e); - } - - // we have to do this so we don't execute any task twice - Collection executableTasks = new HashSet(); - 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) - scheduler_running = false; - readyCount = 0; - activeTask = null; - for (int i = 0; i < Priority.numberOfPriorities; ++i) { - readyLists[i] = new LinkedList(); - } - pending.clear(); - } - } - - - /** - * 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 (checkLiveness()) { - 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 - *

    - *
  • there are no ready tasks
  • - *
  • there is a pending task (which may be of higher priority)
  • - *
- */ - 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 queue = readyLists[p]; - while (!queue.isEmpty()) { - TaskConfiguration tid = queue.removeFirst(); - readyCount--; - tid.run(); - } - } - } while (pending.size() == 0); - - } - - /** - * Request the shutdown of a 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(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(); - } - - } - - 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); - } - - public static class AsyncProcess { - // getIn, getOut, getErr - - } - - public static AsyncProcess openAsyncProcess(/*...*/) { - throw new UnsupportedOperationException("not implemented yet"); - } -} diff --git a/src/org/gnunet/util/Server.java b/src/org/gnunet/util/Server.java deleted file mode 100644 index 8a86b45..0000000 --- a/src/org/gnunet/util/Server.java +++ /dev/null @@ -1,509 +0,0 @@ -/* - 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 listenSockets = new ArrayList(); - - /** - * The list of all clients connected to this server. - */ - private List clientHandles = new LinkedList(); - - /** - * 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 disconnectHandlers = new LinkedList(); - - /** - * 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 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. - *

- * 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). - *

- * 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. - *

- * 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. - *

- * 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. - *

- * 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. - *

- * 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 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. - *

- * 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(); - } -} diff --git a/src/org/gnunet/util/Service.java b/src/org/gnunet/util/Service.java deleted file mode 100644 index d93e296..0000000 --- a/src/org/gnunet/util/Service.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - 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 addrs = new LinkedList(); - - 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 diff --git a/src/org/gnunet/util/Strings.java b/src/org/gnunet/util/Strings.java deleted file mode 100644 index a35568a..0000000 --- a/src/org/gnunet/util/Strings.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - 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; - } - -} diff --git a/src/org/gnunet/util/TestMessage.java b/src/org/gnunet/util/TestMessage.java deleted file mode 100644 index b08a706..0000000 --- a/src/org/gnunet/util/TestMessage.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - 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. - */ -@UnionCase(1) -public class TestMessage implements GnunetMessage.Body { - // empty -} diff --git a/src/org/gnunet/util/UnknownMessageBody.java b/src/org/gnunet/util/UnknownMessageBody.java deleted file mode 100644 index b978ec6..0000000 --- a/src/org/gnunet/util/UnknownMessageBody.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - 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; -} diff --git a/src/org/gnunet/util/getopt/Argument.java b/src/org/gnunet/util/getopt/Argument.java deleted file mode 100644 index 34159d0..0000000 --- a/src/org/gnunet/util/getopt/Argument.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - 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. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(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(); -} diff --git a/src/org/gnunet/util/getopt/ArgumentAction.java b/src/org/gnunet/util/getopt/ArgumentAction.java deleted file mode 100644 index 077e71c..0000000 --- a/src/org/gnunet/util/getopt/ArgumentAction.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - 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 -} diff --git a/src/org/gnunet/util/getopt/Parser.java b/src/org/gnunet/util/getopt/Parser.java deleted file mode 100644 index 6ecc220..0000000 --- a/src/org/gnunet/util/getopt/Parser.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - 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 getFields(Class c) { - LinkedList fields = new LinkedList(Arrays.asList(c.getDeclaredFields())); - while ((c = c.getSuperclass()) != null) { - fields.addAll(0, Arrays.asList(c.getDeclaredFields())); - } - return fields; - } - - private Map longOpt = new HashMap(); - private Map shortOpt = new HashMap(); - - private Collection arguments = new LinkedList(); - - 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 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 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 positionalArgs = new LinkedList(); - - LinkedList argsList = new LinkedList(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()]); - } - -} diff --git a/src/org/gnunet/util/getopt/package-info.java b/src/org/gnunet/util/getopt/package-info.java deleted file mode 100644 index 0e3bdf5..0000000 --- a/src/org/gnunet/util/getopt/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - 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; diff --git a/src/org/gnunet/util/package-info.java b/src/org/gnunet/util/package-info.java deleted file mode 100644 index df61afd..0000000 --- a/src/org/gnunet/util/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - 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; diff --git a/src/org/gnunet/voting/Authority.java b/src/org/gnunet/voting/Authority.java deleted file mode 100644 index 8c39100..0000000 --- a/src/org/gnunet/voting/Authority.java +++ /dev/null @@ -1,266 +0,0 @@ -package org.gnunet.voting; - -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 participatingAuthorities; - - private List ballots = Lists.newLinkedList(); - - private Map specializedKeyShares = Maps.newTreeMap(); - - private Cyphertext encryptedTally; - private BigInteger tallyBaseG; - - - /** - * The commitments of each authority to it's share of the group secret. - */ - Map 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 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 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(); - } - } -} diff --git a/src/org/gnunet/voting/Ballot.java b/src/org/gnunet/voting/Ballot.java deleted file mode 100644 index fbc6e11..0000000 --- a/src/org/gnunet/voting/Ballot.java +++ /dev/null @@ -1,105 +0,0 @@ -package org.gnunet.voting; - -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(); - } - - - } -} diff --git a/src/org/gnunet/voting/BogusAuthority.java b/src/org/gnunet/voting/BogusAuthority.java deleted file mode 100644 index 8c0363d..0000000 --- a/src/org/gnunet/voting/BogusAuthority.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.gnunet.voting; - -/** - * ... - * - * @author Florian Dold - */ -public class BogusAuthority extends Authority { -} diff --git a/src/org/gnunet/voting/CallForVoters.java b/src/org/gnunet/voting/CallForVoters.java deleted file mode 100644 index d6436eb..0000000 --- a/src/org/gnunet/voting/CallForVoters.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.gnunet.voting; - -import java.util.List; - -/** - * ... - * - * @author Florian Dold - */ -public class CallForVoters { - public List authorities; - public VotingParameters parameters; - public GroupPublicKey publicKey; -} diff --git a/src/org/gnunet/voting/CryptoUtil.java b/src/org/gnunet/voting/CryptoUtil.java deleted file mode 100644 index 6f15bf6..0000000 --- a/src/org/gnunet/voting/CryptoUtil.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.gnunet.voting; - -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()); - } - -} diff --git a/src/org/gnunet/voting/Cyphertext.java b/src/org/gnunet/voting/Cyphertext.java deleted file mode 100644 index 218252c..0000000 --- a/src/org/gnunet/voting/Cyphertext.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.gnunet.voting; - -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; - } -} diff --git a/src/org/gnunet/voting/ElectionSupervisor.java b/src/org/gnunet/voting/ElectionSupervisor.java deleted file mode 100644 index 106095b..0000000 --- a/src/org/gnunet/voting/ElectionSupervisor.java +++ /dev/null @@ -1,105 +0,0 @@ -package org.gnunet.voting; - -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 availableAuthorities; - - /** - * Authorities that have agreed to participate. - */ - private List participatingAuthorities = Lists.newArrayList(); - - - - private enum Phase { START, INVITED, KEYS_GENERATED, PUBKEY_PUBLISHED} - - private Phase currentPhase = Phase.START; - - - public ElectionSupervisor(List 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; - } -} diff --git a/src/org/gnunet/voting/GroupPublicKey.java b/src/org/gnunet/voting/GroupPublicKey.java deleted file mode 100644 index a7b0cae..0000000 --- a/src/org/gnunet/voting/GroupPublicKey.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.gnunet.voting; - -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; - } -} diff --git a/src/org/gnunet/voting/TallyKeyShare.java b/src/org/gnunet/voting/TallyKeyShare.java deleted file mode 100644 index d67cfa9..0000000 --- a/src/org/gnunet/voting/TallyKeyShare.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.gnunet.voting; - -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)); - } -} - diff --git a/src/org/gnunet/voting/TransmitShareVerification.java b/src/org/gnunet/voting/TransmitShareVerification.java deleted file mode 100644 index a30e327..0000000 --- a/src/org/gnunet/voting/TransmitShareVerification.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.gnunet.voting; - -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); - } - } -} diff --git a/src/org/gnunet/voting/Voter.java b/src/org/gnunet/voting/Voter.java deleted file mode 100644 index fa658dd..0000000 --- a/src/org/gnunet/voting/Voter.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.gnunet.voting; - -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); - } - } -} diff --git a/src/org/gnunet/voting/VotingParameters.java b/src/org/gnunet/voting/VotingParameters.java deleted file mode 100644 index b563bff..0000000 --- a/src/org/gnunet/voting/VotingParameters.java +++ /dev/null @@ -1,166 +0,0 @@ -package org.gnunet.voting; - -import java.math.BigInteger; -import java.security.SecureRandom; -import java.util.Random; - -/** - * Utilities for the modified ElGamal algorithm. - *

- * 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. - *

- * 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. - *

- * (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))); - } - - -} diff --git a/src/org/gnunet/voting/VotingSimulation.java b/src/org/gnunet/voting/VotingSimulation.java deleted file mode 100644 index 853fdff..0000000 --- a/src/org/gnunet/voting/VotingSimulation.java +++ /dev/null @@ -1,122 +0,0 @@ -package org.gnunet.voting; - -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 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 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 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 spawnAuthorities(int authorityCount, int authorityThreshold) { - List authorities = Lists.newArrayList(); - Collection 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 spawnVoters(CallForVoters callForVote, int voterCount, int honestVoterCount) { - List 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 randomIndices(int authorityCount, int authorityThreshold) { - ArrayList 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)); - } -} diff --git a/src/org/grothoff/Runabout.java b/src/org/grothoff/Runabout.java deleted file mode 100644 index 2a1dbb0..0000000 --- a/src/org/grothoff/Runabout.java +++ /dev/null @@ -1,574 +0,0 @@ -/* - * (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. - *

- * 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. - *

- * 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. - *

- * 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. - *

- * 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!).
- * A per-thread Cache is used to speed-up the creation of the Runabout by - * caching reflection, code creation and dynamic loading operations. - *

- * Restrictions: Java semantics require: - *

    - *
  • all subclasses must be public, sadly this also means that you - * can not use an anonymous inner class (!)
  • - *
  • the types_length to all arguments of visit methods must be public
  • - *
  • all visit methods must be public (!)
  • - *
- * Otherwise the visitor will die with an IllegalAccessError during execution. - *

- * - * @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 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 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 result = new HashMap(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 - * {@code 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> 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>(); - 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 628 - * 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 get(Runabout r) { - Class c = r.getClass(); - HashMap 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 diff --git a/src/org/grothoff/package-info.java b/src/org/grothoff/package-info.java deleted file mode 100644 index 2a8b8f0..0000000 --- a/src/org/grothoff/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Pure java implementation of single argument multiple dispatch - */ -package org.grothoff; diff --git a/src/test/java/org/gnunet/construct/ByteFillMessage.java b/src/test/java/org/gnunet/construct/ByteFillMessage.java new file mode 100644 index 0000000..090f7d0 --- /dev/null +++ b/src/test/java/org/gnunet/construct/ByteFillMessage.java @@ -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; + +} diff --git a/src/test/java/org/gnunet/construct/ConstructTest.java b/src/test/java/org/gnunet/construct/ConstructTest.java new file mode 100644 index 0000000..ed6ac51 --- /dev/null +++ b/src/test/java/org/gnunet/construct/ConstructTest.java @@ -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); + } + + +} + diff --git a/src/test/java/org/gnunet/construct/DoubleTest.java b/src/test/java/org/gnunet/construct/DoubleTest.java new file mode 100644 index 0000000..c66bd93 --- /dev/null +++ b/src/test/java/org/gnunet/construct/DoubleTest.java @@ -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); + } + +} diff --git a/src/test/java/org/gnunet/construct/FillParserTest.java b/src/test/java/org/gnunet/construct/FillParserTest.java new file mode 100644 index 0000000..d982088 --- /dev/null +++ b/src/test/java/org/gnunet/construct/FillParserTest.java @@ -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]); + } +} diff --git a/src/test/java/org/gnunet/construct/FixedSizeTest.java b/src/test/java/org/gnunet/construct/FixedSizeTest.java new file mode 100644 index 0000000..149862c --- /dev/null +++ b/src/test/java/org/gnunet/construct/FixedSizeTest.java @@ -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); + } +} diff --git a/src/test/java/org/gnunet/construct/FrameSizeTest.java b/src/test/java/org/gnunet/construct/FrameSizeTest.java new file mode 100644 index 0000000..1aa53e2 --- /dev/null +++ b/src/test/java/org/gnunet/construct/FrameSizeTest.java @@ -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); + } +} diff --git a/src/test/java/org/gnunet/construct/IntMessage.java b/src/test/java/org/gnunet/construct/IntMessage.java new file mode 100644 index 0000000..14971b2 --- /dev/null +++ b/src/test/java/org/gnunet/construct/IntMessage.java @@ -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; +} diff --git a/src/test/java/org/gnunet/construct/OptionalUnionTest.java b/src/test/java/org/gnunet/construct/OptionalUnionTest.java new file mode 100644 index 0000000..1c45972 --- /dev/null +++ b/src/test/java/org/gnunet/construct/OptionalUnionTest.java @@ -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); + + } +} diff --git a/src/test/java/org/gnunet/construct/PrivateMemberMessage.java b/src/test/java/org/gnunet/construct/PrivateMemberMessage.java new file mode 100644 index 0000000..726d1b7 --- /dev/null +++ b/src/test/java/org/gnunet/construct/PrivateMemberMessage.java @@ -0,0 +1,13 @@ +package org.gnunet.construct; + +/** + * ... + * + * @author Florian Dold + */ +public class PrivateMemberMessage implements Message { + @UInt32 + public int foo; + @UInt32 + private int bar; +} diff --git a/src/test/java/org/gnunet/construct/QueryMessage.java b/src/test/java/org/gnunet/construct/QueryMessage.java new file mode 100644 index 0000000..4bf9af5 --- /dev/null +++ b/src/test/java/org/gnunet/construct/QueryMessage.java @@ -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; +} diff --git a/src/test/java/org/gnunet/construct/SendMessageTest.java b/src/test/java/org/gnunet/construct/SendMessageTest.java new file mode 100644 index 0000000..b95cc78 --- /dev/null +++ b/src/test/java/org/gnunet/construct/SendMessageTest.java @@ -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); + } +} diff --git a/src/test/java/org/gnunet/construct/StringMessage.java b/src/test/java/org/gnunet/construct/StringMessage.java new file mode 100644 index 0000000..20158a1 --- /dev/null +++ b/src/test/java/org/gnunet/construct/StringMessage.java @@ -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; +} diff --git a/src/test/java/org/gnunet/construct/StringTest.java b/src/test/java/org/gnunet/construct/StringTest.java new file mode 100644 index 0000000..7dbedab --- /dev/null +++ b/src/test/java/org/gnunet/construct/StringTest.java @@ -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); + } +} + diff --git a/src/test/java/org/gnunet/construct/StringTuple.java b/src/test/java/org/gnunet/construct/StringTuple.java new file mode 100644 index 0000000..1820ae1 --- /dev/null +++ b/src/test/java/org/gnunet/construct/StringTuple.java @@ -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); + } +} diff --git a/src/test/java/org/gnunet/construct/VariableSizeArrayTest.java b/src/test/java/org/gnunet/construct/VariableSizeArrayTest.java new file mode 100644 index 0000000..e6772a1 --- /dev/null +++ b/src/test/java/org/gnunet/construct/VariableSizeArrayTest.java @@ -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]); + + } +} diff --git a/src/test/java/org/gnunet/construct/VariableSizeMessage.java b/src/test/java/org/gnunet/construct/VariableSizeMessage.java new file mode 100644 index 0000000..9444108 --- /dev/null +++ b/src/test/java/org/gnunet/construct/VariableSizeMessage.java @@ -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; +} diff --git a/src/test/java/org/gnunet/core/CoreTest.java b/src/test/java/org/gnunet/core/CoreTest.java new file mode 100644 index 0000000..0cb7817 --- /dev/null +++ b/src/test/java/org/gnunet/core/CoreTest.java @@ -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 res = new Wrapper(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 gotResponse = new Wrapper(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()); + + } +} diff --git a/src/test/java/org/gnunet/dht/DHTTest.java b/src/test/java/org/gnunet/dht/DHTTest.java new file mode 100644 index 0000000..9540af1 --- /dev/null +++ b/src/test/java/org/gnunet/dht/DHTTest.java @@ -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 putFinished = new Wrapper(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 getFinished = new Wrapper(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 getPath, List 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 putMonitorCount = new Wrapper(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 ok = new Wrapper(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()); + } + + +} + diff --git a/src/test/java/org/gnunet/mesh/MeshTest.java b/src/test/java/org/gnunet/mesh/MeshTest.java new file mode 100644 index 0000000..ad5eaa3 --- /dev/null +++ b/src/test/java/org/gnunet/mesh/MeshTest.java @@ -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 tunnel = mesh2.createTunnel(null, 42, false, true, null); + tunnel.send(new TestMessage()); + Scheduler.run(); + } +} diff --git a/src/test/java/org/gnunet/nse/NSETest.java b/src/test/java/org/gnunet/nse/NSETest.java new file mode 100644 index 0000000..c3e6512 --- /dev/null +++ b/src/test/java/org/gnunet/nse/NSETest.java @@ -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 gotResult = new Wrapper(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()); + } +} diff --git a/src/test/java/org/gnunet/peerinfo/PeerInfoTest.java b/src/test/java/org/gnunet/peerinfo/PeerInfoTest.java new file mode 100644 index 0000000..4239731 --- /dev/null +++ b/src/test/java/org/gnunet/peerinfo/PeerInfoTest.java @@ -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 ended = new Wrapper(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()); + } +} diff --git a/src/test/java/org/gnunet/statistics/StatisticsTest.java b/src/test/java/org/gnunet/statistics/StatisticsTest.java new file mode 100644 index 0000000..f4bdbe9 --- /dev/null +++ b/src/test/java/org/gnunet/statistics/StatisticsTest.java @@ -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 contReached = new Wrapper(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(); + } +} diff --git a/src/test/java/org/gnunet/testing/TestingSetupTest.java b/src/test/java/org/gnunet/testing/TestingSetupTest.java new file mode 100644 index 0000000..263d88f --- /dev/null +++ b/src/test/java/org/gnunet/testing/TestingSetupTest.java @@ -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(); + } +} diff --git a/src/test/java/org/gnunet/util/Assertion.java b/src/test/java/org/gnunet/util/Assertion.java new file mode 100644 index 0000000..3636aa8 --- /dev/null +++ b/src/test/java/org/gnunet/util/Assertion.java @@ -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; + } +} diff --git a/src/test/java/org/gnunet/util/AssertionList.java b/src/test/java/org/gnunet/util/AssertionList.java new file mode 100644 index 0000000..d80ed0e --- /dev/null +++ b/src/test/java/org/gnunet/util/AssertionList.java @@ -0,0 +1,30 @@ +package org.gnunet.util; + +import java.util.LinkedList; +import java.util.List; + +public class AssertionList { + + List asyncAssertions = new LinkedList(); + + + 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)); + } + } + } + +} diff --git a/src/test/java/org/gnunet/util/ClientServerTest.java b/src/test/java/org/gnunet/util/ClientServerTest.java new file mode 100644 index 0000000..616ce98 --- /dev/null +++ b/src/test/java/org/gnunet/util/ClientServerTest.java @@ -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 gotMessage = new Wrapper(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 msgCount = new Wrapper(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 msgCount = new Wrapper(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 msgCount = new Wrapper(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); + } + }); + } +} diff --git a/src/test/java/org/gnunet/util/FilePipeExample.java b/src/test/java/org/gnunet/util/FilePipeExample.java new file mode 100644 index 0000000..94696c9 --- /dev/null +++ b/src/test/java/org/gnunet/util/FilePipeExample.java @@ -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(); + } +} diff --git a/src/test/java/org/gnunet/util/ResolverTest.java b/src/test/java/org/gnunet/util/ResolverTest.java new file mode 100644 index 0000000..ae56b79 --- /dev/null +++ b/src/test/java/org/gnunet/util/ResolverTest.java @@ -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 finished1 = new Wrapper(true); + final Wrapper finished2 = new Wrapper(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()); + } +} + diff --git a/src/test/java/org/gnunet/util/ServerExample.java b/src/test/java/org/gnunet/util/ServerExample.java new file mode 100644 index 0000000..a344e2a --- /dev/null +++ b/src/test/java/org/gnunet/util/ServerExample.java @@ -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(); + } +} diff --git a/src/test/java/org/gnunet/util/StringsTest.java b/src/test/java/org/gnunet/util/StringsTest.java new file mode 100644 index 0000000..49cbfe9 --- /dev/null +++ b/src/test/java/org/gnunet/util/StringsTest.java @@ -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); + } +} + diff --git a/src/test/java/org/gnunet/util/TimeTest.java b/src/test/java/org/gnunet/util/TimeTest.java new file mode 100644 index 0000000..92115a8 --- /dev/null +++ b/src/test/java/org/gnunet/util/TimeTest.java @@ -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()); + } +} diff --git a/src/test/java/org/gnunet/util/Wrapper.java b/src/test/java/org/gnunet/util/Wrapper.java new file mode 100644 index 0000000..be84b54 --- /dev/null +++ b/src/test/java/org/gnunet/util/Wrapper.java @@ -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 type of the stored value + */ +public class Wrapper { + 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; + } +} diff --git a/src/test/java/org/gnunet/util/getopt/GetoptTest.java b/src/test/java/org/gnunet/util/getopt/GetoptTest.java new file mode 100644 index 0000000..010c240 --- /dev/null +++ b/src/test/java/org/gnunet/util/getopt/GetoptTest.java @@ -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"}); + } +} diff --git a/src/test/java/org/grothoff/RunaboutBenchmark.java b/src/test/java/org/grothoff/RunaboutBenchmark.java new file mode 100644 index 0000000..18f456d --- /dev/null +++ b/src/test/java/org/grothoff/RunaboutBenchmark.java @@ -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); + + } +} -- cgit v1.2.3